Commit cbaadc3a77b99126978e39c768bbf08fdceaf352

Authored by niou233
2 parents 5facac73 4ae3d348

Merge branch 'feature/mall_product' of https://gitee.com/zhijiantianya/ruoyi-vue…

…-pro into feature/mall_product_org
Showing 266 changed files with 3598 additions and 2181 deletions
README.md
@@ -256,7 +256,7 @@ _鍓嶇鍩轰簬 crmeb uniapp 缁忚繃鎺堟潈閲嶆瀯锛屼紭鍖栦唬鐮佸疄鐜帮紝鎺ュ叆鑺嬮 @@ -256,7 +256,7 @@ _鍓嶇鍩轰簬 crmeb uniapp 缁忚繃鎺堟潈閲嶆瀯锛屼紭鍖栦唬鐮佸疄鐜帮紝鎺ュ叆鑺嬮
256 256
257 | 妗嗘灦 | 璇存槑 | 鐗堟湰 | 瀛︿範鎸囧崡 | 257 | 妗嗘灦 | 璇存槑 | 鐗堟湰 | 瀛︿範鎸囧崡 |
258 |---------------------------------------------------------------------------------------------|------------------|----------------|----------------------------------------------------------------| 258 |---------------------------------------------------------------------------------------------|------------------|----------------|----------------------------------------------------------------|
259 -| [Spring Boot](https://spring.io/projects/spring-boot) | 搴旂敤寮鍙戞鏋 | 2.7.16 | [鏂囨。](https://github.com/YunaiV/SpringBoot-Labs) | 259 +| [Spring Boot](https://spring.io/projects/spring-boot) | 搴旂敤寮鍙戞鏋 | 2.7.17 | [鏂囨。](https://github.com/YunaiV/SpringBoot-Labs) |
260 | [MySQL](https://www.mysql.com/cn/) | 鏁版嵁搴撴湇鍔″櫒 | 5.7 / 8.0+ | | 260 | [MySQL](https://www.mysql.com/cn/) | 鏁版嵁搴撴湇鍔″櫒 | 5.7 / 8.0+ | |
261 | [Druid](https://github.com/alibaba/druid) | JDBC 杩炴帴姹犮佺洃鎺х粍浠 | 1.2.19 | [鏂囨。](http://www.iocoder.cn/Spring-Boot/datasource-pool/?yudao) | 261 | [Druid](https://github.com/alibaba/druid) | JDBC 杩炴帴姹犮佺洃鎺х粍浠 | 1.2.19 | [鏂囨。](http://www.iocoder.cn/Spring-Boot/datasource-pool/?yudao) |
262 | [MyBatis Plus](https://mp.baomidou.com/) | MyBatis 澧炲己宸ュ叿鍖 | 3.5.3.2 | [鏂囨。](http://www.iocoder.cn/Spring-Boot/MyBatis/?yudao) | 262 | [MyBatis Plus](https://mp.baomidou.com/) | MyBatis 澧炲己宸ュ叿鍖 | 3.5.3.2 | [鏂囨。](http://www.iocoder.cn/Spring-Boot/MyBatis/?yudao) |
@@ -13,16 +13,16 @@ @@ -13,16 +13,16 @@
13 <!-- Server 主项目 --> 13 <!-- Server 主项目 -->
14 <module>yudao-server</module> 14 <module>yudao-server</module>
15 <!-- 各种 module 拓展 --> 15 <!-- 各种 module 拓展 -->
16 - <module>yudao-module-member</module>  
17 <module>yudao-module-system</module> 16 <module>yudao-module-system</module>
18 <module>yudao-module-infra</module> 17 <module>yudao-module-infra</module>
19 - <!-- <module>yudao-module-bpm</module>--> 18 + <module>yudao-module-member</module>
  19 +<!-- <module>yudao-module-bpm</module>-->
20 <!-- <module>yudao-module-report</module>--> 20 <!-- <module>yudao-module-report</module>-->
21 <!-- <module>yudao-module-mp</module>--> 21 <!-- <module>yudao-module-mp</module>-->
22 <module>yudao-module-pay</module> 22 <module>yudao-module-pay</module>
23 <module>yudao-module-mall</module> 23 <module>yudao-module-mall</module>
24 <!-- 示例项目 --> 24 <!-- 示例项目 -->
25 - <module>yudao-example</module> 25 +<!-- <module>yudao-example</module>-->
26 </modules> 26 </modules>
27 27
28 <name>${project.artifactId}</name> 28 <name>${project.artifactId}</name>
@@ -30,7 +30,7 @@ @@ -30,7 +30,7 @@
30 <url>https://github.com/YunaiV/ruoyi-vue-pro</url> 30 <url>https://github.com/YunaiV/ruoyi-vue-pro</url>
31 31
32 <properties> 32 <properties>
33 - <revision>1.8.2-snapshot</revision> 33 + <revision>1.8.3-snapshot</revision>
34 <!-- Maven 相关 --> 34 <!-- Maven 相关 -->
35 <java.version>1.8</java.version> 35 <java.version>1.8</java.version>
36 <maven.compiler.source>${java.version}</maven.compiler.source> 36 <maven.compiler.source>${java.version}</maven.compiler.source>
@@ -40,7 +40,7 @@ @@ -40,7 +40,7 @@
40 <flatten-maven-plugin.version>1.5.0</flatten-maven-plugin.version> 40 <flatten-maven-plugin.version>1.5.0</flatten-maven-plugin.version>
41 <!-- 看看咋放到 bom 里 --> 41 <!-- 看看咋放到 bom 里 -->
42 <lombok.version>1.18.30</lombok.version> 42 <lombok.version>1.18.30</lombok.version>
43 - <spring.boot.version>2.7.16</spring.boot.version> 43 + <spring.boot.version>2.7.17</spring.boot.version>
44 <mapstruct.version>1.5.5.Final</mapstruct.version> 44 <mapstruct.version>1.5.5.Final</mapstruct.version>
45 <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> 45 <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
46 </properties> 46 </properties>
sql/mysql/pay_wallet.sql
@@ -224,14 +224,33 @@ VALUES ( @@ -224,14 +224,33 @@ VALUES (
224 ); 224 );
225 225
226 -- 转账状态和转账类型数据字典 226 -- 转账状态和转账类型数据字典
227 -INSERT INTO `system_dict_type`(`id`, `name`, `type`, `status`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `deleted_time`) VALUES (171, '支付转账类型', 'pay_transfer_type', 0, '', '1', '2023-10-28 16:27:18', '1', '2023-10-28 16:27:18', b'0', '1970-01-01 00:00:00');  
228 -INSERT INTO `system_dict_type`(`id`, `name`, `type`, `status`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `deleted_time`) VALUES (170, '转账订单状态', 'pay_transfer_status', 0, '', '1', '2023-10-28 16:18:32', '1', '2023-10-28 16:18:32', b'0', '1970-01-01 00:00:00');  
229 -  
230 -INSERT INTO `system_dict_data`(`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1245, 4, '钱包余额', '4', 'pay_transfer_type', 0, 'info', '', '', '1', '2023-10-28 16:28:37', '1', '2023-10-28 16:28:37', b'0');  
231 -INSERT INTO `system_dict_data`(`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1244, 3, '银行卡', '3', 'pay_transfer_type', 0, 'default', '', '', '1', '2023-10-28 16:28:21', '1', '2023-10-28 16:28:21', b'0');  
232 -INSERT INTO `system_dict_data`(`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1243, 2, '微信余额', '2', 'pay_transfer_type', 0, 'info', '', '', '1', '2023-10-28 16:28:07', '1', '2023-10-28 16:28:07', b'0');  
233 -INSERT INTO `system_dict_data`(`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1242, 1, '支付宝余额', '1', 'pay_transfer_type', 0, 'default', '', '', '1', '2023-10-28 16:27:44', '1', '2023-10-28 16:27:44', b'0');  
234 -INSERT INTO `system_dict_data`(`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1241, 4, '转账失败', '30', 'pay_transfer_status', 0, 'warning', '', '', '1', '2023-10-28 16:24:16', '1', '2023-10-28 16:24:16', b'0');  
235 -INSERT INTO `system_dict_data`(`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1240, 3, '转账成功', '20', 'pay_transfer_status', 0, 'success', '', '', '1', '2023-10-28 16:23:50', '1', '2023-10-28 16:23:50', b'0');  
236 -INSERT INTO `system_dict_data`(`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1239, 2, '转账进行中', '10', 'pay_transfer_status', 0, 'info', '', '', '1', '2023-10-28 16:23:12', '1', '2023-10-28 16:23:12', b'0');  
237 -INSERT INTO `system_dict_data`(`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1238, 1, '等待转账', '0', 'pay_transfer_status', 0, 'default', '', '', '1', '2023-10-28 16:21:43', '1', '2023-10-28 16:23:22', b'0'); 227 +INSERT INTO `system_dict_type`(`name`, `type`, `status`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `deleted_time`) VALUES ('支付转账类型', 'pay_transfer_type', 0, '', '1', '2023-10-28 16:27:18', '1', '2023-10-28 16:27:18', b'0', '1970-01-01 00:00:00');
  228 +INSERT INTO `system_dict_type`(`name`, `type`, `status`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `deleted_time`) VALUES ('转账订单状态', 'pay_transfer_status', 0, '', '1', '2023-10-28 16:18:32', '1', '2023-10-28 16:18:32', b'0', '1970-01-01 00:00:00');
  229 +
  230 +INSERT INTO `system_dict_data`(`sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (4, '钱包余额', '4', 'pay_transfer_type', 0, 'info', '', '', '1', '2023-10-28 16:28:37', '1', '2023-10-28 16:28:37', b'0');
  231 +INSERT INTO `system_dict_data`(`sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (3, '银行卡', '3', 'pay_transfer_type', 0, 'default', '', '', '1', '2023-10-28 16:28:21', '1', '2023-10-28 16:28:21', b'0');
  232 +INSERT INTO `system_dict_data`(`sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2, '微信余额', '2', 'pay_transfer_type', 0, 'info', '', '', '1', '2023-10-28 16:28:07', '1', '2023-10-28 16:28:07', b'0');
  233 +INSERT INTO `system_dict_data`(`sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1, '支付宝余额', '1', 'pay_transfer_type', 0, 'default', '', '', '1', '2023-10-28 16:27:44', '1', '2023-10-28 16:27:44', b'0');
  234 +INSERT INTO `system_dict_data`(`sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (4, '转账失败', '30', 'pay_transfer_status', 0, 'warning', '', '', '1', '2023-10-28 16:24:16', '1', '2023-10-28 16:24:16', b'0');
  235 +INSERT INTO `system_dict_data`(`sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (3, '转账成功', '20', 'pay_transfer_status', 0, 'success', '', '', '1', '2023-10-28 16:23:50', '1', '2023-10-28 16:23:50', b'0');
  236 +INSERT INTO `system_dict_data`(`sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2, '转账进行中', '10', 'pay_transfer_status', 0, 'info', '', '', '1', '2023-10-28 16:23:12', '1', '2023-10-28 16:23:12', b'0');
  237 +INSERT INTO `system_dict_data`(`sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1, '等待转账', '0', 'pay_transfer_status', 0, 'default', '', '', '1', '2023-10-28 16:21:43', '1', '2023-10-28 16:23:22', b'0');
  238 +
  239 +-- 转账订单菜单脚本
  240 +
  241 +INSERT INTO system_menu(
  242 + name, permission, type, sort, parent_id,
  243 + path, icon, component, status, component_name
  244 +)
  245 +VALUES (
  246 + '转账订单', '', 2, 3, 1117,
  247 + 'transfer', 'ep:credit-card', 'pay/transfer/index', 0, 'PayTransfer'
  248 + );
  249 +
  250 +-- 转账通知脚本
  251 +
  252 +ALTER TABLE `pay_app`
  253 + ADD COLUMN `transfer_notify_url` varchar(1024) NOT NULL COMMENT '转账结果的回调地址' AFTER `refund_notify_url`;
  254 +ALTER TABLE `pay_notify_task`
  255 + MODIFY COLUMN `merchant_order_id` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci COMMENT '商户订单编号' AFTER `status`,
  256 + ADD COLUMN `merchant_transfer_id` varchar(64) COMMENT '商户转账单编号' AFTER `merchant_order_id`;
238 \ No newline at end of file 257 \ No newline at end of file
sql/mysql/ruoyi-vue-pro.sql
@@ -11,7 +11,7 @@ @@ -11,7 +11,7 @@
11 Target Server Version : 80034 11 Target Server Version : 80034
12 File Encoding : 65001 12 File Encoding : 65001
13 13
14 - Date: 18/10/2023 23:33:15 14 + Date: 04/11/2023 20:42:49
15 */ 15 */
16 16
17 SET NAMES utf8mb4; 17 SET NAMES utf8mb4;
@@ -341,7 +341,8 @@ CREATE TABLE `infra_api_access_log` ( @@ -341,7 +341,8 @@ CREATE TABLE `infra_api_access_log` (
341 `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间', 341 `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
342 `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除', 342 `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除',
343 `tenant_id` bigint NOT NULL DEFAULT 0 COMMENT '租户编号', 343 `tenant_id` bigint NOT NULL DEFAULT 0 COMMENT '租户编号',
344 - PRIMARY KEY (`id`) USING BTREE 344 + PRIMARY KEY (`id`) USING BTREE,
  345 + INDEX `idx_create_time`(`create_time` ASC) USING BTREE
345 ) ENGINE = InnoDB AUTO_INCREMENT = 35832 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = 'API 访问日志表'; 346 ) ENGINE = InnoDB AUTO_INCREMENT = 35832 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = 'API 访问日志表';
346 347
347 -- ---------------------------- 348 -- ----------------------------
@@ -384,7 +385,7 @@ CREATE TABLE `infra_api_error_log` ( @@ -384,7 +385,7 @@ CREATE TABLE `infra_api_error_log` (
384 `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除', 385 `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除',
385 `tenant_id` bigint NOT NULL DEFAULT 0 COMMENT '租户编号', 386 `tenant_id` bigint NOT NULL DEFAULT 0 COMMENT '租户编号',
386 PRIMARY KEY (`id`) USING BTREE 387 PRIMARY KEY (`id`) USING BTREE
387 -) ENGINE = InnoDB AUTO_INCREMENT = 1739 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '系统异常日志'; 388 +) ENGINE = InnoDB AUTO_INCREMENT = 1781 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '系统异常日志';
388 389
389 -- ---------------------------- 390 -- ----------------------------
390 -- Records of infra_api_error_log 391 -- Records of infra_api_error_log
@@ -422,7 +423,7 @@ CREATE TABLE `infra_codegen_column` ( @@ -422,7 +423,7 @@ CREATE TABLE `infra_codegen_column` (
422 `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间', 423 `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
423 `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除', 424 `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除',
424 PRIMARY KEY (`id`) USING BTREE 425 PRIMARY KEY (`id`) USING BTREE
425 -) ENGINE = InnoDB AUTO_INCREMENT = 1805 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '代码生成表字段定义'; 426 +) ENGINE = InnoDB AUTO_INCREMENT = 1804 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '代码生成表字段定义';
426 427
427 -- ---------------------------- 428 -- ----------------------------
428 -- Records of infra_codegen_column 429 -- Records of infra_codegen_column
@@ -455,7 +456,7 @@ CREATE TABLE `infra_codegen_table` ( @@ -455,7 +456,7 @@ CREATE TABLE `infra_codegen_table` (
455 `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间', 456 `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
456 `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除', 457 `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除',
457 PRIMARY KEY (`id`) USING BTREE 458 PRIMARY KEY (`id`) USING BTREE
458 -) ENGINE = InnoDB AUTO_INCREMENT = 137 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '代码生成表定义'; 459 +) ENGINE = InnoDB AUTO_INCREMENT = 136 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '代码生成表定义';
459 460
460 -- ---------------------------- 461 -- ----------------------------
461 -- Records of infra_codegen_table 462 -- Records of infra_codegen_table
@@ -538,7 +539,7 @@ CREATE TABLE `infra_file` ( @@ -538,7 +539,7 @@ CREATE TABLE `infra_file` (
538 `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间', 539 `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
539 `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除', 540 `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除',
540 PRIMARY KEY (`id`) USING BTREE 541 PRIMARY KEY (`id`) USING BTREE
541 -) ENGINE = InnoDB AUTO_INCREMENT = 1098 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '文件表'; 542 +) ENGINE = InnoDB AUTO_INCREMENT = 1108 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '文件表';
542 543
543 -- ---------------------------- 544 -- ----------------------------
544 -- Records of infra_file 545 -- Records of infra_file
@@ -587,7 +588,7 @@ CREATE TABLE `infra_file_content` ( @@ -587,7 +588,7 @@ CREATE TABLE `infra_file_content` (
587 `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间', 588 `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
588 `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除', 589 `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除',
589 PRIMARY KEY (`id`) USING BTREE 590 PRIMARY KEY (`id`) USING BTREE
590 -) ENGINE = InnoDB AUTO_INCREMENT = 191 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '文件表'; 591 +) ENGINE = InnoDB AUTO_INCREMENT = 202 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '文件表';
591 592
592 -- ---------------------------- 593 -- ----------------------------
593 -- Records of infra_file_content 594 -- Records of infra_file_content
@@ -615,7 +616,7 @@ CREATE TABLE `infra_job` ( @@ -615,7 +616,7 @@ CREATE TABLE `infra_job` (
615 `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间', 616 `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
616 `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除', 617 `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除',
617 PRIMARY KEY (`id`) USING BTREE 618 PRIMARY KEY (`id`) USING BTREE
618 -) ENGINE = InnoDB AUTO_INCREMENT = 28 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '定时任务表'; 619 +) ENGINE = InnoDB AUTO_INCREMENT = 27 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '定时任务表';
619 620
620 -- ---------------------------- 621 -- ----------------------------
621 -- Records of infra_job 622 -- Records of infra_job
@@ -656,7 +657,7 @@ CREATE TABLE `infra_job_log` ( @@ -656,7 +657,7 @@ CREATE TABLE `infra_job_log` (
656 `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间', 657 `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
657 `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除', 658 `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除',
658 PRIMARY KEY (`id`) USING BTREE 659 PRIMARY KEY (`id`) USING BTREE
659 -) ENGINE = InnoDB AUTO_INCREMENT = 233 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '定时任务日志表'; 660 +) ENGINE = InnoDB AUTO_INCREMENT = 232 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '定时任务日志表';
660 661
661 -- ---------------------------- 662 -- ----------------------------
662 -- Records of infra_job_log 663 -- Records of infra_job_log
@@ -709,7 +710,7 @@ CREATE TABLE `member_address` ( @@ -709,7 +710,7 @@ CREATE TABLE `member_address` (
709 `tenant_id` bigint NOT NULL DEFAULT 0 COMMENT '租户编号', 710 `tenant_id` bigint NOT NULL DEFAULT 0 COMMENT '租户编号',
710 PRIMARY KEY (`id`) USING BTREE, 711 PRIMARY KEY (`id`) USING BTREE,
711 INDEX `idx_userId`(`user_id` ASC) USING BTREE 712 INDEX `idx_userId`(`user_id` ASC) USING BTREE
712 -) ENGINE = InnoDB AUTO_INCREMENT = 25 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_bin COMMENT = '用户收件地址'; 713 +) ENGINE = InnoDB AUTO_INCREMENT = 24 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_bin COMMENT = '用户收件地址';
713 714
714 -- ---------------------------- 715 -- ----------------------------
715 -- Records of member_address 716 -- Records of member_address
@@ -807,6 +808,7 @@ INSERT INTO `member_experience_record` (`id`, `user_id`, `biz_id`, `biz_type`, ` @@ -807,6 +808,7 @@ INSERT INTO `member_experience_record` (`id`, `user_id`, `biz_id`, `biz_type`, `
807 INSERT INTO `member_experience_record` (`id`, `user_id`, `biz_id`, `biz_type`, `title`, `description`, `experience`, `total_experience`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (34, 248, '125', 11, '下单奖励', '下单获得 700100 经验', 700100, 700100, NULL, '2023-10-11 07:33:29', NULL, '2023-10-11 07:33:29', b'0', 1); 808 INSERT INTO `member_experience_record` (`id`, `user_id`, `biz_id`, `biz_type`, `title`, `description`, `experience`, `total_experience`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (34, 248, '125', 11, '下单奖励', '下单获得 700100 经验', 700100, 700100, NULL, '2023-10-11 07:33:29', NULL, '2023-10-11 07:33:29', b'0', 1);
808 INSERT INTO `member_experience_record` (`id`, `user_id`, `biz_id`, `biz_type`, `title`, `description`, `experience`, `total_experience`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (37, 248, '127', 11, '下单奖励', '下单获得 385145 经验', 385145, 385145, NULL, '2023-10-11 07:36:44', NULL, '2023-10-11 07:36:44', b'0', 1); 809 INSERT INTO `member_experience_record` (`id`, `user_id`, `biz_id`, `biz_type`, `title`, `description`, `experience`, `total_experience`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (37, 248, '127', 11, '下单奖励', '下单获得 385145 经验', 385145, 385145, NULL, '2023-10-11 07:36:44', NULL, '2023-10-11 07:36:44', b'0', 1);
809 INSERT INTO `member_experience_record` (`id`, `user_id`, `biz_id`, `biz_type`, `title`, `description`, `experience`, `total_experience`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (40, 248, '120', 13, '下单奖励(单个取消)', '退款订单获得 -385145 经验', -385145, 0, '1', '2023-10-11 07:39:26', '1', '2023-10-11 07:39:26', b'0', 1); 810 INSERT INTO `member_experience_record` (`id`, `user_id`, `biz_id`, `biz_type`, `title`, `description`, `experience`, `total_experience`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (40, 248, '120', 13, '下单奖励(单个取消)', '退款订单获得 -385145 经验', -385145, 0, '1', '2023-10-11 07:39:26', '1', '2023-10-11 07:39:26', b'0', 1);
  811 +INSERT INTO `member_experience_record` (`id`, `user_id`, `biz_id`, `biz_type`, `title`, `description`, `experience`, `total_experience`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (41, 248, '131', 11, '下单奖励', '下单获得 700100 经验', 700100, 700100, NULL, '2023-10-24 12:33:22', NULL, '2023-10-24 12:33:22', b'0', 1);
810 COMMIT; 812 COMMIT;
811 813
812 -- ---------------------------- 814 -- ----------------------------
@@ -825,7 +827,7 @@ CREATE TABLE `member_group` ( @@ -825,7 +827,7 @@ CREATE TABLE `member_group` (
825 `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除', 827 `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除',
826 `tenant_id` bigint NOT NULL DEFAULT 0 COMMENT '租户编号', 828 `tenant_id` bigint NOT NULL DEFAULT 0 COMMENT '租户编号',
827 PRIMARY KEY (`id`) USING BTREE 829 PRIMARY KEY (`id`) USING BTREE
828 -) ENGINE = InnoDB AUTO_INCREMENT = 2 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '用户分组'; 830 +) ENGINE = InnoDB AUTO_INCREMENT = 1 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '用户分组';
829 831
830 -- ---------------------------- 832 -- ----------------------------
831 -- Records of member_group 833 -- Records of member_group
@@ -853,7 +855,7 @@ CREATE TABLE `member_level` ( @@ -853,7 +855,7 @@ CREATE TABLE `member_level` (
853 `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除', 855 `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除',
854 `tenant_id` bigint NOT NULL DEFAULT 0 COMMENT '租户编号', 856 `tenant_id` bigint NOT NULL DEFAULT 0 COMMENT '租户编号',
855 PRIMARY KEY (`id`) USING BTREE 857 PRIMARY KEY (`id`) USING BTREE
856 -) ENGINE = InnoDB AUTO_INCREMENT = 4 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '会员等级'; 858 +) ENGINE = InnoDB AUTO_INCREMENT = 3 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '会员等级';
857 859
858 -- ---------------------------- 860 -- ----------------------------
859 -- Records of member_level 861 -- Records of member_level
@@ -971,6 +973,7 @@ INSERT INTO `member_point_record` (`id`, `user_id`, `biz_id`, `biz_type`, `title @@ -971,6 +973,7 @@ INSERT INTO `member_point_record` (`id`, `user_id`, `biz_id`, `biz_type`, `title
971 INSERT INTO `member_point_record` (`id`, `user_id`, `biz_id`, `biz_type`, `title`, `description`, `point`, `total_point`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (53, 248, '125', 21, '订单积分奖励', '下单获得 21003 积分', 21003, 21003, NULL, '2023-10-11 07:33:29', NULL, '2023-10-11 07:33:29', b'0', 1); 973 INSERT INTO `member_point_record` (`id`, `user_id`, `biz_id`, `biz_type`, `title`, `description`, `point`, `total_point`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (53, 248, '125', 21, '订单积分奖励', '下单获得 21003 积分', 21003, 21003, NULL, '2023-10-11 07:33:29', NULL, '2023-10-11 07:33:29', b'0', 1);
972 INSERT INTO `member_point_record` (`id`, `user_id`, `biz_id`, `biz_type`, `title`, `description`, `point`, `total_point`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (56, 248, '127', 21, '订单积分奖励', '下单获得 11554 积分', 11554, 11554, NULL, '2023-10-11 07:36:44', NULL, '2023-10-11 07:36:44', b'0', 1); 974 INSERT INTO `member_point_record` (`id`, `user_id`, `biz_id`, `biz_type`, `title`, `description`, `point`, `total_point`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (56, 248, '127', 21, '订单积分奖励', '下单获得 11554 积分', 11554, 11554, NULL, '2023-10-11 07:36:44', NULL, '2023-10-11 07:36:44', b'0', 1);
973 INSERT INTO `member_point_record` (`id`, `user_id`, `biz_id`, `biz_type`, `title`, `description`, `point`, `total_point`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (59, 248, '120', 23, '订单积分奖励(单个退款)', '订单退款,扣除赠送的 -11554 积分', -11554, 0, '1', '2023-10-11 07:39:26', '1', '2023-10-11 07:39:26', b'0', 1); 975 INSERT INTO `member_point_record` (`id`, `user_id`, `biz_id`, `biz_type`, `title`, `description`, `point`, `total_point`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (59, 248, '120', 23, '订单积分奖励(单个退款)', '订单退款,扣除赠送的 -11554 积分', -11554, 0, '1', '2023-10-11 07:39:26', '1', '2023-10-11 07:39:26', b'0', 1);
  976 +INSERT INTO `member_point_record` (`id`, `user_id`, `biz_id`, `biz_type`, `title`, `description`, `point`, `total_point`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (60, 248, '131', 21, '订单积分奖励', '下单获得 21003 积分', 21003, 21003, NULL, '2023-10-24 12:33:22', NULL, '2023-10-24 12:33:22', b'0', 1);
974 COMMIT; 977 COMMIT;
975 978
976 -- ---------------------------- 979 -- ----------------------------
@@ -1052,7 +1055,7 @@ CREATE TABLE `member_tag` ( @@ -1052,7 +1055,7 @@ CREATE TABLE `member_tag` (
1052 `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除', 1055 `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除',
1053 `tenant_id` bigint NOT NULL DEFAULT 0 COMMENT '租户编号', 1056 `tenant_id` bigint NOT NULL DEFAULT 0 COMMENT '租户编号',
1054 PRIMARY KEY (`id`) USING BTREE 1057 PRIMARY KEY (`id`) USING BTREE
1055 -) ENGINE = InnoDB AUTO_INCREMENT = 3 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '会员标签'; 1058 +) ENGINE = InnoDB AUTO_INCREMENT = 2 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '会员标签';
1056 1059
1057 -- ---------------------------- 1060 -- ----------------------------
1058 -- Records of member_tag 1061 -- Records of member_tag
@@ -1162,7 +1165,7 @@ CREATE TABLE `system_dict_data` ( @@ -1162,7 +1165,7 @@ CREATE TABLE `system_dict_data` (
1162 `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间', 1165 `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
1163 `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除', 1166 `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除',
1164 PRIMARY KEY (`id`) USING BTREE 1167 PRIMARY KEY (`id`) USING BTREE
1165 -) ENGINE = InnoDB AUTO_INCREMENT = 1398 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '字典数据表'; 1168 +) ENGINE = InnoDB AUTO_INCREMENT = 1435 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '字典数据表';
1166 1169
1167 -- ---------------------------- 1170 -- ----------------------------
1168 -- Records of system_dict_data 1171 -- Records of system_dict_data
@@ -1248,6 +1251,11 @@ INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `st @@ -1248,6 +1251,11 @@ INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `st
1248 INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (123, 10, '支付成功', '10', 'pay_order_status', 0, 'success', '', '支付成功', '1', '2021-12-03 11:18:29', '1', '2023-07-19 18:04:28', b'0'); 1251 INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (123, 10, '支付成功', '10', 'pay_order_status', 0, 'success', '', '支付成功', '1', '2021-12-03 11:18:29', '1', '2023-07-19 18:04:28', b'0');
1249 INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (124, 30, '支付关闭', '30', 'pay_order_status', 0, 'info', '', '支付关闭', '1', '2021-12-03 11:18:42', '1', '2023-07-19 18:05:07', b'0'); 1252 INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (124, 30, '支付关闭', '30', 'pay_order_status', 0, 'info', '', '支付关闭', '1', '2021-12-03 11:18:42', '1', '2023-07-19 18:05:07', b'0');
1250 INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (125, 0, '等待支付', '0', 'pay_order_status', 0, 'info', '', '未支付', '1', '2021-12-03 11:18:18', '1', '2023-07-19 18:04:15', b'0'); 1253 INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (125, 0, '等待支付', '0', 'pay_order_status', 0, 'info', '', '未支付', '1', '2021-12-03 11:18:18', '1', '2023-07-19 18:04:15', b'0');
  1254 +INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (600, 5, '首页', '1', 'promotion_banner_position', 0, 'warning', '', '', '1', '2023-10-11 07:45:24', '1', '2023-10-11 07:45:38', b'0');
  1255 +INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (601, 4, '秒杀活动页', '2', 'promotion_banner_position', 0, 'warning', '', '', '1', '2023-10-11 07:45:24', '1', '2023-10-11 07:45:38', b'0');
  1256 +INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (602, 3, '砍价活动页', '3', 'promotion_banner_position', 0, 'warning', '', '', '1', '2023-10-11 07:45:24', '1', '2023-10-11 07:45:38', b'0');
  1257 +INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (603, 2, '限时折扣页', '4', 'promotion_banner_position', 0, 'warning', '', '', '1', '2023-10-11 07:45:24', '1', '2023-10-11 07:45:38', b'0');
  1258 +INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (604, 1, '满减送页', '5', 'promotion_banner_position', 0, 'warning', '', '', '1', '2023-10-11 07:45:24', '1', '2023-10-11 07:45:38', b'0');
1251 INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1118, 0, '等待退款', '0', 'pay_refund_status', 0, 'info', '', '等待退款', '1', '2021-12-10 16:44:59', '1', '2023-07-19 10:14:39', b'0'); 1259 INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1118, 0, '等待退款', '0', 'pay_refund_status', 0, 'info', '', '等待退款', '1', '2021-12-10 16:44:59', '1', '2023-07-19 10:14:39', b'0');
1252 INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1119, 20, '退款失败', '20', 'pay_refund_status', 0, 'danger', '', '退款失败', '1', '2021-12-10 16:45:10', '1', '2023-07-19 10:15:10', b'0'); 1260 INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1119, 20, '退款失败', '20', 'pay_refund_status', 0, 'danger', '', '退款失败', '1', '2021-12-10 16:45:10', '1', '2023-07-19 10:15:10', b'0');
1253 INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1124, 10, '退款成功', '10', 'pay_refund_status', 0, 'success', '', '退款成功', '1', '2021-12-10 16:46:26', '1', '2023-07-19 10:15:00', b'0'); 1261 INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1124, 10, '退款成功', '10', 'pay_refund_status', 0, 'success', '', '退款成功', '1', '2021-12-10 16:46:26', '1', '2023-07-19 10:15:00', b'0');
@@ -1427,6 +1435,45 @@ INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `st @@ -1427,6 +1435,45 @@ INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `st
1427 INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1395, 22, '订单积分奖励(整单取消)', '22', 'member_point_biz_type', 0, 'default', '', '', '1', '2023-10-11 07:42:55', '1', '2023-10-11 07:43:01', b'0'); 1435 INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1395, 22, '订单积分奖励(整单取消)', '22', 'member_point_biz_type', 0, 'default', '', '', '1', '2023-10-11 07:42:55', '1', '2023-10-11 07:43:01', b'0');
1428 INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1396, 23, '订单积分奖励(单个退款)', '23', 'member_point_biz_type', 0, 'default', '', '', '1', '2023-10-11 07:43:16', '1', '2023-10-11 07:43:16', b'0'); 1436 INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1396, 23, '订单积分奖励(单个退款)', '23', 'member_point_biz_type', 0, 'default', '', '', '1', '2023-10-11 07:43:16', '1', '2023-10-11 07:43:16', b'0');
1429 INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1397, 13, '下单奖励(单个退款)', '13', 'member_experience_biz_type', 0, 'warning', '', '', '1', '2023-10-11 07:45:24', '1', '2023-10-11 07:45:38', b'0'); 1437 INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1397, 13, '下单奖励(单个退款)', '13', 'member_experience_biz_type', 0, 'warning', '', '', '1', '2023-10-11 07:45:24', '1', '2023-10-11 07:45:38', b'0');
  1438 +INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1402, 1, 'A 农、林、牧、渔业', '1', 'crm_customer_industry', 0, 'default', '', '', '1', '2023-10-28 23:02:15', '1', '2023-10-28 23:02:15', b'0');
  1439 +INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1403, 2, 'B 采矿业', '2', 'crm_customer_industry', 0, 'default', '', '', '1', '2023-10-28 23:02:29', '1', '2023-10-28 23:02:29', b'0');
  1440 +INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1404, 3, 'C 制造业', '3', 'crm_customer_industry', 0, 'default', '', '', '1', '2023-10-28 23:02:41', '1', '2023-10-28 23:02:41', b'0');
  1441 +INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1405, 4, 'D 电力、热力、燃气及水生产和供应业', '4', 'crm_customer_industry', 0, 'default', '', '', '1', '2023-10-28 23:02:54', '1', '2023-10-28 23:02:54', b'0');
  1442 +INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1406, 5, 'E 建筑业', '5', 'crm_customer_industry', 0, 'default', '', '', '1', '2023-10-28 23:03:03', '1', '2023-10-28 23:03:03', b'0');
  1443 +INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1407, 6, 'F 批发和零售业', '6', 'crm_customer_industry', 0, 'default', '', '', '1', '2023-10-28 23:03:13', '1', '2023-10-28 23:03:13', b'0');
  1444 +INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1408, 7, 'G 交通运输、仓储和邮政业', '7', 'crm_customer_industry', 0, 'default', '', '', '1', '2023-10-28 23:03:27', '1', '2023-10-28 23:03:27', b'0');
  1445 +INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1409, 8, 'H 住宿和餐饮业', '8', 'crm_customer_industry', 0, 'default', '', '', '1', '2023-10-28 23:03:37', '1', '2023-10-28 23:03:37', b'0');
  1446 +INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1410, 9, 'I 信息传输、软件和信息技术服务业', '9', 'crm_customer_industry', 0, 'default', '', '', '1', '2023-10-28 23:03:47', '1', '2023-10-28 23:03:47', b'0');
  1447 +INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1411, 10, 'J 金融业', '10', 'crm_customer_industry', 0, 'default', '', '', '1', '2023-10-28 23:03:57', '1', '2023-10-28 23:03:57', b'0');
  1448 +INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1412, 11, 'K 房地产业', '11', 'crm_customer_industry', 0, 'default', '', '', '1', '2023-10-28 23:04:15', '1', '2023-10-28 23:04:22', b'0');
  1449 +INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1413, 12, 'L 租赁和商务服务业', '12', 'crm_customer_industry', 0, 'default', '', '', '1', '2023-10-28 23:04:33', '1', '2023-10-28 23:04:33', b'0');
  1450 +INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1414, 13, 'M 科学研究和技术服务业', '13', 'crm_customer_industry', 0, 'default', '', '', '1', '2023-10-28 23:04:43', '1', '2023-10-28 23:04:43', b'0');
  1451 +INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1415, 14, 'N 水利、环境和公共设施管理业', '14', 'crm_customer_industry', 0, 'default', '', '', '1', '2023-10-28 23:04:53', '1', '2023-10-28 23:04:53', b'0');
  1452 +INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1416, 15, 'O 居民服务、修理和其他服务业', '15', 'crm_customer_industry', 0, 'default', '', '', '1', '2023-10-28 23:05:05', '1', '2023-10-28 23:05:05', b'0');
  1453 +INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1417, 16, 'P 教育', '16', 'crm_customer_industry', 0, 'default', '', '', '1', '2023-10-28 23:05:15', '1', '2023-10-28 23:05:15', b'0');
  1454 +INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1418, 17, 'Q 卫生和社会工作', '17', 'crm_customer_industry', 0, 'default', '', '', '1', '2023-10-28 23:05:44', '1', '2023-10-28 23:05:44', b'0');
  1455 +INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1419, 18, 'R 文化、体育和娱乐业', '18', 'crm_customer_industry', 0, 'default', '', '', '1', '2023-10-28 23:05:55', '1', '2023-10-28 23:05:55', b'0');
  1456 +INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1420, 19, 'S 公共管理、社会保障和社会组织', '19', 'crm_customer_industry', 0, 'default', '', '', '1', '2023-10-28 23:06:05', '1', '2023-10-28 23:06:05', b'0');
  1457 +INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1421, 20, 'T 国际组织', '20', 'crm_customer_industry', 0, 'default', '', '', '1', '2023-10-28 23:06:15', '1', '2023-10-28 23:06:15', b'0');
  1458 +INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1422, 1, 'A (重点客户)', '1', 'crm_customer_level', 0, 'primary', '', '', '1', '2023-10-28 23:07:13', '1', '2023-10-28 23:07:13', b'0');
  1459 +INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1423, 2, 'B (普通客户)', '2', 'crm_customer_level', 0, 'info', '', '', '1', '2023-10-28 23:07:35', '1', '2023-10-28 23:07:35', b'0');
  1460 +INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1424, 3, 'C (非优先客户)', '3', 'crm_customer_level', 0, 'default', '', '', '1', '2023-10-28 23:07:53', '1', '2023-10-28 23:07:53', b'0');
  1461 +INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1425, 1, '促销', '1', 'crm_customer_source', 0, 'default', '', '', '1', '2023-10-28 23:08:29', '1', '2023-10-28 23:08:29', b'0');
  1462 +INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1426, 2, '搜索引擎', '2', 'crm_customer_source', 0, 'default', '', '', '1', '2023-10-28 23:08:39', '1', '2023-10-28 23:08:39', b'0');
  1463 +INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1427, 3, '广告', '3', 'crm_customer_source', 0, 'default', '', '', '1', '2023-10-28 23:08:47', '1', '2023-10-28 23:08:47', b'0');
  1464 +INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1428, 4, '转介绍', '4', 'crm_customer_source', 0, 'default', '', '', '1', '2023-10-28 23:08:58', '1', '2023-10-28 23:08:58', b'0');
  1465 +INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1429, 5, '线上注册', '5', 'crm_customer_source', 0, 'default', '', '', '1', '2023-10-28 23:09:12', '1', '2023-10-28 23:09:12', b'0');
  1466 +INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1430, 6, '线上咨询', '6', 'crm_customer_source', 0, 'default', '', '', '1', '2023-10-28 23:09:22', '1', '2023-10-28 23:09:22', b'0');
  1467 +INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1431, 7, '预约上门', '7', 'crm_customer_source', 0, 'default', '', '', '1', '2023-10-28 23:09:39', '1', '2023-10-28 23:09:39', b'0');
  1468 +INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1432, 8, '陌拜', '8', 'crm_customer_source', 0, 'default', '', '', '1', '2023-10-28 23:10:04', '1', '2023-10-28 23:10:04', b'0');
  1469 +INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1433, 9, '电话咨询', '9', 'crm_customer_source', 0, 'default', '', '', '1', '2023-10-28 23:10:18', '1', '2023-10-28 23:10:18', b'0');
  1470 +INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1434, 10, '邮件咨询', '10', 'crm_customer_source', 0, 'default', '', '', '1', '2023-10-28 23:10:33', '1', '2023-10-28 23:10:33', b'0');
  1471 +INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1435, 10, 'Gitee', '10', 'system_social_type', 0, '', '', '', '1', '2023-11-04 13:04:42', '1', '2023-11-04 13:04:42', b'0');
  1472 +INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1436, 20, '钉钉', '20', 'system_social_type', 0, '', '', '', '1', '2023-11-04 13:04:54', '1', '2023-11-04 13:04:54', b'0');
  1473 +INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1437, 30, '企业微信', '30', 'system_social_type', 0, '', '', '', '1', '2023-11-04 13:05:09', '1', '2023-11-04 13:05:09', b'0');
  1474 +INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1438, 31, '微信公众平台', '31', 'system_social_type', 0, '', '', '', '1', '2023-11-04 13:05:18', '1', '2023-11-04 13:05:18', b'0');
  1475 +INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1439, 32, '微信开放平台', '32', 'system_social_type', 0, '', '', '', '1', '2023-11-04 13:05:30', '1', '2023-11-04 13:05:30', b'0');
  1476 +INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1440, 34, '微信小程序', '34', 'system_social_type', 0, '', '', '', '1', '2023-11-04 13:05:38', '1', '2023-11-04 13:07:16', b'0');
1430 COMMIT; 1477 COMMIT;
1431 1478
1432 -- ---------------------------- 1479 -- ----------------------------
@@ -1447,7 +1494,7 @@ CREATE TABLE `system_dict_type` ( @@ -1447,7 +1494,7 @@ CREATE TABLE `system_dict_type` (
1447 `deleted_time` datetime NULL DEFAULT NULL COMMENT '删除时间', 1494 `deleted_time` datetime NULL DEFAULT NULL COMMENT '删除时间',
1448 PRIMARY KEY (`id`) USING BTREE, 1495 PRIMARY KEY (`id`) USING BTREE,
1449 UNIQUE INDEX `dict_type`(`type` ASC) USING BTREE 1496 UNIQUE INDEX `dict_type`(`type` ASC) USING BTREE
1450 -) ENGINE = InnoDB AUTO_INCREMENT = 185 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '字典类型表'; 1497 +) ENGINE = InnoDB AUTO_INCREMENT = 600 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '字典类型表';
1451 1498
1452 -- ---------------------------- 1499 -- ----------------------------
1453 -- Records of system_dict_type 1500 -- Records of system_dict_type
@@ -1521,6 +1568,11 @@ INSERT INTO `system_dict_type` (`id`, `name`, `type`, `status`, `remark`, `creat @@ -1521,6 +1568,11 @@ INSERT INTO `system_dict_type` (`id`, `name`, `type`, `status`, `remark`, `creat
1521 INSERT INTO `system_dict_type` (`id`, `name`, `type`, `status`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `deleted_time`) VALUES (182, '佣金提现银行', 'brokerage_bank_name', 0, NULL, '', '2023-09-28 02:46:05', '', '2023-09-28 02:46:05', b'0', NULL); 1568 INSERT INTO `system_dict_type` (`id`, `name`, `type`, `status`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `deleted_time`) VALUES (182, '佣金提现银行', 'brokerage_bank_name', 0, NULL, '', '2023-09-28 02:46:05', '', '2023-09-28 02:46:05', b'0', NULL);
1522 INSERT INTO `system_dict_type` (`id`, `name`, `type`, `status`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `deleted_time`) VALUES (183, '砍价记录的状态', 'promotion_bargain_record_status', 0, '', '1', '2023-10-05 10:41:08', '1', '2023-10-05 10:41:08', b'0', '1970-01-01 00:00:00'); 1569 INSERT INTO `system_dict_type` (`id`, `name`, `type`, `status`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `deleted_time`) VALUES (183, '砍价记录的状态', 'promotion_bargain_record_status', 0, '', '1', '2023-10-05 10:41:08', '1', '2023-10-05 10:41:08', b'0', '1970-01-01 00:00:00');
1523 INSERT INTO `system_dict_type` (`id`, `name`, `type`, `status`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `deleted_time`) VALUES (184, '拼团记录的状态', 'promotion_combination_record_status', 0, '', '1', '2023-10-08 07:24:25', '1', '2023-10-08 07:24:25', b'0', '1970-01-01 00:00:00'); 1570 INSERT INTO `system_dict_type` (`id`, `name`, `type`, `status`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `deleted_time`) VALUES (184, '拼团记录的状态', 'promotion_combination_record_status', 0, '', '1', '2023-10-08 07:24:25', '1', '2023-10-08 07:24:25', b'0', '1970-01-01 00:00:00');
  1571 +INSERT INTO `system_dict_type` (`id`, `name`, `type`, `status`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `deleted_time`) VALUES (186, '客户所属行业', 'crm_customer_industry', 0, 'CRM 客户所属行业', '1', '2023-10-28 22:57:07', '1', '2023-10-28 15:11:16', b'0', NULL);
  1572 +INSERT INTO `system_dict_type` (`id`, `name`, `type`, `status`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `deleted_time`) VALUES (187, '客户等级', 'crm_customer_level', 0, 'CRM 客户等级', '1', '2023-10-28 22:59:12', '1', '2023-10-28 15:11:16', b'0', NULL);
  1573 +INSERT INTO `system_dict_type` (`id`, `name`, `type`, `status`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `deleted_time`) VALUES (188, '客户来源', 'crm_customer_source', 0, 'CRM 客户来源', '1', '2023-10-28 23:00:34', '1', '2023-10-28 15:11:16', b'0', NULL);
  1574 +INSERT INTO `system_dict_type` (`id`, `name`, `type`, `status`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `deleted_time`) VALUES (600, 'Banner 位置', 'promotion_banner_position', 0, '', '1', '2023-10-08 07:24:25', '1', '2023-11-04 13:04:02', b'0', '1970-01-01 00:00:00');
  1575 +INSERT INTO `system_dict_type` (`id`, `name`, `type`, `status`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `deleted_time`) VALUES (601, '社交类型', 'system_social_type', 0, '', '1', '2023-11-04 13:03:54', '1', '2023-11-04 13:03:54', b'0', '1970-01-01 00:00:00');
1524 COMMIT; 1576 COMMIT;
1525 1577
1526 -- ---------------------------- 1578 -- ----------------------------
@@ -1540,7 +1592,7 @@ CREATE TABLE `system_error_code` ( @@ -1540,7 +1592,7 @@ CREATE TABLE `system_error_code` (
1540 `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间', 1592 `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
1541 `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除', 1593 `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除',
1542 PRIMARY KEY (`id`) USING BTREE 1594 PRIMARY KEY (`id`) USING BTREE
1543 -) ENGINE = InnoDB AUTO_INCREMENT = 5933 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '错误码表'; 1595 +) ENGINE = InnoDB AUTO_INCREMENT = 5932 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '错误码表';
1544 1596
1545 -- ---------------------------- 1597 -- ----------------------------
1546 -- Records of system_error_code 1598 -- Records of system_error_code
@@ -1569,7 +1621,7 @@ CREATE TABLE `system_login_log` ( @@ -1569,7 +1621,7 @@ CREATE TABLE `system_login_log` (
1569 `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除', 1621 `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除',
1570 `tenant_id` bigint NOT NULL DEFAULT 0 COMMENT '租户编号', 1622 `tenant_id` bigint NOT NULL DEFAULT 0 COMMENT '租户编号',
1571 PRIMARY KEY (`id`) USING BTREE 1623 PRIMARY KEY (`id`) USING BTREE
1572 -) ENGINE = InnoDB AUTO_INCREMENT = 2599 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '系统访问记录'; 1624 +) ENGINE = InnoDB AUTO_INCREMENT = 2631 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '系统访问记录';
1573 1625
1574 -- ---------------------------- 1626 -- ----------------------------
1575 -- Records of system_login_log 1627 -- Records of system_login_log
@@ -1699,7 +1751,7 @@ CREATE TABLE `system_menu` ( @@ -1699,7 +1751,7 @@ CREATE TABLE `system_menu` (
1699 `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间', 1751 `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
1700 `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除', 1752 `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除',
1701 PRIMARY KEY (`id`) USING BTREE 1753 PRIMARY KEY (`id`) USING BTREE
1702 -) ENGINE = InnoDB AUTO_INCREMENT = 2389 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '菜单权限表'; 1754 +) ENGINE = InnoDB AUTO_INCREMENT = 2449 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '菜单权限表';
1703 1755
1704 -- ---------------------------- 1756 -- ----------------------------
1705 -- Records of system_menu 1757 -- Records of system_menu
@@ -1951,11 +2003,11 @@ INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_i @@ -1951,11 +2003,11 @@ INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_i
1951 INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2021, '规格创建', 'product:property:create', 3, 2, 2019, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2022-08-01 14:55:35', '', '2022-12-12 20:26:30', b'0'); 2003 INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2021, '规格创建', 'product:property:create', 3, 2, 2019, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2022-08-01 14:55:35', '', '2022-12-12 20:26:30', b'0');
1952 INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2022, '规格更新', 'product:property:update', 3, 3, 2019, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2022-08-01 14:55:35', '', '2022-12-12 20:26:33', b'0'); 2004 INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2022, '规格更新', 'product:property:update', 3, 3, 2019, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2022-08-01 14:55:35', '', '2022-12-12 20:26:33', b'0');
1953 INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2023, '规格删除', 'product:property:delete', 3, 4, 2019, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2022-08-01 14:55:35', '', '2022-12-12 20:26:37', b'0'); 2005 INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2023, '规格删除', 'product:property:delete', 3, 4, 2019, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2022-08-01 14:55:35', '', '2022-12-12 20:26:37', b'0');
1954 -INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2025, 'Banner管理', '', 2, 100, 2387, 'banner', 'fa:bandcamp', 'mall/market/banner/index', NULL, 0, b'1', b'1', b'1', '', '2022-08-01 14:56:14', '1', '2023-10-16 09:41:54', b'0');  
1955 -INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2026, 'Banner查询', 'market:banner:query', 3, 1, 2025, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2022-08-01 14:56:14', '', '2022-08-01 14:56:14', b'0');  
1956 -INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2027, 'Banner创建', 'market:banner:create', 3, 2, 2025, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2022-08-01 14:56:14', '', '2022-08-01 14:56:14', b'0');  
1957 -INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2028, 'Banner更新', 'market:banner:update', 3, 3, 2025, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2022-08-01 14:56:14', '', '2022-08-01 14:56:14', b'0');  
1958 -INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2029, 'Banner删除', 'market:banner:delete', 3, 4, 2025, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2022-08-01 14:56:14', '', '2022-08-01 14:56:14', b'0'); 2006 +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2025, 'Banner', '', 2, 100, 2387, 'banner', 'fa:bandcamp', 'mall/promotion/banner/index', NULL, 0, b'1', b'1', b'1', '', '2022-08-01 14:56:14', '1', '2023-10-24 20:20:06', b'0');
  2007 +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2026, 'Banner查询', 'promotion:banner:query', 3, 1, 2025, '', '', '', '', 0, b'1', b'1', b'1', '', '2022-08-01 14:56:14', '1', '2023-10-24 20:20:18', b'0');
  2008 +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2027, 'Banner创建', 'promotion:banner:create', 3, 2, 2025, '', '', '', '', 0, b'1', b'1', b'1', '', '2022-08-01 14:56:14', '1', '2023-10-24 20:20:23', b'0');
  2009 +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2028, 'Banner更新', 'promotion:banner:update', 3, 3, 2025, '', '', '', '', 0, b'1', b'1', b'1', '', '2022-08-01 14:56:14', '1', '2023-10-24 20:20:28', b'0');
  2010 +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2029, 'Banner删除', 'promotion:banner:delete', 3, 4, 2025, '', '', '', '', 0, b'1', b'1', b'1', '', '2022-08-01 14:56:14', '1', '2023-10-24 20:20:36', b'0');
1959 INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2030, '营销中心', '', 1, 70, 2362, 'promotion', 'ep:present', NULL, NULL, 0, b'1', b'1', b'1', '1', '2022-10-31 21:25:09', '1', '2023-09-30 11:54:27', b'0'); 2011 INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2030, '营销中心', '', 1, 70, 2362, 'promotion', 'ep:present', NULL, NULL, 0, b'1', b'1', b'1', '1', '2022-10-31 21:25:09', '1', '2023-09-30 11:54:27', b'0');
1960 INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2032, '优惠劵列表', '', 2, 1, 2365, 'template', 'ep:discount', 'mall/promotion/coupon/template/index', 'PromotionCouponTemplate', 0, b'1', b'1', b'1', '', '2022-10-31 22:27:14', '1', '2023-10-03 12:40:06', b'0'); 2012 INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2032, '优惠劵列表', '', 2, 1, 2365, 'template', 'ep:discount', 'mall/promotion/coupon/template/index', 'PromotionCouponTemplate', 0, b'1', b'1', b'1', '', '2022-10-31 22:27:14', '1', '2023-10-03 12:40:06', b'0');
1961 INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2033, '优惠劵模板查询', 'promotion:coupon-template:query', 3, 1, 2032, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2022-10-31 22:27:14', '', '2022-10-31 22:27:14', b'0'); 2013 INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2033, '优惠劵模板查询', 'promotion:coupon-template:query', 3, 1, 2032, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2022-10-31 22:27:14', '', '2022-10-31 22:27:14', b'0');
@@ -1965,13 +2017,13 @@ INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_i @@ -1965,13 +2017,13 @@ INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_i
1965 INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2038, '领取记录', '', 2, 2, 2365, 'list', 'ep:collection-tag', 'mall/promotion/coupon/index', 'PromotionCoupon', 0, b'1', b'1', b'1', '', '2022-11-03 23:21:31', '1', '2023-10-03 12:55:30', b'0'); 2017 INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2038, '领取记录', '', 2, 2, 2365, 'list', 'ep:collection-tag', 'mall/promotion/coupon/index', 'PromotionCoupon', 0, b'1', b'1', b'1', '', '2022-11-03 23:21:31', '1', '2023-10-03 12:55:30', b'0');
1966 INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2039, '优惠劵查询', 'promotion:coupon:query', 3, 1, 2038, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2022-11-03 23:21:31', '', '2022-11-03 23:21:31', b'0'); 2018 INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2039, '优惠劵查询', 'promotion:coupon:query', 3, 1, 2038, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2022-11-03 23:21:31', '', '2022-11-03 23:21:31', b'0');
1967 INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2040, '优惠劵删除', 'promotion:coupon:delete', 3, 4, 2038, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2022-11-03 23:21:31', '', '2022-11-03 23:21:31', b'0'); 2019 INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2040, '优惠劵删除', 'promotion:coupon:delete', 3, 4, 2038, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2022-11-03 23:21:31', '', '2022-11-03 23:21:31', b'0');
1968 -INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2041, '满减送活动', '', 2, 10, 2030, 'reward-activity', 'ep:goblet-square-full', 'mall/promotion/rewardActivity/index', 'PromotionRewardActivity', 0, b'1', b'1', b'1', '', '2022-11-04 23:47:49', '1', '2023-10-05 00:16:38', b'0'); 2020 +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2041, '满减送', '', 2, 10, 2390, 'reward-activity', 'ep:goblet-square-full', 'mall/promotion/rewardActivity/index', 'PromotionRewardActivity', 0, b'1', b'1', b'1', '', '2022-11-04 23:47:49', '1', '2023-10-21 19:24:46', b'0');
1969 INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2042, '满减送活动查询', 'promotion:reward-activity:query', 3, 1, 2041, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2022-11-04 23:47:49', '', '2022-11-04 23:47:49', b'0'); 2021 INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2042, '满减送活动查询', 'promotion:reward-activity:query', 3, 1, 2041, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2022-11-04 23:47:49', '', '2022-11-04 23:47:49', b'0');
1970 INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2043, '满减送活动创建', 'promotion:reward-activity:create', 3, 2, 2041, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2022-11-04 23:47:49', '', '2022-11-04 23:47:49', b'0'); 2022 INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2043, '满减送活动创建', 'promotion:reward-activity:create', 3, 2, 2041, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2022-11-04 23:47:49', '', '2022-11-04 23:47:49', b'0');
1971 INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2044, '满减送活动更新', 'promotion:reward-activity:update', 3, 3, 2041, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2022-11-04 23:47:50', '', '2022-11-04 23:47:50', b'0'); 2023 INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2044, '满减送活动更新', 'promotion:reward-activity:update', 3, 3, 2041, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2022-11-04 23:47:50', '', '2022-11-04 23:47:50', b'0');
1972 INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2045, '满减送活动删除', 'promotion:reward-activity:delete', 3, 4, 2041, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2022-11-04 23:47:50', '', '2022-11-04 23:47:50', b'0'); 2024 INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2045, '满减送活动删除', 'promotion:reward-activity:delete', 3, 4, 2041, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2022-11-04 23:47:50', '', '2022-11-04 23:47:50', b'0');
1973 INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2046, '满减送活动关闭', 'promotion:reward-activity:close', 3, 5, 2041, '', '', '', NULL, 0, b'1', b'1', b'1', '1', '2022-11-05 10:42:53', '1', '2022-11-05 10:42:53', b'0'); 2025 INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2046, '满减送活动关闭', 'promotion:reward-activity:close', 3, 5, 2041, '', '', '', NULL, 0, b'1', b'1', b'1', '1', '2022-11-05 10:42:53', '1', '2022-11-05 10:42:53', b'0');
1974 -INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2047, '限时折扣活动', '', 2, 7, 2030, 'discount-activity', 'ep:timer', 'mall/promotion/discountActivity/index', 'PromotionDiscountActivity', 0, b'1', b'1', b'1', '', '2022-11-05 17:12:15', '1', '2023-10-05 00:16:25', b'0'); 2026 +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2047, '限时折扣', '', 2, 7, 2390, 'discount-activity', 'ep:timer', 'mall/promotion/discountActivity/index', 'PromotionDiscountActivity', 0, b'1', b'1', b'1', '', '2022-11-05 17:12:15', '1', '2023-10-21 19:24:21', b'0');
1975 INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2048, '限时折扣活动查询', 'promotion:discount-activity:query', 3, 1, 2047, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2022-11-05 17:12:15', '', '2022-11-05 17:12:15', b'0'); 2027 INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2048, '限时折扣活动查询', 'promotion:discount-activity:query', 3, 1, 2047, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2022-11-05 17:12:15', '', '2022-11-05 17:12:15', b'0');
1976 INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2049, '限时折扣活动创建', 'promotion:discount-activity:create', 3, 2, 2047, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2022-11-05 17:12:15', '', '2022-11-05 17:12:15', b'0'); 2028 INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2049, '限时折扣活动创建', 'promotion:discount-activity:create', 3, 2, 2047, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2022-11-05 17:12:15', '', '2022-11-05 17:12:15', b'0');
1977 INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2050, '限时折扣活动更新', 'promotion:discount-activity:update', 3, 3, 2047, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2022-11-05 17:12:16', '', '2022-11-05 17:12:16', b'0'); 2029 INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2050, '限时折扣活动更新', 'promotion:discount-activity:update', 3, 3, 2047, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2022-11-05 17:12:16', '', '2022-11-05 17:12:16', b'0');
@@ -2193,6 +2245,71 @@ INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_i @@ -2193,6 +2245,71 @@ INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_i
2193 INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2386, '文章管理删除', 'promotion:article:delete', 3, 4, 2382, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2023-10-16 01:26:18', '', '2023-10-16 01:26:18', b'0'); 2245 INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2386, '文章管理删除', 'promotion:article:delete', 3, 4, 2382, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2023-10-16 01:26:18', '', '2023-10-16 01:26:18', b'0');
2194 INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2387, '内容管理', '', 1, 1, 2030, 'content', 'ep:collection', '', '', 0, b'1', b'1', b'1', '1', '2023-10-16 09:37:31', '1', '2023-10-16 09:37:31', b'0'); 2246 INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2387, '内容管理', '', 1, 1, 2030, 'content', 'ep:collection', '', '', 0, b'1', b'1', b'1', '1', '2023-10-16 09:37:31', '1', '2023-10-16 09:37:31', b'0');
2195 INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2388, '商城首页', '', 2, 1, 2362, 'home', 'ep:home-filled', 'mall/home/index', 'MallHome', 0, b'1', b'1', b'1', '', '2023-10-16 12:10:33', '', '2023-10-16 12:10:33', b'0'); 2247 INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2388, '商城首页', '', 2, 1, 2362, 'home', 'ep:home-filled', 'mall/home/index', 'MallHome', 0, b'1', b'1', b'1', '', '2023-10-16 12:10:33', '', '2023-10-16 12:10:33', b'0');
  2248 +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2389, '核销订单', '', 2, 2, 2166, 'pick-up-order', 'ep:list', 'mall/trade/delivery/pickUpOrder/index', 'PickUpOrder', 0, b'1', b'1', b'1', '', '2023-10-19 16:09:51', '', '2023-10-19 16:09:51', b'0');
  2249 +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2390, '优惠活动', '', 1, 99, 2030, 'youhui', 'ep:aim', '', '', 0, b'1', b'1', b'1', '1', '2023-10-21 19:23:49', '1', '2023-10-21 19:23:49', b'0');
  2250 +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2391, '客户管理', '', 2, 0, 2397, 'customer', 'fa:address-book-o', 'crm/customer/index', 'CrmCustomer', 0, b'1', b'1', b'1', '', '2023-10-29 09:04:21', '1', '2023-10-29 17:11:03', b'0');
  2251 +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2392, '客户查询', 'crm:customer:query', 3, 1, 2391, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2023-10-29 09:04:21', '', '2023-10-29 09:04:21', b'0');
  2252 +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2393, '客户创建', 'crm:customer:create', 3, 2, 2391, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2023-10-29 09:04:21', '', '2023-10-29 09:04:21', b'0');
  2253 +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2394, '客户更新', 'crm:customer:update', 3, 3, 2391, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2023-10-29 09:04:21', '', '2023-10-29 09:04:21', b'0');
  2254 +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2395, '客户删除', 'crm:customer:delete', 3, 4, 2391, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2023-10-29 09:04:21', '', '2023-10-29 09:04:21', b'0');
  2255 +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2396, '客户导出', 'crm:customer:export', 3, 5, 2391, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2023-10-29 09:04:21', '', '2023-10-29 09:04:21', b'0');
  2256 +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2397, '客户管理系统', '', 1, 200, 0, '/crm', 'ep:avatar', '', '', 0, b'1', b'1', b'1', '1', '2023-10-29 17:08:30', '1', '2023-10-29 17:08:30', b'0');
  2257 +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2398, '合同管理', '', 2, 1, 2397, 'contract', 'ep:notebook', 'crm/contract/index', 'CrmContract', 0, b'1', b'1', b'1', '', '2023-10-29 10:50:41', '1', '2023-10-29 18:55:53', b'0');
  2258 +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2399, '合同查询', 'crm:contract:query', 3, 1, 2398, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2023-10-29 10:50:41', '', '2023-10-29 10:50:41', b'0');
  2259 +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2400, '合同创建', 'crm:contract:create', 3, 2, 2398, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2023-10-29 10:50:41', '', '2023-10-29 10:50:41', b'0');
  2260 +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2401, '合同更新', 'crm:contract:update', 3, 3, 2398, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2023-10-29 10:50:41', '', '2023-10-29 10:50:41', b'0');
  2261 +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2402, '合同删除', 'crm:contract:delete', 3, 4, 2398, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2023-10-29 10:50:41', '', '2023-10-29 10:50:41', b'0');
  2262 +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2403, '合同导出', 'crm:contract:export', 3, 5, 2398, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2023-10-29 10:50:41', '', '2023-10-29 10:50:41', b'0');
  2263 +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2404, '线索管理', '', 2, 0, 2397, 'clue', 'fa:pagelines', 'crm/clue/index', 'CrmClue', 0, b'1', b'1', b'1', '', '2023-10-29 11:06:29', '1', '2023-10-29 19:08:35', b'0');
  2264 +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2405, '线索查询', 'crm:clue:query', 3, 1, 2404, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2023-10-29 11:06:29', '', '2023-10-29 11:06:29', b'0');
  2265 +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2406, '线索创建', 'crm:clue:create', 3, 2, 2404, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2023-10-29 11:06:29', '', '2023-10-29 11:06:29', b'0');
  2266 +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2407, '线索更新', 'crm:clue:update', 3, 3, 2404, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2023-10-29 11:06:29', '', '2023-10-29 11:06:29', b'0');
  2267 +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2408, '线索删除', 'crm:clue:delete', 3, 4, 2404, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2023-10-29 11:06:29', '', '2023-10-29 11:06:29', b'0');
  2268 +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2409, '线索导出', 'crm:clue:export', 3, 5, 2404, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2023-10-29 11:06:29', '', '2023-10-29 11:06:29', b'0');
  2269 +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2410, '商机管理', '', 2, 0, 2397, 'business', 'fa:bus', 'crm/business/index', 'CrmBusiness', 0, b'1', b'1', b'1', '', '2023-10-29 11:12:35', '1', '2023-10-29 19:13:01', b'0');
  2270 +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2411, '商机查询', 'crm:business:query', 3, 1, 2410, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2023-10-29 11:12:35', '', '2023-10-29 11:12:35', b'0');
  2271 +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2412, '商机创建', 'crm:business:create', 3, 2, 2410, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2023-10-29 11:12:35', '', '2023-10-29 11:12:35', b'0');
  2272 +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2413, '商机更新', 'crm:business:update', 3, 3, 2410, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2023-10-29 11:12:35', '', '2023-10-29 11:12:35', b'0');
  2273 +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2414, '商机删除', 'crm:business:delete', 3, 4, 2410, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2023-10-29 11:12:35', '', '2023-10-29 11:12:35', b'0');
  2274 +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2415, '商机导出', 'crm:business:export', 3, 5, 2410, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2023-10-29 11:12:35', '', '2023-10-29 11:12:35', b'0');
  2275 +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2416, '联系人管理', '', 2, 0, 2397, 'contact', 'fa:address-book-o', 'crm/contact/index', 'Contact', 0, b'1', b'1', b'1', '', '2023-10-29 11:14:56', '1', '2023-10-29 19:15:32', b'0');
  2276 +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2417, '联系人查询', 'crm:contact:query', 3, 1, 2416, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2023-10-29 11:14:56', '', '2023-10-29 11:14:56', b'0');
  2277 +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2418, '联系人创建', 'crm:contact:create', 3, 2, 2416, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2023-10-29 11:14:56', '', '2023-10-29 11:14:56', b'0');
  2278 +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2419, '联系人更新', 'crm:contact:update', 3, 3, 2416, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2023-10-29 11:14:56', '', '2023-10-29 11:14:56', b'0');
  2279 +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2420, '联系人删除', 'crm:contact:delete', 3, 4, 2416, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2023-10-29 11:14:56', '', '2023-10-29 11:14:56', b'0');
  2280 +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2421, '联系人导出', 'crm:contact:export', 3, 5, 2416, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2023-10-29 11:14:56', '', '2023-10-29 11:14:56', b'0');
  2281 +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2422, '回款管理', '', 2, 0, 2397, 'receivable', 'ep:money', 'crm/receivable/index', 'CrmReceivable', 0, b'1', b'1', b'1', '', '2023-10-29 11:18:09', '1', '2023-10-29 19:18:52', b'0');
  2282 +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2423, '回款管理查询', 'crm:receivable:query', 3, 1, 2422, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2023-10-29 11:18:09', '', '2023-10-29 11:18:09', b'0');
  2283 +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2424, '回款管理创建', 'crm:receivable:create', 3, 2, 2422, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2023-10-29 11:18:09', '', '2023-10-29 11:18:09', b'0');
  2284 +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2425, '回款管理更新', 'crm:receivable:update', 3, 3, 2422, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2023-10-29 11:18:09', '', '2023-10-29 11:18:09', b'0');
  2285 +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2426, '回款管理删除', 'crm:receivable:delete', 3, 4, 2422, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2023-10-29 11:18:09', '', '2023-10-29 11:18:09', b'0');
  2286 +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2427, '回款管理导出', 'crm:receivable:export', 3, 5, 2422, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2023-10-29 11:18:09', '', '2023-10-29 11:18:09', b'0');
  2287 +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2428, '回款计划管理', '', 2, 0, 2397, 'receivable-plan', 'fa:money', 'crm/receivablePlan/index', 'CrmReceivablePlan', 0, b'1', b'1', b'1', '', '2023-10-29 11:18:09', '1', '2023-10-29 19:19:08', b'0');
  2288 +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2429, '回款计划查询', 'crm:receivable-plan:query', 3, 1, 2428, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2023-10-29 11:18:09', '', '2023-10-29 11:18:09', b'0');
  2289 +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2430, '回款计划创建', 'crm:receivable-plan:create', 3, 2, 2428, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2023-10-29 11:18:09', '', '2023-10-29 11:18:09', b'0');
  2290 +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2431, '回款计划更新', 'crm:receivable-plan:update', 3, 3, 2428, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2023-10-29 11:18:09', '', '2023-10-29 11:18:09', b'0');
  2291 +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2432, '回款计划删除', 'crm:receivable-plan:delete', 3, 4, 2428, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2023-10-29 11:18:09', '', '2023-10-29 11:18:09', b'0');
  2292 +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2433, '回款计划导出', 'crm:receivable-plan:export', 3, 5, 2428, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2023-10-29 11:18:09', '', '2023-10-29 11:18:09', b'0');
  2293 +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2434, '核销订单', '', 2, 2, 2166, 'pick-up-order', 'ep:list', 'mall/trade/delivery/pickUpOrder/index', 'PickUpOrder', 0, b'1', b'1', b'1', '', '2023-10-29 14:19:25', '', '2023-10-29 14:19:25', b'0');
  2294 +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2435, '商城装修', '', 2, 20, 2030, 'diy-template', 'fa6-solid:brush', 'mall/promotion/diy/template/index', 'DiyTemplate', 0, b'1', b'1', b'1', '', '2023-10-29 14:19:25', '', '2023-10-29 14:19:25', b'0');
  2295 +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2436, '装修模板', '', 2, 1, 2435, 'diy-template', 'fa6-solid:brush', 'mall/promotion/diy/template/index', 'DiyTemplate', 0, b'1', b'1', b'1', '', '2023-10-29 14:19:25', '', '2023-10-29 14:19:25', b'0');
  2296 +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2437, '装修模板查询', 'promotion:diy-template:query', 3, 1, 2436, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2023-10-29 14:19:25', '', '2023-10-29 14:19:25', b'0');
  2297 +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2438, '装修模板创建', 'promotion:diy-template:create', 3, 2, 2436, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2023-10-29 14:19:25', '', '2023-10-29 14:19:25', b'0');
  2298 +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2439, '装修模板更新', 'promotion:diy-template:update', 3, 3, 2436, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2023-10-29 14:19:25', '', '2023-10-29 14:19:25', b'0');
  2299 +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2440, '装修模板删除', 'promotion:diy-template:delete', 3, 4, 2436, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2023-10-29 14:19:25', '', '2023-10-29 14:19:25', b'0');
  2300 +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2441, '装修模板使用', 'promotion:diy-template:use', 3, 5, 2436, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2023-10-29 14:19:25', '', '2023-10-29 14:19:25', b'0');
  2301 +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2442, '装修页面', '', 2, 2, 2435, 'diy-page', 'foundation:page-edit', 'mall/promotion/diy/page/index', 'DiyPage', 0, b'1', b'1', b'1', '', '2023-10-29 14:19:25', '', '2023-10-29 14:19:25', b'0');
  2302 +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2443, '装修页面查询', 'promotion:diy-page:query', 3, 1, 2442, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2023-10-29 14:19:25', '', '2023-10-29 14:19:25', b'0');
  2303 +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2444, '装修页面创建', 'promotion:diy-page:create', 3, 2, 2442, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2023-10-29 14:19:26', '', '2023-10-29 14:19:26', b'0');
  2304 +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2445, '装修页面更新', 'promotion:diy-page:update', 3, 3, 2442, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2023-10-29 14:19:26', '', '2023-10-29 14:19:26', b'0');
  2305 +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2446, '装修页面删除', 'promotion:diy-page:delete', 3, 4, 2442, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2023-10-29 14:19:26', '', '2023-10-29 14:19:26', b'0');
  2306 +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2447, '三方登录', '', 1, 10, 1, 'social', 'fa:500px', '', '', 0, b'1', b'1', b'1', '1', '2023-11-04 12:12:01', '1', '2023-11-04 13:06:45', b'0');
  2307 +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2448, '三方应用', '', 2, 1, 2447, 'client', 'ep:set-up', 'views/system/social/client/index.vue', 'SocialClient', 0, b'1', b'1', b'1', '1', '2023-11-04 12:17:19', '1', '2023-11-04 12:17:19', b'0');
  2308 +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2449, '三方应用查询', 'system:social-client:query', 3, 1, 2448, '', '', '', '', 0, b'1', b'1', b'1', '1', '2023-11-04 12:43:12', '1', '2023-11-04 12:43:33', b'0');
  2309 +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2450, '三方应用创建', 'system:social-client:create', 3, 2, 2448, '', '', '', '', 0, b'1', b'1', b'1', '1', '2023-11-04 12:43:58', '1', '2023-11-04 12:43:58', b'0');
  2310 +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2451, '三方应用更新', 'system:social-client:update', 3, 3, 2448, '', '', '', '', 0, b'1', b'1', b'1', '1', '2023-11-04 12:44:27', '1', '2023-11-04 12:44:27', b'0');
  2311 +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2452, '三方应用删除', 'system:social-client:delete', 3, 4, 2448, '', '', '', '', 0, b'1', b'1', b'1', '1', '2023-11-04 12:44:43', '1', '2023-11-04 12:44:43', b'0');
  2312 +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2453, '三方用户', 'system:social-user:query', 2, 2, 2447, 'user', 'ep:avatar', 'system/social/user/index.vue', 'SocialUser', 0, b'1', b'1', b'1', '1', '2023-11-04 14:01:05', '1', '2023-11-04 14:01:05', b'0');
2196 COMMIT; 2313 COMMIT;
2197 2314
2198 -- ---------------------------- 2315 -- ----------------------------
@@ -2283,7 +2400,7 @@ CREATE TABLE `system_notify_template` ( @@ -2283,7 +2400,7 @@ CREATE TABLE `system_notify_template` (
2283 `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间', 2400 `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
2284 `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除', 2401 `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除',
2285 PRIMARY KEY (`id`) USING BTREE 2402 PRIMARY KEY (`id`) USING BTREE
2286 -) ENGINE = InnoDB AUTO_INCREMENT = 6 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '站内信模板表'; 2403 +) ENGINE = InnoDB AUTO_INCREMENT = 5 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '站内信模板表';
2287 2404
2288 -- ---------------------------- 2405 -- ----------------------------
2289 -- Records of system_notify_template 2406 -- Records of system_notify_template
@@ -2310,8 +2427,10 @@ CREATE TABLE `system_oauth2_access_token` ( @@ -2310,8 +2427,10 @@ CREATE TABLE `system_oauth2_access_token` (
2310 `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间', 2427 `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
2311 `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除', 2428 `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除',
2312 `tenant_id` bigint NOT NULL DEFAULT 0 COMMENT '租户编号', 2429 `tenant_id` bigint NOT NULL DEFAULT 0 COMMENT '租户编号',
2313 - PRIMARY KEY (`id`) USING BTREE  
2314 -) ENGINE = InnoDB AUTO_INCREMENT = 3063 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = 'OAuth2 访问令牌'; 2430 + PRIMARY KEY (`id`) USING BTREE,
  2431 + INDEX `idx_access_token`(`access_token` ASC) USING BTREE,
  2432 + INDEX `idx_refresh_token`(`refresh_token` ASC) USING BTREE
  2433 +) ENGINE = InnoDB AUTO_INCREMENT = 3152 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = 'OAuth2 访问令牌';
2315 2434
2316 -- ---------------------------- 2435 -- ----------------------------
2317 -- Records of system_oauth2_access_token 2436 -- Records of system_oauth2_access_token
@@ -2433,7 +2552,7 @@ CREATE TABLE `system_oauth2_refresh_token` ( @@ -2433,7 +2552,7 @@ CREATE TABLE `system_oauth2_refresh_token` (
2433 `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除', 2552 `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除',
2434 `tenant_id` bigint NOT NULL DEFAULT 0 COMMENT '租户编号', 2553 `tenant_id` bigint NOT NULL DEFAULT 0 COMMENT '租户编号',
2435 PRIMARY KEY (`id`) USING BTREE 2554 PRIMARY KEY (`id`) USING BTREE
2436 -) ENGINE = InnoDB AUTO_INCREMENT = 1070 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = 'OAuth2 刷新令牌'; 2555 +) ENGINE = InnoDB AUTO_INCREMENT = 1099 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = 'OAuth2 刷新令牌';
2437 2556
2438 -- ---------------------------- 2557 -- ----------------------------
2439 -- Records of system_oauth2_refresh_token 2558 -- Records of system_oauth2_refresh_token
@@ -2473,7 +2592,7 @@ CREATE TABLE `system_operate_log` ( @@ -2473,7 +2592,7 @@ CREATE TABLE `system_operate_log` (
2473 `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除', 2592 `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除',
2474 `tenant_id` bigint NOT NULL DEFAULT 0 COMMENT '租户编号', 2593 `tenant_id` bigint NOT NULL DEFAULT 0 COMMENT '租户编号',
2475 PRIMARY KEY (`id`) USING BTREE 2594 PRIMARY KEY (`id`) USING BTREE
2476 -) ENGINE = InnoDB AUTO_INCREMENT = 8738 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '操作日志记录'; 2595 +) ENGINE = InnoDB AUTO_INCREMENT = 8845 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '操作日志记录';
2477 2596
2478 -- ---------------------------- 2597 -- ----------------------------
2479 -- Records of system_operate_log 2598 -- Records of system_operate_log
@@ -3481,7 +3600,7 @@ CREATE TABLE `system_sms_code` ( @@ -3481,7 +3600,7 @@ CREATE TABLE `system_sms_code` (
3481 `tenant_id` bigint NOT NULL DEFAULT 0 COMMENT '租户编号', 3600 `tenant_id` bigint NOT NULL DEFAULT 0 COMMENT '租户编号',
3482 PRIMARY KEY (`id`) USING BTREE, 3601 PRIMARY KEY (`id`) USING BTREE,
3483 INDEX `idx_mobile`(`mobile` ASC) USING BTREE COMMENT '手机号' 3602 INDEX `idx_mobile`(`mobile` ASC) USING BTREE COMMENT '手机号'
3484 -) ENGINE = InnoDB AUTO_INCREMENT = 531 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '手机验证码'; 3603 +) ENGINE = InnoDB AUTO_INCREMENT = 535 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '手机验证码';
3485 3604
3486 -- ---------------------------- 3605 -- ----------------------------
3487 -- Records of system_sms_code 3606 -- Records of system_sms_code
@@ -3524,7 +3643,7 @@ CREATE TABLE `system_sms_log` ( @@ -3524,7 +3643,7 @@ CREATE TABLE `system_sms_log` (
3524 `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间', 3643 `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
3525 `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除', 3644 `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除',
3526 PRIMARY KEY (`id`) USING BTREE 3645 PRIMARY KEY (`id`) USING BTREE
3527 -) ENGINE = InnoDB AUTO_INCREMENT = 445 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '短信日志'; 3646 +) ENGINE = InnoDB AUTO_INCREMENT = 503 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '短信日志';
3528 3647
3529 -- ---------------------------- 3648 -- ----------------------------
3530 -- Records of system_sms_log 3649 -- Records of system_sms_log
@@ -3585,6 +3704,7 @@ CREATE TABLE `system_social_client` ( @@ -3585,6 +3704,7 @@ CREATE TABLE `system_social_client` (
3585 `user_type` tinyint NOT NULL COMMENT '用户类型', 3704 `user_type` tinyint NOT NULL COMMENT '用户类型',
3586 `client_id` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '客户端编号', 3705 `client_id` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '客户端编号',
3587 `client_secret` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '客户端密钥', 3706 `client_secret` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '客户端密钥',
  3707 + `agent_id` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '代理编号',
3588 `status` tinyint NOT NULL COMMENT '状态', 3708 `status` tinyint NOT NULL COMMENT '状态',
3589 `creator` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT '' COMMENT '创建者', 3709 `creator` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT '' COMMENT '创建者',
3590 `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', 3710 `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
@@ -3593,7 +3713,7 @@ CREATE TABLE `system_social_client` ( @@ -3593,7 +3713,7 @@ CREATE TABLE `system_social_client` (
3593 `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除', 3713 `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除',
3594 `tenant_id` bigint NOT NULL DEFAULT 0 COMMENT '租户编号', 3714 `tenant_id` bigint NOT NULL DEFAULT 0 COMMENT '租户编号',
3595 PRIMARY KEY (`id`) USING BTREE 3715 PRIMARY KEY (`id`) USING BTREE
3596 -) ENGINE = InnoDB AUTO_INCREMENT = 43 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '社交客户端表'; 3716 +) ENGINE = InnoDB AUTO_INCREMENT = 44 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '社交客户端表';
3597 3717
3598 -- ---------------------------- 3718 -- ----------------------------
3599 -- Records of system_social_client 3719 -- Records of system_social_client
@@ -3623,7 +3743,7 @@ CREATE TABLE `system_social_user` ( @@ -3623,7 +3743,7 @@ CREATE TABLE `system_social_user` (
3623 `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除', 3743 `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除',
3624 `tenant_id` bigint NOT NULL DEFAULT 0 COMMENT '租户编号', 3744 `tenant_id` bigint NOT NULL DEFAULT 0 COMMENT '租户编号',
3625 PRIMARY KEY (`id`) USING BTREE 3745 PRIMARY KEY (`id`) USING BTREE
3626 -) ENGINE = InnoDB AUTO_INCREMENT = 25 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '社交用户表'; 3746 +) ENGINE = InnoDB AUTO_INCREMENT = 24 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '社交用户表';
3627 3747
3628 -- ---------------------------- 3748 -- ----------------------------
3629 -- Records of system_social_user 3749 -- Records of system_social_user
@@ -3648,7 +3768,7 @@ CREATE TABLE `system_social_user_bind` ( @@ -3648,7 +3768,7 @@ CREATE TABLE `system_social_user_bind` (
3648 `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除', 3768 `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除',
3649 `tenant_id` bigint NOT NULL DEFAULT 0 COMMENT '租户编号', 3769 `tenant_id` bigint NOT NULL DEFAULT 0 COMMENT '租户编号',
3650 PRIMARY KEY (`id`) USING BTREE 3770 PRIMARY KEY (`id`) USING BTREE
3651 -) ENGINE = InnoDB AUTO_INCREMENT = 79 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '社交绑定表'; 3771 +) ENGINE = InnoDB AUTO_INCREMENT = 80 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '社交绑定表';
3652 3772
3653 -- ---------------------------- 3773 -- ----------------------------
3654 -- Records of system_social_user_bind 3774 -- Records of system_social_user_bind
@@ -3824,7 +3944,7 @@ CREATE TABLE `system_users` ( @@ -3824,7 +3944,7 @@ CREATE TABLE `system_users` (
3824 -- Records of system_users 3944 -- Records of system_users
3825 -- ---------------------------- 3945 -- ----------------------------
3826 BEGIN; 3946 BEGIN;
3827 -INSERT INTO `system_users` (`id`, `username`, `password`, `nickname`, `remark`, `dept_id`, `post_ids`, `email`, `mobile`, `sex`, `avatar`, `status`, `login_ip`, `login_date`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (1, 'admin', '$2a$10$mRMIYLDtRHlf6.9ipiqH1.Z.bh/R9dO9d5iHiGYPigi6r5KOoR2Wm', '芋道源码', '管理员', 103, '[1]', 'aoteman@126.com', '15612345678', 1, 'http://test.yudao.iocoder.cn/e1fdd7271685ec143a0900681606406621717a666ad0b2798b096df41422b32f.png', 0, '0:0:0:0:0:0:0:1', '2023-10-18 22:31:35', 'admin', '2021-01-05 17:03:47', NULL, '2023-10-18 22:31:35', b'0', 1); 3947 +INSERT INTO `system_users` (`id`, `username`, `password`, `nickname`, `remark`, `dept_id`, `post_ids`, `email`, `mobile`, `sex`, `avatar`, `status`, `login_ip`, `login_date`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (1, 'admin', '$2a$10$mRMIYLDtRHlf6.9ipiqH1.Z.bh/R9dO9d5iHiGYPigi6r5KOoR2Wm', '芋道源码', '管理员', 103, '[1]', 'aoteman@126.com', '15612345678', 1, 'http://127.0.0.1:48080/admin-api/infra/file/4/get/37e56010ecbee472cdd821ac4b608e151e62a74d9633f15d085aee026eedeb60.png', 0, '0:0:0:0:0:0:0:1', '2023-11-04 10:33:16', 'admin', '2021-01-05 17:03:47', NULL, '2023-11-04 10:33:16', b'0', 1);
3828 INSERT INTO `system_users` (`id`, `username`, `password`, `nickname`, `remark`, `dept_id`, `post_ids`, `email`, `mobile`, `sex`, `avatar`, `status`, `login_ip`, `login_date`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (100, 'yudao', '$2a$10$11U48RhyJ5pSBYWSn12AD./ld671.ycSzJHbyrtpeoMeYiw31eo8a', '芋道', '不要吓我', 104, '[1]', 'yudao@iocoder.cn', '15601691300', 1, '', 1, '127.0.0.1', '2022-07-09 23:03:33', '', '2021-01-07 09:07:17', NULL, '2022-07-09 23:03:33', b'0', 1); 3948 INSERT INTO `system_users` (`id`, `username`, `password`, `nickname`, `remark`, `dept_id`, `post_ids`, `email`, `mobile`, `sex`, `avatar`, `status`, `login_ip`, `login_date`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (100, 'yudao', '$2a$10$11U48RhyJ5pSBYWSn12AD./ld671.ycSzJHbyrtpeoMeYiw31eo8a', '芋道', '不要吓我', 104, '[1]', 'yudao@iocoder.cn', '15601691300', 1, '', 1, '127.0.0.1', '2022-07-09 23:03:33', '', '2021-01-07 09:07:17', NULL, '2022-07-09 23:03:33', b'0', 1);
3829 INSERT INTO `system_users` (`id`, `username`, `password`, `nickname`, `remark`, `dept_id`, `post_ids`, `email`, `mobile`, `sex`, `avatar`, `status`, `login_ip`, `login_date`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (103, 'yuanma', '$2a$10$YMpimV4T6BtDhIaA8jSW.u8UTGBeGhc/qwXP4oxoMr4mOw9.qttt6', '源码', NULL, 106, NULL, 'yuanma@iocoder.cn', '15601701300', 0, '', 0, '127.0.0.1', '2022-07-08 01:26:27', '', '2021-01-13 23:50:35', NULL, '2022-07-08 01:26:27', b'0', 1); 3949 INSERT INTO `system_users` (`id`, `username`, `password`, `nickname`, `remark`, `dept_id`, `post_ids`, `email`, `mobile`, `sex`, `avatar`, `status`, `login_ip`, `login_date`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (103, 'yuanma', '$2a$10$YMpimV4T6BtDhIaA8jSW.u8UTGBeGhc/qwXP4oxoMr4mOw9.qttt6', '源码', NULL, 106, NULL, 'yuanma@iocoder.cn', '15601701300', 0, '', 0, '127.0.0.1', '2022-07-08 01:26:27', '', '2021-01-13 23:50:35', NULL, '2022-07-08 01:26:27', b'0', 1);
3830 INSERT INTO `system_users` (`id`, `username`, `password`, `nickname`, `remark`, `dept_id`, `post_ids`, `email`, `mobile`, `sex`, `avatar`, `status`, `login_ip`, `login_date`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (104, 'test', '$2a$10$GP8zvqHB//TekuzYZSBYAuBQJiNq1.fxQVDYJ.uBCOnWCtDVKE4H6', '测试号', NULL, 107, '[1,2]', '111@qq.com', '15601691200', 1, '', 0, '0:0:0:0:0:0:0:1', '2023-09-24 18:21:19', '', '2021-01-21 02:13:53', NULL, '2023-09-24 18:21:19', b'0', 1); 3950 INSERT INTO `system_users` (`id`, `username`, `password`, `nickname`, `remark`, `dept_id`, `post_ids`, `email`, `mobile`, `sex`, `avatar`, `status`, `login_ip`, `login_date`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (104, 'test', '$2a$10$GP8zvqHB//TekuzYZSBYAuBQJiNq1.fxQVDYJ.uBCOnWCtDVKE4H6', '测试号', NULL, 107, '[1,2]', '111@qq.com', '15601691200', 1, '', 0, '0:0:0:0:0:0:0:1', '2023-09-24 18:21:19', '', '2021-01-21 02:13:53', NULL, '2023-09-24 18:21:19', b'0', 1);
yudao-dependencies/pom.xml
@@ -14,28 +14,30 @@ @@ -14,28 +14,30 @@
14 <url>https://github.com/YunaiV/ruoyi-vue-pro</url> 14 <url>https://github.com/YunaiV/ruoyi-vue-pro</url>
15 15
16 <properties> 16 <properties>
17 - <revision>1.8.2-snapshot</revision> 17 + <revision>1.8.3-snapshot</revision>
18 <flatten-maven-plugin.version>1.5.0</flatten-maven-plugin.version> 18 <flatten-maven-plugin.version>1.5.0</flatten-maven-plugin.version>
19 <!-- 统一依赖管理 --> 19 <!-- 统一依赖管理 -->
20 - <spring.boot.version>2.7.16</spring.boot.version> 20 + <spring.boot.version>2.7.17</spring.boot.version>
21 <!-- Web 相关 --> 21 <!-- Web 相关 -->
22 <springdoc.version>1.6.15</springdoc.version> 22 <springdoc.version>1.6.15</springdoc.version>
23 <knife4j.version>4.3.0</knife4j.version> 23 <knife4j.version>4.3.0</knife4j.version>
24 <servlet.versoin>2.5</servlet.versoin> 24 <servlet.versoin>2.5</servlet.versoin>
25 <!-- DB 相关 --> 25 <!-- DB 相关 -->
26 - <druid.version>1.2.19</druid.version>  
27 - <mybatis-plus.version>3.5.3.2</mybatis-plus.version>  
28 - <mybatis-plus-generator.version>3.5.3.2</mybatis-plus-generator.version> 26 + <druid.version>1.2.20</druid.version>
  27 + <mybatis-plus.version>3.5.4</mybatis-plus.version>
  28 + <mybatis-plus-generator.version>3.5.4</mybatis-plus-generator.version>
29 <dynamic-datasource.version>3.6.1</dynamic-datasource.version> 29 <dynamic-datasource.version>3.6.1</dynamic-datasource.version>
30 - <mybatis-plus-join.version>1.4.6</mybatis-plus-join.version> 30 + <mybatis-plus-join.version>1.4.7</mybatis-plus-join.version>
31 <redisson.version>3.18.0</redisson.version> 31 <redisson.version>3.18.0</redisson.version>
32 - <dm8.jdbc.version>8.1.2.141</dm8.jdbc.version> 32 + <dm8.jdbc.version>8.1.3.62</dm8.jdbc.version>
  33 + <!-- 消息队列 -->
  34 + <rocketmq-spring.version>2.2.3</rocketmq-spring.version>
33 <!-- 服务保障相关 --> 35 <!-- 服务保障相关 -->
34 - <lock4j.version>2.2.3</lock4j.version> 36 + <lock4j.version>2.2.5</lock4j.version>
35 <resilience4j.version>1.7.1</resilience4j.version> 37 <resilience4j.version>1.7.1</resilience4j.version>
36 <!-- 监控相关 --> 38 <!-- 监控相关 -->
37 <skywalking.version>8.12.0</skywalking.version> 39 <skywalking.version>8.12.0</skywalking.version>
38 - <spring-boot-admin.version>2.7.10</spring-boot-admin.version> 40 + <spring-boot-admin.version>2.7.11</spring-boot-admin.version>
39 <opentracing.version>0.33.0</opentracing.version> 41 <opentracing.version>0.33.0</opentracing.version>
40 <!-- Test 测试相关 --> 42 <!-- Test 测试相关 -->
41 <podam.version>7.2.11.RELEASE</podam.version> 43 <podam.version>7.2.11.RELEASE</podam.version>
@@ -44,8 +46,8 @@ @@ -44,8 +46,8 @@
44 <!-- Bpm 工作流相关 --> 46 <!-- Bpm 工作流相关 -->
45 <flowable.version>6.8.0</flowable.version> 47 <flowable.version>6.8.0</flowable.version>
46 <!-- 工具类相关 --> 48 <!-- 工具类相关 -->
47 - <captcha-plus.version>1.0.8</captcha-plus.version>  
48 - <jsoup.version>1.16.1</jsoup.version> 49 + <captcha-plus.version>1.0.10</captcha-plus.version>
  50 + <jsoup.version>1.16.2</jsoup.version>
49 <lombok.version>1.18.30</lombok.version> 51 <lombok.version>1.18.30</lombok.version>
50 <mapstruct.version>1.5.5.Final</mapstruct.version> 52 <mapstruct.version>1.5.5.Final</mapstruct.version>
51 <hutool.version>5.8.22</hutool.version> 53 <hutool.version>5.8.22</hutool.version>
@@ -53,10 +55,10 @@ @@ -53,10 +55,10 @@
53 <velocity.version>2.3</velocity.version> 55 <velocity.version>2.3</velocity.version>
54 <screw.version>1.0.5</screw.version> 56 <screw.version>1.0.5</screw.version>
55 <fastjson.version>1.2.83</fastjson.version> 57 <fastjson.version>1.2.83</fastjson.version>
56 - <guava.version>32.1.2-jre</guava.version> 58 + <guava.version>32.1.3-jre</guava.version>
57 <guice.version>5.1.0</guice.version> 59 <guice.version>5.1.0</guice.version>
58 <transmittable-thread-local.version>2.14.2</transmittable-thread-local.version> 60 <transmittable-thread-local.version>2.14.2</transmittable-thread-local.version>
59 - <commons-net.version>3.9.0</commons-net.version> 61 + <commons-net.version>3.10.0</commons-net.version>
60 <jsch.version>0.1.55</jsch.version> 62 <jsch.version>0.1.55</jsch.version>
61 <tika-core.version>2.7.0</tika-core.version> 63 <tika-core.version>2.7.0</tika-core.version>
62 <ip2region.version>2.7.0</ip2region.version> 64 <ip2region.version>2.7.0</ip2region.version>
@@ -67,8 +69,8 @@ @@ -67,8 +69,8 @@
67 <minio.version>8.5.6</minio.version> 69 <minio.version>8.5.6</minio.version>
68 <aliyun-java-sdk-core.version>4.6.4</aliyun-java-sdk-core.version> 70 <aliyun-java-sdk-core.version>4.6.4</aliyun-java-sdk-core.version>
69 <aliyun-java-sdk-dysmsapi.version>2.2.1</aliyun-java-sdk-dysmsapi.version> 71 <aliyun-java-sdk-dysmsapi.version>2.2.1</aliyun-java-sdk-dysmsapi.version>
70 - <tencentcloud-sdk-java.version>3.1.853</tencentcloud-sdk-java.version>  
71 - <justauth.version>1.0.5</justauth.version> 72 + <tencentcloud-sdk-java.version>3.1.880</tencentcloud-sdk-java.version>
  73 + <justauth.version>1.0.7</justauth.version>
72 <jimureport.version>1.6.1</jimureport.version> 74 <jimureport.version>1.6.1</jimureport.version>
73 <xercesImpl.version>2.12.2</xercesImpl.version> 75 <xercesImpl.version>2.12.2</xercesImpl.version>
74 <weixin-java.version>4.5.0</weixin-java.version> 76 <weixin-java.version>4.5.0</weixin-java.version>
@@ -98,11 +100,6 @@ @@ -98,11 +100,6 @@
98 </dependency> 100 </dependency>
99 <dependency> 101 <dependency>
100 <groupId>cn.iocoder.boot</groupId> 102 <groupId>cn.iocoder.boot</groupId>
101 - <artifactId>yudao-spring-boot-starter-biz-trade</artifactId>  
102 - <version>${revision}</version>  
103 - </dependency>  
104 - <dependency>  
105 - <groupId>cn.iocoder.boot</groupId>  
106 <artifactId>yudao-spring-boot-starter-biz-dict</artifactId> 103 <artifactId>yudao-spring-boot-starter-biz-dict</artifactId>
107 <version>${revision}</version> 104 <version>${revision}</version>
108 </dependency> 105 </dependency>
@@ -260,6 +257,12 @@ @@ -260,6 +257,12 @@
260 <version>${revision}</version> 257 <version>${revision}</version>
261 </dependency> 258 </dependency>
262 259
  260 + <dependency>
  261 + <groupId>org.apache.rocketmq</groupId>
  262 + <artifactId>rocketmq-spring-boot-starter</artifactId>
  263 + <version>${rocketmq-spring.version}</version>
  264 + </dependency>
  265 +
263 <!-- 服务保障相关 --> 266 <!-- 服务保障相关 -->
264 <dependency> 267 <dependency>
265 <groupId>cn.iocoder.boot</groupId> 268 <groupId>cn.iocoder.boot</groupId>
yudao-example/yudao-sso-demo-by-code/pom.xml
@@ -21,7 +21,7 @@ @@ -21,7 +21,7 @@
21 <maven.compiler.target>8</maven.compiler.target> 21 <maven.compiler.target>8</maven.compiler.target>
22 <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> 22 <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
23 <!-- 统一依赖管理 --> 23 <!-- 统一依赖管理 -->
24 - <spring.boot.version>2.7.16</spring.boot.version> 24 + <spring.boot.version>2.7.17</spring.boot.version>
25 </properties> 25 </properties>
26 26
27 <dependencyManagement> 27 <dependencyManagement>
yudao-example/yudao-sso-demo-by-password/pom.xml
@@ -21,7 +21,7 @@ @@ -21,7 +21,7 @@
21 <maven.compiler.target>8</maven.compiler.target> 21 <maven.compiler.target>8</maven.compiler.target>
22 <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> 22 <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
23 <!-- 统一依赖管理 --> 23 <!-- 统一依赖管理 -->
24 - <spring.boot.version>2.7.16</spring.boot.version> 24 + <spring.boot.version>2.7.17</spring.boot.version>
25 </properties> 25 </properties>
26 26
27 <dependencyManagement> 27 <dependencyManagement>
yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/core/KeyValue.java
@@ -4,6 +4,8 @@ import lombok.AllArgsConstructor; @@ -4,6 +4,8 @@ import lombok.AllArgsConstructor;
4 import lombok.Data; 4 import lombok.Data;
5 import lombok.NoArgsConstructor; 5 import lombok.NoArgsConstructor;
6 6
  7 +import java.io.Serializable;
  8 +
7 /** 9 /**
8 * Key Value 的键值对 10 * Key Value 的键值对
9 * 11 *
@@ -12,7 +14,7 @@ import lombok.NoArgsConstructor; @@ -12,7 +14,7 @@ import lombok.NoArgsConstructor;
12 @Data 14 @Data
13 @NoArgsConstructor 15 @NoArgsConstructor
14 @AllArgsConstructor 16 @AllArgsConstructor
15 -public class KeyValue<K, V> { 17 +public class KeyValue<K, V> implements Serializable {
16 18
17 private K key; 19 private K key;
18 private V value; 20 private V value;
yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/util/collection/CollectionUtils.java
@@ -8,6 +8,7 @@ import com.google.common.collect.ImmutableMap; @@ -8,6 +8,7 @@ import com.google.common.collect.ImmutableMap;
8 import java.util.*; 8 import java.util.*;
9 import java.util.function.*; 9 import java.util.function.*;
10 import java.util.stream.Collectors; 10 import java.util.stream.Collectors;
  11 +import java.util.stream.Stream;
11 12
12 import static java.util.Arrays.asList; 13 import static java.util.Arrays.asList;
13 14
@@ -223,10 +224,14 @@ public class CollectionUtils { @@ -223,10 +224,14 @@ public class CollectionUtils {
223 } 224 }
224 225
225 public static <T> T findFirst(List<T> from, Predicate<T> predicate) { 226 public static <T> T findFirst(List<T> from, Predicate<T> predicate) {
  227 + return findFirst(from, predicate, Function.identity());
  228 + }
  229 +
  230 + public static <T, U> U findFirst(List<T> from, Predicate<T> predicate, Function<T, U> func) {
226 if (CollUtil.isEmpty(from)) { 231 if (CollUtil.isEmpty(from)) {
227 return null; 232 return null;
228 } 233 }
229 - return from.stream().filter(predicate).findFirst().orElse(null); 234 + return from.stream().filter(predicate).findFirst().map(func).orElse(null);
230 } 235 }
231 236
232 public static <T, V extends Comparable<? super V>> V getMaxValue(Collection<T> from, Function<T, V> valueFunc) { 237 public static <T, V extends Comparable<? super V>> V getMaxValue(Collection<T> from, Function<T, V> valueFunc) {
@@ -267,4 +272,20 @@ public class CollectionUtils { @@ -267,4 +272,20 @@ public class CollectionUtils {
267 return deptId == null ? Collections.emptyList() : Collections.singleton(deptId); 272 return deptId == null ? Collections.emptyList() : Collections.singleton(deptId);
268 } 273 }
269 274
  275 + public static <T, U> List<U> convertListByFlatMap(Collection<T> from,
  276 + Function<T, ? extends Stream<? extends U>> func) {
  277 + if (CollUtil.isEmpty(from)) {
  278 + return new ArrayList<>();
  279 + }
  280 + return from.stream().flatMap(func).filter(Objects::nonNull).collect(Collectors.toList());
  281 + }
  282 +
  283 + public static <T, U> Set<U> convertSetByFlatMap(Collection<T> from,
  284 + Function<T, ? extends Stream<? extends U>> func) {
  285 + if (CollUtil.isEmpty(from)) {
  286 + return new HashSet<>();
  287 + }
  288 + return from.stream().flatMap(func).filter(Objects::nonNull).collect(Collectors.toSet());
  289 + }
  290 +
270 } 291 }
yudao-framework/yudao-spring-boot-starter-biz-error-code/src/main/java/cn/iocoder/yudao/framework/errorcode/config/YudaoErrorCodeConfiguration.java renamed to yudao-framework/yudao-spring-boot-starter-biz-error-code/src/main/java/cn/iocoder/yudao/framework/errorcode/config/YudaoErrorCodeAutoConfiguration.java
@@ -21,7 +21,7 @@ import org.springframework.scheduling.annotation.EnableScheduling; @@ -21,7 +21,7 @@ import org.springframework.scheduling.annotation.EnableScheduling;
21 @ConditionalOnProperty(prefix = "yudao.error-code", value = "enable", matchIfMissing = true) // 允许使用 yudao.error-code.enable=false 禁用访问日志 21 @ConditionalOnProperty(prefix = "yudao.error-code", value = "enable", matchIfMissing = true) // 允许使用 yudao.error-code.enable=false 禁用访问日志
22 @EnableConfigurationProperties(ErrorCodeProperties.class) 22 @EnableConfigurationProperties(ErrorCodeProperties.class)
23 @EnableScheduling // 开启调度任务的功能,因为 ErrorCodeRemoteLoader 通过定时刷新错误码 23 @EnableScheduling // 开启调度任务的功能,因为 ErrorCodeRemoteLoader 通过定时刷新错误码
24 -public class YudaoErrorCodeConfiguration { 24 +public class YudaoErrorCodeAutoConfiguration {
25 25
26 @Bean 26 @Bean
27 public ErrorCodeAutoGenerator errorCodeAutoGenerator(@Value("${spring.application.name}") String applicationName, 27 public ErrorCodeAutoGenerator errorCodeAutoGenerator(@Value("${spring.application.name}") String applicationName,
yudao-framework/yudao-spring-boot-starter-biz-error-code/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports
1 -cn.iocoder.yudao.framework.errorcode.config.YudaoErrorCodeConfiguration  
2 \ No newline at end of file 1 \ No newline at end of file
  2 +cn.iocoder.yudao.framework.errorcode.config.YudaoErrorCodeAutoConfiguration
yudao-framework/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/PayClient.java
@@ -6,6 +6,7 @@ import cn.iocoder.yudao.framework.pay.core.client.dto.refund.PayRefundRespDTO; @@ -6,6 +6,7 @@ import cn.iocoder.yudao.framework.pay.core.client.dto.refund.PayRefundRespDTO;
6 import cn.iocoder.yudao.framework.pay.core.client.dto.refund.PayRefundUnifiedReqDTO; 6 import cn.iocoder.yudao.framework.pay.core.client.dto.refund.PayRefundUnifiedReqDTO;
7 import cn.iocoder.yudao.framework.pay.core.client.dto.transfer.PayTransferRespDTO; 7 import cn.iocoder.yudao.framework.pay.core.client.dto.transfer.PayTransferRespDTO;
8 import cn.iocoder.yudao.framework.pay.core.client.dto.transfer.PayTransferUnifiedReqDTO; 8 import cn.iocoder.yudao.framework.pay.core.client.dto.transfer.PayTransferUnifiedReqDTO;
  9 +import cn.iocoder.yudao.framework.pay.core.enums.transfer.PayTransferTypeEnum;
9 10
10 import java.util.Map; 11 import java.util.Map;
11 12
@@ -86,4 +87,12 @@ public interface PayClient { @@ -86,4 +87,12 @@ public interface PayClient {
86 */ 87 */
87 PayTransferRespDTO unifiedTransfer(PayTransferUnifiedReqDTO reqDTO); 88 PayTransferRespDTO unifiedTransfer(PayTransferUnifiedReqDTO reqDTO);
88 89
  90 + /**
  91 + * 获得转账订单信息
  92 + *
  93 + * @param outTradeNo 外部订单号
  94 + * @param type 转账类型
  95 + * @return 转账信息
  96 + */
  97 + PayTransferRespDTO getTransfer(String outTradeNo, PayTransferTypeEnum type);
89 } 98 }
yudao-framework/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/dto/transfer/PayTransferRespDTO.java
@@ -53,11 +53,24 @@ public class PayTransferRespDTO { @@ -53,11 +53,24 @@ public class PayTransferRespDTO {
53 /** 53 /**
54 * 创建【WAITING】状态的转账返回 54 * 创建【WAITING】状态的转账返回
55 */ 55 */
56 - public static PayTransferRespDTO waitingOf(String channelOrderNo, 56 + public static PayTransferRespDTO waitingOf(String channelTransferNo,
57 String outTransferNo, Object rawData) { 57 String outTransferNo, Object rawData) {
58 PayTransferRespDTO respDTO = new PayTransferRespDTO(); 58 PayTransferRespDTO respDTO = new PayTransferRespDTO();
59 respDTO.status = PayTransferStatusRespEnum.WAITING.getStatus(); 59 respDTO.status = PayTransferStatusRespEnum.WAITING.getStatus();
60 - respDTO.channelTransferNo = channelOrderNo; 60 + respDTO.channelTransferNo = channelTransferNo;
  61 + respDTO.outTransferNo = outTransferNo;
  62 + respDTO.rawData = rawData;
  63 + return respDTO;
  64 + }
  65 +
  66 + /**
  67 + * 创建【IN_PROGRESS】状态的转账返回
  68 + */
  69 + public static PayTransferRespDTO dealingOf(String channelTransferNo,
  70 + String outTransferNo, Object rawData) {
  71 + PayTransferRespDTO respDTO = new PayTransferRespDTO();
  72 + respDTO.status = PayTransferStatusRespEnum.IN_PROGRESS.getStatus();
  73 + respDTO.channelTransferNo = channelTransferNo;
61 respDTO.outTransferNo = outTransferNo; 74 respDTO.outTransferNo = outTransferNo;
62 respDTO.rawData = rawData; 75 respDTO.rawData = rawData;
63 return respDTO; 76 return respDTO;
yudao-framework/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/impl/AbstractPayClient.java
@@ -188,11 +188,11 @@ public abstract class AbstractPayClient&lt;Config extends PayClientConfig&gt; implemen @@ -188,11 +188,11 @@ public abstract class AbstractPayClient&lt;Config extends PayClientConfig&gt; implemen
188 188
189 @Override 189 @Override
190 public final PayTransferRespDTO unifiedTransfer(PayTransferUnifiedReqDTO reqDTO) { 190 public final PayTransferRespDTO unifiedTransfer(PayTransferUnifiedReqDTO reqDTO) {
  191 + validatePayTransferReqDTO(reqDTO);
191 PayTransferRespDTO resp; 192 PayTransferRespDTO resp;
192 - try{  
193 - validatePayTransferReqDTO(reqDTO); 193 + try {
194 resp = doUnifiedTransfer(reqDTO); 194 resp = doUnifiedTransfer(reqDTO);
195 - }catch (ServiceException ex) { // 业务异常,都是实现类已经翻译,所以直接抛出即可 195 + } catch (ServiceException ex) { // 业务异常,都是实现类已经翻译,所以直接抛出即可
196 throw ex; 196 throw ex;
197 } catch (Throwable ex) { 197 } catch (Throwable ex) {
198 // 系统异常,则包装成 PayException 异常抛出 198 // 系统异常,则包装成 PayException 异常抛出
@@ -219,9 +219,25 @@ public abstract class AbstractPayClient&lt;Config extends PayClientConfig&gt; implemen @@ -219,9 +219,25 @@ public abstract class AbstractPayClient&lt;Config extends PayClientConfig&gt; implemen
219 } 219 }
220 } 220 }
221 221
  222 + @Override
  223 + public final PayTransferRespDTO getTransfer(String outTradeNo, PayTransferTypeEnum type) {
  224 + try {
  225 + return doGetTransfer(outTradeNo, type);
  226 + } catch (ServiceException ex) { // 业务异常,都是实现类已经翻译,所以直接抛出即可
  227 + throw ex;
  228 + } catch (Throwable ex) {
  229 + log.error("[getTransfer][客户端({}) outTradeNo({}) type({}) 查询转账单异常]",
  230 + getId(), outTradeNo, type, ex);
  231 + throw buildPayException(ex);
  232 + }
  233 + }
  234 +
222 protected abstract PayTransferRespDTO doUnifiedTransfer(PayTransferUnifiedReqDTO reqDTO) 235 protected abstract PayTransferRespDTO doUnifiedTransfer(PayTransferUnifiedReqDTO reqDTO)
223 throws Throwable; 236 throws Throwable;
224 237
  238 + protected abstract PayTransferRespDTO doGetTransfer(String outTradeNo, PayTransferTypeEnum type)
  239 + throws Throwable;
  240 +
225 // ========== 各种工具方法 ========== 241 // ========== 各种工具方法 ==========
226 242
227 private PayException buildPayException(Throwable ex) { 243 private PayException buildPayException(Throwable ex) {
yudao-framework/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/impl/alipay/AbstractAlipayPayClient.java
@@ -23,14 +23,8 @@ import com.alipay.api.AlipayResponse; @@ -23,14 +23,8 @@ import com.alipay.api.AlipayResponse;
23 import com.alipay.api.DefaultAlipayClient; 23 import com.alipay.api.DefaultAlipayClient;
24 import com.alipay.api.domain.*; 24 import com.alipay.api.domain.*;
25 import com.alipay.api.internal.util.AlipaySignature; 25 import com.alipay.api.internal.util.AlipaySignature;
26 -import com.alipay.api.request.AlipayFundTransUniTransferRequest;  
27 -import com.alipay.api.request.AlipayTradeFastpayRefundQueryRequest;  
28 -import com.alipay.api.request.AlipayTradeQueryRequest;  
29 -import com.alipay.api.request.AlipayTradeRefundRequest;  
30 -import com.alipay.api.response.AlipayFundTransUniTransferResponse;  
31 -import com.alipay.api.response.AlipayTradeFastpayRefundQueryResponse;  
32 -import com.alipay.api.response.AlipayTradeQueryResponse;  
33 -import com.alipay.api.response.AlipayTradeRefundResponse; 26 +import com.alipay.api.request.*;
  27 +import com.alipay.api.response.*;
34 import lombok.Getter; 28 import lombok.Getter;
35 import lombok.SneakyThrows; 29 import lombok.SneakyThrows;
36 import lombok.extern.slf4j.Slf4j; 30 import lombok.extern.slf4j.Slf4j;
@@ -126,7 +120,7 @@ public abstract class AbstractAlipayPayClient extends AbstractPayClient&lt;AlipayPa @@ -126,7 +120,7 @@ public abstract class AbstractAlipayPayClient extends AbstractPayClient&lt;AlipayPa
126 } 120 }
127 // 2.2 解析订单的状态 121 // 2.2 解析订单的状态
128 Integer status = parseStatus(response.getTradeStatus()); 122 Integer status = parseStatus(response.getTradeStatus());
129 - Assert.notNull(status, () -> { 123 + Assert.notNull(status, () -> {
130 throw new IllegalArgumentException(StrUtil.format("body({}) 的 trade_status 不正确", response.getBody())); 124 throw new IllegalArgumentException(StrUtil.format("body({}) 的 trade_status 不正确", response.getBody()));
131 }); 125 });
132 return PayOrderRespDTO.of(status, response.getTradeNo(), response.getBuyerUserId(), LocalDateTimeUtil.of(response.getSendPayDate()), 126 return PayOrderRespDTO.of(status, response.getTradeNo(), response.getBuyerUserId(), LocalDateTimeUtil.of(response.getSendPayDate()),
@@ -228,7 +222,7 @@ public abstract class AbstractAlipayPayClient extends AbstractPayClient&lt;AlipayPa @@ -228,7 +222,7 @@ public abstract class AbstractAlipayPayClient extends AbstractPayClient&lt;AlipayPa
228 protected PayTransferRespDTO doUnifiedTransfer(PayTransferUnifiedReqDTO reqDTO) throws AlipayApiException { 222 protected PayTransferRespDTO doUnifiedTransfer(PayTransferUnifiedReqDTO reqDTO) throws AlipayApiException {
229 // 1.1 校验公钥类型 必须使用公钥证书模式 223 // 1.1 校验公钥类型 必须使用公钥证书模式
230 if (!Objects.equals(config.getMode(), MODE_CERTIFICATE)) { 224 if (!Objects.equals(config.getMode(), MODE_CERTIFICATE)) {
231 - throw exception0(ERROR_CONFIGURATION.getCode(),"支付宝单笔转账必须使用公钥证书模式"); 225 + throw exception0(ERROR_CONFIGURATION.getCode(), "支付宝单笔转账必须使用公钥证书模式");
232 } 226 }
233 // 1.2 构建 AlipayFundTransUniTransferModel 227 // 1.2 构建 AlipayFundTransUniTransferModel
234 AlipayFundTransUniTransferModel model = new AlipayFundTransUniTransferModel(); 228 AlipayFundTransUniTransferModel model = new AlipayFundTransUniTransferModel();
@@ -238,44 +232,96 @@ public abstract class AbstractAlipayPayClient extends AbstractPayClient&lt;AlipayPa @@ -238,44 +232,96 @@ public abstract class AbstractAlipayPayClient extends AbstractPayClient&lt;AlipayPa
238 model.setOutBizNo(reqDTO.getOutTransferNo()); 232 model.setOutBizNo(reqDTO.getOutTransferNo());
239 model.setProductCode("TRANS_ACCOUNT_NO_PWD"); // 销售产品码。单笔无密转账固定为 TRANS_ACCOUNT_NO_PWD 233 model.setProductCode("TRANS_ACCOUNT_NO_PWD"); // 销售产品码。单笔无密转账固定为 TRANS_ACCOUNT_NO_PWD
240 model.setBizScene("DIRECT_TRANSFER"); // 业务场景 单笔无密转账固定为 DIRECT_TRANSFER 234 model.setBizScene("DIRECT_TRANSFER"); // 业务场景 单笔无密转账固定为 DIRECT_TRANSFER
241 - model.setBusinessParams(JsonUtils.toJsonString(reqDTO.getChannelExtras())); 235 + if (reqDTO.getChannelExtras() != null) {
  236 + model.setBusinessParams(JsonUtils.toJsonString(reqDTO.getChannelExtras()));
  237 + }
  238 + // ② 个性化的参数
  239 + Participant payeeInfo = new Participant();
242 PayTransferTypeEnum transferType = PayTransferTypeEnum.typeOf(reqDTO.getType()); 240 PayTransferTypeEnum transferType = PayTransferTypeEnum.typeOf(reqDTO.getType());
243 switch (transferType) { 241 switch (transferType) {
244 // TODO @jason:是不是不用传递 transferType 参数哈?因为应该已经明确是支付宝啦? 242 // TODO @jason:是不是不用传递 transferType 参数哈?因为应该已经明确是支付宝啦?
245 // @芋艿。 是不是还要考虑转账到银行卡。所以传 transferType 但是转账到银行卡不知道要如何测试?? 243 // @芋艿。 是不是还要考虑转账到银行卡。所以传 transferType 但是转账到银行卡不知道要如何测试??
246 case ALIPAY_BALANCE: { 244 case ALIPAY_BALANCE: {
247 - // ② 个性化的参数  
248 - Participant payeeInfo = new Participant();  
249 payeeInfo.setIdentityType("ALIPAY_LOGON_ID"); 245 payeeInfo.setIdentityType("ALIPAY_LOGON_ID");
250 payeeInfo.setIdentity(reqDTO.getAlipayLogonId()); // 支付宝登录号 246 payeeInfo.setIdentity(reqDTO.getAlipayLogonId()); // 支付宝登录号
251 payeeInfo.setName(reqDTO.getUserName()); // 支付宝账号姓名 247 payeeInfo.setName(reqDTO.getUserName()); // 支付宝账号姓名
252 model.setPayeeInfo(payeeInfo); 248 model.setPayeeInfo(payeeInfo);
253 - // 1.3 构建 AlipayFundTransUniTransferRequest  
254 - AlipayFundTransUniTransferRequest request = new AlipayFundTransUniTransferRequest();  
255 - request.setBizModel(model);  
256 - // 执行请求  
257 - AlipayFundTransUniTransferResponse response = client.certificateExecute(request);  
258 - // 处理结果  
259 - if (!response.isSuccess()) {  
260 - // 当出现 SYSTEM_ERROR, 转账可能成功也可能失败。 返回 WAIT 状态. 后续 job 会轮询  
261 - if (ObjectUtils.equalsAny(response.getSubCode(), "SYSTEM_ERROR", "ACQ.SYSTEM_ERROR")) {  
262 - return PayTransferRespDTO.waitingOf(null, reqDTO.getOutTransferNo(), response);  
263 - }  
264 - return PayTransferRespDTO.closedOf(response.getSubCode(), response.getSubMsg(),  
265 - reqDTO.getOutTransferNo(), response);  
266 - }  
267 - return PayTransferRespDTO.successOf(response.getOrderId(), parseTime(response.getTransDate()),  
268 - response.getOutBizNo(), response); 249 + break;
269 } 250 }
270 case BANK_CARD: { 251 case BANK_CARD: {
271 - Participant payeeInfo = new Participant();  
272 payeeInfo.setIdentityType("BANKCARD_ACCOUNT"); 252 payeeInfo.setIdentityType("BANKCARD_ACCOUNT");
273 // TODO 待实现 253 // TODO 待实现
274 throw exception(NOT_IMPLEMENTED); 254 throw exception(NOT_IMPLEMENTED);
275 } 255 }
276 default: { 256 default: {
277 - throw exception0(BAD_REQUEST.getCode(),"不正确的转账类型: {}",transferType); 257 + throw exception0(BAD_REQUEST.getCode(), "不正确的转账类型: {}", transferType);
  258 + }
  259 + }
  260 + // 1.3 构建 AlipayFundTransUniTransferRequest
  261 + AlipayFundTransUniTransferRequest request = new AlipayFundTransUniTransferRequest();
  262 + request.setBizModel(model);
  263 + // 执行请求
  264 + AlipayFundTransUniTransferResponse response = client.certificateExecute(request);
  265 + // 处理结果
  266 + if (!response.isSuccess()) {
  267 + // 当出现 SYSTEM_ERROR, 转账可能成功也可能失败。 返回 WAIT 状态. 后续 job 会轮询,或相同 outBizNo 重新发起转账
  268 + // 发现 outBizNo 相同 两次请求参数相同. 会返回 "PAYMENT_INFO_INCONSISTENCY", 不知道哪里的问题. 暂时返回 WAIT. 后续job 会轮询
  269 + if (ObjectUtils.equalsAny(response.getSubCode(),"PAYMENT_INFO_INCONSISTENCY", "SYSTEM_ERROR", "ACQ.SYSTEM_ERROR")) {
  270 + return PayTransferRespDTO.waitingOf(null, reqDTO.getOutTransferNo(), response);
  271 + }
  272 + return PayTransferRespDTO.closedOf(response.getSubCode(), response.getSubMsg(),
  273 + reqDTO.getOutTransferNo(), response);
  274 + } else {
  275 + if (ObjectUtils.equalsAny(response.getStatus(), "REFUND", "FAIL")) { // 转账到银行卡会出现 "REFUND" "FAIL"
  276 + return PayTransferRespDTO.closedOf(response.getSubCode(), response.getSubMsg(),
  277 + reqDTO.getOutTransferNo(), response);
  278 + }
  279 + if (Objects.equals(response.getStatus(), "DEALING")) { // 转账到银行卡会出现 "DEALING" 处理中
  280 + return PayTransferRespDTO.dealingOf(response.getOrderId(), reqDTO.getOutTransferNo(), response);
  281 + }
  282 + return PayTransferRespDTO.successOf(response.getOrderId(), parseTime(response.getTransDate()),
  283 + response.getOutBizNo(), response);
  284 + }
  285 +
  286 + }
  287 +
  288 + @Override
  289 + protected PayTransferRespDTO doGetTransfer(String outTradeNo, PayTransferTypeEnum type) throws Throwable {
  290 + // 1.1 构建 AlipayFundTransCommonQueryModel
  291 + AlipayFundTransCommonQueryModel model = new AlipayFundTransCommonQueryModel();
  292 + model.setProductCode(type == PayTransferTypeEnum.BANK_CARD ? "TRANS_BANKCARD_NO_PWD" : "TRANS_ACCOUNT_NO_PWD");
  293 + model.setBizScene("DIRECT_TRANSFER"); //业务场景
  294 + model.setOutBizNo(outTradeNo);
  295 + // 1.2 构建 AlipayFundTransCommonQueryRequest
  296 + AlipayFundTransCommonQueryRequest request = new AlipayFundTransCommonQueryRequest();
  297 + request.setBizModel(model);
  298 +
  299 + // 2.1 执行请求
  300 + AlipayFundTransCommonQueryResponse response;
  301 + if (Objects.equals(config.getMode(), MODE_CERTIFICATE)) { // 证书模式
  302 + response = client.certificateExecute(request);
  303 + } else {
  304 + response = client.execute(request);
  305 + }
  306 + // 2.2 处理返回结果
  307 + if (response.isSuccess()) {
  308 + if (ObjectUtils.equalsAny(response.getStatus(), "REFUND", "FAIL")) { // 转账到银行卡会出现 "REFUND" "FAIL"
  309 + return PayTransferRespDTO.closedOf(response.getSubCode(), response.getSubMsg(),
  310 + outTradeNo, response);
  311 + }
  312 + if (Objects.equals(response.getStatus(), "DEALING")) { // 转账到银行卡会出现 "DEALING" 处理中
  313 + return PayTransferRespDTO.dealingOf(response.getOrderId(), outTradeNo, response);
278 } 314 }
  315 + return PayTransferRespDTO.successOf(response.getOrderId(), parseTime(response.getPayDate()),
  316 + response.getOutBizNo(), response);
  317 + } else {
  318 + // 当出现 SYSTEM_ERROR, 转账可能成功也可能失败。 返回 WAIT 状态. 后续 job 会轮询, 或相同 outBizNo 重新发起转账
  319 + // 当出现 ORDER_NOT_EXIST 可能是转账还在处理中,也可能是转账处理失败. 返回 WAIT 状态. 后续 job 会轮询, 或相同 outBizNo 重新发起转账
  320 + if (ObjectUtils.equalsAny(response.getSubCode(), "ORDER_NOT_EXIST", "SYSTEM_ERROR", "ACQ.SYSTEM_ERROR")) {
  321 + return PayTransferRespDTO.waitingOf(null, outTradeNo, response);
  322 + }
  323 + return PayTransferRespDTO.closedOf(response.getSubCode(), response.getSubMsg(),
  324 + outTradeNo, response);
279 } 325 }
280 } 326 }
281 327
yudao-framework/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/impl/mock/MockPayClient.java
@@ -9,6 +9,7 @@ import cn.iocoder.yudao.framework.pay.core.client.dto.transfer.PayTransferUnifie @@ -9,6 +9,7 @@ import cn.iocoder.yudao.framework.pay.core.client.dto.transfer.PayTransferUnifie
9 import cn.iocoder.yudao.framework.pay.core.client.impl.AbstractPayClient; 9 import cn.iocoder.yudao.framework.pay.core.client.impl.AbstractPayClient;
10 import cn.iocoder.yudao.framework.pay.core.client.impl.NonePayClientConfig; 10 import cn.iocoder.yudao.framework.pay.core.client.impl.NonePayClientConfig;
11 import cn.iocoder.yudao.framework.pay.core.enums.channel.PayChannelEnum; 11 import cn.iocoder.yudao.framework.pay.core.enums.channel.PayChannelEnum;
  12 +import cn.iocoder.yudao.framework.pay.core.enums.transfer.PayTransferTypeEnum;
12 13
13 import java.time.LocalDateTime; 14 import java.time.LocalDateTime;
14 import java.util.Map; 15 import java.util.Map;
@@ -71,4 +72,9 @@ public class MockPayClient extends AbstractPayClient&lt;NonePayClientConfig&gt; { @@ -71,4 +72,9 @@ public class MockPayClient extends AbstractPayClient&lt;NonePayClientConfig&gt; {
71 throw new UnsupportedOperationException("待实现"); 72 throw new UnsupportedOperationException("待实现");
72 } 73 }
73 74
  75 + @Override
  76 + protected PayTransferRespDTO doGetTransfer(String outTradeNo, PayTransferTypeEnum type) {
  77 + throw new UnsupportedOperationException("待实现");
  78 + }
  79 +
74 } 80 }
yudao-framework/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/impl/weixin/AbstractWxPayClient.java
@@ -16,6 +16,7 @@ import cn.iocoder.yudao.framework.pay.core.client.dto.transfer.PayTransferRespDT @@ -16,6 +16,7 @@ import cn.iocoder.yudao.framework.pay.core.client.dto.transfer.PayTransferRespDT
16 import cn.iocoder.yudao.framework.pay.core.client.dto.transfer.PayTransferUnifiedReqDTO; 16 import cn.iocoder.yudao.framework.pay.core.client.dto.transfer.PayTransferUnifiedReqDTO;
17 import cn.iocoder.yudao.framework.pay.core.client.impl.AbstractPayClient; 17 import cn.iocoder.yudao.framework.pay.core.client.impl.AbstractPayClient;
18 import cn.iocoder.yudao.framework.pay.core.enums.order.PayOrderStatusRespEnum; 18 import cn.iocoder.yudao.framework.pay.core.enums.order.PayOrderStatusRespEnum;
  19 +import cn.iocoder.yudao.framework.pay.core.enums.transfer.PayTransferTypeEnum;
19 import com.github.binarywang.wxpay.bean.notify.WxPayOrderNotifyResult; 20 import com.github.binarywang.wxpay.bean.notify.WxPayOrderNotifyResult;
20 import com.github.binarywang.wxpay.bean.notify.WxPayOrderNotifyV3Result; 21 import com.github.binarywang.wxpay.bean.notify.WxPayOrderNotifyV3Result;
21 import com.github.binarywang.wxpay.bean.notify.WxPayRefundNotifyResult; 22 import com.github.binarywang.wxpay.bean.notify.WxPayRefundNotifyResult;
@@ -431,6 +432,12 @@ public abstract class AbstractWxPayClient extends AbstractPayClient&lt;WxPayClientC @@ -431,6 +432,12 @@ public abstract class AbstractWxPayClient extends AbstractPayClient&lt;WxPayClientC
431 protected PayTransferRespDTO doUnifiedTransfer(PayTransferUnifiedReqDTO reqDTO) { 432 protected PayTransferRespDTO doUnifiedTransfer(PayTransferUnifiedReqDTO reqDTO) {
432 throw new UnsupportedOperationException("待实现"); 433 throw new UnsupportedOperationException("待实现");
433 } 434 }
  435 +
  436 + @Override
  437 + protected PayTransferRespDTO doGetTransfer(String outTradeNo, PayTransferTypeEnum type) {
  438 + throw new UnsupportedOperationException("待实现");
  439 + }
  440 +
434 // ========== 各种工具方法 ========== 441 // ========== 各种工具方法 ==========
435 442
436 static String formatDateV2(LocalDateTime time) { 443 static String formatDateV2(LocalDateTime time) {
yudao-framework/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/enums/transfer/PayTransferStatusRespEnum.java
@@ -38,4 +38,8 @@ public enum PayTransferStatusRespEnum { @@ -38,4 +38,8 @@ public enum PayTransferStatusRespEnum {
38 public static boolean isClosed(Integer status) { 38 public static boolean isClosed(Integer status) {
39 return Objects.equals(status, CLOSED.getStatus()); 39 return Objects.equals(status, CLOSED.getStatus());
40 } 40 }
  41 +
  42 + public static boolean isInProgress(Integer status) {
  43 + return Objects.equals(status, IN_PROGRESS.getStatus());
  44 + }
41 } 45 }
yudao-framework/yudao-spring-boot-starter-biz-tenant/pom.xml
@@ -48,6 +48,22 @@ @@ -48,6 +48,22 @@
48 <dependency> 48 <dependency>
49 <groupId>cn.iocoder.boot</groupId> 49 <groupId>cn.iocoder.boot</groupId>
50 <artifactId>yudao-spring-boot-starter-mq</artifactId> 50 <artifactId>yudao-spring-boot-starter-mq</artifactId>
  51 + <optional>true</optional>
  52 + </dependency>
  53 + <dependency>
  54 + <groupId>org.springframework.kafka</groupId>
  55 + <artifactId>spring-kafka</artifactId>
  56 + <optional>true</optional>
  57 + </dependency>
  58 + <dependency>
  59 + <groupId>org.springframework.amqp</groupId>
  60 + <artifactId>spring-rabbit</artifactId>
  61 + <optional>true</optional>
  62 + </dependency>
  63 + <dependency>
  64 + <groupId>org.apache.rocketmq</groupId>
  65 + <artifactId>rocketmq-spring-boot-starter</artifactId>
  66 + <optional>true</optional>
51 </dependency> 67 </dependency>
52 68
53 <!-- Test 测试相关 --> 69 <!-- Test 测试相关 -->
yudao-framework/yudao-spring-boot-starter-biz-tenant/src/main/java/cn/iocoder/yudao/framework/tenant/config/YudaoTenantAutoConfiguration.java
@@ -6,7 +6,9 @@ import cn.iocoder.yudao.framework.redis.config.YudaoCacheProperties; @@ -6,7 +6,9 @@ import cn.iocoder.yudao.framework.redis.config.YudaoCacheProperties;
6 import cn.iocoder.yudao.framework.tenant.core.aop.TenantIgnoreAspect; 6 import cn.iocoder.yudao.framework.tenant.core.aop.TenantIgnoreAspect;
7 import cn.iocoder.yudao.framework.tenant.core.db.TenantDatabaseInterceptor; 7 import cn.iocoder.yudao.framework.tenant.core.db.TenantDatabaseInterceptor;
8 import cn.iocoder.yudao.framework.tenant.core.job.TenantJobAspect; 8 import cn.iocoder.yudao.framework.tenant.core.job.TenantJobAspect;
9 -import cn.iocoder.yudao.framework.tenant.core.mq.TenantRedisMessageInterceptor; 9 +import cn.iocoder.yudao.framework.tenant.core.mq.rabbitmq.TenantRabbitMQInitializer;
  10 +import cn.iocoder.yudao.framework.tenant.core.mq.redis.TenantRedisMessageInterceptor;
  11 +import cn.iocoder.yudao.framework.tenant.core.mq.rocketmq.TenantRocketMQInitializer;
10 import cn.iocoder.yudao.framework.tenant.core.redis.TenantRedisCacheManager; 12 import cn.iocoder.yudao.framework.tenant.core.redis.TenantRedisCacheManager;
11 import cn.iocoder.yudao.framework.tenant.core.security.TenantSecurityWebFilter; 13 import cn.iocoder.yudao.framework.tenant.core.security.TenantSecurityWebFilter;
12 import cn.iocoder.yudao.framework.tenant.core.service.TenantFrameworkService; 14 import cn.iocoder.yudao.framework.tenant.core.service.TenantFrameworkService;
@@ -18,6 +20,7 @@ import cn.iocoder.yudao.module.system.api.tenant.TenantApi; @@ -18,6 +20,7 @@ import cn.iocoder.yudao.module.system.api.tenant.TenantApi;
18 import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor; 20 import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor;
19 import com.baomidou.mybatisplus.extension.plugins.inner.TenantLineInnerInterceptor; 21 import com.baomidou.mybatisplus.extension.plugins.inner.TenantLineInnerInterceptor;
20 import org.springframework.boot.autoconfigure.AutoConfiguration; 22 import org.springframework.boot.autoconfigure.AutoConfiguration;
  23 +import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
21 import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; 24 import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
22 import org.springframework.boot.context.properties.EnableConfigurationProperties; 25 import org.springframework.boot.context.properties.EnableConfigurationProperties;
23 import org.springframework.boot.web.servlet.FilterRegistrationBean; 26 import org.springframework.boot.web.servlet.FilterRegistrationBean;
@@ -92,6 +95,18 @@ public class YudaoTenantAutoConfiguration { @@ -92,6 +95,18 @@ public class YudaoTenantAutoConfiguration {
92 return new TenantRedisMessageInterceptor(); 95 return new TenantRedisMessageInterceptor();
93 } 96 }
94 97
  98 + @Bean
  99 + @ConditionalOnClass(name = "org.springframework.amqp.rabbit.core.RabbitTemplate")
  100 + public TenantRabbitMQInitializer tenantRabbitMQInitializer() {
  101 + return new TenantRabbitMQInitializer();
  102 + }
  103 +
  104 + @Bean
  105 + @ConditionalOnClass(name = "org.apache.rocketmq.spring.core.RocketMQTemplate")
  106 + public TenantRocketMQInitializer tenantRocketMQInitializer() {
  107 + return new TenantRocketMQInitializer();
  108 + }
  109 +
95 // ========== Job ========== 110 // ========== Job ==========
96 111
97 @Bean 112 @Bean
yudao-framework/yudao-spring-boot-starter-biz-tenant/src/main/java/cn/iocoder/yudao/framework/tenant/core/mq/kafka/TenantKafkaEnvironmentPostProcessor.java 0 → 100644
  1 +package cn.iocoder.yudao.framework.tenant.core.mq.kafka;
  2 +
  3 +import cn.hutool.core.util.StrUtil;
  4 +import lombok.extern.slf4j.Slf4j;
  5 +import org.springframework.boot.SpringApplication;
  6 +import org.springframework.boot.env.EnvironmentPostProcessor;
  7 +import org.springframework.core.env.ConfigurableEnvironment;
  8 +
  9 +/**
  10 + * 多租户的 Kafka 的 {@link EnvironmentPostProcessor} 实现类
  11 + *
  12 + * Kafka Producer 发送消息时,增加 {@link TenantKafkaProducerInterceptor} 拦截器
  13 + *
  14 + * @author 芋道源码
  15 + */
  16 +@Slf4j
  17 +public class TenantKafkaEnvironmentPostProcessor implements EnvironmentPostProcessor {
  18 +
  19 + private static final String PROPERTY_KEY_INTERCEPTOR_CLASSES = "spring.kafka.producer.properties.interceptor.classes";
  20 +
  21 + @Override
  22 + public void postProcessEnvironment(ConfigurableEnvironment environment, SpringApplication application) {
  23 + // 添加 TenantKafkaProducerInterceptor 拦截器
  24 + try {
  25 + String value = environment.getProperty(PROPERTY_KEY_INTERCEPTOR_CLASSES);
  26 + if (StrUtil.isEmpty(value)) {
  27 + value = TenantKafkaProducerInterceptor.class.getName();
  28 + } else {
  29 + value += "," + TenantKafkaProducerInterceptor.class.getName();
  30 + }
  31 + environment.getSystemProperties().put(PROPERTY_KEY_INTERCEPTOR_CLASSES, value);
  32 + } catch (NoClassDefFoundError ignore) {
  33 + // 如果触发 NoClassDefFoundError 异常,说明 TenantKafkaProducerInterceptor 类不存在,即没引入 kafka-spring 依赖
  34 + }
  35 + }
  36 +
  37 +}
yudao-framework/yudao-spring-boot-starter-biz-tenant/src/main/java/cn/iocoder/yudao/framework/tenant/core/mq/kafka/TenantKafkaProducerInterceptor.java 0 → 100644
  1 +package cn.iocoder.yudao.framework.tenant.core.mq.kafka;
  2 +
  3 +import cn.hutool.core.util.ReflectUtil;
  4 +import cn.iocoder.yudao.framework.tenant.core.context.TenantContextHolder;
  5 +import org.apache.kafka.clients.producer.ProducerInterceptor;
  6 +import org.apache.kafka.clients.producer.ProducerRecord;
  7 +import org.apache.kafka.clients.producer.RecordMetadata;
  8 +import org.apache.kafka.common.header.Headers;
  9 +import org.springframework.messaging.handler.invocation.InvocableHandlerMethod;
  10 +
  11 +import java.util.Map;
  12 +
  13 +import static cn.iocoder.yudao.framework.web.core.util.WebFrameworkUtils.HEADER_TENANT_ID;
  14 +
  15 +/**
  16 + * Kafka 消息队列的多租户 {@link ProducerInterceptor} 实现类
  17 + *
  18 + * 1. Producer 发送消息时,将 {@link TenantContextHolder} 租户编号,添加到消息的 Header 中
  19 + * 2. Consumer 消费消息时,将消息的 Header 的租户编号,添加到 {@link TenantContextHolder} 中,通过 {@link InvocableHandlerMethod} 实现
  20 + *
  21 + * @author 芋道源码
  22 + */
  23 +public class TenantKafkaProducerInterceptor implements ProducerInterceptor<Object, Object> {
  24 +
  25 + @Override
  26 + public ProducerRecord<Object, Object> onSend(ProducerRecord<Object, Object> record) {
  27 + Long tenantId = TenantContextHolder.getTenantId();
  28 + if (tenantId != null) {
  29 + Headers headers = (Headers) ReflectUtil.getFieldValue(record, "headers"); // private 属性,没有 get 方法,智能反射
  30 + headers.add(HEADER_TENANT_ID, tenantId.toString().getBytes());
  31 + }
  32 + return record;
  33 + }
  34 +
  35 + @Override
  36 + public void onAcknowledgement(RecordMetadata metadata, Exception exception) {
  37 + }
  38 +
  39 + @Override
  40 + public void close() {
  41 + }
  42 +
  43 + @Override
  44 + public void configure(Map<String, ?> configs) {
  45 + }
  46 +
  47 +}
yudao-framework/yudao-spring-boot-starter-biz-tenant/src/main/java/cn/iocoder/yudao/framework/tenant/core/mq/rabbitmq/TenantRabbitMQInitializer.java 0 → 100644
  1 +package cn.iocoder.yudao.framework.tenant.core.mq.rabbitmq;
  2 +
  3 +import org.springframework.amqp.rabbit.core.RabbitTemplate;
  4 +import org.springframework.beans.BeansException;
  5 +import org.springframework.beans.factory.config.BeanPostProcessor;
  6 +
  7 +/**
  8 + * 多租户的 RabbitMQ 初始化器
  9 + *
  10 + * @author 芋道源码
  11 + */
  12 +public class TenantRabbitMQInitializer implements BeanPostProcessor {
  13 +
  14 + @Override
  15 + public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
  16 + if (bean instanceof RabbitTemplate) {
  17 + RabbitTemplate rabbitTemplate = (RabbitTemplate) bean;
  18 + rabbitTemplate.addBeforePublishPostProcessors(new TenantRabbitMQMessagePostProcessor());
  19 + }
  20 + return bean;
  21 + }
  22 +
  23 +}
0 \ No newline at end of file 24 \ No newline at end of file
yudao-framework/yudao-spring-boot-starter-biz-tenant/src/main/java/cn/iocoder/yudao/framework/tenant/core/mq/rabbitmq/TenantRabbitMQMessagePostProcessor.java 0 → 100644
  1 +package cn.iocoder.yudao.framework.tenant.core.mq.rabbitmq;
  2 +
  3 +import cn.iocoder.yudao.framework.tenant.core.context.TenantContextHolder;
  4 +import org.apache.kafka.clients.producer.ProducerInterceptor;
  5 +import org.springframework.amqp.AmqpException;
  6 +import org.springframework.amqp.core.Message;
  7 +import org.springframework.amqp.core.MessagePostProcessor;
  8 +import org.springframework.messaging.handler.invocation.InvocableHandlerMethod;
  9 +
  10 +import static cn.iocoder.yudao.framework.web.core.util.WebFrameworkUtils.HEADER_TENANT_ID;
  11 +
  12 +/**
  13 + * RabbitMQ 消息队列的多租户 {@link ProducerInterceptor} 实现类
  14 + *
  15 + * 1. Producer 发送消息时,将 {@link TenantContextHolder} 租户编号,添加到消息的 Header 中
  16 + * 2. Consumer 消费消息时,将消息的 Header 的租户编号,添加到 {@link TenantContextHolder} 中,通过 {@link InvocableHandlerMethod} 实现
  17 + *
  18 + * @author 芋道源码
  19 + */
  20 +public class TenantRabbitMQMessagePostProcessor implements MessagePostProcessor {
  21 +
  22 + @Override
  23 + public Message postProcessMessage(Message message) throws AmqpException {
  24 + Long tenantId = TenantContextHolder.getTenantId();
  25 + if (tenantId != null) {
  26 + message.getMessageProperties().getHeaders().put(HEADER_TENANT_ID, tenantId);
  27 + }
  28 + return message;
  29 + }
  30 +
  31 +}
yudao-framework/yudao-spring-boot-starter-biz-tenant/src/main/java/cn/iocoder/yudao/framework/tenant/core/mq/TenantRedisMessageInterceptor.java renamed to yudao-framework/yudao-spring-boot-starter-biz-tenant/src/main/java/cn/iocoder/yudao/framework/tenant/core/mq/redis/TenantRedisMessageInterceptor.java
1 -package cn.iocoder.yudao.framework.tenant.core.mq; 1 +package cn.iocoder.yudao.framework.tenant.core.mq.redis;
2 2
3 import cn.hutool.core.util.StrUtil; 3 import cn.hutool.core.util.StrUtil;
4 -import cn.iocoder.yudao.framework.mq.core.interceptor.RedisMessageInterceptor;  
5 -import cn.iocoder.yudao.framework.mq.core.message.AbstractRedisMessage; 4 +import cn.iocoder.yudao.framework.mq.redis.core.interceptor.RedisMessageInterceptor;
  5 +import cn.iocoder.yudao.framework.mq.redis.core.message.AbstractRedisMessage;
6 import cn.iocoder.yudao.framework.tenant.core.context.TenantContextHolder; 6 import cn.iocoder.yudao.framework.tenant.core.context.TenantContextHolder;
7 7
8 import static cn.iocoder.yudao.framework.web.core.util.WebFrameworkUtils.HEADER_TENANT_ID; 8 import static cn.iocoder.yudao.framework.web.core.util.WebFrameworkUtils.HEADER_TENANT_ID;
yudao-framework/yudao-spring-boot-starter-biz-tenant/src/main/java/cn/iocoder/yudao/framework/tenant/core/mq/rocketmq/TenantRocketMQConsumeMessageHook.java 0 → 100644
  1 +package cn.iocoder.yudao.framework.tenant.core.mq.rocketmq;
  2 +
  3 +import cn.hutool.core.lang.Assert;
  4 +import cn.hutool.core.util.StrUtil;
  5 +import cn.iocoder.yudao.framework.tenant.core.context.TenantContextHolder;
  6 +import org.apache.rocketmq.client.hook.ConsumeMessageContext;
  7 +import org.apache.rocketmq.client.hook.ConsumeMessageHook;
  8 +import org.apache.rocketmq.common.message.MessageExt;
  9 +import org.springframework.messaging.handler.invocation.InvocableHandlerMethod;
  10 +
  11 +import java.util.List;
  12 +
  13 +import static cn.iocoder.yudao.framework.web.core.util.WebFrameworkUtils.HEADER_TENANT_ID;
  14 +
  15 +/**
  16 + * RocketMQ 消息队列的多租户 {@link ConsumeMessageHook} 实现类
  17 + *
  18 + * Consumer 消费消息时,将消息的 Header 的租户编号,添加到 {@link TenantContextHolder} 中,通过 {@link InvocableHandlerMethod} 实现
  19 + *
  20 + * @author 芋道源码
  21 + */
  22 +public class TenantRocketMQConsumeMessageHook implements ConsumeMessageHook {
  23 +
  24 + @Override
  25 + public String hookName() {
  26 + return getClass().getSimpleName();
  27 + }
  28 +
  29 + @Override
  30 + public void consumeMessageBefore(ConsumeMessageContext context) {
  31 + // 校验,消息必须是单条,不然设置租户可能不正确
  32 + List<MessageExt> messages = context.getMsgList();
  33 + Assert.isTrue(messages.size() == 1, "消息条数({})不正确", messages.size());
  34 + // 设置租户编号
  35 + String tenantId = messages.get(0).getUserProperty(HEADER_TENANT_ID);
  36 + if (StrUtil.isNotEmpty(tenantId)) {
  37 + TenantContextHolder.setTenantId(Long.parseLong(tenantId));
  38 + }
  39 + }
  40 +
  41 + @Override
  42 + public void consumeMessageAfter(ConsumeMessageContext context) {
  43 + TenantContextHolder.clear();
  44 + }
  45 +
  46 +}
yudao-framework/yudao-spring-boot-starter-biz-tenant/src/main/java/cn/iocoder/yudao/framework/tenant/core/mq/rocketmq/TenantRocketMQInitializer.java 0 → 100644
  1 +package cn.iocoder.yudao.framework.tenant.core.mq.rocketmq;
  2 +
  3 +import org.apache.rocketmq.client.consumer.DefaultMQPushConsumer;
  4 +import org.apache.rocketmq.client.impl.consumer.DefaultMQPushConsumerImpl;
  5 +import org.apache.rocketmq.client.impl.producer.DefaultMQProducerImpl;
  6 +import org.apache.rocketmq.client.producer.DefaultMQProducer;
  7 +import org.apache.rocketmq.spring.core.RocketMQTemplate;
  8 +import org.apache.rocketmq.spring.support.DefaultRocketMQListenerContainer;
  9 +import org.springframework.beans.BeansException;
  10 +import org.springframework.beans.factory.config.BeanPostProcessor;
  11 +
  12 +/**
  13 + * 多租户的 RocketMQ 初始化器
  14 + *
  15 + * @author 芋道源码
  16 + */
  17 +public class TenantRocketMQInitializer implements BeanPostProcessor {
  18 +
  19 + @Override
  20 + public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
  21 + if (bean instanceof DefaultRocketMQListenerContainer) {
  22 + DefaultRocketMQListenerContainer container = (DefaultRocketMQListenerContainer) bean;
  23 + initTenantConsumer(container.getConsumer());
  24 + } else if (bean instanceof RocketMQTemplate) {
  25 + RocketMQTemplate template = (RocketMQTemplate) bean;
  26 + initTenantProducer(template.getProducer());
  27 + }
  28 + return bean;
  29 + }
  30 +
  31 + private void initTenantProducer(DefaultMQProducer producer) {
  32 + if (producer == null) {
  33 + return;
  34 + }
  35 + DefaultMQProducerImpl producerImpl = producer.getDefaultMQProducerImpl();
  36 + if (producerImpl == null) {
  37 + return;
  38 + }
  39 + producerImpl.registerSendMessageHook(new TenantRocketMQSendMessageHook());
  40 + }
  41 +
  42 + private void initTenantConsumer(DefaultMQPushConsumer consumer) {
  43 + if (consumer == null) {
  44 + return;
  45 + }
  46 + DefaultMQPushConsumerImpl consumerImpl = consumer.getDefaultMQPushConsumerImpl();
  47 + if (consumerImpl == null) {
  48 + return;
  49 + }
  50 + consumerImpl.registerConsumeMessageHook(new TenantRocketMQConsumeMessageHook());
  51 + }
  52 +
  53 +}
0 \ No newline at end of file 54 \ No newline at end of file
yudao-framework/yudao-spring-boot-starter-biz-tenant/src/main/java/cn/iocoder/yudao/framework/tenant/core/mq/rocketmq/TenantRocketMQSendMessageHook.java 0 → 100644
  1 +package cn.iocoder.yudao.framework.tenant.core.mq.rocketmq;
  2 +
  3 +import cn.iocoder.yudao.framework.tenant.core.context.TenantContextHolder;
  4 +import org.apache.rocketmq.client.hook.SendMessageContext;
  5 +import org.apache.rocketmq.client.hook.SendMessageHook;
  6 +
  7 +import static cn.iocoder.yudao.framework.web.core.util.WebFrameworkUtils.HEADER_TENANT_ID;
  8 +
  9 +/**
  10 + * RocketMQ 消息队列的多租户 {@link SendMessageHook} 实现类
  11 + *
  12 + * Producer 发送消息时,将 {@link TenantContextHolder} 租户编号,添加到消息的 Header 中
  13 + *
  14 + * @author 芋道源码
  15 + */
  16 +public class TenantRocketMQSendMessageHook implements SendMessageHook {
  17 +
  18 + @Override
  19 + public String hookName() {
  20 + return getClass().getSimpleName();
  21 + }
  22 +
  23 + @Override
  24 + public void sendMessageBefore(SendMessageContext sendMessageContext) {
  25 + Long tenantId = TenantContextHolder.getTenantId();
  26 + if (tenantId == null) {
  27 + return;
  28 + }
  29 + sendMessageContext.getMessage().putUserProperty(HEADER_TENANT_ID, tenantId.toString());
  30 + }
  31 +
  32 + @Override
  33 + public void sendMessageAfter(SendMessageContext sendMessageContext) {
  34 + }
  35 +
  36 +}
yudao-framework/yudao-spring-boot-starter-biz-tenant/src/main/java/org/springframework/messaging/handler/invocation/InvocableHandlerMethod.java 0 → 100644
  1 +/*
  2 + * Copyright 2002-2021 the original author or authors.
  3 + *
  4 + * Licensed under the Apache License, Version 2.0 (the "License");
  5 + * you may not use this file except in compliance with the License.
  6 + * You may obtain a copy of the License at
  7 + *
  8 + * https://www.apache.org/licenses/LICENSE-2.0
  9 + *
  10 + * Unless required by applicable law or agreed to in writing, software
  11 + * distributed under the License is distributed on an "AS IS" BASIS,
  12 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13 + * See the License for the specific language governing permissions and
  14 + * limitations under the License.
  15 + */
  16 +
  17 +package org.springframework.messaging.handler.invocation;
  18 +
  19 +import cn.iocoder.yudao.framework.tenant.core.context.TenantContextHolder;
  20 +import cn.iocoder.yudao.framework.tenant.core.util.TenantUtils;
  21 +import org.springframework.core.DefaultParameterNameDiscoverer;
  22 +import org.springframework.core.MethodParameter;
  23 +import org.springframework.core.ParameterNameDiscoverer;
  24 +import org.springframework.core.ResolvableType;
  25 +import org.springframework.lang.Nullable;
  26 +import org.springframework.messaging.Message;
  27 +import org.springframework.messaging.handler.HandlerMethod;
  28 +import org.springframework.util.ObjectUtils;
  29 +
  30 +import java.lang.reflect.InvocationTargetException;
  31 +import java.lang.reflect.Method;
  32 +import java.lang.reflect.Type;
  33 +import java.util.Arrays;
  34 +
  35 +import static cn.iocoder.yudao.framework.web.core.util.WebFrameworkUtils.HEADER_TENANT_ID;
  36 +
  37 +/**
  38 + * Extension of {@link HandlerMethod} that invokes the underlying method with
  39 + * argument values resolved from the current HTTP request through a list of
  40 + * {@link HandlerMethodArgumentResolver}.
  41 + *
  42 + * 针对 rabbitmq-spring 和 kafka-spring,不存在合适的拓展点,可以实现 Consumer 消费前,读取 Header 中的 tenant-id 设置到 {@link TenantContextHolder} 中
  43 + * TODO 芋艿:持续跟进,看看有没新的拓展点
  44 + *
  45 + * @author Rossen Stoyanchev
  46 + * @author Juergen Hoeller
  47 + * @since 4.0
  48 + */
  49 +public class InvocableHandlerMethod extends HandlerMethod {
  50 +
  51 + private static final Object[] EMPTY_ARGS = new Object[0];
  52 +
  53 + private HandlerMethodArgumentResolverComposite resolvers = new HandlerMethodArgumentResolverComposite();
  54 +
  55 + private ParameterNameDiscoverer parameterNameDiscoverer = new DefaultParameterNameDiscoverer();
  56 +
  57 + /**
  58 + * Create an instance from a {@code HandlerMethod}.
  59 + */
  60 + public InvocableHandlerMethod(HandlerMethod handlerMethod) {
  61 + super(handlerMethod);
  62 + }
  63 +
  64 + /**
  65 + * Create an instance from a bean instance and a method.
  66 + */
  67 + public InvocableHandlerMethod(Object bean, Method method) {
  68 + super(bean, method);
  69 + }
  70 +
  71 + /**
  72 + * Construct a new handler method with the given bean instance, method name and parameters.
  73 + * @param bean the object bean
  74 + * @param methodName the method name
  75 + * @param parameterTypes the method parameter types
  76 + * @throws NoSuchMethodException when the method cannot be found
  77 + */
  78 + public InvocableHandlerMethod(Object bean, String methodName, Class<?>... parameterTypes)
  79 + throws NoSuchMethodException {
  80 +
  81 + super(bean, methodName, parameterTypes);
  82 + }
  83 +
  84 + /**
  85 + * Set {@link HandlerMethodArgumentResolver HandlerMethodArgumentResolvers} to use for resolving method argument values.
  86 + */
  87 + public void setMessageMethodArgumentResolvers(HandlerMethodArgumentResolverComposite argumentResolvers) {
  88 + this.resolvers = argumentResolvers;
  89 + }
  90 +
  91 + /**
  92 + * Set the ParameterNameDiscoverer for resolving parameter names when needed
  93 + * (e.g. default request attribute name).
  94 + * <p>Default is a {@link DefaultParameterNameDiscoverer}.
  95 + */
  96 + public void setParameterNameDiscoverer(ParameterNameDiscoverer parameterNameDiscoverer) {
  97 + this.parameterNameDiscoverer = parameterNameDiscoverer;
  98 + }
  99 +
  100 + /**
  101 + * Invoke the method after resolving its argument values in the context of the given message.
  102 + * <p>Argument values are commonly resolved through
  103 + * {@link HandlerMethodArgumentResolver HandlerMethodArgumentResolvers}.
  104 + * The {@code providedArgs} parameter however may supply argument values to be used directly,
  105 + * i.e. without argument resolution.
  106 + * <p>Delegates to {@link #getMethodArgumentValues} and calls {@link #doInvoke} with the
  107 + * resolved arguments.
  108 + * @param message the current message being processed
  109 + * @param providedArgs "given" arguments matched by type, not resolved
  110 + * @return the raw value returned by the invoked method
  111 + * @throws Exception raised if no suitable argument resolver can be found,
  112 + * or if the method raised an exception
  113 + * @see #getMethodArgumentValues
  114 + * @see #doInvoke
  115 + */
  116 + @Nullable
  117 + public Object invoke(Message<?> message, Object... providedArgs) throws Exception {
  118 + Object[] args = getMethodArgumentValues(message, providedArgs);
  119 + if (logger.isTraceEnabled()) {
  120 + logger.trace("Arguments: " + Arrays.toString(args));
  121 + }
  122 + // 注意:如下是本类的改动点!!!
  123 + // 情况一:无租户编号的情况
  124 + Long tenantId= parseTenantId(message);
  125 + if (tenantId == null) {
  126 + return doInvoke(args);
  127 + }
  128 + // 情况二:有租户的情况下
  129 + return TenantUtils.execute(tenantId, () -> doInvoke(args));
  130 + }
  131 +
  132 + private Long parseTenantId(Message<?> message) {
  133 + Object tenantId = message.getHeaders().get(HEADER_TENANT_ID);
  134 + if (tenantId == null) {
  135 + return null;
  136 + }
  137 + if (tenantId instanceof Long) {
  138 + return (Long) tenantId;
  139 + }
  140 + if (tenantId instanceof Number) {
  141 + return ((Number) tenantId).longValue();
  142 + }
  143 + if (tenantId instanceof String) {
  144 + return Long.parseLong((String) tenantId);
  145 + }
  146 + if (tenantId instanceof byte[]) {
  147 + return Long.parseLong(new String((byte[]) tenantId));
  148 + }
  149 + throw new IllegalArgumentException("未知的数据类型:" + tenantId);
  150 + }
  151 +
  152 + /**
  153 + * Get the method argument values for the current message, checking the provided
  154 + * argument values and falling back to the configured argument resolvers.
  155 + * <p>The resulting array will be passed into {@link #doInvoke}.
  156 + * @since 5.1.2
  157 + */
  158 + protected Object[] getMethodArgumentValues(Message<?> message, Object... providedArgs) throws Exception {
  159 + MethodParameter[] parameters = getMethodParameters();
  160 + if (ObjectUtils.isEmpty(parameters)) {
  161 + return EMPTY_ARGS;
  162 + }
  163 +
  164 + Object[] args = new Object[parameters.length];
  165 + for (int i = 0; i < parameters.length; i++) {
  166 + MethodParameter parameter = parameters[i];
  167 + parameter.initParameterNameDiscovery(this.parameterNameDiscoverer);
  168 + args[i] = findProvidedArgument(parameter, providedArgs);
  169 + if (args[i] != null) {
  170 + continue;
  171 + }
  172 + if (!this.resolvers.supportsParameter(parameter)) {
  173 + throw new MethodArgumentResolutionException(
  174 + message, parameter, formatArgumentError(parameter, "No suitable resolver"));
  175 + }
  176 + try {
  177 + args[i] = this.resolvers.resolveArgument(parameter, message);
  178 + }
  179 + catch (Exception ex) {
  180 + // Leave stack trace for later, exception may actually be resolved and handled...
  181 + if (logger.isDebugEnabled()) {
  182 + String exMsg = ex.getMessage();
  183 + if (exMsg != null && !exMsg.contains(parameter.getExecutable().toGenericString())) {
  184 + logger.debug(formatArgumentError(parameter, exMsg));
  185 + }
  186 + }
  187 + throw ex;
  188 + }
  189 + }
  190 + return args;
  191 + }
  192 +
  193 + /**
  194 + * Invoke the handler method with the given argument values.
  195 + */
  196 + @Nullable
  197 + protected Object doInvoke(Object... args) throws Exception {
  198 + try {
  199 + return getBridgedMethod().invoke(getBean(), args);
  200 + }
  201 + catch (IllegalArgumentException ex) {
  202 + assertTargetBean(getBridgedMethod(), getBean(), args);
  203 + String text = (ex.getMessage() != null ? ex.getMessage() : "Illegal argument");
  204 + throw new IllegalStateException(formatInvokeError(text, args), ex);
  205 + }
  206 + catch (InvocationTargetException ex) {
  207 + // Unwrap for HandlerExceptionResolvers ...
  208 + Throwable targetException = ex.getTargetException();
  209 + if (targetException instanceof RuntimeException) {
  210 + throw (RuntimeException) targetException;
  211 + }
  212 + else if (targetException instanceof Error) {
  213 + throw (Error) targetException;
  214 + }
  215 + else if (targetException instanceof Exception) {
  216 + throw (Exception) targetException;
  217 + }
  218 + else {
  219 + throw new IllegalStateException(formatInvokeError("Invocation failure", args), targetException);
  220 + }
  221 + }
  222 + }
  223 +
  224 + MethodParameter getAsyncReturnValueType(@Nullable Object returnValue) {
  225 + return new AsyncResultMethodParameter(returnValue);
  226 + }
  227 +
  228 + private class AsyncResultMethodParameter extends HandlerMethodParameter {
  229 +
  230 + @Nullable
  231 + private final Object returnValue;
  232 +
  233 + private final ResolvableType returnType;
  234 +
  235 + public AsyncResultMethodParameter(@Nullable Object returnValue) {
  236 + super(-1);
  237 + this.returnValue = returnValue;
  238 + this.returnType = ResolvableType.forType(super.getGenericParameterType()).getGeneric();
  239 + }
  240 +
  241 + protected AsyncResultMethodParameter(AsyncResultMethodParameter original) {
  242 + super(original);
  243 + this.returnValue = original.returnValue;
  244 + this.returnType = original.returnType;
  245 + }
  246 +
  247 + @Override
  248 + public Class<?> getParameterType() {
  249 + if (this.returnValue != null) {
  250 + return this.returnValue.getClass();
  251 + }
  252 + if (!ResolvableType.NONE.equals(this.returnType)) {
  253 + return this.returnType.toClass();
  254 + }
  255 + return super.getParameterType();
  256 + }
  257 +
  258 + @Override
  259 + public Type getGenericParameterType() {
  260 + return this.returnType.getType();
  261 + }
  262 +
  263 + @Override
  264 + public AsyncResultMethodParameter clone() {
  265 + return new AsyncResultMethodParameter(this);
  266 + }
  267 + }
  268 +
  269 +}
yudao-framework/yudao-spring-boot-starter-biz-tenant/src/main/resources/META-INF/spring.factories 0 → 100644
  1 +org.springframework.boot.env.EnvironmentPostProcessor=\
  2 + cn.iocoder.yudao.framework.tenant.core.mq.kafka.TenantKafkaEnvironmentPostProcessor
yudao-framework/yudao-spring-boot-starter-biz-tenant/src/test/java/cn/iocoder/yudao/framework/tenant/core/job/TestJob.java deleted
1 -package cn.iocoder.yudao.framework.tenant.core.job;  
2 -  
3 -import cn.hutool.core.collection.CollUtil;  
4 -import cn.iocoder.yudao.framework.quartz.core.handler.JobHandler;  
5 -import cn.iocoder.yudao.framework.tenant.core.context.TenantContextHolder;  
6 -import org.springframework.stereotype.Component;  
7 -  
8 -import java.util.List;  
9 -import java.util.concurrent.CopyOnWriteArrayList;  
10 -  
11 -@Component  
12 -public class TestJob implements JobHandler {  
13 -  
14 - private final List<Long> tenantIds = new CopyOnWriteArrayList<>();  
15 -  
16 - @Override  
17 - @TenantJob // 标记多租户  
18 - public String execute(String param) throws Exception {  
19 - tenantIds.add(TenantContextHolder.getTenantId());  
20 - return "success";  
21 - }  
22 -  
23 - public List<Long> getTenantIds() {  
24 - CollUtil.sort(tenantIds, Long::compareTo);  
25 - return tenantIds;  
26 - }  
27 -  
28 -}  
yudao-framework/yudao-spring-boot-starter-mq/pom.xml
@@ -12,7 +12,7 @@ @@ -12,7 +12,7 @@
12 <packaging>jar</packaging> 12 <packaging>jar</packaging>
13 13
14 <name>${project.artifactId}</name> 14 <name>${project.artifactId}</name>
15 - <description>消息队列,基于 Redis Pub/Sub 实现广播消费,基于 Stream 实现集群消费</description> 15 + <description>消息队列,支持 Redis、RocketMQ、RabbitMQ、Kafka 四种</description>
16 <url>https://github.com/YunaiV/ruoyi-vue-pro</url> 16 <url>https://github.com/YunaiV/ruoyi-vue-pro</url>
17 17
18 <dependencies> 18 <dependencies>
@@ -21,6 +21,23 @@ @@ -21,6 +21,23 @@
21 <groupId>cn.iocoder.boot</groupId> 21 <groupId>cn.iocoder.boot</groupId>
22 <artifactId>yudao-spring-boot-starter-redis</artifactId> 22 <artifactId>yudao-spring-boot-starter-redis</artifactId>
23 </dependency> 23 </dependency>
  24 +
  25 + <!-- 消息队列相关 -->
  26 + <dependency>
  27 + <groupId>org.springframework.kafka</groupId>
  28 + <artifactId>spring-kafka</artifactId>
  29 + <optional>true</optional>
  30 + </dependency>
  31 + <dependency>
  32 + <groupId>org.springframework.amqp</groupId>
  33 + <artifactId>spring-rabbit</artifactId>
  34 + <optional>true</optional>
  35 + </dependency>
  36 + <dependency>
  37 + <groupId>org.apache.rocketmq</groupId>
  38 + <artifactId>rocketmq-spring-boot-starter</artifactId>
  39 + <optional>true</optional>
  40 + </dependency>
24 </dependencies> 41 </dependencies>
25 42
26 -</project> 43 -</project>
  44 +</project>
27 \ No newline at end of file 45 \ No newline at end of file
yudao-framework/yudao-spring-boot-starter-mq/src/main/java/cn/iocoder/yudao/framework/mq/package-info.java
1 /** 1 /**
2 - * 消息队列,基于 Redis 提供:  
3 - * 1. 基于 Pub/Sub 实现广播消费  
4 - * 2. 基于 Stream 实现集群消费 2 + * 消息队列,支持 Redis、RocketMQ、RabbitMQ、Kafka 四种
5 */ 3 */
6 package cn.iocoder.yudao.framework.mq; 4 package cn.iocoder.yudao.framework.mq;
yudao-framework/yudao-spring-boot-starter-mq/src/main/java/cn/iocoder/yudao/framework/mq/rabbitmq/config/YudaoRabbitMQAutoConfiguration.java 0 → 100644
  1 +package cn.iocoder.yudao.framework.mq.rabbitmq.config;
  2 +
  3 +import cn.hutool.core.util.ReflectUtil;
  4 +import lombok.extern.slf4j.Slf4j;
  5 +import org.springframework.amqp.utils.SerializationUtils;
  6 +import org.springframework.boot.autoconfigure.AutoConfiguration;
  7 +import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
  8 +
  9 +import java.lang.reflect.Field;
  10 +
  11 +/**
  12 + * RabbitMQ 消息队列配置类
  13 + *
  14 + * @author 芋道源码
  15 + */
  16 +@AutoConfiguration
  17 +@Slf4j
  18 +@ConditionalOnClass(name = "org.springframework.amqp.rabbit.core.RabbitTemplate")
  19 +public class YudaoRabbitMQAutoConfiguration {
  20 +
  21 + static {
  22 + // 强制设置 SerializationUtils 的 TRUST_ALL 为 true,避免 RabbitMQ Consumer 反序列化消息报错
  23 + // 为什么不通过设置 spring.amqp.deserialization.trust.all 呢?因为可能在 SerializationUtils static 初始化后
  24 + Field trustAllField = ReflectUtil.getField(SerializationUtils.class, "TRUST_ALL");
  25 + ReflectUtil.removeFinalModify(trustAllField);
  26 + ReflectUtil.setFieldValue(SerializationUtils.class, trustAllField, true);
  27 + }
  28 +
  29 +}
yudao-framework/yudao-spring-boot-starter-mq/src/main/java/cn/iocoder/yudao/framework/mq/rabbitmq/core/package-info.java 0 → 100644
  1 +/**
  2 + * 占位符,无特殊逻辑
  3 + */
  4 +package cn.iocoder.yudao.framework.mq.rabbitmq.core;
0 \ No newline at end of file 5 \ No newline at end of file
yudao-framework/yudao-spring-boot-starter-mq/src/main/java/cn/iocoder/yudao/framework/mq/rabbitmq/package-info.java 0 → 100644
  1 +/**
  2 + * 消息队列,基于 RabbitMQ 提供
  3 + */
  4 +package cn.iocoder.yudao.framework.mq.rabbitmq;
yudao-framework/yudao-spring-boot-starter-mq/src/main/java/cn/iocoder/yudao/framework/mq/config/YudaoMQAutoConfiguration.java renamed to yudao-framework/yudao-spring-boot-starter-mq/src/main/java/cn/iocoder/yudao/framework/mq/redis/config/YudaoRedisMQAutoConfiguration.java
1 -package cn.iocoder.yudao.framework.mq.config; 1 +package cn.iocoder.yudao.framework.mq.redis.config;
2 2
3 import cn.hutool.core.map.MapUtil; 3 import cn.hutool.core.map.MapUtil;
4 import cn.hutool.core.util.StrUtil; 4 import cn.hutool.core.util.StrUtil;
5 import cn.hutool.system.SystemUtil; 5 import cn.hutool.system.SystemUtil;
6 import cn.iocoder.yudao.framework.common.enums.DocumentEnum; 6 import cn.iocoder.yudao.framework.common.enums.DocumentEnum;
7 -import cn.iocoder.yudao.framework.mq.core.RedisMQTemplate;  
8 -import cn.iocoder.yudao.framework.mq.core.interceptor.RedisMessageInterceptor;  
9 -import cn.iocoder.yudao.framework.mq.core.pubsub.AbstractChannelMessageListener;  
10 -import cn.iocoder.yudao.framework.mq.core.stream.AbstractStreamMessageListener;  
11 -import cn.iocoder.yudao.framework.mq.job.RedisPendingMessageResendJob; 7 +import cn.iocoder.yudao.framework.mq.redis.core.RedisMQTemplate;
  8 +import cn.iocoder.yudao.framework.mq.redis.core.interceptor.RedisMessageInterceptor;
  9 +import cn.iocoder.yudao.framework.mq.redis.core.job.RedisPendingMessageResendJob;
  10 +import cn.iocoder.yudao.framework.mq.redis.core.pubsub.AbstractRedisChannelMessageListener;
  11 +import cn.iocoder.yudao.framework.mq.redis.core.stream.AbstractRedisStreamMessageListener;
12 import cn.iocoder.yudao.framework.redis.config.YudaoRedisAutoConfiguration; 12 import cn.iocoder.yudao.framework.redis.config.YudaoRedisAutoConfiguration;
13 import lombok.extern.slf4j.Slf4j; 13 import lombok.extern.slf4j.Slf4j;
14 import org.redisson.api.RedissonClient; 14 import org.redisson.api.RedissonClient;
15 import org.springframework.beans.factory.annotation.Value; 15 import org.springframework.beans.factory.annotation.Value;
16 import org.springframework.boot.autoconfigure.AutoConfiguration; 16 import org.springframework.boot.autoconfigure.AutoConfiguration;
17 import org.springframework.boot.autoconfigure.condition.ConditionalOnBean; 17 import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
18 -import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;  
19 import org.springframework.context.annotation.Bean; 18 import org.springframework.context.annotation.Bean;
20 import org.springframework.data.redis.connection.RedisServerCommands; 19 import org.springframework.data.redis.connection.RedisServerCommands;
21 import org.springframework.data.redis.connection.stream.Consumer; 20 import org.springframework.data.redis.connection.stream.Consumer;
@@ -27,7 +26,6 @@ import org.springframework.data.redis.core.RedisTemplate; @@ -27,7 +26,6 @@ import org.springframework.data.redis.core.RedisTemplate;
27 import org.springframework.data.redis.core.StringRedisTemplate; 26 import org.springframework.data.redis.core.StringRedisTemplate;
28 import org.springframework.data.redis.listener.ChannelTopic; 27 import org.springframework.data.redis.listener.ChannelTopic;
29 import org.springframework.data.redis.listener.RedisMessageListenerContainer; 28 import org.springframework.data.redis.listener.RedisMessageListenerContainer;
30 -import org.springframework.data.redis.stream.DefaultStreamMessageListenerContainerX;  
31 import org.springframework.data.redis.stream.StreamMessageListenerContainer; 29 import org.springframework.data.redis.stream.StreamMessageListenerContainer;
32 import org.springframework.scheduling.annotation.EnableScheduling; 30 import org.springframework.scheduling.annotation.EnableScheduling;
33 31
@@ -42,7 +40,7 @@ import java.util.Properties; @@ -42,7 +40,7 @@ import java.util.Properties;
42 @Slf4j 40 @Slf4j
43 @EnableScheduling // 启用定时任务,用于 RedisPendingMessageResendJob 重发消息 41 @EnableScheduling // 启用定时任务,用于 RedisPendingMessageResendJob 重发消息
44 @AutoConfiguration(after = YudaoRedisAutoConfiguration.class) 42 @AutoConfiguration(after = YudaoRedisAutoConfiguration.class)
45 -public class YudaoMQAutoConfiguration { 43 +public class YudaoRedisMQAutoConfiguration {
46 44
47 @Bean 45 @Bean
48 public RedisMQTemplate redisMQTemplate(StringRedisTemplate redisTemplate, 46 public RedisMQTemplate redisMQTemplate(StringRedisTemplate redisTemplate,
@@ -59,10 +57,9 @@ public class YudaoMQAutoConfiguration { @@ -59,10 +57,9 @@ public class YudaoMQAutoConfiguration {
59 * 创建 Redis Pub/Sub 广播消费的容器 57 * 创建 Redis Pub/Sub 广播消费的容器
60 */ 58 */
61 @Bean(initMethod = "start", destroyMethod = "stop") 59 @Bean(initMethod = "start", destroyMethod = "stop")
62 - @ConditionalOnBean(AbstractChannelMessageListener.class) // 只有 AbstractChannelMessageListener 存在的时候,才需要注册 Redis pubsub 监听  
63 - @ConditionalOnProperty(prefix = "yudao.mq.redis.pubsub", value = "enable", matchIfMissing = true) // 允许使用 yudao.mq.redis.pubsub.enable=false 禁用多租户 60 + @ConditionalOnBean(AbstractRedisChannelMessageListener.class) // 只有 AbstractChannelMessageListener 存在的时候,才需要注册 Redis pubsub 监听
64 public RedisMessageListenerContainer redisMessageListenerContainer( 61 public RedisMessageListenerContainer redisMessageListenerContainer(
65 - RedisMQTemplate redisMQTemplate, List<AbstractChannelMessageListener<?>> listeners) { 62 + RedisMQTemplate redisMQTemplate, List<AbstractRedisChannelMessageListener<?>> listeners) {
66 // 创建 RedisMessageListenerContainer 对象 63 // 创建 RedisMessageListenerContainer 对象
67 RedisMessageListenerContainer container = new RedisMessageListenerContainer(); 64 RedisMessageListenerContainer container = new RedisMessageListenerContainer();
68 // 设置 RedisConnection 工厂。 65 // 设置 RedisConnection 工厂。
@@ -81,9 +78,8 @@ public class YudaoMQAutoConfiguration { @@ -81,9 +78,8 @@ public class YudaoMQAutoConfiguration {
81 * 创建 Redis Stream 重新消费的任务 78 * 创建 Redis Stream 重新消费的任务
82 */ 79 */
83 @Bean 80 @Bean
84 - @ConditionalOnBean(AbstractStreamMessageListener.class) // 只有 AbstractStreamMessageListener 存在的时候,才需要注册 Redis pubsub 监听  
85 - @ConditionalOnProperty(prefix = "yudao.mq.redis.stream", value = "enable", matchIfMissing = true) // 允许使用 yudao.mq.redis.stream.enable=false 禁用多租户  
86 - public RedisPendingMessageResendJob redisPendingMessageResendJob(List<AbstractStreamMessageListener<?>> listeners, 81 + @ConditionalOnBean(AbstractRedisStreamMessageListener.class) // 只有 AbstractStreamMessageListener 存在的时候,才需要注册 Redis pubsub 监听
  82 + public RedisPendingMessageResendJob redisPendingMessageResendJob(List<AbstractRedisStreamMessageListener<?>> listeners,
87 RedisMQTemplate redisTemplate, 83 RedisMQTemplate redisTemplate,
88 @Value("${spring.application.name}") String groupName, 84 @Value("${spring.application.name}") String groupName,
89 RedissonClient redissonClient) { 85 RedissonClient redissonClient) {
@@ -92,14 +88,13 @@ public class YudaoMQAutoConfiguration { @@ -92,14 +88,13 @@ public class YudaoMQAutoConfiguration {
92 88
93 /** 89 /**
94 * 创建 Redis Stream 集群消费的容器 90 * 创建 Redis Stream 集群消费的容器
95 - * <p>  
96 - * Redis Stream 的 xreadgroup 命令:https://www.geek-book.com/src/docs/redis/redis/redis.io/commands/xreadgroup.html 91 + *
  92 + * 基础知识:<a href="https://www.geek-book.com/src/docs/redis/redis/redis.io/commands/xreadgroup.html">Redis Stream 的 xreadgroup 命令</a>
97 */ 93 */
98 @Bean(initMethod = "start", destroyMethod = "stop") 94 @Bean(initMethod = "start", destroyMethod = "stop")
99 - @ConditionalOnBean(AbstractStreamMessageListener.class) // 只有 AbstractStreamMessageListener 存在的时候,才需要注册 Redis pubsub 监听  
100 - @ConditionalOnProperty(prefix = "yudao.mq.redis.stream", value = "enable", matchIfMissing = true) // 允许使用 yudao.mq.redis.stream.enable=false 禁用多租户 95 + @ConditionalOnBean(AbstractRedisStreamMessageListener.class) // 只有 AbstractStreamMessageListener 存在的时候,才需要注册 Redis pubsub 监听
101 public StreamMessageListenerContainer<String, ObjectRecord<String, String>> redisStreamMessageListenerContainer( 96 public StreamMessageListenerContainer<String, ObjectRecord<String, String>> redisStreamMessageListenerContainer(
102 - RedisMQTemplate redisMQTemplate, List<AbstractStreamMessageListener<?>> listeners) { 97 + RedisMQTemplate redisMQTemplate, List<AbstractRedisStreamMessageListener<?>> listeners) {
103 RedisTemplate<String, ?> redisTemplate = redisMQTemplate.getRedisTemplate(); 98 RedisTemplate<String, ?> redisTemplate = redisMQTemplate.getRedisTemplate();
104 checkRedisVersion(redisTemplate); 99 checkRedisVersion(redisTemplate);
105 // 第一步,创建 StreamMessageListenerContainer 容器 100 // 第一步,创建 StreamMessageListenerContainer 容器
@@ -111,8 +106,7 @@ public class YudaoMQAutoConfiguration { @@ -111,8 +106,7 @@ public class YudaoMQAutoConfiguration {
111 .build(); 106 .build();
112 // 创建 container 对象 107 // 创建 container 对象
113 StreamMessageListenerContainer<String, ObjectRecord<String, String>> container = 108 StreamMessageListenerContainer<String, ObjectRecord<String, String>> container =
114 -// StreamMessageListenerContainer.create(redisTemplate.getRequiredConnectionFactory(), containerOptions);  
115 - DefaultStreamMessageListenerContainerX.create(redisMQTemplate.getRedisTemplate().getRequiredConnectionFactory(), containerOptions); 109 + StreamMessageListenerContainer.create(redisMQTemplate.getRedisTemplate().getRequiredConnectionFactory(), containerOptions);
116 110
117 // 第二步,注册监听器,消费对应的 Stream 主题 111 // 第二步,注册监听器,消费对应的 Stream 主题
118 String consumerName = buildConsumerName(); 112 String consumerName = buildConsumerName();
yudao-framework/yudao-spring-boot-starter-mq/src/main/java/cn/iocoder/yudao/framework/mq/core/RedisMQTemplate.java renamed to yudao-framework/yudao-spring-boot-starter-mq/src/main/java/cn/iocoder/yudao/framework/mq/redis/core/RedisMQTemplate.java
1 -package cn.iocoder.yudao.framework.mq.core; 1 +package cn.iocoder.yudao.framework.mq.redis.core;
2 2
3 import cn.iocoder.yudao.framework.common.util.json.JsonUtils; 3 import cn.iocoder.yudao.framework.common.util.json.JsonUtils;
4 -import cn.iocoder.yudao.framework.mq.core.interceptor.RedisMessageInterceptor;  
5 -import cn.iocoder.yudao.framework.mq.core.message.AbstractRedisMessage;  
6 -import cn.iocoder.yudao.framework.mq.core.pubsub.AbstractChannelMessage;  
7 -import cn.iocoder.yudao.framework.mq.core.stream.AbstractStreamMessage; 4 +import cn.iocoder.yudao.framework.mq.redis.core.interceptor.RedisMessageInterceptor;
  5 +import cn.iocoder.yudao.framework.mq.redis.core.message.AbstractRedisMessage;
  6 +import cn.iocoder.yudao.framework.mq.redis.core.pubsub.AbstractRedisChannelMessage;
  7 +import cn.iocoder.yudao.framework.mq.redis.core.stream.AbstractRedisStreamMessage;
8 import lombok.AllArgsConstructor; 8 import lombok.AllArgsConstructor;
9 import lombok.Getter; 9 import lombok.Getter;
10 import org.springframework.data.redis.connection.stream.RecordId; 10 import org.springframework.data.redis.connection.stream.RecordId;
@@ -35,7 +35,7 @@ public class RedisMQTemplate { @@ -35,7 +35,7 @@ public class RedisMQTemplate {
35 * 35 *
36 * @param message 消息 36 * @param message 消息
37 */ 37 */
38 - public <T extends AbstractChannelMessage> void send(T message) { 38 + public <T extends AbstractRedisChannelMessage> void send(T message) {
39 try { 39 try {
40 sendMessageBefore(message); 40 sendMessageBefore(message);
41 // 发送消息 41 // 发送消息
@@ -51,7 +51,7 @@ public class RedisMQTemplate { @@ -51,7 +51,7 @@ public class RedisMQTemplate {
51 * @param message 消息 51 * @param message 消息
52 * @return 消息记录的编号对象 52 * @return 消息记录的编号对象
53 */ 53 */
54 - public <T extends AbstractStreamMessage> RecordId send(T message) { 54 + public <T extends AbstractRedisStreamMessage> RecordId send(T message) {
55 try { 55 try {
56 sendMessageBefore(message); 56 sendMessageBefore(message);
57 // 发送消息 57 // 发送消息
yudao-framework/yudao-spring-boot-starter-mq/src/main/java/cn/iocoder/yudao/framework/mq/core/interceptor/RedisMessageInterceptor.java renamed to yudao-framework/yudao-spring-boot-starter-mq/src/main/java/cn/iocoder/yudao/framework/mq/redis/core/interceptor/RedisMessageInterceptor.java
1 -package cn.iocoder.yudao.framework.mq.core.interceptor; 1 +package cn.iocoder.yudao.framework.mq.redis.core.interceptor;
2 2
3 -import cn.iocoder.yudao.framework.mq.core.message.AbstractRedisMessage; 3 +import cn.iocoder.yudao.framework.mq.redis.core.message.AbstractRedisMessage;
4 4
5 /** 5 /**
6 * {@link AbstractRedisMessage} 消息拦截器 6 * {@link AbstractRedisMessage} 消息拦截器
yudao-framework/yudao-spring-boot-starter-mq/src/main/java/cn/iocoder/yudao/framework/mq/job/RedisPendingMessageResendJob.java renamed to yudao-framework/yudao-spring-boot-starter-mq/src/main/java/cn/iocoder/yudao/framework/mq/redis/core/job/RedisPendingMessageResendJob.java
1 -package cn.iocoder.yudao.framework.mq.job; 1 +package cn.iocoder.yudao.framework.mq.redis.core.job;
2 2
3 import cn.hutool.core.collection.CollUtil; 3 import cn.hutool.core.collection.CollUtil;
4 -import cn.iocoder.yudao.framework.mq.core.RedisMQTemplate;  
5 -import cn.iocoder.yudao.framework.mq.core.stream.AbstractStreamMessageListener; 4 +import cn.iocoder.yudao.framework.mq.redis.core.RedisMQTemplate;
  5 +import cn.iocoder.yudao.framework.mq.redis.core.stream.AbstractRedisStreamMessageListener;
6 import lombok.AllArgsConstructor; 6 import lombok.AllArgsConstructor;
7 import lombok.extern.slf4j.Slf4j; 7 import lombok.extern.slf4j.Slf4j;
8 import org.redisson.api.RLock; 8 import org.redisson.api.RLock;
@@ -33,7 +33,7 @@ public class RedisPendingMessageResendJob { @@ -33,7 +33,7 @@ public class RedisPendingMessageResendJob {
33 */ 33 */
34 private static final int EXPIRE_TIME = 5 * 60; 34 private static final int EXPIRE_TIME = 5 * 60;
35 35
36 - private final List<AbstractStreamMessageListener<?>> listeners; 36 + private final List<AbstractRedisStreamMessageListener<?>> listeners;
37 private final RedisMQTemplate redisTemplate; 37 private final RedisMQTemplate redisTemplate;
38 private final String groupName; 38 private final String groupName;
39 private final RedissonClient redissonClient; 39 private final RedissonClient redissonClient;
yudao-framework/yudao-spring-boot-starter-mq/src/main/java/cn/iocoder/yudao/framework/mq/core/message/AbstractRedisMessage.java renamed to yudao-framework/yudao-spring-boot-starter-mq/src/main/java/cn/iocoder/yudao/framework/mq/redis/core/message/AbstractRedisMessage.java
1 -package cn.iocoder.yudao.framework.mq.core.message; 1 +package cn.iocoder.yudao.framework.mq.redis.core.message;
2 2
3 import lombok.Data; 3 import lombok.Data;
4 4
yudao-framework/yudao-spring-boot-starter-mq/src/main/java/cn/iocoder/yudao/framework/mq/core/pubsub/AbstractChannelMessage.java renamed to yudao-framework/yudao-spring-boot-starter-mq/src/main/java/cn/iocoder/yudao/framework/mq/redis/core/pubsub/AbstractRedisChannelMessage.java
1 -package cn.iocoder.yudao.framework.mq.core.pubsub; 1 +package cn.iocoder.yudao.framework.mq.redis.core.pubsub;
2 2
3 -import cn.iocoder.yudao.framework.mq.core.message.AbstractRedisMessage; 3 +import cn.iocoder.yudao.framework.mq.redis.core.message.AbstractRedisMessage;
4 import com.fasterxml.jackson.annotation.JsonIgnore; 4 import com.fasterxml.jackson.annotation.JsonIgnore;
5 5
6 /** 6 /**
@@ -8,14 +8,16 @@ import com.fasterxml.jackson.annotation.JsonIgnore; @@ -8,14 +8,16 @@ import com.fasterxml.jackson.annotation.JsonIgnore;
8 * 8 *
9 * @author 芋道源码 9 * @author 芋道源码
10 */ 10 */
11 -public abstract class AbstractChannelMessage extends AbstractRedisMessage { 11 +public abstract class AbstractRedisChannelMessage extends AbstractRedisMessage {
12 12
13 /** 13 /**
14 - * 获得 Redis Channel 14 + * 获得 Redis Channel,默认使用类名
15 * 15 *
16 * @return Channel 16 * @return Channel
17 */ 17 */
18 @JsonIgnore // 避免序列化。原因是,Redis 发布 Channel 消息的时候,已经会指定。 18 @JsonIgnore // 避免序列化。原因是,Redis 发布 Channel 消息的时候,已经会指定。
19 - public abstract String getChannel(); 19 + public String getChannel() {
  20 + return getClass().getSimpleName();
  21 + }
20 22
21 } 23 }
yudao-framework/yudao-spring-boot-starter-mq/src/main/java/cn/iocoder/yudao/framework/mq/core/pubsub/AbstractChannelMessageListener.java renamed to yudao-framework/yudao-spring-boot-starter-mq/src/main/java/cn/iocoder/yudao/framework/mq/redis/core/pubsub/AbstractRedisChannelMessageListener.java
1 -package cn.iocoder.yudao.framework.mq.core.pubsub; 1 +package cn.iocoder.yudao.framework.mq.redis.core.pubsub;
2 2
3 import cn.hutool.core.util.TypeUtil; 3 import cn.hutool.core.util.TypeUtil;
4 import cn.iocoder.yudao.framework.common.util.json.JsonUtils; 4 import cn.iocoder.yudao.framework.common.util.json.JsonUtils;
5 -import cn.iocoder.yudao.framework.mq.core.RedisMQTemplate;  
6 -import cn.iocoder.yudao.framework.mq.core.interceptor.RedisMessageInterceptor;  
7 -import cn.iocoder.yudao.framework.mq.core.message.AbstractRedisMessage; 5 +import cn.iocoder.yudao.framework.mq.redis.core.RedisMQTemplate;
  6 +import cn.iocoder.yudao.framework.mq.redis.core.interceptor.RedisMessageInterceptor;
  7 +import cn.iocoder.yudao.framework.mq.redis.core.message.AbstractRedisMessage;
8 import lombok.Setter; 8 import lombok.Setter;
9 import lombok.SneakyThrows; 9 import lombok.SneakyThrows;
10 import org.springframework.data.redis.connection.Message; 10 import org.springframework.data.redis.connection.Message;
@@ -20,7 +20,7 @@ import java.util.List; @@ -20,7 +20,7 @@ import java.util.List;
20 * 20 *
21 * @author 芋道源码 21 * @author 芋道源码
22 */ 22 */
23 -public abstract class AbstractChannelMessageListener<T extends AbstractChannelMessage> implements MessageListener { 23 +public abstract class AbstractRedisChannelMessageListener<T extends AbstractRedisChannelMessage> implements MessageListener {
24 24
25 /** 25 /**
26 * 消息类型 26 * 消息类型
@@ -37,7 +37,7 @@ public abstract class AbstractChannelMessageListener&lt;T extends AbstractChannelMe @@ -37,7 +37,7 @@ public abstract class AbstractChannelMessageListener&lt;T extends AbstractChannelMe
37 private RedisMQTemplate redisMQTemplate; 37 private RedisMQTemplate redisMQTemplate;
38 38
39 @SneakyThrows 39 @SneakyThrows
40 - protected AbstractChannelMessageListener() { 40 + protected AbstractRedisChannelMessageListener() {
41 this.messageType = getMessageClass(); 41 this.messageType = getMessageClass();
42 this.channel = messageType.getDeclaredConstructor().newInstance().getChannel(); 42 this.channel = messageType.getDeclaredConstructor().newInstance().getChannel();
43 } 43 }
yudao-framework/yudao-spring-boot-starter-mq/src/main/java/cn/iocoder/yudao/framework/mq/core/stream/AbstractStreamMessage.java renamed to yudao-framework/yudao-spring-boot-starter-mq/src/main/java/cn/iocoder/yudao/framework/mq/redis/core/stream/AbstractRedisStreamMessage.java
1 -package cn.iocoder.yudao.framework.mq.core.stream; 1 +package cn.iocoder.yudao.framework.mq.redis.core.stream;
2 2
3 -import cn.iocoder.yudao.framework.mq.core.message.AbstractRedisMessage; 3 +import cn.iocoder.yudao.framework.mq.redis.core.message.AbstractRedisMessage;
4 import com.fasterxml.jackson.annotation.JsonIgnore; 4 import com.fasterxml.jackson.annotation.JsonIgnore;
5 5
6 /** 6 /**
@@ -8,14 +8,16 @@ import com.fasterxml.jackson.annotation.JsonIgnore; @@ -8,14 +8,16 @@ import com.fasterxml.jackson.annotation.JsonIgnore;
8 * 8 *
9 * @author 芋道源码 9 * @author 芋道源码
10 */ 10 */
11 -public abstract class AbstractStreamMessage extends AbstractRedisMessage { 11 +public abstract class AbstractRedisStreamMessage extends AbstractRedisMessage {
12 12
13 /** 13 /**
14 - * 获得 Redis Stream Key 14 + * 获得 Redis Stream Key,默认使用类名
15 * 15 *
16 * @return Channel 16 * @return Channel
17 */ 17 */
18 @JsonIgnore // 避免序列化 18 @JsonIgnore // 避免序列化
19 - public abstract String getStreamKey(); 19 + public String getStreamKey() {
  20 + return getClass().getSimpleName();
  21 + }
20 22
21 } 23 }
yudao-framework/yudao-spring-boot-starter-mq/src/main/java/cn/iocoder/yudao/framework/mq/core/stream/AbstractStreamMessageListener.java renamed to yudao-framework/yudao-spring-boot-starter-mq/src/main/java/cn/iocoder/yudao/framework/mq/redis/core/stream/AbstractRedisStreamMessageListener.java
1 -package cn.iocoder.yudao.framework.mq.core.stream; 1 +package cn.iocoder.yudao.framework.mq.redis.core.stream;
2 2
3 import cn.hutool.core.util.TypeUtil; 3 import cn.hutool.core.util.TypeUtil;
4 import cn.iocoder.yudao.framework.common.util.json.JsonUtils; 4 import cn.iocoder.yudao.framework.common.util.json.JsonUtils;
5 -import cn.iocoder.yudao.framework.mq.core.RedisMQTemplate;  
6 -import cn.iocoder.yudao.framework.mq.core.interceptor.RedisMessageInterceptor;  
7 -import cn.iocoder.yudao.framework.mq.core.message.AbstractRedisMessage; 5 +import cn.iocoder.yudao.framework.mq.redis.core.RedisMQTemplate;
  6 +import cn.iocoder.yudao.framework.mq.redis.core.interceptor.RedisMessageInterceptor;
  7 +import cn.iocoder.yudao.framework.mq.redis.core.message.AbstractRedisMessage;
8 import lombok.Getter; 8 import lombok.Getter;
9 import lombok.Setter; 9 import lombok.Setter;
10 import lombok.SneakyThrows; 10 import lombok.SneakyThrows;
@@ -22,7 +22,7 @@ import java.util.List; @@ -22,7 +22,7 @@ import java.util.List;
22 * 22 *
23 * @author 芋道源码 23 * @author 芋道源码
24 */ 24 */
25 -public abstract class AbstractStreamMessageListener<T extends AbstractStreamMessage> 25 +public abstract class AbstractRedisStreamMessageListener<T extends AbstractRedisStreamMessage>
26 implements StreamListener<String, ObjectRecord<String, String>> { 26 implements StreamListener<String, ObjectRecord<String, String>> {
27 27
28 /** 28 /**
@@ -48,7 +48,7 @@ public abstract class AbstractStreamMessageListener&lt;T extends AbstractStreamMess @@ -48,7 +48,7 @@ public abstract class AbstractStreamMessageListener&lt;T extends AbstractStreamMess
48 private RedisMQTemplate redisMQTemplate; 48 private RedisMQTemplate redisMQTemplate;
49 49
50 @SneakyThrows 50 @SneakyThrows
51 - protected AbstractStreamMessageListener() { 51 + protected AbstractRedisStreamMessageListener() {
52 this.messageType = getMessageClass(); 52 this.messageType = getMessageClass();
53 this.streamKey = messageType.getDeclaredConstructor().newInstance().getStreamKey(); 53 this.streamKey = messageType.getDeclaredConstructor().newInstance().getStreamKey();
54 } 54 }
yudao-framework/yudao-spring-boot-starter-mq/src/main/java/cn/iocoder/yudao/framework/mq/redis/package-info.java 0 → 100644
  1 +/**
  2 + * 消息队列,基于 Redis 提供:
  3 + * 1. 基于 Pub/Sub 实现广播消费
  4 + * 2. 基于 Stream 实现集群消费
  5 + */
  6 +package cn.iocoder.yudao.framework.mq.redis;
yudao-framework/yudao-spring-boot-starter-mq/src/main/java/org/springframework/data/redis/stream/DefaultStreamMessageListenerContainerX.java deleted
1 -package org.springframework.data.redis.stream;  
2 -  
3 -import cn.hutool.core.util.ReflectUtil;  
4 -import org.springframework.data.redis.connection.RedisConnectionFactory;  
5 -import org.springframework.data.redis.connection.stream.ByteRecord;  
6 -import org.springframework.data.redis.connection.stream.ReadOffset;  
7 -import org.springframework.data.redis.connection.stream.Record;  
8 -import org.springframework.util.Assert;  
9 -  
10 -import java.util.Collections;  
11 -import java.util.List;  
12 -import java.util.function.Function;  
13 -  
14 -/**  
15 - * 拓展 DefaultStreamMessageListenerContainer 实现,解决 Spring Data Redis + Redisson 结合使用时,Redisson 在 Stream 获得不到数据时,返回 null 而不是空 List,导致 NPE 异常。  
16 - * 对应 issue:https://github.com/spring-projects/spring-data-redis/issues/2147 和 https://github.com/redisson/redisson/issues/4006  
17 - * 目前看下来 Spring Data Redis 不肯加 null 判断,Redisson 暂时也没改返回 null 到空 List 的打算,所以暂时只能自己改,哽咽!  
18 - *  
19 - * @author 芋道源码  
20 - */  
21 -public class DefaultStreamMessageListenerContainerX<K, V extends Record<K, ?>> extends DefaultStreamMessageListenerContainer<K, V> {  
22 -  
23 - /**  
24 - * 参考 {@link StreamMessageListenerContainer#create(RedisConnectionFactory, StreamMessageListenerContainerOptions)} 的实现  
25 - */  
26 - public static <K, V extends Record<K, ?>> StreamMessageListenerContainer<K, V> create(RedisConnectionFactory connectionFactory, StreamMessageListenerContainer.StreamMessageListenerContainerOptions<K, V> options) {  
27 - Assert.notNull(connectionFactory, "RedisConnectionFactory must not be null!");  
28 - Assert.notNull(options, "StreamMessageListenerContainerOptions must not be null!");  
29 - return new DefaultStreamMessageListenerContainerX<>(connectionFactory, options);  
30 - }  
31 -  
32 - public DefaultStreamMessageListenerContainerX(RedisConnectionFactory connectionFactory, StreamMessageListenerContainerOptions<K, V> containerOptions) {  
33 - super(connectionFactory, containerOptions);  
34 - }  
35 -  
36 - /**  
37 - * 参考 {@link DefaultStreamMessageListenerContainer#register(StreamReadRequest, StreamListener)} 的实现  
38 - */  
39 - @Override  
40 - public Subscription register(StreamReadRequest<K> streamRequest, StreamListener<K, V> listener) {  
41 - return this.doRegisterX(getReadTaskX(streamRequest, listener));  
42 - }  
43 -  
44 - @SuppressWarnings("unchecked")  
45 - private StreamPollTask<K, V> getReadTaskX(StreamReadRequest<K> streamRequest, StreamListener<K, V> listener) {  
46 - StreamPollTask<K, V> task = ReflectUtil.invoke(this, "getReadTask", streamRequest, listener);  
47 - // 修改 readFunction 方法  
48 - Function<ReadOffset, List<ByteRecord>> readFunction = (Function<ReadOffset, List<ByteRecord>>) ReflectUtil.getFieldValue(task, "readFunction");  
49 - ReflectUtil.setFieldValue(task, "readFunction", (Function<ReadOffset, List<ByteRecord>>) readOffset -> {  
50 - List<ByteRecord> records = readFunction.apply(readOffset);  
51 - //【重点】保证 records 不是空,避免 NPE 的问题!!!  
52 - return records != null ? records : Collections.emptyList();  
53 - });  
54 - return task;  
55 - }  
56 -  
57 - private Subscription doRegisterX(Task task) {  
58 - return ReflectUtil.invoke(this, "doRegister", task);  
59 - }  
60 -  
61 -}  
62 -  
yudao-framework/yudao-spring-boot-starter-mq/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports
1 -cn.iocoder.yudao.framework.mq.config.YudaoMQAutoConfiguration  
2 \ No newline at end of file 1 \ No newline at end of file
  2 +cn.iocoder.yudao.framework.mq.redis.config.YudaoRedisMQAutoConfiguration
  3 +cn.iocoder.yudao.framework.mq.rabbitmq.config.YudaoRabbitMQAutoConfiguration
3 \ No newline at end of file 4 \ No newline at end of file
yudao-framework/yudao-spring-boot-starter-mq/《芋道 Spring Boot 事件机制 Event 入门》.md 0 → 100644
  1 +<http://www.iocoder.cn/Spring-Boot/RocketMQ/?yudao>
yudao-framework/yudao-spring-boot-starter-mq/《芋道 Spring Boot 消息队列 Kafka 入门》.md 0 → 100644
  1 +<http://www.iocoder.cn/Spring-Boot/Kafka/?yudao>
yudao-framework/yudao-spring-boot-starter-mq/《芋道 Spring Boot 消息队列 RabbitMQ 入门》.md 0 → 100644
  1 +<http://www.iocoder.cn/Spring-Boot/RabbitMQ/?yudao>
yudao-framework/yudao-spring-boot-starter-mq/《芋道 Spring Boot 消息队列 RocketMQ 入门》.md 0 → 100644
  1 +<http://www.iocoder.cn/Spring-Boot/RocketMQ/?yudao>
yudao-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/apilog/core/service/ApiAccessLog.java
@@ -5,7 +5,6 @@ import lombok.Data; @@ -5,7 +5,6 @@ import lombok.Data;
5 import javax.validation.constraints.NotNull; 5 import javax.validation.constraints.NotNull;
6 import java.time.LocalDateTime; 6 import java.time.LocalDateTime;
7 7
8 -// TODO @小吉祥:搞个 job,清理 14 天外的访问日志;  
9 /** 8 /**
10 * API 访问日志 9 * API 访问日志
11 * 10 *
yudao-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/apilog/core/service/ApiErrorLog.java
@@ -5,7 +5,6 @@ import lombok.Data; @@ -5,7 +5,6 @@ import lombok.Data;
5 import javax.validation.constraints.NotNull; 5 import javax.validation.constraints.NotNull;
6 import java.time.LocalDateTime; 6 import java.time.LocalDateTime;
7 7
8 -// TODO @小吉祥:搞个 job,清理 14 天外的异常日志;  
9 /** 8 /**
10 * API 错误日志 9 * API 错误日志
11 * 10 *
yudao-module-bpm/yudao-module-bpm-api/src/main/java/cn/iocoder/yudao/module/bpm/enums/task/BpmCommentTypeEnum.java
@@ -20,16 +20,16 @@ public enum BpmCommentTypeEnum { @@ -20,16 +20,16 @@ public enum BpmCommentTypeEnum {
20 ; 20 ;
21 21
22 /** 22 /**
23 - * 结果 23 + * 操作类型
24 */ 24 */
25 private final Integer type; 25 private final Integer type;
26 /** 26 /**
27 - * 描述 27 + * 操作名字
28 */ 28 */
29 - private final String desc; 29 + private final String name;
30 /** 30 /**
31 - * 模板信息 31 + * 操作描述
32 */ 32 */
33 - private final String templateComment; 33 + private final String comment;
34 34
35 } 35 }
yudao-module-bpm/yudao-module-bpm-api/src/main/java/cn/iocoder/yudao/module/bpm/enums/task/BpmProcessInstanceResultEnum.java
@@ -30,13 +30,13 @@ public enum BpmProcessInstanceResultEnum { @@ -30,13 +30,13 @@ public enum BpmProcessInstanceResultEnum {
30 * 相当于是 通过 APPROVE 的特殊状态 30 * 相当于是 通过 APPROVE 的特殊状态
31 * 例如:A审批, A 后加签了 B,并且审批通过了任务,但是 B 还未审批,则当前任务状态为“待后加签任务完成” 31 * 例如:A审批, A 后加签了 B,并且审批通过了任务,但是 B 还未审批,则当前任务状态为“待后加签任务完成”
32 */ 32 */
33 - ADD_SIGN_AFTER(7, "待后加签任务完成"), 33 + SIGN_AFTER(7, "待后加签任务完成"),
34 /** 34 /**
35 * 【加签】源任务未审批,但是向前加签了,所以源任务状态变为“待前加签任务完成” 35 * 【加签】源任务未审批,但是向前加签了,所以源任务状态变为“待前加签任务完成”
36 * 相当于是 处理中 PROCESS 的特殊状态 36 * 相当于是 处理中 PROCESS 的特殊状态
37 * 例如:A 审批, A 前加签了 B,B 还未审核 37 * 例如:A 审批, A 前加签了 B,B 还未审核
38 */ 38 */
39 - ADD_SIGN_BEFORE(8, "待前加签任务完成"), 39 + SIGN_BEFORE(8, "待前加签任务完成"),
40 /** 40 /**
41 * 【加签】后加签任务被创建时的初始状态 41 * 【加签】后加签任务被创建时的初始状态
42 * 相当于是 处理中 PROCESS 的特殊状态 42 * 相当于是 处理中 PROCESS 的特殊状态
@@ -71,7 +71,7 @@ public enum BpmProcessInstanceResultEnum { @@ -71,7 +71,7 @@ public enum BpmProcessInstanceResultEnum {
71 public static boolean isEndResult(Integer result) { 71 public static boolean isEndResult(Integer result) {
72 return ObjectUtils.equalsAny(result, APPROVE.getResult(), REJECT.getResult(), 72 return ObjectUtils.equalsAny(result, APPROVE.getResult(), REJECT.getResult(),
73 CANCEL.getResult(), BACK.getResult(), 73 CANCEL.getResult(), BACK.getResult(),
74 - ADD_SIGN_AFTER.getResult()); 74 + SIGN_AFTER.getResult());
75 } 75 }
76 76
77 } 77 }
yudao-module-bpm/yudao-module-bpm-api/src/main/java/cn/iocoder/yudao/module/bpm/enums/task/BpmTaskAddSignTypeEnum.java
@@ -3,7 +3,6 @@ package cn.iocoder.yudao.module.bpm.enums.task; @@ -3,7 +3,6 @@ package cn.iocoder.yudao.module.bpm.enums.task;
3 import lombok.AllArgsConstructor; 3 import lombok.AllArgsConstructor;
4 import lombok.Getter; 4 import lombok.Getter;
5 5
6 -  
7 /** 6 /**
8 * 流程任务 -- 加签类型枚举类型 7 * 流程任务 -- 加签类型枚举类型
9 */ 8 */
yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/task/BpmTaskController.java
@@ -74,7 +74,7 @@ public class BpmTaskController { @@ -74,7 +74,7 @@ public class BpmTaskController {
74 return success(true); 74 return success(true);
75 } 75 }
76 76
77 - @GetMapping("/get-return-list") 77 + @GetMapping("/return-list")
78 @Operation(summary = "获取所有可回退的节点", description = "用于【流程详情】的【回退】按钮") 78 @Operation(summary = "获取所有可回退的节点", description = "用于【流程详情】的【回退】按钮")
79 @Parameter(name = "taskId", description = "当前任务ID", required = true) 79 @Parameter(name = "taskId", description = "当前任务ID", required = true)
80 @PreAuthorize("@ss.hasPermission('bpm:task:update')") 80 @PreAuthorize("@ss.hasPermission('bpm:task:update')")
@@ -98,27 +98,28 @@ public class BpmTaskController { @@ -98,27 +98,28 @@ public class BpmTaskController {
98 return success(true); 98 return success(true);
99 } 99 }
100 100
101 - @PutMapping("/add-sign") 101 + @PutMapping("/create-sign")
102 @Operation(summary = "加签", description = "before 前加签,after 后加签") 102 @Operation(summary = "加签", description = "before 前加签,after 后加签")
103 @PreAuthorize("@ss.hasPermission('bpm:task:update')") 103 @PreAuthorize("@ss.hasPermission('bpm:task:update')")
104 - public CommonResult<Boolean> addSignTask(@Valid @RequestBody BpmTaskAddSignReqVO reqVO) {  
105 - taskService.addSignTask(getLoginUserId(), reqVO); 104 + public CommonResult<Boolean> createSignTask(@Valid @RequestBody BpmTaskAddSignReqVO reqVO) {
  105 + taskService.createSignTask(getLoginUserId(), reqVO);
106 return success(true); 106 return success(true);
107 } 107 }
108 108
109 - @PutMapping("/sub-sign") 109 + @DeleteMapping("/delete-sign")
110 @Operation(summary = "减签") 110 @Operation(summary = "减签")
111 @PreAuthorize("@ss.hasPermission('bpm:task:update')") 111 @PreAuthorize("@ss.hasPermission('bpm:task:update')")
112 - public CommonResult<Boolean> subSignTask(@Valid @RequestBody BpmTaskSubSignReqVO reqVO) {  
113 - taskService.subSignTask(getLoginUserId(), reqVO); 112 + public CommonResult<Boolean> deleteSignTask(@Valid @RequestBody BpmTaskSubSignReqVO reqVO) {
  113 + taskService.deleteSignTask(getLoginUserId(), reqVO);
114 return success(true); 114 return success(true);
115 } 115 }
116 116
117 - @GetMapping("/get-children-task-list") 117 + @GetMapping("children-list")
118 @Operation(summary = "获取能被减签的任务") 118 @Operation(summary = "获取能被减签的任务")
  119 + @Parameter(name = "parentId", description = "父级任务 ID", required = true)
119 @PreAuthorize("@ss.hasPermission('bpm:task:update')") 120 @PreAuthorize("@ss.hasPermission('bpm:task:update')")
120 - public CommonResult<List<BpmTaskSubSignRespVO>> getChildrenTaskList(@RequestParam("taskId") String taskId) {  
121 - return success(taskService.getChildrenTaskList(taskId)); 121 + public CommonResult<List<BpmTaskSubSignRespVO>> getChildrenTaskList(@RequestParam("parentId") String parentId) {
  122 + return success(taskService.getChildrenTaskList(parentId));
122 } 123 }
123 124
124 } 125 }
yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/task/vo/task/BpmTaskAddSignReqVO.java
@@ -6,6 +6,7 @@ import lombok.Data; @@ -6,6 +6,7 @@ import lombok.Data;
6 import javax.validation.constraints.NotEmpty; 6 import javax.validation.constraints.NotEmpty;
7 import java.util.Set; 7 import java.util.Set;
8 8
  9 +// TODO @海洋:类名,应该是 create 哈
9 @Schema(description = "管理后台 - 加签流程任务的 Request VO") 10 @Schema(description = "管理后台 - 加签流程任务的 Request VO")
10 @Data 11 @Data
11 public class BpmTaskAddSignReqVO { 12 public class BpmTaskAddSignReqVO {
@@ -26,4 +27,4 @@ public class BpmTaskAddSignReqVO { @@ -26,4 +27,4 @@ public class BpmTaskAddSignReqVO {
26 @NotEmpty(message = "加签原因不能为空") 27 @NotEmpty(message = "加签原因不能为空")
27 private String reason; 28 private String reason;
28 29
29 -}  
30 \ No newline at end of file 30 \ No newline at end of file
  31 +}
yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/task/vo/task/BpmTaskSubSignReqVO.java
@@ -5,6 +5,7 @@ import lombok.Data; @@ -5,6 +5,7 @@ import lombok.Data;
5 5
6 import javax.validation.constraints.NotEmpty; 6 import javax.validation.constraints.NotEmpty;
7 7
  8 +// TODO @海洋:类名,应该是 delete 哈
8 @Schema(description = "管理后台 - 减签流程任务的 Request VO") 9 @Schema(description = "管理后台 - 减签流程任务的 Request VO")
9 @Data 10 @Data
10 public class BpmTaskSubSignReqVO { 11 public class BpmTaskSubSignReqVO {
yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/convert/task/BpmTaskConvert.java
1 package cn.iocoder.yudao.module.bpm.convert.task; 1 package cn.iocoder.yudao.module.bpm.convert.task;
2 2
3 -import cn.hutool.core.collection.CollUtil;  
4 import cn.hutool.core.date.LocalDateTimeUtil; 3 import cn.hutool.core.date.LocalDateTimeUtil;
  4 +import cn.hutool.core.util.ObjectUtil;
5 import cn.hutool.core.util.StrUtil; 5 import cn.hutool.core.util.StrUtil;
6 import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils; 6 import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils;
  7 +import cn.iocoder.yudao.framework.common.util.collection.MapUtils;
7 import cn.iocoder.yudao.framework.common.util.date.DateUtils; 8 import cn.iocoder.yudao.framework.common.util.date.DateUtils;
8 import cn.iocoder.yudao.framework.common.util.number.NumberUtils; 9 import cn.iocoder.yudao.framework.common.util.number.NumberUtils;
9 import cn.iocoder.yudao.module.bpm.controller.admin.task.vo.task.*; 10 import cn.iocoder.yudao.module.bpm.controller.admin.task.vo.task.*;
@@ -25,6 +26,9 @@ import java.util.Date; @@ -25,6 +26,9 @@ import java.util.Date;
25 import java.util.List; 26 import java.util.List;
26 import java.util.Map; 27 import java.util.Map;
27 28
  29 +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertMultiMap;
  30 +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.filterList;
  31 +
28 /** 32 /**
29 * Bpm 任务 Convert 33 * Bpm 任务 Convert
30 * 34 *
@@ -167,32 +171,31 @@ public interface BpmTaskConvert { @@ -167,32 +171,31 @@ public interface BpmTaskConvert {
167 default List<BpmTaskSubSignRespVO> convertList(List<BpmTaskExtDO> bpmTaskExtDOList, 171 default List<BpmTaskSubSignRespVO> convertList(List<BpmTaskExtDO> bpmTaskExtDOList,
168 Map<Long, AdminUserRespDTO> userMap, 172 Map<Long, AdminUserRespDTO> userMap,
169 Map<String, Task> idTaskMap){ 173 Map<String, Task> idTaskMap){
170 - return CollectionUtils.convertList(bpmTaskExtDOList, task->{  
171 - BpmTaskSubSignRespVO bpmTaskSubSignRespVO = new BpmTaskSubSignRespVO();  
172 - bpmTaskSubSignRespVO.setName(task.getName());  
173 - bpmTaskSubSignRespVO.setId(task.getTaskId());  
174 - Task sourceTask = idTaskMap.get(task.getTaskId()); 174 + return CollectionUtils.convertList(bpmTaskExtDOList, task -> {
  175 + BpmTaskSubSignRespVO bpmTaskSubSignRespVO = new BpmTaskSubSignRespVO()
  176 + .setId(task.getTaskId()).setName(task.getName());
175 // 后加签任务不会直接设置 assignee ,所以不存在 assignee 的情况,则去取 owner 177 // 后加签任务不会直接设置 assignee ,所以不存在 assignee 的情况,则去取 owner
176 - String assignee = StrUtil.isNotEmpty(sourceTask.getAssignee()) ? sourceTask.getAssignee() : sourceTask.getOwner();  
177 - AdminUserRespDTO assignUser = userMap.get(NumberUtils.parseLong(assignee));  
178 - if (assignUser != null) {  
179 - bpmTaskSubSignRespVO.setAssigneeUser(convert3(assignUser));  
180 - } 178 + Task sourceTask = idTaskMap.get(task.getTaskId());
  179 + String assignee = ObjectUtil.defaultIfBlank(sourceTask.getOwner(),sourceTask.getAssignee());
  180 + MapUtils.findAndThen(userMap,NumberUtils.parseLong(assignee),
  181 + assignUser-> bpmTaskSubSignRespVO.setAssigneeUser(convert3(assignUser)));
181 return bpmTaskSubSignRespVO; 182 return bpmTaskSubSignRespVO;
182 }); 183 });
183 } 184 }
184 185
185 /** 186 /**
186 * 转换任务为父子级 187 * 转换任务为父子级
  188 + *
187 * @param sourceList 原始数据 189 * @param sourceList 原始数据
188 * @return 转换后的父子级数组 190 * @return 转换后的父子级数组
189 */ 191 */
190 - default List<BpmTaskRespVO> convertChildrenList(List<BpmTaskRespVO> sourceList){  
191 - List<BpmTaskRespVO> childrenTaskList = CollectionUtils.filterList(sourceList, r -> StrUtil.isNotEmpty(r.getParentTaskId()));  
192 - Map<String, List<BpmTaskRespVO>> parentChildrenTaskListMap = CollectionUtils.convertMultiMap(childrenTaskList, BpmTaskRespVO::getParentTaskId); 192 + default List<BpmTaskRespVO> convertChildrenList(List<BpmTaskRespVO> sourceList) {
  193 + List<BpmTaskRespVO> childrenTaskList = filterList(sourceList, r -> StrUtil.isNotEmpty(r.getParentTaskId()));
  194 + Map<String, List<BpmTaskRespVO>> parentChildrenTaskListMap = convertMultiMap(childrenTaskList, BpmTaskRespVO::getParentTaskId);
193 for (BpmTaskRespVO bpmTaskRespVO : sourceList) { 195 for (BpmTaskRespVO bpmTaskRespVO : sourceList) {
194 bpmTaskRespVO.setChildren(parentChildrenTaskListMap.get(bpmTaskRespVO.getId())); 196 bpmTaskRespVO.setChildren(parentChildrenTaskListMap.get(bpmTaskRespVO.getId()));
195 } 197 }
196 - return CollectionUtils.filterList(sourceList, r -> StrUtil.isEmpty(r.getParentTaskId())); 198 + return filterList(sourceList, r -> StrUtil.isEmpty(r.getParentTaskId()));
197 } 199 }
  200 +
198 } 201 }
yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/dal/mysql/task/BpmTaskExtMapper.java
@@ -21,13 +21,13 @@ public interface BpmTaskExtMapper extends BaseMapperX&lt;BpmTaskExtDO&gt; { @@ -21,13 +21,13 @@ public interface BpmTaskExtMapper extends BaseMapperX&lt;BpmTaskExtDO&gt; {
21 return selectList(BpmTaskExtDO::getTaskId, taskIds); 21 return selectList(BpmTaskExtDO::getTaskId, taskIds);
22 } 22 }
23 23
  24 + // TODO @海:BpmProcessInstanceResultEnum.CAN_SUB_SIGN_STATUS_LIST) 应该作为条件,mapper 不要有业务
24 default List<BpmTaskExtDO> selectProcessListByTaskIds(Collection<String> taskIds) { 25 default List<BpmTaskExtDO> selectProcessListByTaskIds(Collection<String> taskIds) {
25 return selectList(new LambdaQueryWrapperX<BpmTaskExtDO>() 26 return selectList(new LambdaQueryWrapperX<BpmTaskExtDO>()
26 .in(BpmTaskExtDO::getTaskId, taskIds) 27 .in(BpmTaskExtDO::getTaskId, taskIds)
27 .in(BpmTaskExtDO::getResult, BpmProcessInstanceResultEnum.CAN_SUB_SIGN_STATUS_LIST)); 28 .in(BpmTaskExtDO::getResult, BpmProcessInstanceResultEnum.CAN_SUB_SIGN_STATUS_LIST));
28 } 29 }
29 30
30 -  
31 default BpmTaskExtDO selectByTaskId(String taskId) { 31 default BpmTaskExtDO selectByTaskId(String taskId) {
32 return selectOne(BpmTaskExtDO::getTaskId, taskId); 32 return selectOne(BpmTaskExtDO::getTaskId, taskId);
33 } 33 }
yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/bpm/config/BpmSecurityConfiguration.java deleted
1 -package cn.iocoder.yudao.module.bpm.framework.bpm.config;  
2 -  
3 -import cn.iocoder.yudao.framework.security.config.AuthorizeRequestsCustomizer;  
4 -import org.springframework.context.annotation.Bean;  
5 -import org.springframework.context.annotation.Configuration;  
6 -import org.springframework.security.config.annotation.web.builders.HttpSecurity;  
7 -import org.springframework.security.config.annotation.web.configurers.ExpressionUrlAuthorizationConfigurer;  
8 -  
9 -/**  
10 - * @author kemengkai  
11 - * @create 2022-05-07 08:15  
12 - */  
13 -@Configuration("bpmSecurityConfiguration")  
14 -public class BpmSecurityConfiguration {  
15 -  
16 - @Bean("bpmAuthorizeRequestsCustomizer")  
17 - public AuthorizeRequestsCustomizer authorizeRequestsCustomizer() {  
18 - return new AuthorizeRequestsCustomizer() {  
19 -  
20 - @Override  
21 - public void customize(ExpressionUrlAuthorizationConfigurer<HttpSecurity>.ExpressionInterceptUrlRegistry registry) {  
22 - // 任务回退接口  
23 - registry.antMatchers(buildAdminApi("/bpm/task/back")).permitAll();  
24 - }  
25 -  
26 - };  
27 - }  
28 -}  
yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/definition/BpmModelService.java
@@ -12,6 +12,7 @@ import javax.validation.Valid; @@ -12,6 +12,7 @@ import javax.validation.Valid;
12 * @author yunlongn 12 * @author yunlongn
13 */ 13 */
14 public interface BpmModelService { 14 public interface BpmModelService {
  15 +
15 /** 16 /**
16 * 获得流程模型分页 17 * 获得流程模型分页
17 * 18 *
yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/definition/BpmModelServiceImpl.java
@@ -288,5 +288,4 @@ public class BpmModelServiceImpl implements BpmModelService { @@ -288,5 +288,4 @@ public class BpmModelServiceImpl implements BpmModelService {
288 processDefinitionService.updateProcessDefinitionState(oldDefinition.getId(), SuspensionState.SUSPENDED.getStateCode()); 288 processDefinitionService.updateProcessDefinitionState(oldDefinition.getId(), SuspensionState.SUSPENDED.getStateCode());
289 } 289 }
290 290
291 -  
292 } 291 }
yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/task/BpmTaskService.java
@@ -163,7 +163,7 @@ public interface BpmTaskService { @@ -163,7 +163,7 @@ public interface BpmTaskService {
163 * @param userId 被加签的用户和任务 ID,加签类型 163 * @param userId 被加签的用户和任务 ID,加签类型
164 * @param reqVO 当前用户 ID 164 * @param reqVO 当前用户 ID
165 */ 165 */
166 - void addSignTask(Long userId, BpmTaskAddSignReqVO reqVO); 166 + void createSignTask(Long userId, BpmTaskAddSignReqVO reqVO);
167 167
168 /** 168 /**
169 * 任务减签名 169 * 任务减签名
@@ -171,14 +171,14 @@ public interface BpmTaskService { @@ -171,14 +171,14 @@ public interface BpmTaskService {
171 * @param userId 当前用户ID 171 * @param userId 当前用户ID
172 * @param reqVO 被减签的任务 ID,理由 172 * @param reqVO 被减签的任务 ID,理由
173 */ 173 */
174 - void subSignTask(Long userId, BpmTaskSubSignReqVO reqVO); 174 + void deleteSignTask(Long userId, BpmTaskSubSignReqVO reqVO);
175 175
176 /** 176 /**
177 * 获取指定任务的子任务和审批人信息 177 * 获取指定任务的子任务和审批人信息
178 * 178 *
179 - * @param taskId 指定任务ID 179 + * @param parentId 指定任务ID
180 * @return 子任务列表 180 * @return 子任务列表
181 */ 181 */
182 - List<BpmTaskSubSignRespVO> getChildrenTaskList(String taskId); 182 + List<BpmTaskSubSignRespVO> getChildrenTaskList(String parentId);
183 183
184 } 184 }
yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/task/BpmTaskServiceImpl.java
@@ -53,7 +53,6 @@ import javax.annotation.Resource; @@ -53,7 +53,6 @@ import javax.annotation.Resource;
53 import javax.validation.Valid; 53 import javax.validation.Valid;
54 import java.time.LocalDateTime; 54 import java.time.LocalDateTime;
55 import java.util.*; 55 import java.util.*;
56 -import java.util.stream.Collectors;  
57 import java.util.stream.Stream; 56 import java.util.stream.Stream;
58 57
59 import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; 58 import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
@@ -240,10 +239,11 @@ public class BpmTaskServiceImpl implements BpmTaskService { @@ -240,10 +239,11 @@ public class BpmTaskServiceImpl implements BpmTaskService {
240 handleParentTask(task); 239 handleParentTask(task);
241 } 240 }
242 241
  242 +
243 /** 243 /**
244 * 审批通过存在“后加签”的任务。 244 * 审批通过存在“后加签”的任务。
245 * <p> 245 * <p>
246 - * 注意:该任务不能马上完成,需要一个中间状态(ADD_SIGN_AFTER),并激活剩余所有子任务(PROCESS)为可审批处理 246 + * 注意:该任务不能马上完成,需要一个中间状态(SIGN_AFTER),并激活剩余所有子任务(PROCESS)为可审批处理
247 * 247 *
248 * @param task 当前任务 248 * @param task 当前任务
249 * @param reqVO 前端请求参数 249 * @param reqVO 前端请求参数
@@ -251,7 +251,7 @@ public class BpmTaskServiceImpl implements BpmTaskService { @@ -251,7 +251,7 @@ public class BpmTaskServiceImpl implements BpmTaskService {
251 private void approveAfterSignTask(Task task, BpmTaskApproveReqVO reqVO) { 251 private void approveAfterSignTask(Task task, BpmTaskApproveReqVO reqVO) {
252 // 1. 有向后加签,则该任务状态临时设置为 ADD_SIGN_AFTER 状态 252 // 1. 有向后加签,则该任务状态临时设置为 ADD_SIGN_AFTER 状态
253 taskExtMapper.updateByTaskId( 253 taskExtMapper.updateByTaskId(
254 - new BpmTaskExtDO().setTaskId(task.getId()).setResult(BpmProcessInstanceResultEnum.ADD_SIGN_AFTER.getResult()) 254 + new BpmTaskExtDO().setTaskId(task.getId()).setResult(BpmProcessInstanceResultEnum.SIGN_AFTER.getResult())
255 .setReason(reqVO.getReason()).setEndTime(LocalDateTime.now())); 255 .setReason(reqVO.getReason()).setEndTime(LocalDateTime.now()));
256 256
257 // 2. 激活子任务 257 // 2. 激活子任务
@@ -265,7 +265,7 @@ public class BpmTaskServiceImpl implements BpmTaskService { @@ -265,7 +265,7 @@ public class BpmTaskServiceImpl implements BpmTaskService {
265 } 265 }
266 266
267 /** 267 /**
268 - * 处理当前任务的父任务 268 + * 处理当前任务的父任务,主要处理“加签”的情况
269 * 269 *
270 * @param task 当前任务 270 * @param task 当前任务
271 */ 271 */
@@ -274,76 +274,79 @@ public class BpmTaskServiceImpl implements BpmTaskService { @@ -274,76 +274,79 @@ public class BpmTaskServiceImpl implements BpmTaskService {
274 if (StrUtil.isBlank(parentTaskId)) { 274 if (StrUtil.isBlank(parentTaskId)) {
275 return; 275 return;
276 } 276 }
277 - if (StrUtil.isNotBlank(parentTaskId)) {  
278 - // 1. 判断当前任务的父任务是否还有子任务  
279 - Long childrenTaskCount = getChildrenTaskCount(parentTaskId);  
280 - if (childrenTaskCount > 0) {  
281 - return;  
282 - }  
283 - // 2. 获取父任务  
284 - Task parentTask = validateTaskExist(parentTaskId);  
285 -  
286 - // 3. 情况一:处理向前加签  
287 - String scopeType = parentTask.getScopeType();  
288 - if (BpmTaskAddSignTypeEnum.BEFORE.getType().equals(scopeType)) {  
289 - // 3.1 如果是向前加签的任务,则调用 resolveTask 指派父任务,将 owner 重新赋值给父任务的 assignee  
290 - taskService.resolveTask(parentTaskId);  
291 - // 3.2 更新任务拓展表为处理中  
292 - taskExtMapper.updateByTaskId(  
293 - new BpmTaskExtDO().setTaskId(parentTask.getId()).setResult(BpmProcessInstanceResultEnum.PROCESS.getResult()));  
294 - } else if (BpmTaskAddSignTypeEnum.AFTER.getType().equals(scopeType)) {  
295 - // 3. 情况二:处理向后加签  
296 - handleAfterSign(parentTask);  
297 - } 277 + // 1. 判断当前任务的父任务是否还有子任务
  278 + Long childrenTaskCount = getChildrenTaskCount(parentTaskId);
  279 + if (childrenTaskCount > 0) {
  280 + return;
  281 + }
  282 + // 2. 获取父任务
  283 + Task parentTask = validateTaskExist(parentTaskId);
298 284
299 - // 4. 子任务已处理完成,清空 scopeType 字段,修改 parentTask 信息,方便后续可以继续向前后向后加签  
300 - // 再查询一次的原因是避免报错:Task was updated by another transaction concurrently  
301 - // 因为前面处理后可能会导致 parentTask rev 字段被修改,需要重新获取最新的  
302 - parentTask = getTask(parentTaskId);  
303 - if (parentTask == null) {  
304 - // 为空的情况是:已经通过 handleAfterSign 方法将任务完成了,所以 ru_task 表会查不到数据  
305 - return;  
306 - }  
307 - clearTaskScopeTypeAndSave(parentTask); 285 + // 3. 处理加签情况
  286 + String scopeType = parentTask.getScopeType();
  287 + if(!validateSignType(scopeType)){
  288 + return;
308 } 289 }
  290 + // 3.1 情况一:处理向前加签
  291 + if (BpmTaskAddSignTypeEnum.BEFORE.getType().equals(scopeType)) {
  292 + // 3.1.1 如果是向前加签的任务,则调用 resolveTask 指派父任务,将 owner 重新赋值给父任务的 assignee,这样它就可以被审批
  293 + taskService.resolveTask(parentTaskId);
  294 + // 3.1.2 更新任务拓展表为处理中
  295 + taskExtMapper.updateByTaskId(
  296 + new BpmTaskExtDO().setTaskId(parentTask.getId()).setResult(BpmProcessInstanceResultEnum.PROCESS.getResult()));
  297 + } else if (BpmTaskAddSignTypeEnum.AFTER.getType().equals(scopeType)) {
  298 + // 3.2 情况二:处理向后加签
  299 + handleParentTaskForAfterSign(parentTask);
  300 + }
  301 +
  302 + // 4. 子任务已处理完成,清空 scopeType 字段,修改 parentTask 信息,方便后续可以继续向前后向后加签
  303 + // 再查询一次的原因是避免报错:Task was updated by another transaction concurrently
  304 + // 因为前面处理后可能会导致 parentTask rev 字段被修改,需要重新获取最新的
  305 + parentTask = getTask(parentTaskId);
  306 + if (parentTask == null) {
  307 + // 为空的情况是:已经通过 handleAfterSign 方法将任务完成了,所以 ru_task 表会查不到数据
  308 + return;
  309 + }
  310 + clearTaskScopeTypeAndSave(parentTask);
309 } 311 }
310 312
  313 +
311 /** 314 /**
312 * 处理后加签任务 315 * 处理后加签任务
313 * 316 *
314 * @param parentTask 当前审批任务的父任务 317 * @param parentTask 当前审批任务的父任务
315 */ 318 */
316 - private void handleAfterSign(Task parentTask) { 319 + // TODO @海:这个逻辑,怎么感觉可以是 parentTask 的 parent,再去调用 handleParentTask 方法;可以微信聊下;
  320 + private void handleParentTaskForAfterSign(Task parentTask) {
317 String parentTaskId = parentTask.getId(); 321 String parentTaskId = parentTask.getId();
318 - //1. 更新 parentTask 的任务拓展表为通过,并调用 complete 完成自己 322 + // 1. 更新 parentTask 的任务拓展表为通过,并调用 complete 完成自己
319 BpmTaskExtDO currentTaskExt = taskExtMapper.selectByTaskId(parentTask.getId()); 323 BpmTaskExtDO currentTaskExt = taskExtMapper.selectByTaskId(parentTask.getId());
320 - BpmTaskExtDO currentTaskUpdateEntity = new BpmTaskExtDO().setTaskId(parentTask.getId()) 324 + BpmTaskExtDO currentTaskExtUpdateObj = new BpmTaskExtDO().setTaskId(parentTask.getId())
321 .setResult(BpmProcessInstanceResultEnum.APPROVE.getResult()); 325 .setResult(BpmProcessInstanceResultEnum.APPROVE.getResult());
322 if (currentTaskExt.getEndTime() == null) { 326 if (currentTaskExt.getEndTime() == null) {
323 // 1.1 有这个判断是因为,以前没设置过结束时间,才去设置 327 // 1.1 有这个判断是因为,以前没设置过结束时间,才去设置
324 - currentTaskUpdateEntity.setEndTime(LocalDateTime.now()); 328 + currentTaskExtUpdateObj.setEndTime(LocalDateTime.now());
325 } 329 }
326 - // 1.2 完成自己  
327 - taskExtMapper.updateByTaskId(currentTaskUpdateEntity); 330 + taskExtMapper.updateByTaskId(currentTaskExtUpdateObj);
  331 + // 1.2 完成自己(因为它已经没有子任务,所以也可以完成)
328 taskService.complete(parentTaskId); 332 taskService.complete(parentTaskId);
329 333
330 // 2. 如果有父级,递归查询上级任务是否都已经完成 334 // 2. 如果有父级,递归查询上级任务是否都已经完成
331 if (StrUtil.isEmpty(parentTask.getParentTaskId())) { 335 if (StrUtil.isEmpty(parentTask.getParentTaskId())) {
332 return; 336 return;
333 } 337 }
334 - // TODO @海:这块待讨论,脑子略乱;感觉 handleAfterSign 的后半段,和 handleParentTask 有点重叠???  
335 // 2.1 判断整条链路的任务是否完成 338 // 2.1 判断整条链路的任务是否完成
336 // 例如从 A 任务加签了一个 B 任务,B 任务又加签了一个 C 任务,C 任务加签了 D 任务 339 // 例如从 A 任务加签了一个 B 任务,B 任务又加签了一个 C 任务,C 任务加签了 D 任务
337 // 此时,D 任务完成,要一直往上找到祖先任务 A调用 complete 方法完成 A 任务 340 // 此时,D 任务完成,要一直往上找到祖先任务 A调用 complete 方法完成 A 任务
338 boolean allChildrenTaskFinish = true; 341 boolean allChildrenTaskFinish = true;
339 while (StrUtil.isNotBlank(parentTask.getParentTaskId())) { 342 while (StrUtil.isNotBlank(parentTask.getParentTaskId())) {
340 parentTask = validateTaskExist(parentTask.getParentTaskId()); 343 parentTask = validateTaskExist(parentTask.getParentTaskId());
341 - BpmTaskExtDO bpmTaskExtDO = taskExtMapper.selectByTaskId(parentTask.getId());  
342 - if (bpmTaskExtDO == null) { 344 + BpmTaskExtDO parentTaskExt = taskExtMapper.selectByTaskId(parentTask.getId());
  345 + if (parentTaskExt == null) {
343 break; 346 break;
344 } 347 }
345 - boolean currentTaskFinish = BpmProcessInstanceResultEnum.isEndResult(bpmTaskExtDO.getResult());  
346 - // 2.2 如果 allChildrenTaskFinish 已经被赋值为 false ,则不会再赋值为 true,因为整个链路没有完成 348 + boolean currentTaskFinish = BpmProcessInstanceResultEnum.isEndResult(parentTaskExt.getResult());
  349 + // 2.2 如果 allChildrenTaskFinish 已经被赋值为 false,则不会再赋值为 true,因为整个链路没有完成
347 if (allChildrenTaskFinish) { 350 if (allChildrenTaskFinish) {
348 allChildrenTaskFinish = currentTaskFinish; 351 allChildrenTaskFinish = currentTaskFinish;
349 } 352 }
@@ -354,19 +357,19 @@ public class BpmTaskServiceImpl implements BpmTaskService { @@ -354,19 +357,19 @@ public class BpmTaskServiceImpl implements BpmTaskService {
354 357
355 // 3 处理非完成状态的任务 358 // 3 处理非完成状态的任务
356 // 3.1 判断当前任务的父任务是否还有子任务 359 // 3.1 判断当前任务的父任务是否还有子任务
357 - Long childrenTaskCount = getChildrenTaskCount(bpmTaskExtDO.getTaskId()); 360 + Long childrenTaskCount = getChildrenTaskCount(parentTaskExt.getTaskId());
358 if (childrenTaskCount > 0) { 361 if (childrenTaskCount > 0) {
359 continue; 362 continue;
360 } 363 }
361 // 3.2 没有子任务,判断当前任务状态是否为 ADD_SIGN_BEFORE 待前加签任务完成 364 // 3.2 没有子任务,判断当前任务状态是否为 ADD_SIGN_BEFORE 待前加签任务完成
362 - if (BpmProcessInstanceResultEnum.ADD_SIGN_BEFORE.getResult().equals(bpmTaskExtDO.getResult())) { 365 + if (BpmProcessInstanceResultEnum.SIGN_BEFORE.getResult().equals(parentTaskExt.getResult())) {
363 // 3.3 需要修改该任务状态为处理中 366 // 3.3 需要修改该任务状态为处理中
364 - taskService.resolveTask(bpmTaskExtDO.getTaskId());  
365 - bpmTaskExtDO.setResult(BpmProcessInstanceResultEnum.PROCESS.getResult());  
366 - taskExtMapper.updateByTaskId(bpmTaskExtDO); 367 + taskService.resolveTask(parentTaskExt.getTaskId());
  368 + parentTaskExt.setResult(BpmProcessInstanceResultEnum.PROCESS.getResult());
  369 + taskExtMapper.updateByTaskId(parentTaskExt);
367 } 370 }
368 // 3.4 清空 scopeType 字段,用于任务没有子任务时使用该方法,方便任务可以再次被不同的方式加签 371 // 3.4 清空 scopeType 字段,用于任务没有子任务时使用该方法,方便任务可以再次被不同的方式加签
369 - parentTask = validateTaskExist(bpmTaskExtDO.getTaskId()); 372 + parentTask = validateTaskExist(parentTaskExt.getTaskId());
370 clearTaskScopeTypeAndSave(parentTask); 373 clearTaskScopeTypeAndSave(parentTask);
371 } 374 }
372 375
@@ -387,7 +390,6 @@ public class BpmTaskServiceImpl implements BpmTaskService { @@ -387,7 +390,6 @@ public class BpmTaskServiceImpl implements BpmTaskService {
387 taskService.saveTask(task); 390 taskService.saveTask(task);
388 } 391 }
389 392
390 -  
391 /** 393 /**
392 * 获取子任务个数 394 * 获取子任务个数
393 * 395 *
@@ -709,7 +711,7 @@ public class BpmTaskServiceImpl implements BpmTaskService { @@ -709,7 +711,7 @@ public class BpmTaskServiceImpl implements BpmTaskService {
709 711
710 @Override 712 @Override
711 @Transactional(rollbackFor = Exception.class) 713 @Transactional(rollbackFor = Exception.class)
712 - public void addSignTask(Long userId, BpmTaskAddSignReqVO reqVO) { 714 + public void createSignTask(Long userId, BpmTaskAddSignReqVO reqVO) {
713 // 1. 获取和校验任务 715 // 1. 获取和校验任务
714 TaskEntityImpl taskEntity = validateAddSign(userId, reqVO); 716 TaskEntityImpl taskEntity = validateAddSign(userId, reqVO);
715 List<AdminUserRespDTO> userList = adminUserApi.getUserList(reqVO.getUserIdList()); 717 List<AdminUserRespDTO> userList = adminUserApi.getUserList(reqVO.getUserIdList());
@@ -728,7 +730,7 @@ public class BpmTaskServiceImpl implements BpmTaskService { @@ -728,7 +730,7 @@ public class BpmTaskServiceImpl implements BpmTaskService {
728 // 2.3 更新扩展表状态 730 // 2.3 更新扩展表状态
729 taskExtMapper.updateByTaskId( 731 taskExtMapper.updateByTaskId(
730 new BpmTaskExtDO().setTaskId(taskEntity.getId()) 732 new BpmTaskExtDO().setTaskId(taskEntity.getId())
731 - .setResult(BpmProcessInstanceResultEnum.ADD_SIGN_BEFORE.getResult()) 733 + .setResult(BpmProcessInstanceResultEnum.SIGN_BEFORE.getResult())
732 .setReason(reqVO.getReason())); 734 .setReason(reqVO.getReason()));
733 } 735 }
734 // 2.4 记录加签方式,完成任务时需要用到判断 736 // 2.4 记录加签方式,完成任务时需要用到判断
@@ -737,12 +739,12 @@ public class BpmTaskServiceImpl implements BpmTaskService { @@ -737,12 +739,12 @@ public class BpmTaskServiceImpl implements BpmTaskService {
737 taskService.saveTask(taskEntity); 739 taskService.saveTask(taskEntity);
738 740
739 // 3. 创建加签任务 741 // 3. 创建加签任务
740 - createAddSignChildrenTasks(convertList(reqVO.getUserIdList(), String::valueOf), taskEntity); 742 + createSignTask(convertList(reqVO.getUserIdList(), String::valueOf), taskEntity);
741 743
742 // 4. 记录加签 comment,拼接结果为: [当前用户]向前加签/向后加签给了[多个用户],理由为:reason 744 // 4. 记录加签 comment,拼接结果为: [当前用户]向前加签/向后加签给了[多个用户],理由为:reason
743 AdminUserRespDTO currentUser = adminUserApi.getUser(userId); 745 AdminUserRespDTO currentUser = adminUserApi.getUser(userId);
744 - String comment = StrUtil.format(BpmCommentTypeEnum.ADD_SIGN.getTemplateComment(), currentUser.getNickname(), BpmTaskAddSignTypeEnum.formatDesc(reqVO.getType()),  
745 - String.join(",", convertList(userList, AdminUserRespDTO::getNickname)), reqVO.getReason()); 746 + String comment = StrUtil.format(BpmCommentTypeEnum.ADD_SIGN.getComment(), currentUser.getNickname(),
  747 + BpmTaskAddSignTypeEnum.formatDesc(reqVO.getType()), String.join(",", convertList(userList, AdminUserRespDTO::getNickname)), reqVO.getReason());
746 taskService.addComment(reqVO.getId(), taskEntity.getProcessInstanceId(), 748 taskService.addComment(reqVO.getId(), taskEntity.getProcessInstanceId(),
747 BpmCommentTypeEnum.ADD_SIGN.getType().toString(), comment); 749 BpmCommentTypeEnum.ADD_SIGN.getType().toString(), comment);
748 } 750 }
@@ -786,7 +788,7 @@ public class BpmTaskServiceImpl implements BpmTaskService { @@ -786,7 +788,7 @@ public class BpmTaskServiceImpl implements BpmTaskService {
786 * @param addSingUserIdList 被加签的用户 ID 788 * @param addSingUserIdList 被加签的用户 ID
787 * @param taskEntity 被加签的任务 789 * @param taskEntity 被加签的任务
788 */ 790 */
789 - private void createAddSignChildrenTasks(List<String> addSingUserIdList, TaskEntityImpl taskEntity) { 791 + private void createSignTask(List<String> addSingUserIdList, TaskEntityImpl taskEntity) {
790 if (CollUtil.isEmpty(addSingUserIdList)) { 792 if (CollUtil.isEmpty(addSingUserIdList)) {
791 return; 793 return;
792 } 794 }
@@ -795,23 +797,22 @@ public class BpmTaskServiceImpl implements BpmTaskService { @@ -795,23 +797,22 @@ public class BpmTaskServiceImpl implements BpmTaskService {
795 if (StrUtil.isBlank(addSignId)) { 797 if (StrUtil.isBlank(addSignId)) {
796 continue; 798 continue;
797 } 799 }
798 - createChildrenTask(taskEntity, addSignId); 800 + createSignTask(taskEntity, addSignId);
799 } 801 }
800 } 802 }
801 803
802 /** 804 /**
803 - * 创建子任务 805 + * 创建加签子任务
804 * 806 *
805 * @param parentTask 父任务 807 * @param parentTask 父任务
806 * @param assignee 子任务的执行人 808 * @param assignee 子任务的执行人
807 - * @return  
808 */ 809 */
809 - private void createChildrenTask(TaskEntityImpl parentTask, String assignee) { 810 + private void createSignTask(TaskEntityImpl parentTask, String assignee) {
810 // 1. 生成子任务 811 // 1. 生成子任务
811 TaskEntityImpl task = (TaskEntityImpl) taskService.newTask(IdUtil.fastSimpleUUID()); 812 TaskEntityImpl task = (TaskEntityImpl) taskService.newTask(IdUtil.fastSimpleUUID());
812 task = BpmTaskConvert.INSTANCE.convert(task, parentTask); 813 task = BpmTaskConvert.INSTANCE.convert(task, parentTask);
813 if (BpmTaskAddSignTypeEnum.BEFORE.getType().equals(parentTask.getScopeType())) { 814 if (BpmTaskAddSignTypeEnum.BEFORE.getType().equals(parentTask.getScopeType())) {
814 - // 2.1 前加签,才设置审批人,否则设置 owner 815 + // 2.1 前加签,设置审批人
815 task.setAssignee(assignee); 816 task.setAssignee(assignee);
816 } else { 817 } else {
817 // 2.2.1 设置 owner 不设置 assignee 是因为不能同时审批,需要等父任务完成 818 // 2.2.1 设置 owner 不设置 assignee 是因为不能同时审批,需要等父任务完成
@@ -825,9 +826,10 @@ public class BpmTaskServiceImpl implements BpmTaskService { @@ -825,9 +826,10 @@ public class BpmTaskServiceImpl implements BpmTaskService {
825 826
826 @Override 827 @Override
827 @Transactional(rollbackFor = Exception.class) 828 @Transactional(rollbackFor = Exception.class)
828 - public void subSignTask(Long userId, BpmTaskSubSignReqVO reqVO) { 829 + public void deleteSignTask(Long userId, BpmTaskSubSignReqVO reqVO) {
  830 + // 1.1 校验 task 可以被减签
829 Task task = validateSubSign(reqVO.getId()); 831 Task task = validateSubSign(reqVO.getId());
830 - AdminUserRespDTO user = adminUserApi.getUser(userId); 832 + // 1.2 校验取消人存在
831 AdminUserRespDTO cancelUser = null; 833 AdminUserRespDTO cancelUser = null;
832 if (StrUtil.isNotBlank(task.getAssignee())) { 834 if (StrUtil.isNotBlank(task.getAssignee())) {
833 cancelUser = adminUserApi.getUser(NumberUtils.parseLong(task.getAssignee())); 835 cancelUser = adminUserApi.getUser(NumberUtils.parseLong(task.getAssignee()));
@@ -836,20 +838,24 @@ public class BpmTaskServiceImpl implements BpmTaskService { @@ -836,20 +838,24 @@ public class BpmTaskServiceImpl implements BpmTaskService {
836 cancelUser = adminUserApi.getUser(NumberUtils.parseLong(task.getOwner())); 838 cancelUser = adminUserApi.getUser(NumberUtils.parseLong(task.getOwner()));
837 } 839 }
838 Assert.notNull(cancelUser, "任务中没有所有者和审批人,数据错误"); 840 Assert.notNull(cancelUser, "任务中没有所有者和审批人,数据错误");
839 - //1. 获取所有需要删除的任务 ID ,包含当前任务和所有子任务 841 +
  842 + // 2. 删除任务和对应子任务
  843 + // 2.1 获取所有需要删除的任务 ID ,包含当前任务和所有子任务
840 List<String> allTaskIdList = getAllChildTaskIds(task.getId()); 844 List<String> allTaskIdList = getAllChildTaskIds(task.getId());
841 - //2. 删除任务和所有子任务 845 + // 2.2 删除任务和所有子任务
842 taskService.deleteTasks(allTaskIdList); 846 taskService.deleteTasks(allTaskIdList);
843 - //3. 修改扩展表状态为取消 847 + // 2.3 修改扩展表状态为取消
  848 + AdminUserRespDTO user = adminUserApi.getUser(userId);
844 taskExtMapper.updateBatchByTaskIdList(allTaskIdList, new BpmTaskExtDO().setResult(BpmProcessInstanceResultEnum.CANCEL.getResult()) 849 taskExtMapper.updateBatchByTaskIdList(allTaskIdList, new BpmTaskExtDO().setResult(BpmProcessInstanceResultEnum.CANCEL.getResult())
845 .setReason(StrUtil.format("由于{}操作[减签],任务被取消", user.getNickname()))); 850 .setReason(StrUtil.format("由于{}操作[减签],任务被取消", user.getNickname())));
846 - //4.记录日志到父任务中 先记录日志是因为,通过 handleParentTask 方法之后,任务可能被完成了,并且不存在了,会报异常,所以先记录  
847 - String comment = StrUtil.format(BpmCommentTypeEnum.SUB_SIGN.getTemplateComment(), user.getNickname(), cancelUser.getNickname()); 851 +
  852 + // 3. 记录日志到父任务中。先记录日志是因为,通过 handleParentTask 方法之后,任务可能被完成了,并且不存在了,会报异常,所以先记录
  853 + String comment = StrUtil.format(BpmCommentTypeEnum.SUB_SIGN.getComment(), user.getNickname(), cancelUser.getNickname());
848 taskService.addComment(task.getParentTaskId(), task.getProcessInstanceId(), 854 taskService.addComment(task.getParentTaskId(), task.getProcessInstanceId(),
849 BpmCommentTypeEnum.SUB_SIGN.getType().toString(), comment); 855 BpmCommentTypeEnum.SUB_SIGN.getType().toString(), comment);
850 - //5. 处理当前任务的父任务  
851 - this.handleParentTask(task);  
852 856
  857 + // 4. 处理当前任务的父任务
  858 + handleParentTask(task);
853 } 859 }
854 860
855 /** 861 /**
@@ -860,14 +866,29 @@ public class BpmTaskServiceImpl implements BpmTaskService { @@ -860,14 +866,29 @@ public class BpmTaskServiceImpl implements BpmTaskService {
860 */ 866 */
861 private Task validateSubSign(String id) { 867 private Task validateSubSign(String id) {
862 Task task = validateTaskExist(id); 868 Task task = validateTaskExist(id);
863 - //必须有parentId  
864 - if (StrUtil.isEmpty(task.getParentTaskId())) { 869 +
  870 + // 必须有 scopeType
  871 + String scopeType = task.getScopeType();
  872 + if (StrUtil.isEmpty(scopeType)) {
  873 + throw exception(TASK_SUB_SIGN_NO_PARENT);
  874 + }
  875 + // 并且值为 向前和向后加签
  876 + if (!validateSignType(scopeType)) {
865 throw exception(TASK_SUB_SIGN_NO_PARENT); 877 throw exception(TASK_SUB_SIGN_NO_PARENT);
866 } 878 }
867 return task; 879 return task;
868 } 880 }
869 881
870 /** 882 /**
  883 + * 判断当前类型是否为加签
  884 + * @param scopeType 任务的 scopeType
  885 + * @return 当前 scopeType 为加签则返回 true
  886 + */
  887 + private boolean validateSignType(String scopeType){
  888 + return StrUtil.equalsAny(scopeType,BpmTaskAddSignTypeEnum.BEFORE.getType(),scopeType, BpmTaskAddSignTypeEnum.AFTER.getType());
  889 + }
  890 +
  891 + /**
871 * 获取所有要被取消的删除的任务 ID 集合 892 * 获取所有要被取消的删除的任务 ID 集合
872 * 893 *
873 * @param parentTaskId 父级任务ID 894 * @param parentTaskId 父级任务ID
@@ -875,25 +896,40 @@ public class BpmTaskServiceImpl implements BpmTaskService { @@ -875,25 +896,40 @@ public class BpmTaskServiceImpl implements BpmTaskService {
875 */ 896 */
876 public List<String> getAllChildTaskIds(String parentTaskId) { 897 public List<String> getAllChildTaskIds(String parentTaskId) {
877 List<String> allChildTaskIds = new ArrayList<>(); 898 List<String> allChildTaskIds = new ArrayList<>();
878 - //1. 先将自己放入  
879 - allChildTaskIds.add(parentTaskId);  
880 - //2. 递归获取子级  
881 - recursiveGetChildTaskIds(parentTaskId, allChildTaskIds); 899 + // 1. 递归获取子级
  900 + Stack<String> stack = new Stack<>();
  901 + // 1.1 将根任务ID入栈
  902 + stack.push(parentTaskId);
  903 + //控制遍历的次数不超过 Byte.MAX_VALUE,避免脏数据造成死循环
  904 + int count = 0;
  905 + // TODO @海:< 的前后空格,要注意哈;
  906 + while (!stack.isEmpty() && count<Byte.MAX_VALUE) {
  907 + // 1.2 弹出栈顶任务ID
  908 + String taskId = stack.pop();
  909 + // 1.3 将任务ID添加到结果集合中
  910 + allChildTaskIds.add(taskId);
  911 + // 1.4 获取该任务的子任务列表
  912 + // TODO @海:有个更高效的写法;一次性去 in 一层;不然每个节点,都去查询一次 db, 太浪费了;每次 in,最终就是 O(h) 查询,而不是 O(n) 查询;
  913 + List<String> childrenTaskIdList = getChildrenTaskIdList(taskId);
  914 + if (CollUtil.isNotEmpty(childrenTaskIdList)) {
  915 + for (String childTaskId : childrenTaskIdList) {
  916 + // 1.5 将子任务ID入栈,以便后续处理
  917 + stack.push(childTaskId);
  918 + }
  919 + }
  920 + count++;
  921 + }
882 return allChildTaskIds; 922 return allChildTaskIds;
883 } 923 }
884 924
885 /** 925 /**
886 - * 递归处理子级任务 926 + * 获取指定父级任务的所有子任务 ID 集合
887 * 927 *
888 - * @param taskId 当前任务ID  
889 - * @param taskIds 结果 928 + * @param parentTaskId 父任务 ID
  929 + * @return 所有子任务的 ID 集合
890 */ 930 */
891 - private void recursiveGetChildTaskIds(String taskId, List<String> taskIds) {  
892 - List<String> childrenTaskIdList = getChildrenTaskIdList(taskId);  
893 - for (String childTaskId : childrenTaskIdList) {  
894 - taskIds.add(childTaskId); // 将子任务的ID添加到集合中  
895 - recursiveGetChildTaskIds(childTaskId, taskIds); // 递归获取子任务的子任务  
896 - } 931 + private List<String> getChildrenTaskIdList(String parentTaskId) {
  932 + return convertList(getChildrenTaskList0(parentTaskId), Task::getId);
897 } 933 }
898 934
899 /** 935 /**
@@ -902,33 +938,32 @@ public class BpmTaskServiceImpl implements BpmTaskService { @@ -902,33 +938,32 @@ public class BpmTaskServiceImpl implements BpmTaskService {
902 * @param parentTaskId 父任务 ID 938 * @param parentTaskId 父任务 ID
903 * @return 所有子任务的 ID 集合 939 * @return 所有子任务的 ID 集合
904 */ 940 */
905 - private List<String> getChildrenTaskIdList(String parentTaskId) { 941 + private List<Task> getChildrenTaskList0(String parentTaskId) {
906 String tableName = managementService.getTableName(TaskEntity.class); 942 String tableName = managementService.getTableName(TaskEntity.class);
907 - String sql = "select ID_ from " + tableName + " where PARENT_TASK_ID_=#{parentTaskId}";  
908 - List<Task> childrenTaskList = taskService.createNativeTaskQuery().sql(sql).parameter("parentTaskId", parentTaskId).list();  
909 - return convertList(childrenTaskList, Task::getId); 943 + // taskService.createTaskQuery() 没有 parentId 参数,所以写 sql 查询
  944 + String sql = "select ID_,OWNER_,ASSIGNEE_ from " + tableName + " where PARENT_TASK_ID_=#{parentTaskId}";
  945 + return taskService.createNativeTaskQuery().sql(sql).parameter("parentTaskId", parentTaskId).list();
910 } 946 }
911 947
  948 +
912 @Override 949 @Override
913 - public List<BpmTaskSubSignRespVO> getChildrenTaskList(String taskId) {  
914 - List<String> childrenTaskIdList = getChildrenTaskIdList(taskId);  
915 - if (CollUtil.isEmpty(childrenTaskIdList)) { 950 + public List<BpmTaskSubSignRespVO> getChildrenTaskList(String parentId) {
  951 + // 1. 只查询进行中的任务 后加签的任务,可能不存在 assignee,所以还需要查询 owner
  952 + List<Task> taskList = getChildrenTaskList0(parentId);
  953 + if (CollUtil.isEmpty(taskList)) {
916 return Collections.emptyList(); 954 return Collections.emptyList();
917 } 955 }
918 - //1. 只查询进行中的任务  
919 - List<BpmTaskExtDO> bpmTaskExtDOList = taskExtMapper.selectProcessListByTaskIds(childrenTaskIdList);  
920 - //2. 后加签的任务,可能不存在 assignee,所以还需要查询 owner  
921 - List<Task> taskList = taskService.createTaskQuery().taskIds(childrenTaskIdList).list();  
922 - Map<String, Task> idTaskMap = convertMap(taskList, TaskInfo::getId);  
923 - //3. 将 owner 和 assignee 统一到一个集合中  
924 - List<Long> userIds = taskList.stream()  
925 - .flatMap(control ->  
926 - Stream.of(control.getAssignee(), control.getOwner())  
927 - .filter(Objects::nonNull))  
928 - .distinct()  
929 - .map(NumberUtils::parseLong)  
930 - .collect(Collectors.toList()); 956 + List<String> childrenTaskIdList = convertList(taskList, Task::getId);
  957 +
  958 + // 2.1 将 owner 和 assignee 统一到一个集合中
  959 + List<Long> userIds = convertListByFlatMap(taskList, control ->
  960 + Stream.of(NumberUtils.parseLong(control.getAssignee()), NumberUtils.parseLong(control.getOwner()))
  961 + .filter(Objects::nonNull));
  962 + // 2.2 组装数据
931 Map<Long, AdminUserRespDTO> userMap = adminUserApi.getUserMap(userIds); 963 Map<Long, AdminUserRespDTO> userMap = adminUserApi.getUserMap(userIds);
932 - return BpmTaskConvert.INSTANCE.convertList(bpmTaskExtDOList, userMap, idTaskMap); 964 + List<BpmTaskExtDO> taskExtList = taskExtMapper.selectProcessListByTaskIds(childrenTaskIdList);
  965 + Map<String, Task> idTaskMap = convertMap(taskList, TaskInfo::getId);
  966 + return BpmTaskConvert.INSTANCE.convertList(taskExtList, userMap, idTaskMap);
933 } 967 }
  968 +
934 } 969 }
yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/db/DatabaseDocController.java
@@ -147,7 +147,7 @@ public class DatabaseDocController { @@ -147,7 +147,7 @@ public class DatabaseDocController {
147 */ 147 */
148 private static ProcessConfig buildProcessConfig() { 148 private static ProcessConfig buildProcessConfig() {
149 return ProcessConfig.builder() 149 return ProcessConfig.builder()
150 - .ignoreTablePrefix(Arrays.asList("QRTZ_", "ACT_")) // 忽略表前缀 150 + .ignoreTablePrefix(Arrays.asList("QRTZ_", "ACT_", "FLW_")) // 忽略表前缀
151 .build(); 151 .build();
152 } 152 }
153 153
yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/framework/security/config/SecurityConfiguration.java
@@ -29,8 +29,6 @@ public class SecurityConfiguration { @@ -29,8 +29,6 @@ public class SecurityConfiguration {
29 .antMatchers("/swagger-resources/**").anonymous() 29 .antMatchers("/swagger-resources/**").anonymous()
30 .antMatchers("/webjars/**").anonymous() 30 .antMatchers("/webjars/**").anonymous()
31 .antMatchers("/*/api-docs").anonymous(); 31 .antMatchers("/*/api-docs").anonymous();
32 - // 积木报表  
33 - registry.antMatchers("/jmreport/**").permitAll();  
34 // Spring Boot Actuator 的安全配置 32 // Spring Boot Actuator 的安全配置
35 registry.antMatchers("/actuator").anonymous() 33 registry.antMatchers("/actuator").anonymous()
36 .antMatchers("/actuator/**").anonymous(); 34 .antMatchers("/actuator/**").anonymous();
yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/job/logger/JobLogCleanJob.java renamed to yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/job/job/JobLogCleanJob.java
1 -package cn.iocoder.yudao.module.infra.job.logger; 1 +package cn.iocoder.yudao.module.infra.job.job;
2 2
3 import cn.iocoder.yudao.framework.quartz.core.handler.JobHandler; 3 import cn.iocoder.yudao.framework.quartz.core.handler.JobHandler;
4 import cn.iocoder.yudao.framework.tenant.core.aop.TenantIgnore; 4 import cn.iocoder.yudao.framework.tenant.core.aop.TenantIgnore;
@@ -33,7 +33,7 @@ public class JobLogCleanJob implements JobHandler { @@ -33,7 +33,7 @@ public class JobLogCleanJob implements JobHandler {
33 @TenantIgnore 33 @TenantIgnore
34 public String execute(String param) { 34 public String execute(String param) {
35 Integer count = jobLogService.cleanJobLog(JOB_CLEAN_RETAIN_DAY, DELETE_LIMIT); 35 Integer count = jobLogService.cleanJobLog(JOB_CLEAN_RETAIN_DAY, DELETE_LIMIT);
36 - log.info("[count][定时执行清理定时任务日志数量 ({}) 个]", count); 36 + log.info("[execute][定时执行清理定时任务日志数量 ({}) 个]", count);
37 return String.format("定时执行清理定时任务日志数量 %s 个", count); 37 return String.format("定时执行清理定时任务日志数量 %s 个", count);
38 } 38 }
39 39
yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/job/job/AccessLogCleanJob.java renamed to yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/job/logger/AccessLogCleanJob.java
1 -package cn.iocoder.yudao.module.infra.job.job; 1 +package cn.iocoder.yudao.module.infra.job.logger;
2 2
3 import cn.iocoder.yudao.framework.quartz.core.handler.JobHandler; 3 import cn.iocoder.yudao.framework.quartz.core.handler.JobHandler;
4 import cn.iocoder.yudao.framework.tenant.core.aop.TenantIgnore; 4 import cn.iocoder.yudao.framework.tenant.core.aop.TenantIgnore;
@@ -34,7 +34,7 @@ public class AccessLogCleanJob implements JobHandler { @@ -34,7 +34,7 @@ public class AccessLogCleanJob implements JobHandler {
34 @TenantIgnore 34 @TenantIgnore
35 public String execute(String param) { 35 public String execute(String param) {
36 Integer count = apiAccessLogService.cleanAccessLog(JOB_CLEAN_RETAIN_DAY, DELETE_LIMIT); 36 Integer count = apiAccessLogService.cleanAccessLog(JOB_CLEAN_RETAIN_DAY, DELETE_LIMIT);
37 - log.info("[count][定时执行清理访问日志数量 ({}) 个]", count); 37 + log.info("[execute][定时执行清理访问日志数量 ({}) 个]", count);
38 return String.format("定时执行清理错误日志数量 %s 个", count); 38 return String.format("定时执行清理错误日志数量 %s 个", count);
39 } 39 }
40 40
yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/job/job/ErrorLogCleanJob.java renamed to yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/job/logger/ErrorLogCleanJob.java
1 -package cn.iocoder.yudao.module.infra.job.job; 1 +package cn.iocoder.yudao.module.infra.job.logger;
2 2
3 import cn.iocoder.yudao.framework.quartz.core.handler.JobHandler; 3 import cn.iocoder.yudao.framework.quartz.core.handler.JobHandler;
4 import cn.iocoder.yudao.framework.tenant.core.aop.TenantIgnore; 4 import cn.iocoder.yudao.framework.tenant.core.aop.TenantIgnore;
@@ -34,7 +34,7 @@ public class ErrorLogCleanJob implements JobHandler { @@ -34,7 +34,7 @@ public class ErrorLogCleanJob implements JobHandler {
34 @TenantIgnore 34 @TenantIgnore
35 public String execute(String param) { 35 public String execute(String param) {
36 Integer count = apiErrorLogService.cleanErrorLog(JOB_CLEAN_RETAIN_DAY,DELETE_LIMIT); 36 Integer count = apiErrorLogService.cleanErrorLog(JOB_CLEAN_RETAIN_DAY,DELETE_LIMIT);
37 - log.info("[count][定时执行清理错误日志数量 ({}) 个]", count); 37 + log.info("[execute][定时执行清理错误日志数量 ({}) 个]", count);
38 return String.format("定时执行清理错误日志数量 %s 个", count); 38 return String.format("定时执行清理错误日志数量 %s 个", count);
39 } 39 }
40 40
yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/service/file/FileConfigServiceImpl.java
@@ -58,9 +58,9 @@ public class FileConfigServiceImpl implements FileConfigService { @@ -58,9 +58,9 @@ public class FileConfigServiceImpl implements FileConfigService {
58 FileConfigDO config = Objects.equals(CACHE_MASTER_ID, id) ? 58 FileConfigDO config = Objects.equals(CACHE_MASTER_ID, id) ?
59 fileConfigMapper.selectByMaster() : fileConfigMapper.selectById(id); 59 fileConfigMapper.selectByMaster() : fileConfigMapper.selectById(id);
60 if (config != null) { 60 if (config != null) {
61 - fileClientFactory.createOrUpdateFileClient(id, config.getStorage(), config.getConfig()); 61 + fileClientFactory.createOrUpdateFileClient(config.getId(), config.getStorage(), config.getConfig());
62 } 62 }
63 - return fileClientFactory.getFileClient(id); 63 + return fileClientFactory.getFileClient(null == config ? id : config.getId());
64 } 64 }
65 65
66 }); 66 });
yudao-module-infra/yudao-module-infra-biz/src/main/resources/codegen/vue3_vben/api/api.ts.vm
@@ -28,5 +28,5 @@ export function delete${simpleClassName}(id: number) { @@ -28,5 +28,5 @@ export function delete${simpleClassName}(id: number) {
28 28
29 // 导出${table.classComment} Excel 29 // 导出${table.classComment} Excel
30 export function export${simpleClassName}(params) { 30 export function export${simpleClassName}(params) {
31 - return defHttp.download({ url: '${baseURL}/export-excel', params }, '${table.classComment}.xls') 31 + return defHttp.download({ url: '${baseURL}/export-excel', params }, '${table.classComment}.xls')
32 } 32 }
yudao-module-infra/yudao-module-infra-biz/src/main/resources/codegen/vue3_vben/views/data.ts.vm
1 -import type { BasicColumn, FormSchema } from '@/components/Table'  
2 -import { useRender } from '@/components/Table'  
3 -import { DICT_TYPE, getDictOptions } from '@/utils/dict' 1 +import type {BasicColumn, FormSchema} from '@/components/Table'
  2 +import {useRender} from '@/components/Table'
  3 +import {DICT_TYPE, getDictOptions} from '@/utils/dict'
4 4
5 export const columns: BasicColumn[] = [ 5 export const columns: BasicColumn[] = [
6 #foreach($column in $columns) 6 #foreach($column in $columns)
@@ -50,7 +50,7 @@ export const searchFormSchema: FormSchema[] = [ @@ -50,7 +50,7 @@ export const searchFormSchema: FormSchema[] = [
50 field: '${javaField}', 50 field: '${javaField}',
51 #if ($column.htmlType == "input") 51 #if ($column.htmlType == "input")
52 component: 'Input', 52 component: 'Input',
53 - #elseif ($column.htmlType == "select" || $column.htmlType == "radio") 53 + #elseif ($column.htmlType == "select")
54 component: 'Select', 54 component: 'Select',
55 componentProps: { 55 componentProps: {
56 #if ("" != $dictType)## 设置了 dictType 数据字典的情况 56 #if ("" != $dictType)## 设置了 dictType 数据字典的情况
@@ -59,6 +59,15 @@ export const searchFormSchema: FormSchema[] = [ @@ -59,6 +59,15 @@ export const searchFormSchema: FormSchema[] = [
59 options: [], 59 options: [],
60 #end 60 #end
61 }, 61 },
  62 + #elseif ($column.htmlType == "radio")
  63 + component: 'Radio',
  64 + componentProps: {
  65 + #if ("" != $dictType)## 设置了 dictType 数据字典的情况
  66 + options: getDictOptions(DICT_TYPE.$dictType.toUpperCase()),
  67 + #else## 未设置 dictType 数据字典的情况
  68 + options: [],
  69 + #end
  70 + },
62 #elseif($column.htmlType == "datetime") 71 #elseif($column.htmlType == "datetime")
63 component: 'RangePicker', 72 component: 'RangePicker',
64 #end 73 #end
@@ -181,7 +190,8 @@ export const updateFormSchema: FormSchema[] = [ @@ -181,7 +190,8 @@ export const updateFormSchema: FormSchema[] = [
181 fileType: 'file', 190 fileType: 'file',
182 maxCount: 1, 191 maxCount: 1,
183 }, 192 },
184 - #elseif($column.htmlType == "editor")## 文本编辑器component: 'Editor', 193 + #elseif($column.htmlType == "editor")## 文本编辑器
  194 + component: 'Editor',
185 #elseif($column.htmlType == "select")## 下拉框 195 #elseif($column.htmlType == "select")## 下拉框
186 component: 'Select', 196 component: 'Select',
187 componentProps: { 197 componentProps: {
yudao-module-infra/yudao-module-infra-biz/src/main/resources/codegen/vue3_vben/views/index.vue.vm
1 <script lang="ts" setup> 1 <script lang="ts" setup>
2 -import ${ simpleClassName }Modal from './${simpleClassName}Modal.vue' 2 +import ${simpleClassName}Modal from './${simpleClassName}Modal.vue'
3 import { columns, searchFormSchema } from './${classNameVar}.data' 3 import { columns, searchFormSchema } from './${classNameVar}.data'
4 import { useI18n } from '@/hooks/web/useI18n' 4 import { useI18n } from '@/hooks/web/useI18n'
5 import { useMessage } from '@/hooks/web/useMessage' 5 import { useMessage } from '@/hooks/web/useMessage'
6 import { useModal } from '@/components/Modal' 6 import { useModal } from '@/components/Modal'
7 -import { IconEnum } from '@/enums/appEnum'  
8 -import { BasicTable, useTable, TableAction } from '@/components/Table'  
9 -import { delete${ simpleClassName }, export${ simpleClassName }, get${ simpleClassName } Page } from '@/api/${table.moduleName}/${classNameVar}' 7 +import { useTable } from '@/components/Table'
  8 +import { delete${simpleClassName}, export${simpleClassName}, get${simpleClassName}Page } from '@/api/${table.moduleName}/${classNameVar}'
10 9
11 defineOptions({ name: '${table.className}' }) 10 defineOptions({ name: '${table.className}' })
12 11
@@ -16,7 +15,7 @@ const [registerModal, { openModal }] = useModal() @@ -16,7 +15,7 @@ const [registerModal, { openModal }] = useModal()
16 15
17 const [registerTable, { getForm, reload }] = useTable({ 16 const [registerTable, { getForm, reload }] = useTable({
18 title: '${table.classComment}列表', 17 title: '${table.classComment}列表',
19 - api: get${ simpleClassName }Page, 18 + api: get${simpleClassName}Page,
20 columns, 19 columns,
21 formConfig: { labelWidth: 120, schemas: searchFormSchema }, 20 formConfig: { labelWidth: 120, schemas: searchFormSchema },
22 useSearchForm: true, 21 useSearchForm: true,
@@ -43,14 +42,14 @@ async function handleExport() { @@ -43,14 +42,14 @@ async function handleExport() {
43 iconType: 'warning', 42 iconType: 'warning',
44 content: t('common.exportMessage'), 43 content: t('common.exportMessage'),
45 async onOk() { 44 async onOk() {
46 - await export${ simpleClassName } (getForm().getFieldsValue()) 45 + await export${simpleClassName}(getForm().getFieldsValue())
47 createMessage.success(t('common.exportSuccessText')) 46 createMessage.success(t('common.exportSuccessText'))
48 }, 47 },
49 }) 48 })
50 } 49 }
51 50
52 async function handleDelete(record: Recordable) { 51 async function handleDelete(record: Recordable) {
53 - await delete${ simpleClassName } (record.id) 52 + await delete${simpleClassName}(record.id)
54 createMessage.success(t('common.delSuccessText')) 53 createMessage.success(t('common.delSuccessText'))
55 reload() 54 reload()
56 } 55 }
@@ -62,7 +61,7 @@ async function handleDelete(record: Recordable) { @@ -62,7 +61,7 @@ async function handleDelete(record: Recordable) {
62 <a-button type="primary" v-auth="['${permissionPrefix}:create']" :preIcon="IconEnum.ADD" @click="handleCreate"> 61 <a-button type="primary" v-auth="['${permissionPrefix}:create']" :preIcon="IconEnum.ADD" @click="handleCreate">
63 {{ t('action.create') }} 62 {{ t('action.create') }}
64 </a-button> 63 </a-button>
65 - <a-button type="warning" v-auth="['${permissionPrefix}:export']" :preIcon="IconEnum.EXPORT" @click="handleExport"> 64 + <a-button v-auth="['${permissionPrefix}:export']" :preIcon="IconEnum.EXPORT" @click="handleExport">
66 {{ t('action.export') }} 65 {{ t('action.export') }}
67 </a-button> 66 </a-button>
68 </template> 67 </template>
yudao-module-infra/yudao-module-infra-biz/src/test/java/cn/iocoder/yudao/module/infra/service/file/FileConfigServiceImplTest.java
@@ -258,12 +258,12 @@ public class FileConfigServiceImplTest extends BaseDbUnitTest { @@ -258,12 +258,12 @@ public class FileConfigServiceImplTest extends BaseDbUnitTest {
258 Long id = fileConfig.getId(); 258 Long id = fileConfig.getId();
259 // mock 获得 Client 259 // mock 获得 Client
260 FileClient fileClient = new LocalFileClient(id, new LocalFileClientConfig()); 260 FileClient fileClient = new LocalFileClient(id, new LocalFileClientConfig());
261 - when(fileClientFactory.getFileClient(eq(0L))).thenReturn(fileClient); 261 + when(fileClientFactory.getFileClient(eq(fileConfig.getId()))).thenReturn(fileClient);
262 262
263 // 调用,并断言 263 // 调用,并断言
264 assertSame(fileClient, fileConfigService.getMasterFileClient()); 264 assertSame(fileClient, fileConfigService.getMasterFileClient());
265 // 断言缓存 265 // 断言缓存
266 - verify(fileClientFactory).createOrUpdateFileClient(eq(0L), eq(fileConfig.getStorage()), 266 + verify(fileClientFactory).createOrUpdateFileClient(eq(fileConfig.getId()), eq(fileConfig.getStorage()),
267 eq(fileConfig.getConfig())); 267 eq(fileConfig.getConfig()));
268 } 268 }
269 269
yudao-module-mall/yudao-module-product-api/src/main/java/cn/iocoder/yudao/module/product/api/comment/dto/ProductCommentCreateReqDTO.java
@@ -2,6 +2,7 @@ package cn.iocoder.yudao.module.product.api.comment.dto; @@ -2,6 +2,7 @@ package cn.iocoder.yudao.module.product.api.comment.dto;
2 2
3 import lombok.Data; 3 import lombok.Data;
4 4
  5 +import javax.validation.constraints.NotNull;
5 import java.util.List; 6 import java.util.List;
6 7
7 /** 8 /**
@@ -15,6 +16,7 @@ public class ProductCommentCreateReqDTO { @@ -15,6 +16,7 @@ public class ProductCommentCreateReqDTO {
15 /** 16 /**
16 * 商品 SKU 编号 17 * 商品 SKU 编号
17 */ 18 */
  19 + @NotNull(message = "商品 SKU 编号不能为空")
18 private Long skuId; 20 private Long skuId;
19 /** 21 /**
20 * 订单编号 22 * 订单编号
@@ -26,20 +28,19 @@ public class ProductCommentCreateReqDTO { @@ -26,20 +28,19 @@ public class ProductCommentCreateReqDTO {
26 private Long orderItemId; 28 private Long orderItemId;
27 29
28 /** 30 /**
29 - * 评分星级 1-5 分  
30 - */  
31 - private Integer scores;  
32 - /**  
33 * 描述星级 1-5 分 31 * 描述星级 1-5 分
34 */ 32 */
  33 + @NotNull(message = "描述星级不能为空")
35 private Integer descriptionScores; 34 private Integer descriptionScores;
36 /** 35 /**
37 * 服务星级 1-5 分 36 * 服务星级 1-5 分
38 */ 37 */
  38 + @NotNull(message = "服务星级不能为空")
39 private Integer benefitScores; 39 private Integer benefitScores;
40 /** 40 /**
41 * 评论内容 41 * 评论内容
42 */ 42 */
  43 + @NotNull(message = "评论内容不能为空")
43 private String content; 44 private String content;
44 /** 45 /**
45 * 评论图片地址数组,以逗号分隔最多上传 9 张 46 * 评论图片地址数组,以逗号分隔最多上传 9 张
@@ -49,11 +50,12 @@ public class ProductCommentCreateReqDTO { @@ -49,11 +50,12 @@ public class ProductCommentCreateReqDTO {
49 /** 50 /**
50 * 是否匿名 51 * 是否匿名
51 */ 52 */
  53 + @NotNull(message = "是否匿名不能为空")
52 private Boolean anonymous; 54 private Boolean anonymous;
53 /** 55 /**
54 * 评价人 56 * 评价人
55 */ 57 */
  58 + @NotNull(message = "评价人不能为空")
56 private Long userId; 59 private Long userId;
57 60
58 -  
59 } 61 }
yudao-module-mall/yudao-module-product-api/src/main/java/cn/iocoder/yudao/module/product/api/property/ProductPropertyValueApi.java deleted
1 -package cn.iocoder.yudao.module.product.api.property;  
2 -  
3 -import cn.iocoder.yudao.module.product.api.property.dto.ProductPropertyValueDetailRespDTO;  
4 -  
5 -import java.util.Collection;  
6 -import java.util.List;  
7 -  
8 -/**  
9 - * 商品属性值 API 接口  
10 - *  
11 - * @author 芋道源码  
12 - */  
13 -public interface ProductPropertyValueApi {  
14 -  
15 - /**  
16 - * 根据编号数组,获得属性值列表  
17 - *  
18 - * @param ids 编号数组  
19 - * @return 属性值明细列表  
20 - */  
21 - List<ProductPropertyValueDetailRespDTO> getPropertyValueDetailList(Collection<Long> ids);  
22 -  
23 -}  
yudao-module-mall/yudao-module-product-api/src/main/java/cn/iocoder/yudao/module/product/api/spu/dto/ProductSpuRespDTO.java
@@ -3,8 +3,6 @@ package cn.iocoder.yudao.module.product.api.spu.dto; @@ -3,8 +3,6 @@ package cn.iocoder.yudao.module.product.api.spu.dto;
3 import cn.iocoder.yudao.module.product.enums.spu.ProductSpuStatusEnum; 3 import cn.iocoder.yudao.module.product.enums.spu.ProductSpuStatusEnum;
4 import lombok.Data; 4 import lombok.Data;
5 5
6 -import java.util.List;  
7 -  
8 // TODO @LeeYan9: ProductSpuRespDTO 6 // TODO @LeeYan9: ProductSpuRespDTO
9 /** 7 /**
10 * 商品 SPU 信息 Response DTO 8 * 商品 SPU 信息 Response DTO
@@ -27,55 +25,22 @@ public class ProductSpuRespDTO { @@ -27,55 +25,22 @@ public class ProductSpuRespDTO {
27 */ 25 */
28 private String name; 26 private String name;
29 /** 27 /**
30 - * 关键字  
31 - */  
32 - private String keyword;  
33 - /**  
34 * 单位 28 * 单位
35 * 29 *
36 * 对应 product_unit 数据字典 30 * 对应 product_unit 数据字典
37 */ 31 */
38 private Integer unit; 32 private Integer unit;
39 - /**  
40 - * 商品简介  
41 - */  
42 - private String introduction;  
43 - /**  
44 - * 商品详情  
45 - */  
46 - private String description;  
47 - // TODO @芋艿:是不是要删除  
48 - /**  
49 - * 商品条码(一维码)  
50 - */  
51 - private String barCode;  
52 33
53 /** 34 /**
54 * 商品分类编号 35 * 商品分类编号
55 */ 36 */
56 private Long categoryId; 37 private Long categoryId;
57 /** 38 /**
58 - * 商品品牌编号  
59 - */  
60 - private Long brandId;  
61 - /**  
62 * 商品封面图 39 * 商品封面图
63 */ 40 */
64 private String picUrl; 41 private String picUrl;
65 - /**  
66 - * 商品轮播图  
67 - */  
68 - private List<String> sliderPicUrls;  
69 - /**  
70 - * 商品视频  
71 - */  
72 - private String videoUrl;  
73 42
74 /** 43 /**
75 - * 排序字段  
76 - */  
77 - private Integer sort;  
78 - /**  
79 * 商品状态 44 * 商品状态
80 * <p> 45 * <p>
81 * 枚举 {@link ProductSpuStatusEnum} 46 * 枚举 {@link ProductSpuStatusEnum}
@@ -124,22 +89,6 @@ public class ProductSpuRespDTO { @@ -124,22 +89,6 @@ public class ProductSpuRespDTO {
124 */ 89 */
125 private Integer giveIntegral; 90 private Integer giveIntegral;
126 91
127 - // ========== 统计相关字段 =========  
128 -  
129 - /**  
130 - * 商品销量  
131 - */  
132 - private Integer salesCount;  
133 - /**  
134 - * 虚拟销量  
135 - */  
136 - private Integer virtualSalesCount;  
137 - /**  
138 - * 商品点击量  
139 - */  
140 - private Integer clickCount;  
141 -  
142 -  
143 // ========== 分销相关字段 ========= 92 // ========== 分销相关字段 =========
144 93
145 /** 94 /**
yudao-module-mall/yudao-module-product-api/src/main/java/cn/iocoder/yudao/module/product/enums/group/ProductGroupStyleEnum.java deleted
1 -package cn.iocoder.yudao.module.product.enums.group;  
2 -  
3 -import cn.iocoder.yudao.framework.common.core.IntArrayValuable;  
4 -import lombok.AllArgsConstructor;  
5 -import lombok.Getter;  
6 -  
7 -import java.util.Arrays;  
8 -  
9 -/**  
10 - * 商品分组的样式枚举  
11 - *  
12 - * @author 芋道源码  
13 - */  
14 -@Getter  
15 -@AllArgsConstructor  
16 -public enum ProductGroupStyleEnum implements IntArrayValuable {  
17 -  
18 - ONE(1, "每列一个"),  
19 - TWO(2, "每列两个"),  
20 - THREE(2, "每列三个"),;  
21 -  
22 - public static final int[] ARRAYS = Arrays.stream(values()).mapToInt(ProductGroupStyleEnum::getStyle).toArray();  
23 -  
24 - /**  
25 - * 列表样式  
26 - */  
27 - private final Integer style;  
28 - /**  
29 - * 状态名  
30 - */  
31 - private final String name;  
32 -  
33 - @Override  
34 - public int[] array() {  
35 - return ARRAYS;  
36 - }  
37 -  
38 -}  
yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/api/property/ProductPropertyValueApiImpl.java deleted
1 -package cn.iocoder.yudao.module.product.api.property;  
2 -  
3 -import cn.iocoder.yudao.module.product.api.property.dto.ProductPropertyValueDetailRespDTO;  
4 -import cn.iocoder.yudao.module.product.convert.property.ProductPropertyValueConvert;  
5 -import cn.iocoder.yudao.module.product.service.property.ProductPropertyValueService;  
6 -import org.springframework.stereotype.Service;  
7 -import org.springframework.validation.annotation.Validated;  
8 -  
9 -import javax.annotation.Resource;  
10 -import java.util.Collection;  
11 -import java.util.List;  
12 -  
13 -/**  
14 - * 商品属性值 API 实现类  
15 - *  
16 - * @author 芋道源码  
17 - */  
18 -@Service  
19 -@Validated  
20 -public class ProductPropertyValueApiImpl implements ProductPropertyValueApi {  
21 -  
22 - @Resource  
23 - private ProductPropertyValueService productPropertyValueService;  
24 -  
25 - @Override  
26 - public List<ProductPropertyValueDetailRespDTO> getPropertyValueDetailList(Collection<Long> ids) {  
27 - return ProductPropertyValueConvert.INSTANCE.convertList02(  
28 - productPropertyValueService.getPropertyValueDetailList(ids));  
29 - }  
30 -  
31 -}  
yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/api/sku/ProductSkuApiImpl.java
1 package cn.iocoder.yudao.module.product.api.sku; 1 package cn.iocoder.yudao.module.product.api.sku;
2 2
3 -import cn.hutool.core.collection.CollUtil;  
4 import cn.iocoder.yudao.module.product.api.sku.dto.ProductSkuRespDTO; 3 import cn.iocoder.yudao.module.product.api.sku.dto.ProductSkuRespDTO;
5 import cn.iocoder.yudao.module.product.api.sku.dto.ProductSkuUpdateStockReqDTO; 4 import cn.iocoder.yudao.module.product.api.sku.dto.ProductSkuUpdateStockReqDTO;
6 import cn.iocoder.yudao.module.product.convert.sku.ProductSkuConvert; 5 import cn.iocoder.yudao.module.product.convert.sku.ProductSkuConvert;
@@ -11,7 +10,6 @@ import org.springframework.validation.annotation.Validated; @@ -11,7 +10,6 @@ import org.springframework.validation.annotation.Validated;
11 10
12 import javax.annotation.Resource; 11 import javax.annotation.Resource;
13 import java.util.Collection; 12 import java.util.Collection;
14 -import java.util.Collections;  
15 import java.util.List; 13 import java.util.List;
16 14
17 /** 15 /**
@@ -35,18 +33,12 @@ public class ProductSkuApiImpl implements ProductSkuApi { @@ -35,18 +33,12 @@ public class ProductSkuApiImpl implements ProductSkuApi {
35 33
36 @Override 34 @Override
37 public List<ProductSkuRespDTO> getSkuList(Collection<Long> ids) { 35 public List<ProductSkuRespDTO> getSkuList(Collection<Long> ids) {
38 - if (CollUtil.isEmpty(ids)) {  
39 - return Collections.emptyList();  
40 - }  
41 List<ProductSkuDO> skus = productSkuService.getSkuList(ids); 36 List<ProductSkuDO> skus = productSkuService.getSkuList(ids);
42 return ProductSkuConvert.INSTANCE.convertList04(skus); 37 return ProductSkuConvert.INSTANCE.convertList04(skus);
43 } 38 }
44 39
45 @Override 40 @Override
46 public List<ProductSkuRespDTO> getSkuListBySpuId(Collection<Long> spuIds) { 41 public List<ProductSkuRespDTO> getSkuListBySpuId(Collection<Long> spuIds) {
47 - if (CollUtil.isEmpty(spuIds)) {  
48 - return Collections.emptyList();  
49 - }  
50 List<ProductSkuDO> skus = productSkuService.getSkuListBySpuId(spuIds); 42 List<ProductSkuDO> skus = productSkuService.getSkuListBySpuId(spuIds);
51 return ProductSkuConvert.INSTANCE.convertList04(skus); 43 return ProductSkuConvert.INSTANCE.convertList04(skus);
52 } 44 }
yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/api/spu/ProductSpuApiImpl.java
@@ -27,9 +27,6 @@ public class ProductSpuApiImpl implements ProductSpuApi { @@ -27,9 +27,6 @@ public class ProductSpuApiImpl implements ProductSpuApi {
27 27
28 @Override 28 @Override
29 public List<ProductSpuRespDTO> getSpuList(Collection<Long> ids) { 29 public List<ProductSpuRespDTO> getSpuList(Collection<Long> ids) {
30 - if (CollectionUtil.isEmpty(ids)) {  
31 - return Collections.emptyList();  
32 - }  
33 return ProductSpuConvert.INSTANCE.convertList2(spuService.getSpuList(ids)); 30 return ProductSpuConvert.INSTANCE.convertList2(spuService.getSpuList(ids));
34 } 31 }
35 32
yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/convert/property/ProductPropertyValueConvert.java
1 package cn.iocoder.yudao.module.product.convert.property; 1 package cn.iocoder.yudao.module.product.convert.property;
2 2
3 import cn.iocoder.yudao.framework.common.pojo.PageResult; 3 import cn.iocoder.yudao.framework.common.pojo.PageResult;
4 -import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils;  
5 -import cn.iocoder.yudao.framework.common.util.collection.MapUtils;  
6 -import cn.iocoder.yudao.module.product.api.property.dto.ProductPropertyValueDetailRespDTO;  
7 import cn.iocoder.yudao.module.product.controller.admin.property.vo.value.ProductPropertyValueCreateReqVO; 4 import cn.iocoder.yudao.module.product.controller.admin.property.vo.value.ProductPropertyValueCreateReqVO;
8 import cn.iocoder.yudao.module.product.controller.admin.property.vo.value.ProductPropertyValueRespVO; 5 import cn.iocoder.yudao.module.product.controller.admin.property.vo.value.ProductPropertyValueRespVO;
9 import cn.iocoder.yudao.module.product.controller.admin.property.vo.value.ProductPropertyValueUpdateReqVO; 6 import cn.iocoder.yudao.module.product.controller.admin.property.vo.value.ProductPropertyValueUpdateReqVO;
10 -import cn.iocoder.yudao.module.product.dal.dataobject.property.ProductPropertyDO;  
11 import cn.iocoder.yudao.module.product.dal.dataobject.property.ProductPropertyValueDO; 7 import cn.iocoder.yudao.module.product.dal.dataobject.property.ProductPropertyValueDO;
12 -import cn.iocoder.yudao.module.product.service.property.bo.ProductPropertyValueDetailRespBO;  
13 import org.mapstruct.Mapper; 8 import org.mapstruct.Mapper;
14 import org.mapstruct.factory.Mappers; 9 import org.mapstruct.factory.Mappers;
15 10
16 import java.util.List; 11 import java.util.List;
17 -import java.util.Map;  
18 -  
19 -import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertMap;  
20 12
21 /** 13 /**
22 * 属性值 Convert 14 * 属性值 Convert
@@ -38,18 +30,4 @@ public interface ProductPropertyValueConvert { @@ -38,18 +30,4 @@ public interface ProductPropertyValueConvert {
38 30
39 PageResult<ProductPropertyValueRespVO> convertPage(PageResult<ProductPropertyValueDO> page); 31 PageResult<ProductPropertyValueRespVO> convertPage(PageResult<ProductPropertyValueDO> page);
40 32
41 - default List<ProductPropertyValueDetailRespBO> convertList(List<ProductPropertyValueDO> values, List<ProductPropertyDO> keys) {  
42 - Map<Long, ProductPropertyDO> keyMap = convertMap(keys, ProductPropertyDO::getId);  
43 - return CollectionUtils.convertList(values, value -> {  
44 - ProductPropertyValueDetailRespBO valueDetail = new ProductPropertyValueDetailRespBO()  
45 - .setValueId(value.getId()).setValueName(value.getName());  
46 - // 设置属性项  
47 - MapUtils.findAndThen(keyMap, value.getPropertyId(),  
48 - key -> valueDetail.setPropertyId(key.getId()).setPropertyName(key.getName()));  
49 - return valueDetail;  
50 - });  
51 - }  
52 -  
53 - List<ProductPropertyValueDetailRespDTO> convertList02(List<ProductPropertyValueDetailRespBO> list);  
54 -  
55 } 33 }
yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/service/property/ProductPropertyValueService.java
@@ -5,7 +5,6 @@ import cn.iocoder.yudao.module.product.controller.admin.property.vo.value.Produc @@ -5,7 +5,6 @@ import cn.iocoder.yudao.module.product.controller.admin.property.vo.value.Produc
5 import cn.iocoder.yudao.module.product.controller.admin.property.vo.value.ProductPropertyValuePageReqVO; 5 import cn.iocoder.yudao.module.product.controller.admin.property.vo.value.ProductPropertyValuePageReqVO;
6 import cn.iocoder.yudao.module.product.controller.admin.property.vo.value.ProductPropertyValueUpdateReqVO; 6 import cn.iocoder.yudao.module.product.controller.admin.property.vo.value.ProductPropertyValueUpdateReqVO;
7 import cn.iocoder.yudao.module.product.dal.dataobject.property.ProductPropertyValueDO; 7 import cn.iocoder.yudao.module.product.dal.dataobject.property.ProductPropertyValueDO;
8 -import cn.iocoder.yudao.module.product.service.property.bo.ProductPropertyValueDetailRespBO;  
9 8
10 import java.util.Collection; 9 import java.util.Collection;
11 import java.util.List; 10 import java.util.List;
@@ -57,14 +56,6 @@ public interface ProductPropertyValueService { @@ -57,14 +56,6 @@ public interface ProductPropertyValueService {
57 List<ProductPropertyValueDO> getPropertyValueListByPropertyId(Collection<Long> propertyIds); 56 List<ProductPropertyValueDO> getPropertyValueListByPropertyId(Collection<Long> propertyIds);
58 57
59 /** 58 /**
60 - * 根据编号数组,获得属性值列表  
61 - *  
62 - * @param ids 编号数组  
63 - * @return 属性值明细列表  
64 - */  
65 - List<ProductPropertyValueDetailRespBO> getPropertyValueDetailList(Collection<Long> ids);  
66 -  
67 - /**  
68 * 根据属性项编号,活的属性值数量 59 * 根据属性项编号,活的属性值数量
69 * 60 *
70 * @param propertyId 属性项编号数 61 * @param propertyId 属性项编号数
yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/service/property/ProductPropertyValueServiceImpl.java
1 package cn.iocoder.yudao.module.product.service.property; 1 package cn.iocoder.yudao.module.product.service.property;
2 2
3 -import cn.hutool.core.collection.CollUtil;  
4 import cn.iocoder.yudao.framework.common.pojo.PageResult; 3 import cn.iocoder.yudao.framework.common.pojo.PageResult;
5 import cn.iocoder.yudao.module.product.controller.admin.property.vo.value.ProductPropertyValueCreateReqVO; 4 import cn.iocoder.yudao.module.product.controller.admin.property.vo.value.ProductPropertyValueCreateReqVO;
6 import cn.iocoder.yudao.module.product.controller.admin.property.vo.value.ProductPropertyValuePageReqVO; 5 import cn.iocoder.yudao.module.product.controller.admin.property.vo.value.ProductPropertyValuePageReqVO;
7 import cn.iocoder.yudao.module.product.controller.admin.property.vo.value.ProductPropertyValueUpdateReqVO; 6 import cn.iocoder.yudao.module.product.controller.admin.property.vo.value.ProductPropertyValueUpdateReqVO;
8 import cn.iocoder.yudao.module.product.convert.property.ProductPropertyValueConvert; 7 import cn.iocoder.yudao.module.product.convert.property.ProductPropertyValueConvert;
9 -import cn.iocoder.yudao.module.product.dal.dataobject.property.ProductPropertyDO;  
10 import cn.iocoder.yudao.module.product.dal.dataobject.property.ProductPropertyValueDO; 8 import cn.iocoder.yudao.module.product.dal.dataobject.property.ProductPropertyValueDO;
11 import cn.iocoder.yudao.module.product.dal.mysql.property.ProductPropertyValueMapper; 9 import cn.iocoder.yudao.module.product.dal.mysql.property.ProductPropertyValueMapper;
12 -import cn.iocoder.yudao.module.product.service.property.bo.ProductPropertyValueDetailRespBO;  
13 import cn.iocoder.yudao.module.product.service.sku.ProductSkuService; 10 import cn.iocoder.yudao.module.product.service.sku.ProductSkuService;
14 import org.springframework.context.annotation.Lazy; 11 import org.springframework.context.annotation.Lazy;
15 import org.springframework.stereotype.Service; 12 import org.springframework.stereotype.Service;
@@ -17,11 +14,9 @@ import org.springframework.validation.annotation.Validated; @@ -17,11 +14,9 @@ import org.springframework.validation.annotation.Validated;
17 14
18 import javax.annotation.Resource; 15 import javax.annotation.Resource;
19 import java.util.Collection; 16 import java.util.Collection;
20 -import java.util.Collections;  
21 import java.util.List; 17 import java.util.List;
22 18
23 import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; 19 import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
24 -import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet;  
25 import static cn.iocoder.yudao.module.product.enums.ErrorCodeConstants.PROPERTY_VALUE_EXISTS; 20 import static cn.iocoder.yudao.module.product.enums.ErrorCodeConstants.PROPERTY_VALUE_EXISTS;
26 import static cn.iocoder.yudao.module.product.enums.ErrorCodeConstants.PROPERTY_VALUE_NOT_EXISTS; 21 import static cn.iocoder.yudao.module.product.enums.ErrorCodeConstants.PROPERTY_VALUE_NOT_EXISTS;
27 22
@@ -100,23 +95,6 @@ public class ProductPropertyValueServiceImpl implements ProductPropertyValueServ @@ -100,23 +95,6 @@ public class ProductPropertyValueServiceImpl implements ProductPropertyValueServ
100 } 95 }
101 96
102 @Override 97 @Override
103 - public List<ProductPropertyValueDetailRespBO> getPropertyValueDetailList(Collection<Long> ids) {  
104 - // 获得属性值列表  
105 - if (CollUtil.isEmpty(ids)) {  
106 - return Collections.emptyList();  
107 - }  
108 - List<ProductPropertyValueDO> values = productPropertyValueMapper.selectBatchIds(ids);  
109 - if (CollUtil.isEmpty(values)) {  
110 - return Collections.emptyList();  
111 - }  
112 - // 获得属性项列表  
113 - List<ProductPropertyDO> keys = productPropertyService.getPropertyList(  
114 - convertSet(values, ProductPropertyValueDO::getPropertyId));  
115 - // 组装明细  
116 - return ProductPropertyValueConvert.INSTANCE.convertList(values, keys);  
117 - }  
118 -  
119 - @Override  
120 public Integer getPropertyValueCountByPropertyId(Long propertyId) { 98 public Integer getPropertyValueCountByPropertyId(Long propertyId) {
121 return productPropertyValueMapper.selectCountByPropertyId(propertyId); 99 return productPropertyValueMapper.selectCountByPropertyId(propertyId);
122 } 100 }
yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/service/property/bo/ProductPropertyValueDetailRespBO.java deleted
1 -package cn.iocoder.yudao.module.product.service.property.bo;  
2 -  
3 -import lombok.Data;  
4 -  
5 -/**  
6 - * 商品属性项的明细 Response BO  
7 - *  
8 - * @author 芋道源码  
9 - */  
10 -@Data  
11 -public class ProductPropertyValueDetailRespBO {  
12 -  
13 - /**  
14 - * 属性的编号  
15 - */  
16 - private Long propertyId;  
17 -  
18 - /**  
19 - * 属性的名称  
20 - */  
21 - private String propertyName;  
22 -  
23 - /**  
24 - * 属性值的编号  
25 - */  
26 - private Long valueId;  
27 -  
28 - /**  
29 - * 属性值的名称  
30 - */  
31 - private String valueName;  
32 -  
33 -}  
yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/service/sku/ProductSkuServiceImpl.java
@@ -153,6 +153,9 @@ public class ProductSkuServiceImpl implements ProductSkuService { @@ -153,6 +153,9 @@ public class ProductSkuServiceImpl implements ProductSkuService {
153 153
154 @Override 154 @Override
155 public List<ProductSkuDO> getSkuListBySpuId(Collection<Long> spuIds) { 155 public List<ProductSkuDO> getSkuListBySpuId(Collection<Long> spuIds) {
  156 + if (CollUtil.isEmpty(spuIds)) {
  157 + return Collections.emptyList();
  158 + }
156 return productSkuMapper.selectListBySpuId(spuIds); 159 return productSkuMapper.selectListBySpuId(spuIds);
157 } 160 }
158 161
yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/service/spu/ProductSpuServiceImpl.java
@@ -188,6 +188,9 @@ public class ProductSpuServiceImpl implements ProductSpuService { @@ -188,6 +188,9 @@ public class ProductSpuServiceImpl implements ProductSpuService {
188 188
189 @Override 189 @Override
190 public List<ProductSpuDO> getSpuList(Collection<Long> ids) { 190 public List<ProductSpuDO> getSpuList(Collection<Long> ids) {
  191 + if (CollUtil.isEmpty(ids)) {
  192 + return Collections.emptyList();
  193 + }
191 return productSpuMapper.selectBatchIds(ids); 194 return productSpuMapper.selectBatchIds(ids);
192 } 195 }
193 196
yudao-module-mall/yudao-module-promotion-api/pom.xml
@@ -13,7 +13,7 @@ @@ -13,7 +13,7 @@
13 13
14 <name>${project.artifactId}</name> 14 <name>${project.artifactId}</name>
15 <description> 15 <description>
16 - market 模块 API,暴露给其它模块调用 16 + promotion 模块 API,暴露给其它模块调用
17 </description> 17 </description>
18 18
19 <dependencies> 19 <dependencies>
yudao-module-mall/yudao-module-promotion-api/src/main/java/cn/iocoder/yudao/module/promotion/api/combination/CombinationActivityApi.java deleted
1 -package cn.iocoder.yudao.module.promotion.api.combination;  
2 -  
3 -/**  
4 - * 拼团活动 Api 接口  
5 - *  
6 - * @author HUIHUI  
7 - */  
8 -public interface CombinationActivityApi {  
9 -  
10 -}  
yudao-module-mall/yudao-module-promotion-api/src/main/java/cn/iocoder/yudao/module/promotion/api/combination/CombinationRecordApi.java
@@ -42,14 +42,6 @@ public interface CombinationRecordApi { @@ -42,14 +42,6 @@ public interface CombinationRecordApi {
42 boolean isCombinationRecordSuccess(Long userId, Long orderId); 42 boolean isCombinationRecordSuccess(Long userId, Long orderId);
43 43
44 /** 44 /**
45 - * 更新拼团状态为【失败】  
46 - *  
47 - * @param userId 用户编号  
48 - * @param orderId 订单编号  
49 - */  
50 - void updateRecordStatusToFailed(Long userId, Long orderId);  
51 -  
52 - /**  
53 * 【下单前】校验是否满足拼团活动条件 45 * 【下单前】校验是否满足拼团活动条件
54 * 46 *
55 * 如果校验失败,则抛出业务异常 47 * 如果校验失败,则抛出业务异常
yudao-module-mall/yudao-module-promotion-api/src/main/java/cn/iocoder/yudao/module/promotion/api/price/PriceApi.java deleted
1 -package cn.iocoder.yudao.module.promotion.api.price;  
2 -  
3 -import cn.iocoder.yudao.module.promotion.api.price.dto.PriceCalculateReqDTO;  
4 -import cn.iocoder.yudao.module.promotion.api.price.dto.PriceCalculateRespDTO;  
5 -  
6 -/**  
7 - * 价格 API 接口  
8 - *  
9 - * @author 芋道源码  
10 - */  
11 -public interface PriceApi {  
12 -  
13 - /**  
14 - * 计算商品的价格  
15 - *  
16 - * @param calculateReqDTO 价格请求  
17 - * @return 价格相应  
18 - */  
19 - PriceCalculateRespDTO calculatePrice(PriceCalculateReqDTO calculateReqDTO);  
20 -  
21 -}  
yudao-module-mall/yudao-module-promotion-api/src/main/java/cn/iocoder/yudao/module/promotion/api/price/dto/CouponMeetRespDTO.java deleted
1 -package cn.iocoder.yudao.module.promotion.api.price.dto;  
2 -  
3 -import lombok.Data;  
4 -  
5 -/**  
6 - * 优惠劵的匹配信息 Response DTO  
7 - *  
8 - * why 放在 price 包下?主要获取的时候,需要涉及到较多的价格计算逻辑,放在 price 可以更好的复用逻辑  
9 - *  
10 - * @author 芋道源码  
11 - */  
12 -@Data  
13 -public class CouponMeetRespDTO {  
14 -  
15 - /**  
16 - * 优惠劵编号  
17 - */  
18 - private Long id;  
19 -  
20 - // ========== 非优惠劵的基本信息字段 ==========  
21 - /**  
22 - * 是否匹配  
23 - */  
24 - private Boolean meet;  
25 - /**  
26 - * 不匹配的提示,即 {@link #meet} = true 才有值  
27 - *  
28 - * 例如说:  
29 - * 1. 所结算商品没有符合条件的商品  
30 - * 2. 差 XXX 元可用优惠劵  
31 - * 3. 优惠劵未到使用时间  
32 - */  
33 - private String meetTip;  
34 -  
35 -}  
yudao-module-mall/yudao-module-promotion-api/src/main/java/cn/iocoder/yudao/module/promotion/api/price/dto/PriceCalculateReqDTO.java deleted
1 -package cn.iocoder.yudao.module.promotion.api.price.dto;  
2 -  
3 -import lombok.Data;  
4 -  
5 -import javax.validation.constraints.Min;  
6 -import javax.validation.constraints.NotNull;  
7 -import java.util.List;  
8 -  
9 -/**  
10 - * 价格计算 Request DTO  
11 - *  
12 - * @author 芋道源码  
13 - */  
14 -@Data  
15 -@Deprecated  
16 -public class PriceCalculateReqDTO {  
17 -  
18 - /**  
19 - * 用户编号  
20 - *  
21 - * 对应 MemberUserDO 的 id 编号  
22 - */  
23 - private Long userId;  
24 -  
25 - /**  
26 - * 优惠劵编号  
27 - */  
28 - private Long couponId;  
29 -  
30 - /**  
31 - * 收货地址编号  
32 - */  
33 - private Long addressId;  
34 -  
35 - /**  
36 - * 商品 SKU 数组  
37 - */  
38 - @NotNull(message = "商品数组不能为空")  
39 - private List<Item> items;  
40 -  
41 - /**  
42 - * 商品 SKU  
43 - */  
44 - @Data  
45 - public static class Item {  
46 -  
47 - /**  
48 - * SKU 编号  
49 - */  
50 - @NotNull(message = "商品 SKU 编号不能为空")  
51 - private Long skuId;  
52 -  
53 - /**  
54 - * SKU 数量  
55 - */  
56 - @NotNull(message = "商品 SKU 数量不能为空")  
57 - @Min(value = 0L, message = "商品 SKU 数量必须大于等于 0") // 可传递 0 数量,用于购物车未选中的情况  
58 - private Integer count;  
59 -  
60 - }  
61 -  
62 -}  
yudao-module-mall/yudao-module-promotion-api/src/main/java/cn/iocoder/yudao/module/promotion/api/price/dto/PriceCalculateRespDTO.java deleted
1 -package cn.iocoder.yudao.module.promotion.api.price.dto;  
2 -  
3 -import cn.iocoder.yudao.module.promotion.enums.common.PromotionTypeEnum;  
4 -import lombok.Data;  
5 -  
6 -import java.util.List;  
7 -  
8 -/**  
9 - * 价格计算 Response DTO  
10 - *  
11 - * 整体设计,参考 taobao 的技术文档:  
12 - * 1. <a href="https://developer.alibaba.com/docs/doc.htm?treeId=1&articleId=1029&docType=1">订单管理</a>  
13 - * 2. <a href="https://open.taobao.com/docV3.htm?docId=108471&docType=1">常用订单金额说明</a>  
14 - *  
15 - * 举个例子:<a href="https://img.alicdn.com/top/i1/LB1mALAi4HI8KJjy1zbXXaxdpXa">订单图</a>  
16 - * 输入:  
17 - * 1. 订单实付: trade.payment = 198.00;订单邮费:5 元;  
18 - * 2. 商品级优惠 圣诞价: 省 29.00 元 和 圣诞价:省 150.00 元; 订单级优惠,圣诞 2:省 5.00 元;  
19 - * 分摊:  
20 - * 1. 商品 1:原价 108 元,优惠 29 元,子订单实付 79 元,分摊主订单优惠 1.99 元;  
21 - * 2. 商品 2:原价 269 元,优惠 150 元,子订单实付 119 元,分摊主订单优惠 3.01 元;  
22 - *  
23 - * @author 芋道源码  
24 - */  
25 -@Data  
26 -@Deprecated  
27 -public class PriceCalculateRespDTO {  
28 -  
29 - /**  
30 - * 订单  
31 - */  
32 - private Order order;  
33 -  
34 - /**  
35 - * 营销活动数组  
36 - *  
37 - * 只对应 {@link Order#items} 商品匹配的活动  
38 - */  
39 - private List<Promotion> promotions;  
40 -  
41 - // TODO @芋艿:需要改造下,主要是价格字段  
42 - /**  
43 - * 订单  
44 - */  
45 - @Data  
46 - public static class Order {  
47 -  
48 - /**  
49 - * 商品原价(总),单位:分  
50 - *  
51 - * 基于 {@link OrderItem#getOriginalPrice()} 求和  
52 - *  
53 - * 对应 taobao 的 trade.total_fee 字段  
54 - */  
55 - private Integer totalPrice;  
56 - /**  
57 - * 订单优惠(总),单位:分  
58 - *  
59 - * 订单级优惠:对主订单的优惠,常见如:订单满 200 元减 10 元;订单满 80 包邮。  
60 - *  
61 - * 对应 taobao 的 order.discount_fee 字段  
62 - */  
63 - private Integer discountPrice;  
64 - /**  
65 - * 优惠劵减免金额(总),单位:分  
66 - *  
67 - * 对应 taobao 的 trade.coupon_fee 字段  
68 - */  
69 - private Integer couponPrice;  
70 - /**  
71 - * 积分减免金额(总),单位:分  
72 - *  
73 - * 对应 taobao 的 trade.point_fee 字段  
74 - */  
75 - private Integer pointPrice;  
76 - /**  
77 - * 运费金额,单位:分  
78 - */  
79 - private Integer deliveryPrice;  
80 - /**  
81 - * 最终购买金额(总),单位:分  
82 - *  
83 - * = {@link OrderItem#getPayPrice()} 求和  
84 - * - {@link #couponPrice}  
85 - * - {@link #pointPrice}  
86 - * + {@link #deliveryPrice}  
87 - * - {@link #discountPrice}  
88 - */  
89 - private Integer payPrice;  
90 - /**  
91 - * 商品 SKU 数组  
92 - */  
93 - private List<OrderItem> items;  
94 -  
95 - // ========== 营销基本信息 ==========  
96 - /**  
97 - * 优惠劵编号  
98 - */  
99 - private Long couponId;  
100 -  
101 - }  
102 -  
103 - /**  
104 - * 订单商品 SKU  
105 - */  
106 - @Data  
107 - public static class OrderItem {  
108 -  
109 - /**  
110 - * SPU 编号  
111 - */  
112 - private Long spuId;  
113 - /**  
114 - * SKU 编号  
115 - */  
116 - private Long skuId;  
117 - /**  
118 - * 购买数量  
119 - */  
120 - private Integer count;  
121 -  
122 - /**  
123 - * 商品原价(总),单位:分  
124 - *  
125 - * = {@link #originalUnitPrice} * {@link #getCount()}  
126 - */  
127 - private Integer originalPrice;  
128 - /**  
129 - * 商品原价(单),单位:分  
130 - *  
131 - * 对应 ProductSkuDO 的 price 字段  
132 - * 对应 taobao 的 order.price 字段  
133 - */  
134 - private Integer originalUnitPrice;  
135 - /**  
136 - * 商品优惠(总),单位:分  
137 - *  
138 - * 商品级优惠:对单个商品的,常见如:商品原价的 8 折;商品原价的减 50 元  
139 - *  
140 - * 对应 taobao 的 order.discount_fee 字段  
141 - */  
142 - private Integer discountPrice;  
143 - /**  
144 - * 子订单实付金额,不算主订单分摊金额,单位:分  
145 - *  
146 - * = {@link #originalPrice}  
147 - * - {@link #discountPrice}  
148 - *  
149 - * 对应 taobao 的 order.payment 字段  
150 - */  
151 - private Integer payPrice;  
152 -  
153 - /**  
154 - * 子订单分摊金额(总),单位:分  
155 - * 需要分摊 {@link Order#discountPrice}、{@link Order#couponPrice}、{@link Order#pointPrice}  
156 - *  
157 - * 对应 taobao 的 order.part_mjz_discount 字段  
158 - * 淘宝说明:子订单分摊优惠基础逻辑:一般正常优惠券和满减优惠按照子订单的金额进行分摊,特殊情况如果优惠券是指定商品使用的,只会分摊到对应商品子订单上不分摊。  
159 - */  
160 - private Integer orderPartPrice;  
161 - /**  
162 - * 分摊后子订单实付金额(总),单位:分  
163 - *  
164 - * = {@link #payPrice}  
165 - * - {@link #orderPartPrice}  
166 - *  
167 - * 对应 taobao 的 divide_order_fee 字段  
168 - */  
169 - private Integer orderDividePrice;  
170 -  
171 - }  
172 -  
173 - /**  
174 - * 营销明细  
175 - */  
176 - @Data  
177 - @Deprecated  
178 - public static class Promotion {  
179 -  
180 - /**  
181 - * 营销编号  
182 - *  
183 - * 例如说:营销活动的编号、优惠劵的编号  
184 - */  
185 - private Long id;  
186 - /**  
187 - * 营销名字  
188 - */  
189 - private String name;  
190 - /**  
191 - * 营销类型  
192 - *  
193 - * 枚举 {@link PromotionTypeEnum}  
194 - */  
195 - private Integer type;  
196 - /**  
197 - * 营销级别  
198 - *  
199 - * 枚举 @link PromotionLevelEnum} TODO PromotionLevelEnum 没有这个枚举类  
200 - */  
201 - private Integer level;  
202 - /**  
203 - * 计算时的原价(总),单位:分  
204 - */  
205 - private Integer totalPrice;  
206 - /**  
207 - * 计算时的优惠(总),单位:分  
208 - */  
209 - private Integer discountPrice;  
210 - /**  
211 - * 匹配的商品 SKU 数组  
212 - */  
213 - private List<PromotionItem> items;  
214 -  
215 - // ========== 匹配情况 ==========  
216 -  
217 - /**  
218 - * 是否满足优惠条件  
219 - */  
220 - private Boolean match;  
221 - /**  
222 - * 满足条件的提示  
223 - *  
224 - * 如果 {@link #match} = true 满足,则提示“圣诞价:省 150.00 元”  
225 - * 如果 {@link #match} = false 不满足,则提示“购满 85 元,可减 40 元”  
226 - */  
227 - private String description;  
228 -  
229 - }  
230 -  
231 - /**  
232 - * 营销匹配的商品 SKU  
233 - */  
234 - @Data  
235 - public static class PromotionItem {  
236 -  
237 - /**  
238 - * 商品 SKU 编号  
239 - */  
240 - private Long skuId;  
241 - /**  
242 - * 计算时的原价(总),单位:分  
243 - */  
244 - private Integer originalPrice;  
245 - /**  
246 - * 计算时的优惠(总),单位:分  
247 - */  
248 - private Integer discountPrice;  
249 -  
250 - }  
251 -  
252 -}  
yudao-module-mall/yudao-module-promotion-api/src/main/java/cn/iocoder/yudao/module/promotion/enums/ErrorCodeConstants.java
@@ -118,9 +118,11 @@ public interface ErrorCodeConstants { @@ -118,9 +118,11 @@ public interface ErrorCodeConstants {
118 118
119 // ========== 装修模板 1-013-017-000 ========== 119 // ========== 装修模板 1-013-017-000 ==========
120 ErrorCode DIY_TEMPLATE_NOT_EXISTS = new ErrorCode(1_013_017_000, "装修模板不存在"); 120 ErrorCode DIY_TEMPLATE_NOT_EXISTS = new ErrorCode(1_013_017_000, "装修模板不存在");
121 - ErrorCode DIY_TEMPLATE_USED_CANNOT_DELETE = new ErrorCode(1_013_017_001, "不能删除正在使用的装修模板"); 121 + ErrorCode DIY_TEMPLATE_NAME_USED = new ErrorCode(1_013_017_001, "装修模板名称({})已经被使用");
  122 + ErrorCode DIY_TEMPLATE_USED_CANNOT_DELETE = new ErrorCode(1_013_017_002, "不能删除正在使用的装修模板");
122 123
123 // ========== 装修页面 1-013-018-000 ========== 124 // ========== 装修页面 1-013-018-000 ==========
124 ErrorCode DIY_PAGE_NOT_EXISTS = new ErrorCode(1_013_018_000, "装修页面不存在"); 125 ErrorCode DIY_PAGE_NOT_EXISTS = new ErrorCode(1_013_018_000, "装修页面不存在");
  126 + ErrorCode DIY_PAGE_NAME_USED = new ErrorCode(1_013_018_001, "装修页面名称({})已经被使用");
125 127
126 } 128 }
yudao-module-mall/yudao-module-promotion-biz/pom.xml
@@ -14,8 +14,8 @@ @@ -14,8 +14,8 @@
14 <name>${project.artifactId}</name> 14 <name>${project.artifactId}</name>
15 15
16 <description> 16 <description>
17 - market模块,主要实现营销相关功能  
18 - 例如:营销活动、banner广告、优惠券、优惠码等功能。 17 + promotion 模块,主要实现营销相关功能
  18 + 例如:营销活动、banner 广告、优惠券、优惠码等功能。
19 </description> 19 </description>
20 20
21 <dependencies> 21 <dependencies>
@@ -49,10 +49,6 @@ @@ -49,10 +49,6 @@
49 <groupId>cn.iocoder.boot</groupId> 49 <groupId>cn.iocoder.boot</groupId>
50 <artifactId>yudao-spring-boot-starter-biz-tenant</artifactId> 50 <artifactId>yudao-spring-boot-starter-biz-tenant</artifactId>
51 </dependency> 51 </dependency>
52 - <dependency>  
53 - <groupId>cn.iocoder.boot</groupId>  
54 - <artifactId>yudao-spring-boot-starter-biz-weixin</artifactId>  
55 - </dependency>  
56 52
57 <!-- Web 相关 --> 53 <!-- Web 相关 -->
58 <dependency> 54 <dependency>
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/api/bargain/BargainActivityApiImpl.java
@@ -2,6 +2,7 @@ package cn.iocoder.yudao.module.promotion.api.bargain; @@ -2,6 +2,7 @@ package cn.iocoder.yudao.module.promotion.api.bargain;
2 2
3 import cn.iocoder.yudao.module.promotion.service.bargain.BargainActivityService; 3 import cn.iocoder.yudao.module.promotion.service.bargain.BargainActivityService;
4 import org.springframework.stereotype.Service; 4 import org.springframework.stereotype.Service;
  5 +import org.springframework.validation.annotation.Validated;
5 6
6 import javax.annotation.Resource; 7 import javax.annotation.Resource;
7 8
@@ -11,6 +12,7 @@ import javax.annotation.Resource; @@ -11,6 +12,7 @@ import javax.annotation.Resource;
11 * @author HUIHUI 12 * @author HUIHUI
12 */ 13 */
13 @Service 14 @Service
  15 +@Validated
14 public class BargainActivityApiImpl implements BargainActivityApi { 16 public class BargainActivityApiImpl implements BargainActivityApi {
15 17
16 @Resource 18 @Resource
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/api/bargain/BargainRecordApiImpl.java
@@ -3,6 +3,7 @@ package cn.iocoder.yudao.module.promotion.api.bargain; @@ -3,6 +3,7 @@ package cn.iocoder.yudao.module.promotion.api.bargain;
3 import cn.iocoder.yudao.module.promotion.api.bargain.dto.BargainValidateJoinRespDTO; 3 import cn.iocoder.yudao.module.promotion.api.bargain.dto.BargainValidateJoinRespDTO;
4 import cn.iocoder.yudao.module.promotion.service.bargain.BargainRecordService; 4 import cn.iocoder.yudao.module.promotion.service.bargain.BargainRecordService;
5 import org.springframework.stereotype.Service; 5 import org.springframework.stereotype.Service;
  6 +import org.springframework.validation.annotation.Validated;
6 7
7 import javax.annotation.Resource; 8 import javax.annotation.Resource;
8 9
@@ -12,6 +13,7 @@ import javax.annotation.Resource; @@ -12,6 +13,7 @@ import javax.annotation.Resource;
12 * @author HUIHUI 13 * @author HUIHUI
13 */ 14 */
14 @Service 15 @Service
  16 +@Validated
15 public class BargainRecordApiImpl implements BargainRecordApi { 17 public class BargainRecordApiImpl implements BargainRecordApi {
16 18
17 @Resource 19 @Resource
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/api/combination/CombinationActivityApiImpl.java deleted
1 -package cn.iocoder.yudao.module.promotion.api.combination;  
2 -  
3 -import org.springframework.stereotype.Service;  
4 -  
5 -/**  
6 - * 拼团活动 Api 接口实现类  
7 - *  
8 - * @author HUIHUI  
9 - */  
10 -@Service  
11 -public class CombinationActivityApiImpl implements CombinationActivityApi {  
12 -  
13 -}  
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/api/combination/CombinationRecordApiImpl.java
@@ -8,6 +8,7 @@ import cn.iocoder.yudao.module.promotion.dal.dataobject.combination.CombinationR @@ -8,6 +8,7 @@ import cn.iocoder.yudao.module.promotion.dal.dataobject.combination.CombinationR
8 import cn.iocoder.yudao.module.promotion.enums.combination.CombinationRecordStatusEnum; 8 import cn.iocoder.yudao.module.promotion.enums.combination.CombinationRecordStatusEnum;
9 import cn.iocoder.yudao.module.promotion.service.combination.CombinationRecordService; 9 import cn.iocoder.yudao.module.promotion.service.combination.CombinationRecordService;
10 import org.springframework.stereotype.Service; 10 import org.springframework.stereotype.Service;
  11 +import org.springframework.validation.annotation.Validated;
11 12
12 import javax.annotation.Resource; 13 import javax.annotation.Resource;
13 14
@@ -20,6 +21,7 @@ import static cn.iocoder.yudao.module.promotion.enums.ErrorCodeConstants.COMBINA @@ -20,6 +21,7 @@ import static cn.iocoder.yudao.module.promotion.enums.ErrorCodeConstants.COMBINA
20 * @author HUIHUI 21 * @author HUIHUI
21 */ 22 */
22 @Service 23 @Service
  24 +@Validated
23 public class CombinationRecordApiImpl implements CombinationRecordApi { 25 public class CombinationRecordApiImpl implements CombinationRecordApi {
24 26
25 @Resource 27 @Resource
@@ -45,11 +47,6 @@ public class CombinationRecordApiImpl implements CombinationRecordApi { @@ -45,11 +47,6 @@ public class CombinationRecordApiImpl implements CombinationRecordApi {
45 } 47 }
46 48
47 @Override 49 @Override
48 - public void updateRecordStatusToFailed(Long userId, Long orderId) {  
49 - recordService.updateCombinationRecordStatusByUserIdAndOrderId(CombinationRecordStatusEnum.FAILED.getStatus(), userId, orderId);  
50 - }  
51 -  
52 - @Override  
53 public CombinationValidateJoinRespDTO validateJoinCombination(Long userId, Long activityId, Long headId, Long skuId, Integer count) { 50 public CombinationValidateJoinRespDTO validateJoinCombination(Long userId, Long activityId, Long headId, Long skuId, Integer count) {
54 return recordService.validateJoinCombination(userId, activityId, headId, skuId, count); 51 return recordService.validateJoinCombination(userId, activityId, headId, skuId, count);
55 } 52 }
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/api/coupon/CouponApiImpl.java
@@ -8,6 +8,7 @@ import cn.iocoder.yudao.module.promotion.convert.coupon.CouponConvert; @@ -8,6 +8,7 @@ import cn.iocoder.yudao.module.promotion.convert.coupon.CouponConvert;
8 import cn.iocoder.yudao.module.promotion.dal.dataobject.coupon.CouponDO; 8 import cn.iocoder.yudao.module.promotion.dal.dataobject.coupon.CouponDO;
9 import cn.iocoder.yudao.module.promotion.service.coupon.CouponService; 9 import cn.iocoder.yudao.module.promotion.service.coupon.CouponService;
10 import org.springframework.stereotype.Service; 10 import org.springframework.stereotype.Service;
  11 +import org.springframework.validation.annotation.Validated;
11 12
12 import javax.annotation.Resource; 13 import javax.annotation.Resource;
13 14
@@ -17,6 +18,7 @@ import javax.annotation.Resource; @@ -17,6 +18,7 @@ import javax.annotation.Resource;
17 * @author 芋道源码 18 * @author 芋道源码
18 */ 19 */
19 @Service 20 @Service
  21 +@Validated
20 public class CouponApiImpl implements CouponApi { 22 public class CouponApiImpl implements CouponApi {
21 23
22 @Resource 24 @Resource
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/api/discount/DiscountActivityApiImpl.java
@@ -4,6 +4,7 @@ import cn.iocoder.yudao.module.promotion.api.discount.dto.DiscountProductRespDTO @@ -4,6 +4,7 @@ import cn.iocoder.yudao.module.promotion.api.discount.dto.DiscountProductRespDTO
4 import cn.iocoder.yudao.module.promotion.convert.discount.DiscountActivityConvert; 4 import cn.iocoder.yudao.module.promotion.convert.discount.DiscountActivityConvert;
5 import cn.iocoder.yudao.module.promotion.service.discount.DiscountActivityService; 5 import cn.iocoder.yudao.module.promotion.service.discount.DiscountActivityService;
6 import org.springframework.stereotype.Service; 6 import org.springframework.stereotype.Service;
  7 +import org.springframework.validation.annotation.Validated;
7 8
8 import javax.annotation.Resource; 9 import javax.annotation.Resource;
9 import java.util.Collection; 10 import java.util.Collection;
@@ -15,6 +16,7 @@ import java.util.List; @@ -15,6 +16,7 @@ import java.util.List;
15 * @author 芋道源码 16 * @author 芋道源码
16 */ 17 */
17 @Service 18 @Service
  19 +@Validated
18 public class DiscountActivityApiImpl implements DiscountActivityApi { 20 public class DiscountActivityApiImpl implements DiscountActivityApi {
19 21
20 @Resource 22 @Resource
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/api/price/PriceApiImpl.java deleted
1 -package cn.iocoder.yudao.module.promotion.api.price;  
2 -  
3 -import cn.iocoder.yudao.module.promotion.api.price.dto.PriceCalculateReqDTO;  
4 -import cn.iocoder.yudao.module.promotion.api.price.dto.PriceCalculateRespDTO;  
5 -import cn.iocoder.yudao.module.promotion.service.price.PriceService;  
6 -import org.springframework.stereotype.Service;  
7 -  
8 -import javax.annotation.Resource;  
9 -  
10 -/**  
11 - * 价格 API 实现类  
12 - *  
13 - * @author 芋道源码  
14 - */  
15 -@Service  
16 -public class PriceApiImpl implements PriceApi {  
17 -  
18 - @Resource  
19 - private PriceService priceService;  
20 -  
21 - @Override  
22 - public PriceCalculateRespDTO calculatePrice(PriceCalculateReqDTO calculateReqDTO) {  
23 - //return priceService.calculatePrice(calculateReqDTO); TODO 没有 calculatePrice 这个方法  
24 -  
25 - return null;  
26 - }  
27 -  
28 -}  
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/api/reward/RewardActivityApiImpl.java
@@ -3,6 +3,7 @@ package cn.iocoder.yudao.module.promotion.api.reward; @@ -3,6 +3,7 @@ package cn.iocoder.yudao.module.promotion.api.reward;
3 import cn.iocoder.yudao.module.promotion.api.reward.dto.RewardActivityMatchRespDTO; 3 import cn.iocoder.yudao.module.promotion.api.reward.dto.RewardActivityMatchRespDTO;
4 import cn.iocoder.yudao.module.promotion.service.reward.RewardActivityService; 4 import cn.iocoder.yudao.module.promotion.service.reward.RewardActivityService;
5 import org.springframework.stereotype.Service; 5 import org.springframework.stereotype.Service;
  6 +import org.springframework.validation.annotation.Validated;
6 7
7 import javax.annotation.Resource; 8 import javax.annotation.Resource;
8 import java.util.Collection; 9 import java.util.Collection;
@@ -14,6 +15,7 @@ import java.util.List; @@ -14,6 +15,7 @@ import java.util.List;
14 * @author 芋道源码 15 * @author 芋道源码
15 */ 16 */
16 @Service 17 @Service
  18 +@Validated
17 public class RewardActivityApiImpl implements RewardActivityApi { 19 public class RewardActivityApiImpl implements RewardActivityApi {
18 20
19 @Resource 21 @Resource
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/api/seckill/SeckillActivityApiImpl.java
@@ -3,6 +3,7 @@ package cn.iocoder.yudao.module.promotion.api.seckill; @@ -3,6 +3,7 @@ package cn.iocoder.yudao.module.promotion.api.seckill;
3 import cn.iocoder.yudao.module.promotion.api.seckill.dto.SeckillValidateJoinRespDTO; 3 import cn.iocoder.yudao.module.promotion.api.seckill.dto.SeckillValidateJoinRespDTO;
4 import cn.iocoder.yudao.module.promotion.service.seckill.SeckillActivityService; 4 import cn.iocoder.yudao.module.promotion.service.seckill.SeckillActivityService;
5 import org.springframework.stereotype.Service; 5 import org.springframework.stereotype.Service;
  6 +import org.springframework.validation.annotation.Validated;
6 7
7 import javax.annotation.Resource; 8 import javax.annotation.Resource;
8 9
@@ -12,6 +13,7 @@ import javax.annotation.Resource; @@ -12,6 +13,7 @@ import javax.annotation.Resource;
12 * @author HUIHUI 13 * @author HUIHUI
13 */ 14 */
14 @Service 15 @Service
  16 +@Validated
15 public class SeckillActivityApiImpl implements SeckillActivityApi { 17 public class SeckillActivityApiImpl implements SeckillActivityApi {
16 18
17 @Resource 19 @Resource
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/banner/vo/BannerRespVO.java
@@ -4,6 +4,8 @@ import io.swagger.v3.oas.annotations.media.Schema; @@ -4,6 +4,8 @@ import io.swagger.v3.oas.annotations.media.Schema;
4 import lombok.Data; 4 import lombok.Data;
5 import lombok.ToString; 5 import lombok.ToString;
6 6
  7 +import java.time.LocalDateTime;
  8 +
7 @Schema(description = "管理后台 - Banner Response VO") 9 @Schema(description = "管理后台 - Banner Response VO")
8 @Data 10 @Data
9 @ToString(callSuper = true) 11 @ToString(callSuper = true)
@@ -12,4 +14,7 @@ public class BannerRespVO extends BannerBaseVO { @@ -12,4 +14,7 @@ public class BannerRespVO extends BannerBaseVO {
12 @Schema(description = "编号", requiredMode = Schema.RequiredMode.REQUIRED) 14 @Schema(description = "编号", requiredMode = Schema.RequiredMode.REQUIRED)
13 private Long id; 15 private Long id;
14 16
  17 + @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED, example = "2022-07-01 23:59:59")
  18 + private LocalDateTime createTime;
  19 +
15 } 20 }
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/diy/DiyPageController.java
@@ -2,10 +2,7 @@ package cn.iocoder.yudao.module.promotion.controller.admin.diy; @@ -2,10 +2,7 @@ package cn.iocoder.yudao.module.promotion.controller.admin.diy;
2 2
3 import cn.iocoder.yudao.framework.common.pojo.CommonResult; 3 import cn.iocoder.yudao.framework.common.pojo.CommonResult;
4 import cn.iocoder.yudao.framework.common.pojo.PageResult; 4 import cn.iocoder.yudao.framework.common.pojo.PageResult;
5 -import cn.iocoder.yudao.module.promotion.controller.admin.diy.vo.page.DiyPageCreateReqVO;  
6 -import cn.iocoder.yudao.module.promotion.controller.admin.diy.vo.page.DiyPagePageReqVO;  
7 -import cn.iocoder.yudao.module.promotion.controller.admin.diy.vo.page.DiyPageRespVO;  
8 -import cn.iocoder.yudao.module.promotion.controller.admin.diy.vo.page.DiyPageUpdateReqVO; 5 +import cn.iocoder.yudao.module.promotion.controller.admin.diy.vo.page.*;
9 import cn.iocoder.yudao.module.promotion.convert.diy.DiyPageConvert; 6 import cn.iocoder.yudao.module.promotion.convert.diy.DiyPageConvert;
10 import cn.iocoder.yudao.module.promotion.dal.dataobject.diy.DiyPageDO; 7 import cn.iocoder.yudao.module.promotion.dal.dataobject.diy.DiyPageDO;
11 import cn.iocoder.yudao.module.promotion.service.diy.DiyPageService; 8 import cn.iocoder.yudao.module.promotion.service.diy.DiyPageService;
@@ -82,4 +79,21 @@ public class DiyPageController { @@ -82,4 +79,21 @@ public class DiyPageController {
82 return success(DiyPageConvert.INSTANCE.convertPage(pageResult)); 79 return success(DiyPageConvert.INSTANCE.convertPage(pageResult));
83 } 80 }
84 81
  82 + @GetMapping("/get-property")
  83 + @Operation(summary = "获得装修页面属性")
  84 + @Parameter(name = "id", description = "编号", required = true, example = "1024")
  85 + @PreAuthorize("@ss.hasPermission('promotion:diy-page:query')")
  86 + public CommonResult<DiyPagePropertyRespVO> getDiyPageProperty(@RequestParam("id") Long id) {
  87 + DiyPageDO diyPage = diyPageService.getDiyPage(id);
  88 + return success(DiyPageConvert.INSTANCE.convertPropertyVo(diyPage));
  89 + }
  90 +
  91 + @PutMapping("/update-property")
  92 + @Operation(summary = "更新装修页面属性")
  93 + @PreAuthorize("@ss.hasPermission('promotion:diy-page:update')")
  94 + public CommonResult<Boolean> updateDiyPageProperty(@Valid @RequestBody DiyPagePropertyUpdateRequestVO updateReqVO) {
  95 + diyPageService.updateDiyPageProperty(updateReqVO);
  96 + return success(true);
  97 + }
  98 +
85 } 99 }
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/diy/DiyTemplateController.java
@@ -2,12 +2,11 @@ package cn.iocoder.yudao.module.promotion.controller.admin.diy; @@ -2,12 +2,11 @@ package cn.iocoder.yudao.module.promotion.controller.admin.diy;
2 2
3 import cn.iocoder.yudao.framework.common.pojo.CommonResult; 3 import cn.iocoder.yudao.framework.common.pojo.CommonResult;
4 import cn.iocoder.yudao.framework.common.pojo.PageResult; 4 import cn.iocoder.yudao.framework.common.pojo.PageResult;
5 -import cn.iocoder.yudao.module.promotion.controller.admin.diy.vo.template.DiyTemplateCreateReqVO;  
6 -import cn.iocoder.yudao.module.promotion.controller.admin.diy.vo.template.DiyTemplatePageReqVO;  
7 -import cn.iocoder.yudao.module.promotion.controller.admin.diy.vo.template.DiyTemplateRespVO;  
8 -import cn.iocoder.yudao.module.promotion.controller.admin.diy.vo.template.DiyTemplateUpdateReqVO; 5 +import cn.iocoder.yudao.module.promotion.controller.admin.diy.vo.template.*;
9 import cn.iocoder.yudao.module.promotion.convert.diy.DiyTemplateConvert; 6 import cn.iocoder.yudao.module.promotion.convert.diy.DiyTemplateConvert;
  7 +import cn.iocoder.yudao.module.promotion.dal.dataobject.diy.DiyPageDO;
10 import cn.iocoder.yudao.module.promotion.dal.dataobject.diy.DiyTemplateDO; 8 import cn.iocoder.yudao.module.promotion.dal.dataobject.diy.DiyTemplateDO;
  9 +import cn.iocoder.yudao.module.promotion.service.diy.DiyPageService;
11 import cn.iocoder.yudao.module.promotion.service.diy.DiyTemplateService; 10 import cn.iocoder.yudao.module.promotion.service.diy.DiyTemplateService;
12 import io.swagger.v3.oas.annotations.Operation; 11 import io.swagger.v3.oas.annotations.Operation;
13 import io.swagger.v3.oas.annotations.Parameter; 12 import io.swagger.v3.oas.annotations.Parameter;
@@ -19,6 +18,8 @@ import org.springframework.web.bind.annotation.*; @@ -19,6 +18,8 @@ import org.springframework.web.bind.annotation.*;
19 import javax.annotation.Resource; 18 import javax.annotation.Resource;
20 import javax.validation.Valid; 19 import javax.validation.Valid;
21 20
  21 +import java.util.List;
  22 +
22 import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; 23 import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
23 24
24 @Tag(name = "管理后台 - 装修模板") 25 @Tag(name = "管理后台 - 装修模板")
@@ -29,6 +30,8 @@ public class DiyTemplateController { @@ -29,6 +30,8 @@ public class DiyTemplateController {
29 30
30 @Resource 31 @Resource
31 private DiyTemplateService diyTemplateService; 32 private DiyTemplateService diyTemplateService;
  33 + @Resource
  34 + private DiyPageService diyPageService;
32 35
33 @PostMapping("/create") 36 @PostMapping("/create")
34 @Operation(summary = "创建装修模板") 37 @Operation(summary = "创建装修模板")
@@ -79,4 +82,22 @@ public class DiyTemplateController { @@ -79,4 +82,22 @@ public class DiyTemplateController {
79 return success(DiyTemplateConvert.INSTANCE.convertPage(pageResult)); 82 return success(DiyTemplateConvert.INSTANCE.convertPage(pageResult));
80 } 83 }
81 84
  85 + @GetMapping("/get-property")
  86 + @Operation(summary = "获得装修模板属性")
  87 + @Parameter(name = "id", description = "编号", required = true, example = "1024")
  88 + @PreAuthorize("@ss.hasPermission('promotion:diy-template:query')")
  89 + public CommonResult<DiyTemplatePropertyRespVO> getDiyTemplateProperty(@RequestParam("id") Long id) {
  90 + DiyTemplateDO diyTemplate = diyTemplateService.getDiyTemplate(id);
  91 + List<DiyPageDO> pages = diyPageService.getDiyPageByTemplateId(id);
  92 + return success(DiyTemplateConvert.INSTANCE.convertPropertyVo(diyTemplate, pages));
  93 + }
  94 +
  95 + @PutMapping("/update-property")
  96 + @Operation(summary = "更新装修模板属性")
  97 + @PreAuthorize("@ss.hasPermission('promotion:diy-template:update')")
  98 + public CommonResult<Boolean> updateDiyTemplateProperty(@Valid @RequestBody DiyTemplatePropertyUpdateRequestVO updateReqVO) {
  99 + diyTemplateService.updateDiyTemplateProperty(updateReqVO);
  100 + return success(true);
  101 + }
  102 +
82 } 103 }
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/diy/vo/page/DiyPageBaseVO.java
@@ -26,7 +26,4 @@ public class DiyPageBaseVO { @@ -26,7 +26,4 @@ public class DiyPageBaseVO {
26 @Schema(description = "预览图") 26 @Schema(description = "预览图")
27 private List<String> previewImageUrls; 27 private List<String> previewImageUrls;
28 28
29 - @Schema(description = "页面属性", example = "[]")  
30 - private String property;  
31 -  
32 } 29 }
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/diy/vo/page/DiyPagePropertyRespVO.java 0 → 100644
  1 +package cn.iocoder.yudao.module.promotion.controller.admin.diy.vo.page;
  2 +
  3 +import io.swagger.v3.oas.annotations.media.Schema;
  4 +import lombok.Data;
  5 +import lombok.EqualsAndHashCode;
  6 +import lombok.ToString;
  7 +
  8 +@Schema(description = "管理后台 - 装修页面属性 Response VO")
  9 +@Data
  10 +@EqualsAndHashCode(callSuper = true)
  11 +@ToString(callSuper = true)
  12 +public class DiyPagePropertyRespVO extends DiyPageBaseVO {
  13 +
  14 + @Schema(description = "装修页面编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "31209")
  15 + private Long id;
  16 +
  17 + @Schema(description = "页面属性", example = "[]")
  18 + private String property;
  19 +
  20 +}
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/diy/vo/page/DiyPagePropertyUpdateRequestVO.java 0 → 100644
  1 +package cn.iocoder.yudao.module.promotion.controller.admin.diy.vo.page;
  2 +
  3 +import io.swagger.v3.oas.annotations.media.Schema;
  4 +import lombok.Data;
  5 +import lombok.ToString;
  6 +
  7 +import javax.validation.constraints.NotBlank;
  8 +import javax.validation.constraints.NotNull;
  9 +
  10 +@Schema(description = "管理后台 - 装修页面属性更新 Request VO")
  11 +@Data
  12 +@ToString(callSuper = true)
  13 +public class DiyPagePropertyUpdateRequestVO {
  14 +
  15 + @Schema(description = "装修页面编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "31209")
  16 + @NotNull(message = "装修页面编号不能为空")
  17 + private Long id;
  18 +
  19 + @Schema(description = "页面属性,JSON 格式", requiredMode = Schema.RequiredMode.REQUIRED, example = "{}")
  20 + @NotBlank(message = "页面属性不能为空")
  21 + private String property;
  22 +
  23 +}
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/diy/vo/template/DiyTemplateBaseVO.java
@@ -3,7 +3,7 @@ package cn.iocoder.yudao.module.promotion.controller.admin.diy.vo.template; @@ -3,7 +3,7 @@ package cn.iocoder.yudao.module.promotion.controller.admin.diy.vo.template;
3 import io.swagger.v3.oas.annotations.media.Schema; 3 import io.swagger.v3.oas.annotations.media.Schema;
4 import lombok.Data; 4 import lombok.Data;
5 5
6 -import javax.validation.constraints.NotNull; 6 +import javax.validation.constraints.NotEmpty;
7 import java.util.List; 7 import java.util.List;
8 8
9 /** 9 /**
@@ -14,7 +14,7 @@ import java.util.List; @@ -14,7 +14,7 @@ import java.util.List;
14 public class DiyTemplateBaseVO { 14 public class DiyTemplateBaseVO {
15 15
16 @Schema(description = "模板名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "默认主题") 16 @Schema(description = "模板名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "默认主题")
17 - @NotNull(message = "模板名称不能为空") 17 + @NotEmpty(message = "模板名称不能为空")
18 private String name; 18 private String name;
19 19
20 @Schema(description = "备注", example = "默认主题") 20 @Schema(description = "备注", example = "默认主题")
@@ -23,7 +23,4 @@ public class DiyTemplateBaseVO { @@ -23,7 +23,4 @@ public class DiyTemplateBaseVO {
23 @Schema(description = "预览图", example = "[https://www.iocoder.cn/1.jpg]") 23 @Schema(description = "预览图", example = "[https://www.iocoder.cn/1.jpg]")
24 private List<String> previewImageUrls; 24 private List<String> previewImageUrls;
25 25
26 - @Schema(description = "模板属性,JSON 格式", requiredMode = Schema.RequiredMode.REQUIRED, example = "{}")  
27 - private String property;  
28 -  
29 } 26 }
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/diy/vo/template/DiyTemplatePropertyRespVO.java 0 → 100644
  1 +package cn.iocoder.yudao.module.promotion.controller.admin.diy.vo.template;
  2 +
  3 +import cn.iocoder.yudao.module.promotion.controller.admin.diy.vo.page.DiyPagePropertyRespVO;
  4 +import io.swagger.v3.oas.annotations.media.Schema;
  5 +import lombok.Data;
  6 +import lombok.EqualsAndHashCode;
  7 +import lombok.ToString;
  8 +
  9 +import java.util.List;
  10 +
  11 +@Schema(description = "管理后台 - 装修模板属性 Response VO")
  12 +@Data
  13 +@EqualsAndHashCode(callSuper = true)
  14 +@ToString(callSuper = true)
  15 +public class DiyTemplatePropertyRespVO extends DiyTemplateBaseVO {
  16 +
  17 + @Schema(description = "装修模板编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "31209")
  18 + private Long id;
  19 +
  20 + @Schema(description = "模板属性,JSON 格式", requiredMode = Schema.RequiredMode.REQUIRED, example = "{}")
  21 + private String property;
  22 +
  23 + @Schema(description = "模板页面", requiredMode = Schema.RequiredMode.REQUIRED, example = "[]")
  24 + private List<DiyPagePropertyRespVO> pages;
  25 +
  26 +}
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/diy/vo/template/DiyTemplatePropertyUpdateRequestVO.java 0 → 100644
  1 +package cn.iocoder.yudao.module.promotion.controller.admin.diy.vo.template;
  2 +
  3 +import io.swagger.v3.oas.annotations.media.Schema;
  4 +import lombok.Data;
  5 +import lombok.ToString;
  6 +
  7 +import javax.validation.constraints.NotBlank;
  8 +import javax.validation.constraints.NotNull;
  9 +
  10 +@Schema(description = "管理后台 - 装修模板属性更新 Request VO")
  11 +@Data
  12 +@ToString(callSuper = true)
  13 +public class DiyTemplatePropertyUpdateRequestVO {
  14 +
  15 + @Schema(description = "装修模板编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "31209")
  16 + @NotNull(message = "装修模板编号不能为空")
  17 + private Long id;
  18 +
  19 + @Schema(description = "模板属性,JSON 格式", requiredMode = Schema.RequiredMode.REQUIRED, example = "{}")
  20 + @NotBlank(message = "模板属性不能为空")
  21 + private String property;
  22 +
  23 +}
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/app/coupon/AppCouponTemplateController.java
@@ -96,13 +96,13 @@ public class AppCouponTemplateController { @@ -96,13 +96,13 @@ public class AppCouponTemplateController {
96 */ 96 */
97 private Long getProductScopeValue(Integer productScope, Long spuId) { 97 private Long getProductScopeValue(Integer productScope, Long spuId) {
98 // 通用券:没有商品范围 98 // 通用券:没有商品范围
99 - if (productScope == null || ObjectUtils.equalsAny(productScope, PromotionProductScopeEnum.ALL.getScope(), null)) { 99 + if (ObjectUtils.equalsAny(productScope, PromotionProductScopeEnum.ALL.getScope(), null)) {
100 return null; 100 return null;
101 } 101 }
102 // 品类券:查询商品的品类编号 102 // 品类券:查询商品的品类编号
103 if (Objects.equals(productScope, PromotionProductScopeEnum.CATEGORY.getScope()) && spuId != null) { 103 if (Objects.equals(productScope, PromotionProductScopeEnum.CATEGORY.getScope()) && spuId != null) {
104 - return Optional.ofNullable(productSpuApi.getSpu(spuId))  
105 - .map(ProductSpuRespDTO::getCategoryId).orElse(null); 104 + ProductSpuRespDTO spu = productSpuApi.getSpu(spuId);
  105 + return spu != null ? spu.getCategoryId() : null;
106 } 106 }
107 // 商品卷:直接返回 107 // 商品卷:直接返回
108 return spuId; 108 return spuId;
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/app/diy/AppDiyTemplateController.java 0 → 100644
  1 +package cn.iocoder.yudao.module.promotion.controller.app.diy;
  2 +
  3 +import cn.iocoder.yudao.framework.common.pojo.CommonResult;
  4 +import cn.iocoder.yudao.module.promotion.controller.app.diy.vo.AppDiyTemplatePropertyRespVO;
  5 +import cn.iocoder.yudao.module.promotion.convert.diy.DiyTemplateConvert;
  6 +import cn.iocoder.yudao.module.promotion.dal.dataobject.diy.DiyPageDO;
  7 +import cn.iocoder.yudao.module.promotion.dal.dataobject.diy.DiyTemplateDO;
  8 +import cn.iocoder.yudao.module.promotion.service.diy.DiyPageService;
  9 +import cn.iocoder.yudao.module.promotion.service.diy.DiyTemplateService;
  10 +import io.swagger.v3.oas.annotations.Operation;
  11 +import io.swagger.v3.oas.annotations.Parameter;
  12 +import io.swagger.v3.oas.annotations.tags.Tag;
  13 +import org.springframework.validation.annotation.Validated;
  14 +import org.springframework.web.bind.annotation.GetMapping;
  15 +import org.springframework.web.bind.annotation.RequestMapping;
  16 +import org.springframework.web.bind.annotation.RequestParam;
  17 +import org.springframework.web.bind.annotation.RestController;
  18 +
  19 +import javax.annotation.Resource;
  20 +import java.util.List;
  21 +
  22 +import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
  23 +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.findFirst;
  24 +
  25 +@Tag(name = "用户 APP - 装修模板")
  26 +@RestController
  27 +@RequestMapping("/promotion/diy-template")
  28 +@Validated
  29 +public class AppDiyTemplateController {
  30 +
  31 + @Resource
  32 + private DiyTemplateService diyTemplateService;
  33 + @Resource
  34 + private DiyPageService diyPageService;
  35 +
  36 + @GetMapping("/used")
  37 + @Operation(summary = "使用中的装修模板")
  38 + public CommonResult<AppDiyTemplatePropertyRespVO> getUsedDiyTemplate() {
  39 + DiyTemplateDO diyTemplate = diyTemplateService.getUsedDiyTemplate();
  40 + return success(buildVo(diyTemplate));
  41 + }
  42 +
  43 + @GetMapping("/get")
  44 + @Operation(summary = "获得装修模板")
  45 + @Parameter(name = "id", description = "编号", required = true, example = "1024")
  46 + public CommonResult<AppDiyTemplatePropertyRespVO> getDiyTemplate(@RequestParam("id") Long id) {
  47 + DiyTemplateDO diyTemplate = diyTemplateService.getDiyTemplate(id);
  48 + return success(buildVo(diyTemplate));
  49 + }
  50 +
  51 + private AppDiyTemplatePropertyRespVO buildVo(DiyTemplateDO diyTemplate) {
  52 + if (diyTemplate == null) {
  53 + return null;
  54 + }
  55 + // 查询模板下的页面
  56 + List<DiyPageDO> pages = diyPageService.getDiyPageByTemplateId(diyTemplate.getId());
  57 + String home = findFirst(pages, page -> "首页".equals(page.getName()), DiyPageDO::getProperty);
  58 + String user = findFirst(pages, page -> "我的".equals(page.getName()), DiyPageDO::getProperty);
  59 + // 拼接返回
  60 + return DiyTemplateConvert.INSTANCE.convertPropertyVo2(diyTemplate, home, user);
  61 + }
  62 +
  63 +}
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/app/diy/vo/AppDiyPagePropertyRespVO.java 0 → 100644
  1 +package cn.iocoder.yudao.module.promotion.controller.app.diy.vo;
  2 +
  3 +import io.swagger.v3.oas.annotations.media.Schema;
  4 +import lombok.Data;
  5 +import lombok.ToString;
  6 +
  7 +@Schema(description = "用户 App - 装修页面属性 Response VO")
  8 +@Data
  9 +@ToString(callSuper = true)
  10 +public class AppDiyPagePropertyRespVO {
  11 +
  12 + @Schema(description = "装修页面编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "31209")
  13 + private Long id;
  14 +
  15 + @Schema(description = "页面名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "王五")
  16 + private String name;
  17 +
  18 + @Schema(description = "页面属性", example = "[]")
  19 + private String property;
  20 +
  21 +}
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/app/diy/vo/AppDiyTemplatePropertyRespVO.java 0 → 100644
  1 +package cn.iocoder.yudao.module.promotion.controller.app.diy.vo;
  2 +
  3 +import com.fasterxml.jackson.annotation.JsonRawValue;
  4 +import io.swagger.v3.oas.annotations.media.Schema;
  5 +import lombok.Data;
  6 +import lombok.ToString;
  7 +
  8 +@Schema(description = "用户 App - 装修模板属性 Response VO")
  9 +@Data
  10 +@ToString(callSuper = true)
  11 +public class AppDiyTemplatePropertyRespVO {
  12 +
  13 + @Schema(description = "装修模板编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "31209")
  14 + private Long id;
  15 +
  16 + @Schema(description = "模板名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "默认主题")
  17 + private String name;
  18 +
  19 + @Schema(description = "模板属性", requiredMode = Schema.RequiredMode.REQUIRED, example = "{}")
  20 + @JsonRawValue
  21 + private String property;
  22 +
  23 + @Schema(description = "首页", requiredMode = Schema.RequiredMode.REQUIRED, example = "{}")
  24 + @JsonRawValue
  25 + private String home;
  26 +
  27 + @Schema(description = "我的", requiredMode = Schema.RequiredMode.REQUIRED, example = "{}")
  28 + @JsonRawValue
  29 + private String user;
  30 +
  31 +}
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/convert/diy/DiyPageConvert.java
1 package cn.iocoder.yudao.module.promotion.convert.diy; 1 package cn.iocoder.yudao.module.promotion.convert.diy;
2 2
3 import cn.iocoder.yudao.framework.common.pojo.PageResult; 3 import cn.iocoder.yudao.framework.common.pojo.PageResult;
4 -import cn.iocoder.yudao.module.promotion.controller.admin.diy.vo.page.DiyPageCreateReqVO;  
5 -import cn.iocoder.yudao.module.promotion.controller.admin.diy.vo.page.DiyPageRespVO;  
6 -import cn.iocoder.yudao.module.promotion.controller.admin.diy.vo.page.DiyPageUpdateReqVO; 4 +import cn.iocoder.yudao.module.promotion.controller.admin.diy.vo.page.*;
7 import cn.iocoder.yudao.module.promotion.dal.dataobject.diy.DiyPageDO; 5 import cn.iocoder.yudao.module.promotion.dal.dataobject.diy.DiyPageDO;
8 import org.mapstruct.Mapper; 6 import org.mapstruct.Mapper;
9 import org.mapstruct.factory.Mappers; 7 import org.mapstruct.factory.Mappers;
@@ -30,4 +28,10 @@ public interface DiyPageConvert { @@ -30,4 +28,10 @@ public interface DiyPageConvert {
30 28
31 PageResult<DiyPageRespVO> convertPage(PageResult<DiyPageDO> page); 29 PageResult<DiyPageRespVO> convertPage(PageResult<DiyPageDO> page);
32 30
  31 + DiyPageCreateReqVO convertCreateVo(Long templateId, String name, String remark);
  32 +
  33 + DiyPagePropertyRespVO convertPropertyVo(DiyPageDO diyPage);
  34 +
  35 + DiyPageDO convert(DiyPagePropertyUpdateRequestVO updateReqVO);
  36 +
33 } 37 }
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/convert/diy/DiyTemplateConvert.java
1 package cn.iocoder.yudao.module.promotion.convert.diy; 1 package cn.iocoder.yudao.module.promotion.convert.diy;
2 2
3 import cn.iocoder.yudao.framework.common.pojo.PageResult; 3 import cn.iocoder.yudao.framework.common.pojo.PageResult;
4 -import cn.iocoder.yudao.module.promotion.controller.admin.diy.vo.template.DiyTemplateCreateReqVO;  
5 -import cn.iocoder.yudao.module.promotion.controller.admin.diy.vo.template.DiyTemplateRespVO;  
6 -import cn.iocoder.yudao.module.promotion.controller.admin.diy.vo.template.DiyTemplateUpdateReqVO; 4 +import cn.iocoder.yudao.module.promotion.controller.admin.diy.vo.template.*;
  5 +import cn.iocoder.yudao.module.promotion.controller.app.diy.vo.AppDiyTemplatePropertyRespVO;
  6 +import cn.iocoder.yudao.module.promotion.dal.dataobject.diy.DiyPageDO;
7 import cn.iocoder.yudao.module.promotion.dal.dataobject.diy.DiyTemplateDO; 7 import cn.iocoder.yudao.module.promotion.dal.dataobject.diy.DiyTemplateDO;
8 import org.mapstruct.Mapper; 8 import org.mapstruct.Mapper;
9 import org.mapstruct.factory.Mappers; 9 import org.mapstruct.factory.Mappers;
@@ -30,4 +30,10 @@ public interface DiyTemplateConvert { @@ -30,4 +30,10 @@ public interface DiyTemplateConvert {
30 30
31 PageResult<DiyTemplateRespVO> convertPage(PageResult<DiyTemplateDO> page); 31 PageResult<DiyTemplateRespVO> convertPage(PageResult<DiyTemplateDO> page);
32 32
  33 + DiyTemplatePropertyRespVO convertPropertyVo(DiyTemplateDO diyTemplate, List<DiyPageDO> pages);
  34 +
  35 + AppDiyTemplatePropertyRespVO convertPropertyVo2(DiyTemplateDO diyTemplate, String home, String user);
  36 +
  37 + DiyTemplateDO convert(DiyTemplatePropertyUpdateRequestVO updateReqVO);
  38 +
33 } 39 }
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/convert/price/PriceConvert.java deleted
1 -package cn.iocoder.yudao.module.promotion.convert.price;  
2 -  
3 -import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils;  
4 -import cn.iocoder.yudao.module.promotion.api.price.dto.CouponMeetRespDTO;  
5 -import cn.iocoder.yudao.module.promotion.api.price.dto.PriceCalculateReqDTO;  
6 -import cn.iocoder.yudao.module.promotion.api.price.dto.PriceCalculateRespDTO;  
7 -import cn.iocoder.yudao.module.product.api.sku.dto.ProductSkuRespDTO;  
8 -import cn.iocoder.yudao.module.promotion.dal.dataobject.coupon.CouponDO;  
9 -import org.mapstruct.Mapper;  
10 -import org.mapstruct.factory.Mappers;  
11 -  
12 -import java.util.ArrayList;  
13 -import java.util.List;  
14 -import java.util.Map;  
15 -  
16 -@Mapper  
17 -public interface PriceConvert {  
18 -  
19 - PriceConvert INSTANCE = Mappers.getMapper(PriceConvert.class);  
20 -  
21 - default PriceCalculateRespDTO convert(PriceCalculateReqDTO calculateReqDTO, List<ProductSkuRespDTO> skuList) {  
22 - // 创建 PriceCalculateRespDTO 对象  
23 - PriceCalculateRespDTO priceCalculate = new PriceCalculateRespDTO();  
24 - // 创建它的 Order 属性  
25 - PriceCalculateRespDTO.Order order = new PriceCalculateRespDTO.Order().setTotalPrice(0).setDiscountPrice(0)  
26 - .setCouponPrice(0).setPointPrice(0).setDeliveryPrice(0).setPayPrice(0)  
27 - .setItems(new ArrayList<>()).setCouponId(calculateReqDTO.getCouponId());  
28 - priceCalculate.setOrder(order).setPromotions(new ArrayList<>());  
29 - // 创建它的 OrderItem 属性  
30 - Map<Long, Integer> skuIdCountMap = CollectionUtils.convertMap(calculateReqDTO.getItems(),  
31 - PriceCalculateReqDTO.Item::getSkuId, PriceCalculateReqDTO.Item::getCount);  
32 - skuList.forEach(sku -> {  
33 - Integer count = skuIdCountMap.get(sku.getId());  
34 - PriceCalculateRespDTO.OrderItem orderItem = new PriceCalculateRespDTO.OrderItem()  
35 - .setSpuId(sku.getSpuId()).setSkuId(sku.getId()).setCount(count)  
36 - .setOriginalUnitPrice(sku.getPrice()).setOriginalPrice(sku.getPrice() * count)  
37 - .setDiscountPrice(0).setOrderPartPrice(0);  
38 - orderItem.setPayPrice(orderItem.getOriginalPrice()).setOrderDividePrice(orderItem.getOriginalPrice());  
39 - priceCalculate.getOrder().getItems().add(orderItem);  
40 - // 补充价格信息到 Order 中  
41 - order.setTotalPrice(order.getTotalPrice() + orderItem.getOriginalPrice())  
42 - .setPayPrice(order.getTotalPrice());  
43 - });  
44 - return priceCalculate;  
45 - }  
46 -  
47 - CouponMeetRespDTO convert(CouponDO coupon);  
48 -  
49 -}  
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/dal/dataobject/diy/DiyPageDO.java
@@ -32,6 +32,8 @@ public class DiyPageDO extends BaseDO { @@ -32,6 +32,8 @@ public class DiyPageDO extends BaseDO {
32 private Long id; 32 private Long id;
33 /** 33 /**
34 * 装修模板编号 34 * 装修模板编号
  35 + *
  36 + * 关联 {@link DiyTemplateDO#getId()}
35 */ 37 */
36 private Long templateId; 38 private Long templateId;
37 /** 39 /**
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/dal/dataobject/diy/DiyTemplateDO.java
@@ -14,6 +14,9 @@ import java.util.List; @@ -14,6 +14,9 @@ import java.util.List;
14 /** 14 /**
15 * 装修模板 DO 15 * 装修模板 DO
16 * 16 *
  17 + * 1. 新建一个模版,下面可以包含多个 {@link DiyPageDO} 页面,例如说首页、我的
  18 + * 2. 如果需要使用某个模版,则将 {@link #used} 设置为 true,表示已使用,有且仅有一个
  19 + *
17 * @author owen 20 * @author owen
18 */ 21 */
19 @TableName(value = "promotion_diy_template", autoResultMap = true) 22 @TableName(value = "promotion_diy_template", autoResultMap = true)
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/dal/mysql/diy/DiyPageMapper.java
@@ -7,6 +7,8 @@ import cn.iocoder.yudao.module.promotion.controller.admin.diy.vo.page.DiyPagePag @@ -7,6 +7,8 @@ import cn.iocoder.yudao.module.promotion.controller.admin.diy.vo.page.DiyPagePag
7 import cn.iocoder.yudao.module.promotion.dal.dataobject.diy.DiyPageDO; 7 import cn.iocoder.yudao.module.promotion.dal.dataobject.diy.DiyPageDO;
8 import org.apache.ibatis.annotations.Mapper; 8 import org.apache.ibatis.annotations.Mapper;
9 9
  10 +import java.util.List;
  11 +
10 /** 12 /**
11 * 装修页面 Mapper 13 * 装修页面 Mapper
12 * 14 *
@@ -19,8 +21,19 @@ public interface DiyPageMapper extends BaseMapperX&lt;DiyPageDO&gt; { @@ -19,8 +21,19 @@ public interface DiyPageMapper extends BaseMapperX&lt;DiyPageDO&gt; {
19 return selectPage(reqVO, new LambdaQueryWrapperX<DiyPageDO>() 21 return selectPage(reqVO, new LambdaQueryWrapperX<DiyPageDO>()
20 .likeIfPresent(DiyPageDO::getName, reqVO.getName()) 22 .likeIfPresent(DiyPageDO::getName, reqVO.getName())
21 .betweenIfPresent(DiyPageDO::getCreateTime, reqVO.getCreateTime()) 23 .betweenIfPresent(DiyPageDO::getCreateTime, reqVO.getCreateTime())
  24 + // 模板下面的页面,在模板中管理
22 .isNull(DiyPageDO::getTemplateId) 25 .isNull(DiyPageDO::getTemplateId)
23 .orderByDesc(DiyPageDO::getId)); 26 .orderByDesc(DiyPageDO::getId));
24 } 27 }
25 28
  29 + default List<DiyPageDO> selectListByTemplateId(Long templateId) {
  30 + return selectList(DiyPageDO::getTemplateId, templateId);
  31 + }
  32 +
  33 + default DiyPageDO selectByNameAndTemplateIdIsNull(String name) {
  34 + return selectOne(new LambdaQueryWrapperX<DiyPageDO>()
  35 + .eq(DiyPageDO::getName, name)
  36 + .isNull(DiyPageDO::getTemplateId));
  37 + }
  38 +
26 } 39 }
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/dal/mysql/diy/DiyTemplateMapper.java
@@ -29,4 +29,8 @@ public interface DiyTemplateMapper extends BaseMapperX&lt;DiyTemplateDO&gt; { @@ -29,4 +29,8 @@ public interface DiyTemplateMapper extends BaseMapperX&lt;DiyTemplateDO&gt; {
29 return selectOne(DiyTemplateDO::getUsed, used); 29 return selectOne(DiyTemplateDO::getUsed, used);
30 } 30 }
31 31
  32 + default DiyTemplateDO selectByName(String name) {
  33 + return selectOne(DiyTemplateDO::getName, name);
  34 + }
  35 +
32 } 36 }
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/mq/consumer/coupon/UserCreateConsumer.java renamed to yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/mq/consumer/coupon/CouponTakeByRegisterConsumer.java
1 package cn.iocoder.yudao.module.promotion.mq.consumer.coupon; 1 package cn.iocoder.yudao.module.promotion.mq.consumer.coupon;
2 2
3 -import cn.iocoder.yudao.framework.mq.core.stream.AbstractStreamMessageListener;  
4 -import cn.iocoder.yudao.module.promotion.mq.message.coupon.UserCreateMessage; 3 +import cn.iocoder.yudao.module.member.message.user.MemberUserCreateMessage;
5 import cn.iocoder.yudao.module.promotion.service.coupon.CouponService; 4 import cn.iocoder.yudao.module.promotion.service.coupon.CouponService;
6 import lombok.extern.slf4j.Slf4j; 5 import lombok.extern.slf4j.Slf4j;
  6 +import org.springframework.context.event.EventListener;
  7 +import org.springframework.scheduling.annotation.Async;
7 import org.springframework.stereotype.Component; 8 import org.springframework.stereotype.Component;
8 9
9 import javax.annotation.Resource; 10 import javax.annotation.Resource;
10 11
11 /** 12 /**
12 - * 针对 {@link UserCreateMessage} 的消费者 13 + * 用户注册时,发送优惠劵的消费者,基 {@link MemberUserCreateMessage} 消息
13 * 14 *
14 * @author owen 15 * @author owen
15 */ 16 */
16 @Component 17 @Component
17 @Slf4j 18 @Slf4j
18 -public class UserCreateConsumer extends AbstractStreamMessageListener<UserCreateMessage> { 19 +public class CouponTakeByRegisterConsumer {
19 20
20 @Resource 21 @Resource
21 private CouponService couponService; 22 private CouponService couponService;
22 23
23 - @Override  
24 - public void onMessage(UserCreateMessage message) { 24 + @EventListener
  25 + @Async // Spring Event 默认在 Producer 发送的线程,通过 @Async 实现异步
  26 + public void onMessage(MemberUserCreateMessage message) {
25 log.info("[onMessage][消息内容({})]", message); 27 log.info("[onMessage][消息内容({})]", message);
26 couponService.takeCouponByRegister(message.getUserId()); 28 couponService.takeCouponByRegister(message.getUserId());
27 } 29 }
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/mq/consumer/package-info.java 0 → 100644
  1 +/**
  2 + * 消息队列的消费者
  3 + */
  4 +package cn.iocoder.yudao.module.promotion.mq.consumer;
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/mq/message/package-info.java 0 → 100644
  1 +/**
  2 + * 消息队列的消息
  3 + */
  4 +package cn.iocoder.yudao.module.promotion.mq.message;
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/mq/producer/package-info.java 0 → 100644
  1 +/**
  2 + * 消息队列的生产者
  3 + */
  4 +package cn.iocoder.yudao.module.promotion.mq.producer;
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/combination/CombinationActivityServiceImpl.java
@@ -108,8 +108,8 @@ public class CombinationActivityServiceImpl implements CombinationActivityServic @@ -108,8 +108,8 @@ public class CombinationActivityServiceImpl implements CombinationActivityServic
108 } 108 }
109 109
110 // 2. 校验商品 sku 都存在 110 // 2. 校验商品 sku 都存在
111 - Map<Long, ProductSkuRespDTO> skuMap = convertMap(productSkuApi.getSkuListBySpuId(singletonList(spuId)),  
112 - ProductSkuRespDTO::getId); 111 + List<ProductSkuRespDTO> skus = productSkuApi.getSkuListBySpuId(singletonList(spuId));
  112 + Map<Long, ProductSkuRespDTO> skuMap = convertMap(skus, ProductSkuRespDTO::getId);
113 products.forEach(product -> { 113 products.forEach(product -> {
114 if (!skuMap.containsKey(product.getSkuId())) { 114 if (!skuMap.containsKey(product.getSkuId())) {
115 throw exception(SKU_NOT_EXISTS); 115 throw exception(SKU_NOT_EXISTS);
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/combination/CombinationRecordService.java
@@ -22,15 +22,6 @@ import java.util.Map; @@ -22,15 +22,6 @@ import java.util.Map;
22 public interface CombinationRecordService { 22 public interface CombinationRecordService {
23 23
24 /** 24 /**
25 - * 更新拼团状态  
26 - *  
27 - * @param status 状态  
28 - * @param userId 用户编号  
29 - * @param orderId 订单编号  
30 - */  
31 - void updateCombinationRecordStatusByUserIdAndOrderId(Integer status, Long userId, Long orderId);  
32 -  
33 - /**  
34 * 【下单前】校验是否满足拼团活动条件 25 * 【下单前】校验是否满足拼团活动条件
35 * 26 *
36 * 如果校验失败,则抛出业务异常 27 * 如果校验失败,则抛出业务异常
@@ -63,15 +54,6 @@ public interface CombinationRecordService { @@ -63,15 +54,6 @@ public interface CombinationRecordService {
63 CombinationRecordDO getCombinationRecord(Long userId, Long orderId); 54 CombinationRecordDO getCombinationRecord(Long userId, Long orderId);
64 55
65 /** 56 /**
66 - * 获取拼团记录  
67 - *  
68 - * @param userId 用户 id  
69 - * @param activityId 活动 id  
70 - * @return 拼团记录列表  
71 - */  
72 - List<CombinationRecordDO> getCombinationRecordListByUserIdAndActivityId(Long userId, Long activityId);  
73 -  
74 - /**  
75 * 【下单前】校验是否满足拼团活动条件 57 * 【下单前】校验是否满足拼团活动条件
76 * 58 *
77 * 如果校验失败,则抛出业务异常 59 * 如果校验失败,则抛出业务异常
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/combination/CombinationRecordServiceImpl.java
@@ -24,6 +24,7 @@ import cn.iocoder.yudao.module.promotion.dal.mysql.combination.CombinationRecord @@ -24,6 +24,7 @@ import cn.iocoder.yudao.module.promotion.dal.mysql.combination.CombinationRecord
24 import cn.iocoder.yudao.module.promotion.enums.combination.CombinationRecordStatusEnum; 24 import cn.iocoder.yudao.module.promotion.enums.combination.CombinationRecordStatusEnum;
25 import cn.iocoder.yudao.module.trade.api.order.TradeOrderApi; 25 import cn.iocoder.yudao.module.trade.api.order.TradeOrderApi;
26 import lombok.extern.slf4j.Slf4j; 26 import lombok.extern.slf4j.Slf4j;
  27 +import org.springframework.context.annotation.Lazy;
27 import org.springframework.stereotype.Service; 28 import org.springframework.stereotype.Service;
28 import org.springframework.transaction.annotation.Transactional; 29 import org.springframework.transaction.annotation.Transactional;
29 import org.springframework.validation.annotation.Validated; 30 import org.springframework.validation.annotation.Validated;
@@ -64,27 +65,9 @@ public class CombinationRecordServiceImpl implements CombinationRecordService { @@ -64,27 +65,9 @@ public class CombinationRecordServiceImpl implements CombinationRecordService {
64 private ProductSkuApi productSkuApi; 65 private ProductSkuApi productSkuApi;
65 66
66 @Resource 67 @Resource
  68 + @Lazy
67 private TradeOrderApi tradeOrderApi; 69 private TradeOrderApi tradeOrderApi;
68 70
69 - @Override  
70 - @Transactional(rollbackFor = Exception.class)  
71 - public void updateCombinationRecordStatusByUserIdAndOrderId(Integer status, Long userId, Long orderId) {  
72 - // 校验拼团是否存在  
73 - CombinationRecordDO record = validateCombinationRecord(userId, orderId);  
74 -  
75 - // 更新状态  
76 - combinationRecordMapper.updateById(new CombinationRecordDO().setId(record.getId()).setStatus(status));  
77 - }  
78 -  
79 - private CombinationRecordDO validateCombinationRecord(Long userId, Long orderId) {  
80 - // 校验拼团是否存在  
81 - CombinationRecordDO recordDO = combinationRecordMapper.selectByUserIdAndOrderId(userId, orderId);  
82 - if (recordDO == null) {  
83 - throw exception(COMBINATION_RECORD_NOT_EXISTS);  
84 - }  
85 - return recordDO;  
86 - }  
87 -  
88 // TODO @芋艿:在详细预览下; 71 // TODO @芋艿:在详细预览下;
89 @Override 72 @Override
90 public KeyValue<CombinationActivityDO, CombinationProductDO> validateCombinationRecord( 73 public KeyValue<CombinationActivityDO, CombinationProductDO> validateCombinationRecord(
@@ -230,11 +213,6 @@ public class CombinationRecordServiceImpl implements CombinationRecordService { @@ -230,11 +213,6 @@ public class CombinationRecordServiceImpl implements CombinationRecordService {
230 } 213 }
231 214
232 @Override 215 @Override
233 - public List<CombinationRecordDO> getCombinationRecordListByUserIdAndActivityId(Long userId, Long activityId) {  
234 - return combinationRecordMapper.selectListByUserIdAndActivityId(userId, activityId);  
235 - }  
236 -  
237 - @Override  
238 public CombinationValidateJoinRespDTO validateJoinCombination(Long userId, Long activityId, Long headId, 216 public CombinationValidateJoinRespDTO validateJoinCombination(Long userId, Long activityId, Long headId,
239 Long skuId, Integer count) { 217 Long skuId, Integer count) {
240 KeyValue<CombinationActivityDO, CombinationProductDO> keyValue = validateCombinationRecord(userId, activityId, 218 KeyValue<CombinationActivityDO, CombinationProductDO> keyValue = validateCombinationRecord(userId, activityId,
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/coupon/CouponServiceImpl.java
@@ -7,7 +7,6 @@ import cn.hutool.core.util.ObjectUtil; @@ -7,7 +7,6 @@ import cn.hutool.core.util.ObjectUtil;
7 import cn.hutool.core.util.StrUtil; 7 import cn.hutool.core.util.StrUtil;
8 import cn.hutool.extra.spring.SpringUtil; 8 import cn.hutool.extra.spring.SpringUtil;
9 import cn.iocoder.yudao.framework.common.pojo.PageResult; 9 import cn.iocoder.yudao.framework.common.pojo.PageResult;
10 -import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils;  
11 import cn.iocoder.yudao.framework.common.util.date.LocalDateTimeUtils; 10 import cn.iocoder.yudao.framework.common.util.date.LocalDateTimeUtils;
12 import cn.iocoder.yudao.module.member.api.user.MemberUserApi; 11 import cn.iocoder.yudao.module.member.api.user.MemberUserApi;
13 import cn.iocoder.yudao.module.member.api.user.dto.MemberUserRespDTO; 12 import cn.iocoder.yudao.module.member.api.user.dto.MemberUserRespDTO;
@@ -80,12 +79,11 @@ public class CouponServiceImpl implements CouponService { @@ -80,12 +79,11 @@ public class CouponServiceImpl implements CouponService {
80 public PageResult<CouponDO> getCouponPage(CouponPageReqVO pageReqVO) { 79 public PageResult<CouponDO> getCouponPage(CouponPageReqVO pageReqVO) {
81 // 获得用户编号 80 // 获得用户编号
82 if (StrUtil.isNotEmpty(pageReqVO.getNickname())) { 81 if (StrUtil.isNotEmpty(pageReqVO.getNickname())) {
83 - Set<Long> userIds = CollectionUtils.convertSet(memberUserApi.getUserListByNickname(pageReqVO.getNickname()),  
84 - MemberUserRespDTO::getId);  
85 - if (CollUtil.isEmpty(userIds)) { 82 + List<MemberUserRespDTO> users = memberUserApi.getUserListByNickname(pageReqVO.getNickname());
  83 + if (CollUtil.isEmpty(users)) {
86 return PageResult.empty(); 84 return PageResult.empty();
87 } 85 }
88 - pageReqVO.setUserIds(userIds); 86 + pageReqVO.setUserIds(convertSet(users, MemberUserRespDTO::getId));
89 } 87 }
90 // 分页查询 88 // 分页查询
91 return couponMapper.selectPage(pageReqVO); 89 return couponMapper.selectPage(pageReqVO);
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/diy/DiyPageService.java
@@ -3,6 +3,7 @@ package cn.iocoder.yudao.module.promotion.service.diy; @@ -3,6 +3,7 @@ package cn.iocoder.yudao.module.promotion.service.diy;
3 import cn.iocoder.yudao.framework.common.pojo.PageResult; 3 import cn.iocoder.yudao.framework.common.pojo.PageResult;
4 import cn.iocoder.yudao.module.promotion.controller.admin.diy.vo.page.DiyPageCreateReqVO; 4 import cn.iocoder.yudao.module.promotion.controller.admin.diy.vo.page.DiyPageCreateReqVO;
5 import cn.iocoder.yudao.module.promotion.controller.admin.diy.vo.page.DiyPagePageReqVO; 5 import cn.iocoder.yudao.module.promotion.controller.admin.diy.vo.page.DiyPagePageReqVO;
  6 +import cn.iocoder.yudao.module.promotion.controller.admin.diy.vo.page.DiyPagePropertyUpdateRequestVO;
6 import cn.iocoder.yudao.module.promotion.controller.admin.diy.vo.page.DiyPageUpdateReqVO; 7 import cn.iocoder.yudao.module.promotion.controller.admin.diy.vo.page.DiyPageUpdateReqVO;
7 import cn.iocoder.yudao.module.promotion.dal.dataobject.diy.DiyPageDO; 8 import cn.iocoder.yudao.module.promotion.dal.dataobject.diy.DiyPageDO;
8 9
@@ -63,4 +64,19 @@ public interface DiyPageService { @@ -63,4 +64,19 @@ public interface DiyPageService {
63 */ 64 */
64 PageResult<DiyPageDO> getDiyPagePage(DiyPagePageReqVO pageReqVO); 65 PageResult<DiyPageDO> getDiyPagePage(DiyPagePageReqVO pageReqVO);
65 66
  67 + /**
  68 + * 更新装修页面属性
  69 + *
  70 + * @param updateReqVO 更新信息
  71 + */
  72 + void updateDiyPageProperty(DiyPagePropertyUpdateRequestVO updateReqVO);
  73 +
  74 + /**
  75 + * 获得模板所属的页面列表
  76 + *
  77 + * @param templateId 模板编号
  78 + * @return 装修页面列表
  79 + */
  80 + List<DiyPageDO> getDiyPageByTemplateId(Long templateId);
  81 +
66 } 82 }
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/diy/DiyPageServiceImpl.java
@@ -2,9 +2,11 @@ package cn.iocoder.yudao.module.promotion.service.diy; @@ -2,9 +2,11 @@ package cn.iocoder.yudao.module.promotion.service.diy;
2 2
3 import cn.hutool.core.collection.CollUtil; 3 import cn.hutool.core.collection.CollUtil;
4 import cn.hutool.core.collection.ListUtil; 4 import cn.hutool.core.collection.ListUtil;
  5 +import cn.hutool.core.util.StrUtil;
5 import cn.iocoder.yudao.framework.common.pojo.PageResult; 6 import cn.iocoder.yudao.framework.common.pojo.PageResult;
6 import cn.iocoder.yudao.module.promotion.controller.admin.diy.vo.page.DiyPageCreateReqVO; 7 import cn.iocoder.yudao.module.promotion.controller.admin.diy.vo.page.DiyPageCreateReqVO;
7 import cn.iocoder.yudao.module.promotion.controller.admin.diy.vo.page.DiyPagePageReqVO; 8 import cn.iocoder.yudao.module.promotion.controller.admin.diy.vo.page.DiyPagePageReqVO;
  9 +import cn.iocoder.yudao.module.promotion.controller.admin.diy.vo.page.DiyPagePropertyUpdateRequestVO;
8 import cn.iocoder.yudao.module.promotion.controller.admin.diy.vo.page.DiyPageUpdateReqVO; 10 import cn.iocoder.yudao.module.promotion.controller.admin.diy.vo.page.DiyPageUpdateReqVO;
9 import cn.iocoder.yudao.module.promotion.convert.diy.DiyPageConvert; 11 import cn.iocoder.yudao.module.promotion.convert.diy.DiyPageConvert;
10 import cn.iocoder.yudao.module.promotion.dal.dataobject.diy.DiyPageDO; 12 import cn.iocoder.yudao.module.promotion.dal.dataobject.diy.DiyPageDO;
@@ -17,6 +19,7 @@ import java.util.Collection; @@ -17,6 +19,7 @@ import java.util.Collection;
17 import java.util.List; 19 import java.util.List;
18 20
19 import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; 21 import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
  22 +import static cn.iocoder.yudao.module.promotion.enums.ErrorCodeConstants.DIY_PAGE_NAME_USED;
20 import static cn.iocoder.yudao.module.promotion.enums.ErrorCodeConstants.DIY_PAGE_NOT_EXISTS; 23 import static cn.iocoder.yudao.module.promotion.enums.ErrorCodeConstants.DIY_PAGE_NOT_EXISTS;
21 24
22 /** 25 /**
@@ -33,10 +36,12 @@ public class DiyPageServiceImpl implements DiyPageService { @@ -33,10 +36,12 @@ public class DiyPageServiceImpl implements DiyPageService {
33 36
34 @Override 37 @Override
35 public Long createDiyPage(DiyPageCreateReqVO createReqVO) { 38 public Long createDiyPage(DiyPageCreateReqVO createReqVO) {
  39 + // 校验名称唯一
  40 + validateNameUnique(null, createReqVO.getTemplateId(), createReqVO.getName());
36 // 插入 41 // 插入
37 DiyPageDO diyPage = DiyPageConvert.INSTANCE.convert(createReqVO); 42 DiyPageDO diyPage = DiyPageConvert.INSTANCE.convert(createReqVO);
  43 + diyPage.setProperty("{}");
38 diyPageMapper.insert(diyPage); 44 diyPageMapper.insert(diyPage);
39 - // 返回  
40 return diyPage.getId(); 45 return diyPage.getId();
41 } 46 }
42 47
@@ -44,11 +49,37 @@ public class DiyPageServiceImpl implements DiyPageService { @@ -44,11 +49,37 @@ public class DiyPageServiceImpl implements DiyPageService {
44 public void updateDiyPage(DiyPageUpdateReqVO updateReqVO) { 49 public void updateDiyPage(DiyPageUpdateReqVO updateReqVO) {
45 // 校验存在 50 // 校验存在
46 validateDiyPageExists(updateReqVO.getId()); 51 validateDiyPageExists(updateReqVO.getId());
  52 + // 校验名称唯一
  53 + validateNameUnique(updateReqVO.getId(), updateReqVO.getTemplateId(), updateReqVO.getName());
47 // 更新 54 // 更新
48 DiyPageDO updateObj = DiyPageConvert.INSTANCE.convert(updateReqVO); 55 DiyPageDO updateObj = DiyPageConvert.INSTANCE.convert(updateReqVO);
49 diyPageMapper.updateById(updateObj); 56 diyPageMapper.updateById(updateObj);
50 } 57 }
51 58
  59 + /**
  60 + * 校验 Page 页面,在一个 template 模版下的名字是唯一的
  61 + *
  62 + * @param id Page 编号
  63 + * @param templateId 模版编号
  64 + * @param name Page 名字
  65 + */
  66 + void validateNameUnique(Long id, Long templateId, String name) {
  67 + if (templateId != null || StrUtil.isBlank(name)) {
  68 + return;
  69 + }
  70 + DiyPageDO page = diyPageMapper.selectByNameAndTemplateIdIsNull(name);
  71 + if (page == null) {
  72 + return;
  73 + }
  74 + // 如果 id 为空,说明不用比较是否为相同 id 的页面
  75 + if (id == null) {
  76 + throw exception(DIY_PAGE_NAME_USED, name);
  77 + }
  78 + if (!page.getId().equals(id)) {
  79 + throw exception(DIY_PAGE_NAME_USED, name);
  80 + }
  81 + }
  82 +
52 @Override 83 @Override
53 public void deleteDiyPage(Long id) { 84 public void deleteDiyPage(Long id) {
54 // 校验存在 85 // 校验存在
@@ -81,4 +112,18 @@ public class DiyPageServiceImpl implements DiyPageService { @@ -81,4 +112,18 @@ public class DiyPageServiceImpl implements DiyPageService {
81 return diyPageMapper.selectPage(pageReqVO); 112 return diyPageMapper.selectPage(pageReqVO);
82 } 113 }
83 114
  115 + @Override
  116 + public List<DiyPageDO> getDiyPageByTemplateId(Long templateId) {
  117 + return diyPageMapper.selectListByTemplateId(templateId);
  118 + }
  119 +
  120 + @Override
  121 + public void updateDiyPageProperty(DiyPagePropertyUpdateRequestVO updateReqVO) {
  122 + // 校验存在
  123 + validateDiyPageExists(updateReqVO.getId());
  124 + // 更新
  125 + DiyPageDO updateObj = DiyPageConvert.INSTANCE.convert(updateReqVO);
  126 + diyPageMapper.updateById(updateObj);
  127 + }
  128 +
84 } 129 }
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/diy/DiyTemplateService.java
@@ -3,6 +3,7 @@ package cn.iocoder.yudao.module.promotion.service.diy; @@ -3,6 +3,7 @@ package cn.iocoder.yudao.module.promotion.service.diy;
3 import cn.iocoder.yudao.framework.common.pojo.PageResult; 3 import cn.iocoder.yudao.framework.common.pojo.PageResult;
4 import cn.iocoder.yudao.module.promotion.controller.admin.diy.vo.template.DiyTemplateCreateReqVO; 4 import cn.iocoder.yudao.module.promotion.controller.admin.diy.vo.template.DiyTemplateCreateReqVO;
5 import cn.iocoder.yudao.module.promotion.controller.admin.diy.vo.template.DiyTemplatePageReqVO; 5 import cn.iocoder.yudao.module.promotion.controller.admin.diy.vo.template.DiyTemplatePageReqVO;
  6 +import cn.iocoder.yudao.module.promotion.controller.admin.diy.vo.template.DiyTemplatePropertyUpdateRequestVO;
6 import cn.iocoder.yudao.module.promotion.controller.admin.diy.vo.template.DiyTemplateUpdateReqVO; 7 import cn.iocoder.yudao.module.promotion.controller.admin.diy.vo.template.DiyTemplateUpdateReqVO;
7 import cn.iocoder.yudao.module.promotion.dal.dataobject.diy.DiyTemplateDO; 8 import cn.iocoder.yudao.module.promotion.dal.dataobject.diy.DiyTemplateDO;
8 9
@@ -60,4 +61,18 @@ public interface DiyTemplateService { @@ -60,4 +61,18 @@ public interface DiyTemplateService {
60 */ 61 */
61 void useDiyTemplate(Long id); 62 void useDiyTemplate(Long id);
62 63
  64 + /**
  65 + * 更新装修模板属性
  66 + *
  67 + * @param updateReqVO 更新信息
  68 + */
  69 + void updateDiyTemplateProperty(DiyTemplatePropertyUpdateRequestVO updateReqVO);
  70 +
  71 + /**
  72 + * 获取使用中的装修模板
  73 + *
  74 + * @return 装修模板
  75 + */
  76 + DiyTemplateDO getUsedDiyTemplate();
  77 +
63 } 78 }
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/diy/DiyTemplateServiceImpl.java
1 package cn.iocoder.yudao.module.promotion.service.diy; 1 package cn.iocoder.yudao.module.promotion.service.diy;
2 2
3 import cn.hutool.core.util.BooleanUtil; 3 import cn.hutool.core.util.BooleanUtil;
  4 +import cn.hutool.core.util.StrUtil;
4 import cn.iocoder.yudao.framework.common.pojo.PageResult; 5 import cn.iocoder.yudao.framework.common.pojo.PageResult;
5 import cn.iocoder.yudao.module.promotion.controller.admin.diy.vo.template.DiyTemplateCreateReqVO; 6 import cn.iocoder.yudao.module.promotion.controller.admin.diy.vo.template.DiyTemplateCreateReqVO;
6 import cn.iocoder.yudao.module.promotion.controller.admin.diy.vo.template.DiyTemplatePageReqVO; 7 import cn.iocoder.yudao.module.promotion.controller.admin.diy.vo.template.DiyTemplatePageReqVO;
  8 +import cn.iocoder.yudao.module.promotion.controller.admin.diy.vo.template.DiyTemplatePropertyUpdateRequestVO;
7 import cn.iocoder.yudao.module.promotion.controller.admin.diy.vo.template.DiyTemplateUpdateReqVO; 9 import cn.iocoder.yudao.module.promotion.controller.admin.diy.vo.template.DiyTemplateUpdateReqVO;
  10 +import cn.iocoder.yudao.module.promotion.convert.diy.DiyPageConvert;
8 import cn.iocoder.yudao.module.promotion.convert.diy.DiyTemplateConvert; 11 import cn.iocoder.yudao.module.promotion.convert.diy.DiyTemplateConvert;
9 import cn.iocoder.yudao.module.promotion.dal.dataobject.diy.DiyTemplateDO; 12 import cn.iocoder.yudao.module.promotion.dal.dataobject.diy.DiyTemplateDO;
10 import cn.iocoder.yudao.module.promotion.dal.mysql.diy.DiyTemplateMapper; 13 import cn.iocoder.yudao.module.promotion.dal.mysql.diy.DiyTemplateMapper;
11 import org.springframework.stereotype.Service; 14 import org.springframework.stereotype.Service;
  15 +import org.springframework.transaction.annotation.Transactional;
12 import org.springframework.validation.annotation.Validated; 16 import org.springframework.validation.annotation.Validated;
13 17
14 import javax.annotation.Resource; 18 import javax.annotation.Resource;
15 import java.time.LocalDateTime; 19 import java.time.LocalDateTime;
16 20
17 import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; 21 import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
18 -import static cn.iocoder.yudao.module.promotion.enums.ErrorCodeConstants.DIY_TEMPLATE_NOT_EXISTS;  
19 -import static cn.iocoder.yudao.module.promotion.enums.ErrorCodeConstants.DIY_TEMPLATE_USED_CANNOT_DELETE; 22 +import static cn.iocoder.yudao.module.promotion.enums.ErrorCodeConstants.*;
20 23
21 /** 24 /**
22 * 装修模板 Service 实现类 25 * 装修模板 Service 实现类
@@ -30,24 +33,64 @@ public class DiyTemplateServiceImpl implements DiyTemplateService { @@ -30,24 +33,64 @@ public class DiyTemplateServiceImpl implements DiyTemplateService {
30 @Resource 33 @Resource
31 private DiyTemplateMapper diyTemplateMapper; 34 private DiyTemplateMapper diyTemplateMapper;
32 35
  36 + @Resource
  37 + private DiyPageService diyPageService;
  38 +
  39 + // TODO @疯狂:事务;
33 @Override 40 @Override
34 public Long createDiyTemplate(DiyTemplateCreateReqVO createReqVO) { 41 public Long createDiyTemplate(DiyTemplateCreateReqVO createReqVO) {
  42 + // 校验名称唯一
  43 + validateNameUnique(null, createReqVO.getName());
35 // 插入 44 // 插入
36 DiyTemplateDO diyTemplate = DiyTemplateConvert.INSTANCE.convert(createReqVO); 45 DiyTemplateDO diyTemplate = DiyTemplateConvert.INSTANCE.convert(createReqVO);
  46 + diyTemplate.setProperty("{}");
37 diyTemplateMapper.insert(diyTemplate); 47 diyTemplateMapper.insert(diyTemplate);
  48 + // 创建默认页面
  49 + createDefaultPage(diyTemplate);
38 // 返回 50 // 返回
39 return diyTemplate.getId(); 51 return diyTemplate.getId();
40 } 52 }
41 53
  54 + /**
  55 + * 创建模板下面的默认页面
  56 + * 默认创建两个页面:首页、我的
  57 + *
  58 + * @param diyTemplate 模板对象
  59 + */
  60 + private void createDefaultPage(DiyTemplateDO diyTemplate) {
  61 + String remark = String.format("模板【%s】自动创建", diyTemplate.getName());
  62 + diyPageService.createDiyPage(DiyPageConvert.INSTANCE.convertCreateVo(diyTemplate.getId(), "首页", remark));
  63 + diyPageService.createDiyPage(DiyPageConvert.INSTANCE.convertCreateVo(diyTemplate.getId(), "我的", remark));
  64 + }
  65 +
42 @Override 66 @Override
43 public void updateDiyTemplate(DiyTemplateUpdateReqVO updateReqVO) { 67 public void updateDiyTemplate(DiyTemplateUpdateReqVO updateReqVO) {
44 // 校验存在 68 // 校验存在
45 validateDiyTemplateExists(updateReqVO.getId()); 69 validateDiyTemplateExists(updateReqVO.getId());
  70 + // 校验名称唯一
  71 + validateNameUnique(updateReqVO.getId(), updateReqVO.getName());
46 // 更新 72 // 更新
47 DiyTemplateDO updateObj = DiyTemplateConvert.INSTANCE.convert(updateReqVO); 73 DiyTemplateDO updateObj = DiyTemplateConvert.INSTANCE.convert(updateReqVO);
48 diyTemplateMapper.updateById(updateObj); 74 diyTemplateMapper.updateById(updateObj);
49 } 75 }
50 76
  77 + void validateNameUnique(Long id, String name) {
  78 + if (StrUtil.isBlank(name)) {
  79 + return;
  80 + }
  81 + DiyTemplateDO template = diyTemplateMapper.selectByName(name);
  82 + if (template == null) {
  83 + return;
  84 + }
  85 + // 如果 id 为空,说明不用比较是否为相同 id 的模板
  86 + if (id == null) {
  87 + throw exception(DIY_TEMPLATE_NAME_USED, name);
  88 + }
  89 + if (!template.getId().equals(id)) {
  90 + throw exception(DIY_TEMPLATE_NAME_USED, name);
  91 + }
  92 + }
  93 +
51 @Override 94 @Override
52 public void deleteDiyTemplate(Long id) { 95 public void deleteDiyTemplate(Long id) {
53 // 校验存在 96 // 校验存在
@@ -79,18 +122,47 @@ public class DiyTemplateServiceImpl implements DiyTemplateService { @@ -79,18 +122,47 @@ public class DiyTemplateServiceImpl implements DiyTemplateService {
79 } 122 }
80 123
81 @Override 124 @Override
  125 + // TODO @疯狂:事务;
82 public void useDiyTemplate(Long id) { 126 public void useDiyTemplate(Long id) {
83 // 校验存在 127 // 校验存在
84 validateDiyTemplateExists(id); 128 validateDiyTemplateExists(id);
  129 + // TODO @疯狂:要不已使用的情况,抛个业务异常?
85 // 已使用的更新为未使用 130 // 已使用的更新为未使用
86 DiyTemplateDO used = diyTemplateMapper.selectByUsed(true); 131 DiyTemplateDO used = diyTemplateMapper.selectByUsed(true);
87 if (used != null) { 132 if (used != null) {
  133 + // 如果 id 相同,说明未发生变化
  134 + if (used.getId().equals(id)) {
  135 + return;
  136 + }
88 this.updateUsed(used.getId(), false, null); 137 this.updateUsed(used.getId(), false, null);
89 } 138 }
90 // 更新为已使用 139 // 更新为已使用
91 this.updateUsed(id, true, LocalDateTime.now()); 140 this.updateUsed(id, true, LocalDateTime.now());
92 } 141 }
93 142
  143 + @Override
  144 + @Transactional(rollbackFor = Exception.class)
  145 + public void updateDiyTemplateProperty(DiyTemplatePropertyUpdateRequestVO updateReqVO) {
  146 + // 校验存在
  147 + validateDiyTemplateExists(updateReqVO.getId());
  148 + // 更新模板属性
  149 + DiyTemplateDO updateObj = DiyTemplateConvert.INSTANCE.convert(updateReqVO);
  150 + diyTemplateMapper.updateById(updateObj);
  151 + }
  152 +
  153 + @Override
  154 + public DiyTemplateDO getUsedDiyTemplate() {
  155 + return diyTemplateMapper.selectByUsed(true);
  156 + }
  157 +
  158 + // TODO @疯狂:挪到 useDiyTemplate 下面,改名 updateTemplateUsed 会不会好点哈;
  159 + /**
  160 + * 更新模板是否使用
  161 + *
  162 + * @param id 模板编号
  163 + * @param used 是否使用
  164 + * @param usedTime 使用时间
  165 + */
94 private void updateUsed(Long id, Boolean used, LocalDateTime usedTime) { 166 private void updateUsed(Long id, Boolean used, LocalDateTime usedTime) {
95 DiyTemplateDO updateObj = new DiyTemplateDO().setId(id) 167 DiyTemplateDO updateObj = new DiyTemplateDO().setId(id)
96 .setUsed(used).setUsedTime(usedTime); 168 .setUsed(used).setUsedTime(usedTime);
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/price/PriceService.java deleted
1 -package cn.iocoder.yudao.module.promotion.service.price;  
2 -  
3 -import cn.iocoder.yudao.module.promotion.api.price.dto.CouponMeetRespDTO;  
4 -import cn.iocoder.yudao.module.promotion.api.price.dto.PriceCalculateReqDTO;  
5 -  
6 -import java.util.List;  
7 -  
8 -/**  
9 - * 价格计算 Service 接口  
10 - *  
11 - * @author 芋道源码  
12 - */  
13 -public interface PriceService {  
14 -  
15 - /**  
16 - * 获得优惠劵的匹配信息列表  
17 - *  
18 - * @param calculateReqDTO 价格请求  
19 - * @return 价格响应  
20 - */  
21 - List<CouponMeetRespDTO> getMeetCouponList(PriceCalculateReqDTO calculateReqDTO);  
22 -  
23 -}  
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/price/PriceServiceImpl.java deleted
1 -package cn.iocoder.yudao.module.promotion.service.price;  
2 -  
3 -import cn.hutool.core.collection.CollUtil;  
4 -import cn.iocoder.yudao.framework.common.exception.ServiceException;  
5 -import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils;  
6 -import cn.iocoder.yudao.module.promotion.api.price.dto.CouponMeetRespDTO;  
7 -import cn.iocoder.yudao.module.promotion.api.price.dto.PriceCalculateReqDTO;  
8 -import cn.iocoder.yudao.module.promotion.api.price.dto.PriceCalculateRespDTO;  
9 -import cn.iocoder.yudao.module.promotion.convert.price.PriceConvert;  
10 -import cn.iocoder.yudao.module.promotion.dal.dataobject.coupon.CouponDO;  
11 -import cn.iocoder.yudao.module.promotion.enums.coupon.CouponStatusEnum;  
12 -import cn.iocoder.yudao.module.promotion.service.coupon.CouponService;  
13 -import lombok.extern.slf4j.Slf4j;  
14 -import org.springframework.stereotype.Service;  
15 -import org.springframework.validation.annotation.Validated;  
16 -  
17 -import javax.annotation.Resource;  
18 -import java.util.Collections;  
19 -import java.util.List;  
20 -  
21 -import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.getSumValue;  
22 -import static cn.iocoder.yudao.module.promotion.enums.ErrorCodeConstants.COUPON_VALID_TIME_NOT_NOW;  
23 -  
24 -/**  
25 - * 价格计算 Service 实现类  
26 - *  
27 - * 优惠计算顺序:min(限时折扣, 会员折扣) > 满减送 > 优惠券。  
28 - * 参考文档:  
29 - * 1. <a href="https://help.youzan.com/displaylist/detail_4_4-1-60384">有赞文档:限时折扣、满减送、优惠券哪个优先计算?</a>  
30 - *  
31 - * TODO 芋艿:进一步完善  
32 - * 1. 限时折扣:指定金额、减免金额、折扣  
33 - * 2. 满减送:循环、折扣  
34 - * 3. 优惠劵:待定  
35 - *  
36 - * @author 芋道源码  
37 - */  
38 -@Service  
39 -@Validated  
40 -@Slf4j  
41 -public class PriceServiceImpl implements PriceService {  
42 -  
43 - @Resource  
44 - private CouponService couponService;  
45 -  
46 - @Override  
47 - public List<CouponMeetRespDTO> getMeetCouponList(PriceCalculateReqDTO calculateReqDTO) {  
48 - // 先计算一轮价格  
49 -// PriceCalculateRespDTO priceCalculate = calculatePrice(calculateReqDTO);  
50 - PriceCalculateRespDTO priceCalculate = null;  
51 -  
52 - // 获得用户的待使用优惠劵  
53 - List<CouponDO> couponList = couponService.getCouponList(calculateReqDTO.getUserId(), CouponStatusEnum.UNUSED.getStatus());  
54 - if (CollUtil.isEmpty(couponList)) {  
55 - return Collections.emptyList();  
56 - }  
57 -  
58 - // 获得优惠劵的匹配信息  
59 - return CollectionUtils.convertList(couponList, coupon -> {  
60 - CouponMeetRespDTO couponMeetRespDTO = PriceConvert.INSTANCE.convert(coupon);  
61 - try {  
62 - // 校验优惠劵  
63 - couponService.validCoupon(coupon);  
64 -  
65 - // 获得匹配的商品 SKU 数组  
66 - // TODO 芋艿:后续处理  
67 -// List<PriceCalculateRespDTO.OrderItem> orderItems = getMatchCouponOrderItems(priceCalculate, coupon);  
68 - List<PriceCalculateRespDTO.OrderItem> orderItems = null;  
69 - if (CollUtil.isEmpty(orderItems)) {  
70 - return couponMeetRespDTO.setMeet(false).setMeetTip("所结算商品没有符合条件的商品");  
71 - }  
72 -  
73 - // 计算是否满足优惠劵的使用金额  
74 - Integer originPrice = getSumValue(orderItems, PriceCalculateRespDTO.OrderItem::getOrderDividePrice, Integer::sum);  
75 - assert originPrice != null;  
76 - if (originPrice < coupon.getUsePrice()) {  
77 - return couponMeetRespDTO.setMeet(false)  
78 -// .setMeetTip(String.format("差 %s 元可用优惠劵", formatPrice(coupon.getUsePrice() - originPrice)));  
79 - .setMeetTip("所结算的商品中未满足使用的金额");  
80 - }  
81 - } catch (ServiceException serviceException) {  
82 - couponMeetRespDTO.setMeet(false);  
83 - if (serviceException.getCode().equals(COUPON_VALID_TIME_NOT_NOW.getCode())) {  
84 - couponMeetRespDTO.setMeetTip("优惠劵未到使用时间");  
85 - } else {  
86 - log.error("[getMeetCouponList][calculateReqDTO({}) 获得优惠劵匹配信息异常]", calculateReqDTO, serviceException);  
87 - couponMeetRespDTO.setMeetTip("优惠劵不满足使用条件");  
88 - }  
89 - return couponMeetRespDTO;  
90 - }  
91 - // 满足  
92 - return couponMeetRespDTO.setMeet(true);  
93 - });  
94 - }  
95 -  
96 -}  
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/seckill/SeckillActivityServiceImpl.java
@@ -123,8 +123,8 @@ public class SeckillActivityServiceImpl implements SeckillActivityService { @@ -123,8 +123,8 @@ public class SeckillActivityServiceImpl implements SeckillActivityService {
123 } 123 }
124 124
125 // 2. 校验商品 sku 都存在 125 // 2. 校验商品 sku 都存在
126 - Map<Long, ProductSkuRespDTO> skuMap = convertMap(productSkuApi.getSkuListBySpuId(singletonList(spuId)),  
127 - ProductSkuRespDTO::getId); 126 + List<ProductSkuRespDTO> skus = productSkuApi.getSkuListBySpuId(singletonList(spuId));
  127 + Map<Long, ProductSkuRespDTO> skuMap = convertMap(skus, ProductSkuRespDTO::getId);
128 products.forEach(product -> { 128 products.forEach(product -> {
129 if (!skuMap.containsKey(product.getSkuId())) { 129 if (!skuMap.containsKey(product.getSkuId())) {
130 throw exception(SKU_NOT_EXISTS); 130 throw exception(SKU_NOT_EXISTS);
yudao-module-mall/yudao-module-promotion-biz/src/test/java/cn/iocoder/yudao/module/promotion/service/discount/DiscountActivityServiceImplTest.java
@@ -138,7 +138,7 @@ public class DiscountActivityServiceImplTest extends BaseDbUnitTest { @@ -138,7 +138,7 @@ public class DiscountActivityServiceImplTest extends BaseDbUnitTest {
138 Long id = dbDiscountActivity.getId(); 138 Long id = dbDiscountActivity.getId();
139 139
140 // 调用 140 // 调用
141 - discountActivityService.closeRewardActivity(id); 141 + discountActivityService.closeDiscountActivity(id);
142 // 校验状态 142 // 校验状态
143 DiscountActivityDO discountActivity = discountActivityMapper.selectById(id); 143 DiscountActivityDO discountActivity = discountActivityMapper.selectById(id);
144 assertEquals(discountActivity.getStatus(), PromotionActivityStatusEnum.CLOSE.getStatus()); 144 assertEquals(discountActivity.getStatus(), PromotionActivityStatusEnum.CLOSE.getStatus());
yudao-module-mall/yudao-module-promotion-biz/src/test/java/cn/iocoder/yudao/module/promotion/service/price/PriceServiceTest.java deleted
1 -package cn.iocoder.yudao.module.promotion.service.price;  
2 -  
3 -import cn.iocoder.yudao.framework.common.exception.ServiceException;  
4 -import cn.iocoder.yudao.framework.test.core.ut.BaseMockitoUnitTest;  
5 -import cn.iocoder.yudao.module.product.api.sku.ProductSkuApi;  
6 -import cn.iocoder.yudao.module.product.api.sku.dto.ProductSkuRespDTO;  
7 -import cn.iocoder.yudao.module.promotion.api.price.dto.CouponMeetRespDTO;  
8 -import cn.iocoder.yudao.module.promotion.api.price.dto.PriceCalculateReqDTO;  
9 -import cn.iocoder.yudao.module.promotion.dal.dataobject.coupon.CouponDO;  
10 -import cn.iocoder.yudao.module.promotion.enums.common.PromotionProductScopeEnum;  
11 -import cn.iocoder.yudao.module.promotion.enums.coupon.CouponStatusEnum;  
12 -import cn.iocoder.yudao.module.promotion.service.coupon.CouponService;  
13 -import cn.iocoder.yudao.module.promotion.service.reward.RewardActivityService;  
14 -import org.junit.jupiter.api.Test;  
15 -import org.mockito.InjectMocks;  
16 -import org.mockito.Mock;  
17 -  
18 -import java.util.List;  
19 -  
20 -import static cn.iocoder.yudao.framework.common.util.collection.SetUtils.asSet;  
21 -import static cn.iocoder.yudao.framework.test.core.util.AssertUtils.assertPojoEquals;  
22 -import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.randomPojo;  
23 -import static cn.iocoder.yudao.module.promotion.enums.ErrorCodeConstants.COUPON_VALID_TIME_NOT_NOW;  
24 -import static java.util.Arrays.asList;  
25 -import static java.util.Collections.singletonList;  
26 -import static org.junit.jupiter.api.Assertions.*;  
27 -import static org.mockito.ArgumentMatchers.eq;  
28 -import static org.mockito.Mockito.doThrow;  
29 -import static org.mockito.Mockito.when;  
30 -  
31 -/**  
32 - * {@link PriceServiceImpl} 的单元测试  
33 - *  
34 - * @author 芋道源码  
35 - */  
36 -public class PriceServiceTest extends BaseMockitoUnitTest {  
37 -  
38 - @InjectMocks  
39 - private PriceServiceImpl priceService;  
40 -  
41 - @Mock  
42 - private RewardActivityService rewardActivityService;  
43 - @Mock  
44 - private CouponService couponService;  
45 - @Mock  
46 - private ProductSkuApi productSkuApi;  
47 -  
48 - /**  
49 - * 测试满减送活动,不匹配的情况  
50 - */  
51 - @Test  
52 - public void testCalculatePrice_rewardActivityNotMeet() {  
53 -  
54 - }  
55 -  
56 - @Test  
57 - public void testGetMeetCouponList() {  
58 - // 准备参数  
59 - PriceCalculateReqDTO calculateReqDTO = new PriceCalculateReqDTO().setUserId(1024L)  
60 - .setItems(singletonList(new PriceCalculateReqDTO.Item().setSkuId(10L).setCount(2)));  
61 - // mock 方法(商品 SKU 信息)  
62 - ProductSkuRespDTO productSku = randomPojo(ProductSkuRespDTO.class, o -> o.setId(10L).setPrice(100));  
63 - when(productSkuApi.getSkuList(eq(asSet(10L)))).thenReturn(singletonList(productSku));  
64 - // mock 方法(情况一:优惠劵未到使用时间)  
65 - CouponDO coupon01 = randomPojo(CouponDO.class);  
66 - doThrow(new ServiceException(COUPON_VALID_TIME_NOT_NOW)).when(couponService).validCoupon(coupon01);  
67 - // mock 方法(情况二:所结算商品没有符合条件的商品)  
68 - CouponDO coupon02 = randomPojo(CouponDO.class);  
69 - // mock 方法(情况三:使用金额不足)  
70 - CouponDO coupon03 = randomPojo(CouponDO.class, o -> o.setProductScope(PromotionProductScopeEnum.ALL.getScope())  
71 - .setUsePrice(300));  
72 - // mock 方法(情况五:满足条件)  
73 - CouponDO coupon04 = randomPojo(CouponDO.class, o -> o.setProductScope(PromotionProductScopeEnum.ALL.getScope())  
74 - .setUsePrice(190));  
75 - // mock 方法(获得用户的待使用优惠劵)  
76 - when(couponService.getCouponList(eq(1024L), eq(CouponStatusEnum.UNUSED.getStatus())))  
77 - .thenReturn(asList(coupon01, coupon02, coupon03, coupon04));  
78 - // 调用  
79 - List<CouponMeetRespDTO> list = priceService.getMeetCouponList(calculateReqDTO);  
80 - // 断言  
81 - assertEquals(list.size(), 4);  
82 - // 断言情况一:优惠劵未到使用时间  
83 - CouponMeetRespDTO couponMeetRespDTO01 = list.get(0);  
84 - assertPojoEquals(couponMeetRespDTO01, coupon01);  
85 - assertFalse(couponMeetRespDTO01.getMeet());  
86 - assertEquals(couponMeetRespDTO01.getMeetTip(), "优惠劵未到使用时间");  
87 - // 断言情况二:所结算商品没有符合条件的商品  
88 - CouponMeetRespDTO couponMeetRespDTO02 = list.get(1);  
89 - assertPojoEquals(couponMeetRespDTO02, coupon02);  
90 - assertFalse(couponMeetRespDTO02.getMeet());  
91 - assertEquals(couponMeetRespDTO02.getMeetTip(), "所结算商品没有符合条件的商品");  
92 - // 断言情况三:差 %s 元可用优惠劵  
93 - CouponMeetRespDTO couponMeetRespDTO03 = list.get(2);  
94 - assertPojoEquals(couponMeetRespDTO03, coupon03);  
95 - assertFalse(couponMeetRespDTO03.getMeet());  
96 - assertEquals(couponMeetRespDTO03.getMeetTip(), "所结算的商品中未满足使用的金额");  
97 - // 断言情况四:满足条件  
98 - CouponMeetRespDTO couponMeetRespDTO04 = list.get(3);  
99 - assertPojoEquals(couponMeetRespDTO04, coupon04);  
100 - assertTrue(couponMeetRespDTO04.getMeet());  
101 - assertNull(couponMeetRespDTO04.getMeetTip());  
102 - }  
103 -  
104 -}  
yudao-module-mall/yudao-module-statistics-biz/pom.xml
@@ -58,7 +58,6 @@ @@ -58,7 +58,6 @@
58 <groupId>cn.iocoder.boot</groupId> 58 <groupId>cn.iocoder.boot</groupId>
59 <artifactId>yudao-spring-boot-starter-biz-tenant</artifactId> 59 <artifactId>yudao-spring-boot-starter-biz-tenant</artifactId>
60 </dependency> 60 </dependency>
61 -  
62 <dependency> 61 <dependency>
63 <groupId>cn.iocoder.boot</groupId> 62 <groupId>cn.iocoder.boot</groupId>
64 <artifactId>yudao-spring-boot-starter-biz-ip</artifactId> 63 <artifactId>yudao-spring-boot-starter-biz-ip</artifactId>
yudao-module-mall/yudao-module-statistics-biz/src/main/java/cn/iocoder/yudao/module/statistics/dal/dataobject/member/MemberStatisticsDO.java
1 package cn.iocoder.yudao.module.statistics.dal.dataobject.member; 1 package cn.iocoder.yudao.module.statistics.dal.dataobject.member;
2 2
3 -import cn.iocoder.yudao.framework.tenant.core.db.TenantBaseDO; 3 +import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
4 import com.baomidou.mybatisplus.annotation.KeySequence; 4 import com.baomidou.mybatisplus.annotation.KeySequence;
5 import com.baomidou.mybatisplus.annotation.TableId; 5 import com.baomidou.mybatisplus.annotation.TableId;
6 import com.baomidou.mybatisplus.annotation.TableName; 6 import com.baomidou.mybatisplus.annotation.TableName;
@@ -23,7 +23,7 @@ import java.time.LocalDateTime; @@ -23,7 +23,7 @@ import java.time.LocalDateTime;
23 @Builder 23 @Builder
24 @NoArgsConstructor 24 @NoArgsConstructor
25 @AllArgsConstructor 25 @AllArgsConstructor
26 -public class MemberStatisticsDO extends TenantBaseDO { 26 +public class MemberStatisticsDO extends BaseDO {
27 27
28 /** 28 /**
29 * 编号,主键自增 29 * 编号,主键自增
yudao-module-mall/yudao-module-statistics-biz/src/main/java/cn/iocoder/yudao/module/statistics/dal/dataobject/trade/TradeStatisticsDO.java
1 package cn.iocoder.yudao.module.statistics.dal.dataobject.trade; 1 package cn.iocoder.yudao.module.statistics.dal.dataobject.trade;
2 2
3 -import cn.iocoder.yudao.framework.tenant.core.db.TenantBaseDO; 3 +import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
4 import com.baomidou.mybatisplus.annotation.KeySequence; 4 import com.baomidou.mybatisplus.annotation.KeySequence;
5 import com.baomidou.mybatisplus.annotation.TableId; 5 import com.baomidou.mybatisplus.annotation.TableId;
6 import com.baomidou.mybatisplus.annotation.TableName; 6 import com.baomidou.mybatisplus.annotation.TableName;
@@ -23,7 +23,7 @@ import java.time.LocalDateTime; @@ -23,7 +23,7 @@ import java.time.LocalDateTime;
23 @Builder 23 @Builder
24 @NoArgsConstructor 24 @NoArgsConstructor
25 @AllArgsConstructor 25 @AllArgsConstructor
26 -public class TradeStatisticsDO extends TenantBaseDO { 26 +public class TradeStatisticsDO extends BaseDO {
27 27
28 /** 28 /**
29 * 编号,主键自增 29 * 编号,主键自增
yudao-module-mall/yudao-module-statistics-biz/src/main/java/cn/iocoder/yudao/module/statistics/service/pay/PayWalletStatisticsServiceImpl.java
1 package cn.iocoder.yudao.module.statistics.service.pay; 1 package cn.iocoder.yudao.module.statistics.service.pay;
2 2
3 -import cn.iocoder.yudao.module.pay.enums.member.PayWalletBizTypeEnum; 3 +import cn.iocoder.yudao.module.pay.enums.wallet.PayWalletBizTypeEnum;
4 import cn.iocoder.yudao.module.pay.enums.order.PayOrderStatusEnum; 4 import cn.iocoder.yudao.module.pay.enums.order.PayOrderStatusEnum;
5 import cn.iocoder.yudao.module.pay.enums.refund.PayRefundStatusEnum; 5 import cn.iocoder.yudao.module.pay.enums.refund.PayRefundStatusEnum;
6 import cn.iocoder.yudao.module.statistics.dal.mysql.pay.PayWalletStatisticsMapper; 6 import cn.iocoder.yudao.module.statistics.dal.mysql.pay.PayWalletStatisticsMapper;
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/brokerage/BrokerageUserController.java
@@ -77,6 +77,7 @@ public class BrokerageUserController { @@ -77,6 +77,7 @@ public class BrokerageUserController {
77 @PreAuthorize("@ss.hasPermission('trade:brokerage-user:query')") 77 @PreAuthorize("@ss.hasPermission('trade:brokerage-user:query')")
78 public CommonResult<BrokerageUserRespVO> getBrokerageUser(@RequestParam("id") Long id) { 78 public CommonResult<BrokerageUserRespVO> getBrokerageUser(@RequestParam("id") Long id) {
79 BrokerageUserDO brokerageUser = brokerageUserService.getBrokerageUser(id); 79 BrokerageUserDO brokerageUser = brokerageUserService.getBrokerageUser(id);
  80 + // TODO @疯狂:是不是搞成一个统一的 convert?
80 BrokerageUserRespVO respVO = BrokerageUserConvert.INSTANCE.convert(brokerageUser); 81 BrokerageUserRespVO respVO = BrokerageUserConvert.INSTANCE.convert(brokerageUser);
81 return success(BrokerageUserConvert.INSTANCE.copyTo(memberUserApi.getUser(id), respVO)); 82 return success(BrokerageUserConvert.INSTANCE.copyTo(memberUserApi.getUser(id), respVO));
82 } 83 }
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/convert/order/TradeOrderConvert.java
@@ -7,7 +7,7 @@ import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils; @@ -7,7 +7,7 @@ import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils;
7 import cn.iocoder.yudao.framework.common.util.string.StrUtils; 7 import cn.iocoder.yudao.framework.common.util.string.StrUtils;
8 import cn.iocoder.yudao.framework.dict.core.util.DictFrameworkUtils; 8 import cn.iocoder.yudao.framework.dict.core.util.DictFrameworkUtils;
9 import cn.iocoder.yudao.framework.ip.core.utils.AreaUtils; 9 import cn.iocoder.yudao.framework.ip.core.utils.AreaUtils;
10 -import cn.iocoder.yudao.module.member.api.address.dto.AddressRespDTO; 10 +import cn.iocoder.yudao.module.member.api.address.dto.MemberAddressRespDTO;
11 import cn.iocoder.yudao.module.member.api.user.dto.MemberUserRespDTO; 11 import cn.iocoder.yudao.module.member.api.user.dto.MemberUserRespDTO;
12 import cn.iocoder.yudao.module.pay.api.order.dto.PayOrderCreateReqDTO; 12 import cn.iocoder.yudao.module.pay.api.order.dto.PayOrderCreateReqDTO;
13 import cn.iocoder.yudao.module.pay.enums.DictTypeConstants; 13 import cn.iocoder.yudao.module.pay.enums.DictTypeConstants;
@@ -241,7 +241,7 @@ public interface TradeOrderConvert { @@ -241,7 +241,7 @@ public interface TradeOrderConvert {
241 return reqBO; 241 return reqBO;
242 } 242 }
243 243
244 - default AppTradeOrderSettlementRespVO convert(TradePriceCalculateRespBO calculate, AddressRespDTO address) { 244 + default AppTradeOrderSettlementRespVO convert(TradePriceCalculateRespBO calculate, MemberAddressRespDTO address) {
245 AppTradeOrderSettlementRespVO respVO = convert0(calculate, address); 245 AppTradeOrderSettlementRespVO respVO = convert0(calculate, address);
246 if (address != null) { 246 if (address != null) {
247 respVO.getAddress().setAreaName(AreaUtils.format(address.getAreaId())); 247 respVO.getAddress().setAreaName(AreaUtils.format(address.getAreaId()));
@@ -249,7 +249,7 @@ public interface TradeOrderConvert { @@ -249,7 +249,7 @@ public interface TradeOrderConvert {
249 return respVO; 249 return respVO;
250 } 250 }
251 251
252 - AppTradeOrderSettlementRespVO convert0(TradePriceCalculateRespBO calculate, AddressRespDTO address); 252 + AppTradeOrderSettlementRespVO convert0(TradePriceCalculateRespBO calculate, MemberAddressRespDTO address);
253 253
254 List<AppOrderExpressTrackRespDTO> convertList02(List<ExpressTrackRespDTO> list); 254 List<AppOrderExpressTrackRespDTO> convertList02(List<ExpressTrackRespDTO> list);
255 255
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/brokerage/BrokerageUserServiceImpl.java
@@ -232,7 +232,8 @@ public class BrokerageUserServiceImpl implements BrokerageUserService { @@ -232,7 +232,8 @@ public class BrokerageUserServiceImpl implements BrokerageUserService {
232 return PageResult.empty(); 232 return PageResult.empty();
233 } 233 }
234 // 1.2 根据昵称过滤下级用户 234 // 1.2 根据昵称过滤下级用户
235 - Map<Long, MemberUserRespDTO> userMap = convertMapByFilter(memberUserApi.getUserList(childIds), 235 + List<MemberUserRespDTO> users = memberUserApi.getUserList(childIds);
  236 + Map<Long, MemberUserRespDTO> userMap = convertMapByFilter(users,
236 user -> StrUtil.contains(user.getNickname(), pageReqVO.getNickname()), 237 user -> StrUtil.contains(user.getNickname(), pageReqVO.getNickname()),
237 MemberUserRespDTO::getId); 238 MemberUserRespDTO::getId);
238 if (CollUtil.isEmpty(userMap)) { 239 if (CollUtil.isEmpty(userMap)) {
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/order/TradeOrderUpdateServiceImpl.java
@@ -11,8 +11,8 @@ import cn.iocoder.yudao.framework.common.core.KeyValue; @@ -11,8 +11,8 @@ import cn.iocoder.yudao.framework.common.core.KeyValue;
11 import cn.iocoder.yudao.framework.common.enums.UserTypeEnum; 11 import cn.iocoder.yudao.framework.common.enums.UserTypeEnum;
12 import cn.iocoder.yudao.framework.common.util.json.JsonUtils; 12 import cn.iocoder.yudao.framework.common.util.json.JsonUtils;
13 import cn.iocoder.yudao.framework.common.util.number.MoneyUtils; 13 import cn.iocoder.yudao.framework.common.util.number.MoneyUtils;
14 -import cn.iocoder.yudao.module.member.api.address.AddressApi;  
15 -import cn.iocoder.yudao.module.member.api.address.dto.AddressRespDTO; 14 +import cn.iocoder.yudao.module.member.api.address.MemberAddressApi;
  15 +import cn.iocoder.yudao.module.member.api.address.dto.MemberAddressRespDTO;
16 import cn.iocoder.yudao.module.pay.api.order.PayOrderApi; 16 import cn.iocoder.yudao.module.pay.api.order.PayOrderApi;
17 import cn.iocoder.yudao.module.pay.api.order.dto.PayOrderCreateReqDTO; 17 import cn.iocoder.yudao.module.pay.api.order.dto.PayOrderCreateReqDTO;
18 import cn.iocoder.yudao.module.pay.api.order.dto.PayOrderRespDTO; 18 import cn.iocoder.yudao.module.pay.api.order.dto.PayOrderRespDTO;
@@ -98,7 +98,7 @@ public class TradeOrderUpdateServiceImpl implements TradeOrderUpdateService { @@ -98,7 +98,7 @@ public class TradeOrderUpdateServiceImpl implements TradeOrderUpdateService {
98 @Resource 98 @Resource
99 private PayOrderApi payOrderApi; 99 private PayOrderApi payOrderApi;
100 @Resource 100 @Resource
101 - private AddressApi addressApi; 101 + private MemberAddressApi addressApi;
102 @Resource 102 @Resource
103 private ProductCommentApi productCommentApi; 103 private ProductCommentApi productCommentApi;
104 104
@@ -110,7 +110,7 @@ public class TradeOrderUpdateServiceImpl implements TradeOrderUpdateService { @@ -110,7 +110,7 @@ public class TradeOrderUpdateServiceImpl implements TradeOrderUpdateService {
110 @Override 110 @Override
111 public AppTradeOrderSettlementRespVO settlementOrder(Long userId, AppTradeOrderSettlementReqVO settlementReqVO) { 111 public AppTradeOrderSettlementRespVO settlementOrder(Long userId, AppTradeOrderSettlementReqVO settlementReqVO) {
112 // 1. 获得收货地址 112 // 1. 获得收货地址
113 - AddressRespDTO address = getAddress(userId, settlementReqVO.getAddressId()); 113 + MemberAddressRespDTO address = getAddress(userId, settlementReqVO.getAddressId());
114 if (address != null) { 114 if (address != null) {
115 settlementReqVO.setAddressId(address.getId()); 115 settlementReqVO.setAddressId(address.getId());
116 } 116 }
@@ -129,7 +129,7 @@ public class TradeOrderUpdateServiceImpl implements TradeOrderUpdateService { @@ -129,7 +129,7 @@ public class TradeOrderUpdateServiceImpl implements TradeOrderUpdateService {
129 * @param addressId 地址编号 129 * @param addressId 地址编号
130 * @return 地址 130 * @return 地址
131 */ 131 */
132 - private AddressRespDTO getAddress(Long userId, Long addressId) { 132 + private MemberAddressRespDTO getAddress(Long userId, Long addressId) {
133 if (addressId != null) { 133 if (addressId != null) {
134 return addressApi.getAddress(addressId, userId); 134 return addressApi.getAddress(addressId, userId);
135 } 135 }
@@ -193,7 +193,7 @@ public class TradeOrderUpdateServiceImpl implements TradeOrderUpdateService { @@ -193,7 +193,7 @@ public class TradeOrderUpdateServiceImpl implements TradeOrderUpdateService {
193 // 物流信息 193 // 物流信息
194 order.setDeliveryType(createReqVO.getDeliveryType()); 194 order.setDeliveryType(createReqVO.getDeliveryType());
195 if (Objects.equals(createReqVO.getDeliveryType(), DeliveryTypeEnum.EXPRESS.getType())) { 195 if (Objects.equals(createReqVO.getDeliveryType(), DeliveryTypeEnum.EXPRESS.getType())) {
196 - AddressRespDTO address = addressApi.getAddress(createReqVO.getAddressId(), userId); 196 + MemberAddressRespDTO address = addressApi.getAddress(createReqVO.getAddressId(), userId);
197 Assert.notNull(address, "地址({}) 不能为空", createReqVO.getAddressId()); // 价格计算时,已经计算 197 Assert.notNull(address, "地址({}) 不能为空", createReqVO.getAddressId()); // 价格计算时,已经计算
198 order.setReceiverName(address.getName()).setReceiverMobile(address.getMobile()) 198 order.setReceiverName(address.getName()).setReceiverMobile(address.getMobile())
199 .setReceiverAreaId(address.getAreaId()).setReceiverDetailAddress(address.getDetailAddress()); 199 .setReceiverAreaId(address.getAreaId()).setReceiverDetailAddress(address.getDetailAddress());
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/price/calculator/TradeDeliveryPriceCalculator.java
@@ -4,8 +4,8 @@ import cn.hutool.core.collection.CollUtil; @@ -4,8 +4,8 @@ import cn.hutool.core.collection.CollUtil;
4 import cn.hutool.core.lang.Assert; 4 import cn.hutool.core.lang.Assert;
5 import cn.hutool.core.util.StrUtil; 5 import cn.hutool.core.util.StrUtil;
6 import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; 6 import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
7 -import cn.iocoder.yudao.module.member.api.address.AddressApi;  
8 -import cn.iocoder.yudao.module.member.api.address.dto.AddressRespDTO; 7 +import cn.iocoder.yudao.module.member.api.address.MemberAddressApi;
  8 +import cn.iocoder.yudao.module.member.api.address.dto.MemberAddressRespDTO;
9 import cn.iocoder.yudao.module.trade.dal.dataobject.config.TradeConfigDO; 9 import cn.iocoder.yudao.module.trade.dal.dataobject.config.TradeConfigDO;
10 import cn.iocoder.yudao.module.trade.dal.dataobject.delivery.DeliveryPickUpStoreDO; 10 import cn.iocoder.yudao.module.trade.dal.dataobject.delivery.DeliveryPickUpStoreDO;
11 import cn.iocoder.yudao.module.trade.enums.delivery.DeliveryExpressChargeModeEnum; 11 import cn.iocoder.yudao.module.trade.enums.delivery.DeliveryExpressChargeModeEnum;
@@ -41,7 +41,7 @@ import static cn.iocoder.yudao.module.trade.enums.ErrorCodeConstants.*; @@ -41,7 +41,7 @@ import static cn.iocoder.yudao.module.trade.enums.ErrorCodeConstants.*;
41 public class TradeDeliveryPriceCalculator implements TradePriceCalculator { 41 public class TradeDeliveryPriceCalculator implements TradePriceCalculator {
42 42
43 @Resource 43 @Resource
44 - private AddressApi addressApi; 44 + private MemberAddressApi addressApi;
45 45
46 @Resource 46 @Resource
47 private DeliveryPickUpStoreService deliveryPickUpStoreService; 47 private DeliveryPickUpStoreService deliveryPickUpStoreService;
@@ -81,7 +81,7 @@ public class TradeDeliveryPriceCalculator implements TradePriceCalculator { @@ -81,7 +81,7 @@ public class TradeDeliveryPriceCalculator implements TradePriceCalculator {
81 // 价格计算时,如果为空就不算~最终下单,会校验该字段不允许空 81 // 价格计算时,如果为空就不算~最终下单,会校验该字段不允许空
82 return; 82 return;
83 } 83 }
84 - AddressRespDTO address = addressApi.getAddress(param.getAddressId(), param.getUserId()); 84 + MemberAddressRespDTO address = addressApi.getAddress(param.getAddressId(), param.getUserId());
85 Assert.notNull(address, "收件人({})的地址,不能为空", param.getUserId()); 85 Assert.notNull(address, "收件人({})的地址,不能为空", param.getUserId());
86 86
87 // 情况一:全局包邮 87 // 情况一:全局包邮
yudao-module-mall/yudao-module-trade-biz/src/test/java/cn/iocoder/yudao/module/trade/service/order/TradeOrderUpdateServiceTest.java
1 package cn.iocoder.yudao.module.trade.service.order; 1 package cn.iocoder.yudao.module.trade.service.order;
2 2
3 -import cn.iocoder.yudao.framework.common.enums.TerminalEnum;  
4 import cn.iocoder.yudao.framework.test.core.ut.BaseDbUnitTest; 3 import cn.iocoder.yudao.framework.test.core.ut.BaseDbUnitTest;
5 -import cn.iocoder.yudao.module.member.api.address.AddressApi;  
6 -import cn.iocoder.yudao.module.member.api.address.dto.AddressRespDTO; 4 +import cn.iocoder.yudao.module.member.api.address.MemberAddressApi;
7 import cn.iocoder.yudao.module.member.api.user.MemberUserApi; 5 import cn.iocoder.yudao.module.member.api.user.MemberUserApi;
8 import cn.iocoder.yudao.module.pay.api.order.PayOrderApi; 6 import cn.iocoder.yudao.module.pay.api.order.PayOrderApi;
9 import cn.iocoder.yudao.module.pay.api.order.dto.PayOrderRespDTO; 7 import cn.iocoder.yudao.module.pay.api.order.dto.PayOrderRespDTO;
10 import cn.iocoder.yudao.module.pay.enums.order.PayOrderStatusEnum; 8 import cn.iocoder.yudao.module.pay.enums.order.PayOrderStatusEnum;
11 -import cn.iocoder.yudao.module.product.api.property.dto.ProductPropertyValueDetailRespDTO;  
12 import cn.iocoder.yudao.module.product.api.sku.ProductSkuApi; 9 import cn.iocoder.yudao.module.product.api.sku.ProductSkuApi;
13 -import cn.iocoder.yudao.module.product.api.sku.dto.ProductSkuRespDTO;  
14 import cn.iocoder.yudao.module.product.api.spu.ProductSpuApi; 10 import cn.iocoder.yudao.module.product.api.spu.ProductSpuApi;
15 -import cn.iocoder.yudao.module.product.api.spu.dto.ProductSpuRespDTO;  
16 -import cn.iocoder.yudao.module.product.enums.spu.ProductSpuStatusEnum;  
17 import cn.iocoder.yudao.module.promotion.api.coupon.CouponApi; 11 import cn.iocoder.yudao.module.promotion.api.coupon.CouponApi;
18 -import cn.iocoder.yudao.module.promotion.api.price.PriceApi;  
19 -import cn.iocoder.yudao.module.promotion.api.price.dto.PriceCalculateRespDTO;  
20 import cn.iocoder.yudao.module.trade.controller.admin.order.vo.TradeOrderDeliveryReqVO; 12 import cn.iocoder.yudao.module.trade.controller.admin.order.vo.TradeOrderDeliveryReqVO;
21 -import cn.iocoder.yudao.module.trade.controller.app.order.vo.AppTradeOrderCreateReqVO;  
22 import cn.iocoder.yudao.module.trade.dal.dataobject.order.TradeOrderDO; 13 import cn.iocoder.yudao.module.trade.dal.dataobject.order.TradeOrderDO;
23 -import cn.iocoder.yudao.module.trade.dal.dataobject.order.TradeOrderItemDO;  
24 import cn.iocoder.yudao.module.trade.dal.mysql.order.TradeOrderItemMapper; 14 import cn.iocoder.yudao.module.trade.dal.mysql.order.TradeOrderItemMapper;
25 import cn.iocoder.yudao.module.trade.dal.mysql.order.TradeOrderMapper; 15 import cn.iocoder.yudao.module.trade.dal.mysql.order.TradeOrderMapper;
26 -import cn.iocoder.yudao.module.trade.enums.order.TradeOrderItemAfterSaleStatusEnum;  
27 -import cn.iocoder.yudao.module.trade.enums.order.TradeOrderRefundStatusEnum;  
28 import cn.iocoder.yudao.module.trade.enums.order.TradeOrderStatusEnum; 16 import cn.iocoder.yudao.module.trade.enums.order.TradeOrderStatusEnum;
29 -import cn.iocoder.yudao.module.trade.enums.order.TradeOrderTypeEnum;  
30 import cn.iocoder.yudao.module.trade.framework.order.config.TradeOrderConfig; 17 import cn.iocoder.yudao.module.trade.framework.order.config.TradeOrderConfig;
31 import cn.iocoder.yudao.module.trade.framework.order.config.TradeOrderProperties; 18 import cn.iocoder.yudao.module.trade.framework.order.config.TradeOrderProperties;
32 import org.junit.jupiter.api.BeforeEach; 19 import org.junit.jupiter.api.BeforeEach;
@@ -36,17 +23,11 @@ import org.springframework.context.annotation.Import; @@ -36,17 +23,11 @@ import org.springframework.context.annotation.Import;
36 23
37 import javax.annotation.Resource; 24 import javax.annotation.Resource;
38 import java.time.Duration; 25 import java.time.Duration;
39 -import java.util.Arrays;  
40 -import java.util.List;  
41 26
42 -import static cn.iocoder.yudao.framework.common.util.collection.SetUtils.asSet;  
43 import static cn.iocoder.yudao.framework.test.core.util.AssertUtils.assertPojoEquals; 27 import static cn.iocoder.yudao.framework.test.core.util.AssertUtils.assertPojoEquals;
44 import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.randomPojo; 28 import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.randomPojo;
45 -import static java.util.Collections.singletonList;  
46 import static org.junit.jupiter.api.Assertions.*; 29 import static org.junit.jupiter.api.Assertions.*;
47 -import static org.mockito.ArgumentMatchers.argThat;  
48 import static org.mockito.ArgumentMatchers.eq; 30 import static org.mockito.ArgumentMatchers.eq;
49 -import static org.mockito.Mockito.verify;  
50 import static org.mockito.Mockito.when; 31 import static org.mockito.Mockito.when;
51 32
52 /** 33 /**
@@ -72,12 +53,12 @@ public class TradeOrderUpdateServiceTest extends BaseDbUnitTest { @@ -72,12 +53,12 @@ public class TradeOrderUpdateServiceTest extends BaseDbUnitTest {
72 private ProductSpuApi productSpuApi; 53 private ProductSpuApi productSpuApi;
73 @MockBean 54 @MockBean
74 private ProductSkuApi productSkuApi; 55 private ProductSkuApi productSkuApi;
75 - @MockBean  
76 - private PriceApi priceApi; 56 +// @MockBean
  57 +// private PriceApi priceApi;
77 @MockBean 58 @MockBean
78 private PayOrderApi payOrderApi; 59 private PayOrderApi payOrderApi;
79 @MockBean 60 @MockBean
80 - private AddressApi addressApi; 61 + private MemberAddressApi addressApi;
81 @MockBean 62 @MockBean
82 private CouponApi couponApi; 63 private CouponApi couponApi;
83 64
@@ -90,159 +71,159 @@ public class TradeOrderUpdateServiceTest extends BaseDbUnitTest { @@ -90,159 +71,159 @@ public class TradeOrderUpdateServiceTest extends BaseDbUnitTest {
90 when(tradeOrderProperties.getPayExpireTime()).thenReturn(Duration.ofDays(1)); 71 when(tradeOrderProperties.getPayExpireTime()).thenReturn(Duration.ofDays(1));
91 } 72 }
92 73
93 - @Test  
94 - public void testCreateTradeOrder_success() {  
95 - // 准备参数  
96 - Long userId = 100L;  
97 - String userIp = "127.0.0.1";  
98 -// AppTradeOrderCreateReqVO reqVO = new AppTradeOrderCreateReqVO()  
99 -// .setAddressId(10L).setCouponId(101L).setRemark("我是备注").setFromCart(true)  
100 -// .setItems(Arrays.asList(new AppTradeOrderCreateReqVO.Item().setSkuId(1L).setCount(3),  
101 -// new AppTradeOrderCreateReqVO.Item().setSkuId(2L).setCount(4)));  
102 - AppTradeOrderCreateReqVO reqVO = null;  
103 - // TODO 芋艿:重新高下  
104 - // mock 方法(商品 SKU 检查)  
105 - ProductSkuRespDTO sku01 = randomPojo(ProductSkuRespDTO.class, o -> o.setId(1L).setSpuId(11L)  
106 - .setPrice(50).setStock(100)  
107 - .setProperties(singletonList(new ProductPropertyValueDetailRespDTO().setPropertyId(111L).setValueId(222L))));  
108 - ProductSkuRespDTO sku02 = randomPojo(ProductSkuRespDTO.class, o -> o.setId(2L).setSpuId(21L)  
109 - .setPrice(20).setStock(50))  
110 - .setProperties(singletonList(new ProductPropertyValueDetailRespDTO().setPropertyId(333L).setValueId(444L)));  
111 - when(productSkuApi.getSkuList(eq(asSet(1L, 2L)))).thenReturn(Arrays.asList(sku01, sku02));  
112 - // mock 方法(商品 SPU 检查)  
113 - ProductSpuRespDTO spu01 = randomPojo(ProductSpuRespDTO.class, o -> o.setId(11L)  
114 - .setStatus(ProductSpuStatusEnum.ENABLE.getStatus()).setName("商品 1"));  
115 - ProductSpuRespDTO spu02 = randomPojo(ProductSpuRespDTO.class, o -> o.setId(21L)  
116 - .setStatus(ProductSpuStatusEnum.ENABLE.getStatus()));  
117 - when(productSpuApi.getSpuList(eq(asSet(11L, 21L)))).thenReturn(Arrays.asList(spu01, spu02));  
118 - // mock 方法(用户收件地址的校验)  
119 - AddressRespDTO addressRespDTO = new AddressRespDTO().setId(10L).setUserId(userId).setName("芋艿")  
120 - .setMobile("15601691300").setAreaId(3306).setDetailAddress("土豆村");  
121 - when(addressApi.getAddress(eq(10L), eq(userId))).thenReturn(addressRespDTO);  
122 - // mock 方法(价格计算)  
123 - PriceCalculateRespDTO.OrderItem priceOrderItem01 = new PriceCalculateRespDTO.OrderItem()  
124 - .setSpuId(11L).setSkuId(1L).setCount(3).setOriginalPrice(150).setOriginalUnitPrice(50)  
125 - .setDiscountPrice(20).setPayPrice(130).setOrderPartPrice(7).setOrderDividePrice(35);  
126 - PriceCalculateRespDTO.OrderItem priceOrderItem02 = new PriceCalculateRespDTO.OrderItem()  
127 - .setSpuId(21L).setSkuId(2L).setCount(4).setOriginalPrice(80).setOriginalUnitPrice(20)  
128 - .setDiscountPrice(40).setPayPrice(40).setOrderPartPrice(15).setOrderDividePrice(25);  
129 - PriceCalculateRespDTO.Order priceOrder = new PriceCalculateRespDTO.Order()  
130 - .setTotalPrice(230).setDiscountPrice(0).setCouponPrice(30)  
131 - .setPointPrice(10).setDeliveryPrice(20).setPayPrice(80).setCouponId(101L).setCouponPrice(30)  
132 - .setItems(Arrays.asList(priceOrderItem01, priceOrderItem02));  
133 - when(priceApi.calculatePrice(argThat(priceCalculateReqDTO -> {  
134 - assertEquals(priceCalculateReqDTO.getUserId(), 100L);  
135 - assertEquals(priceCalculateReqDTO.getCouponId(), 101L);  
136 - assertEquals(priceCalculateReqDTO.getItems().get(0).getSkuId(), 1L);  
137 - assertEquals(priceCalculateReqDTO.getItems().get(0).getCount(), 3);  
138 - assertEquals(priceCalculateReqDTO.getItems().get(1).getSkuId(), 2L);  
139 - assertEquals(priceCalculateReqDTO.getItems().get(1).getCount(), 4);  
140 - return true;  
141 - }))).thenReturn(new PriceCalculateRespDTO().setOrder(priceOrder));  
142 - // mock 方法(创建支付单)  
143 - when(payOrderApi.createOrder(argThat(createReqDTO -> {  
144 - assertEquals(createReqDTO.getAppId(), 888L);  
145 - assertEquals(createReqDTO.getUserIp(), userIp);  
146 - assertNotNull(createReqDTO.getMerchantOrderId()); // 由于 tradeOrderId 后生成,只能校验非空  
147 - assertEquals(createReqDTO.getSubject(), "商品 1 等多件");  
148 - assertNull(createReqDTO.getBody());  
149 - assertEquals(createReqDTO.getPrice(), 80);  
150 - assertNotNull(createReqDTO.getExpireTime());  
151 - return true;  
152 - }))).thenReturn(1000L);  
153 -  
154 - // 调用方法  
155 - TradeOrderDO order = tradeOrderUpdateService.createOrder(userId, userIp, reqVO, null);  
156 - // 断言 TradeOrderDO 订单  
157 - List<TradeOrderDO> tradeOrderDOs = tradeOrderMapper.selectList();  
158 - assertEquals(tradeOrderDOs.size(), 1);  
159 - TradeOrderDO tradeOrderDO = tradeOrderDOs.get(0);  
160 - assertEquals(tradeOrderDO.getId(), order.getId());  
161 - assertNotNull(tradeOrderDO.getNo());  
162 - assertEquals(tradeOrderDO.getType(), TradeOrderTypeEnum.NORMAL.getType());  
163 - assertEquals(tradeOrderDO.getTerminal(), TerminalEnum.H5.getTerminal());  
164 - assertEquals(tradeOrderDO.getUserId(), userId);  
165 - assertEquals(tradeOrderDO.getUserIp(), userIp);  
166 - assertEquals(tradeOrderDO.getStatus(), TradeOrderStatusEnum.UNPAID.getStatus());  
167 - assertEquals(tradeOrderDO.getProductCount(), 7);  
168 - assertNull(tradeOrderDO.getFinishTime());  
169 - assertNull(tradeOrderDO.getCancelTime());  
170 - assertNull(tradeOrderDO.getCancelType());  
171 - assertEquals(tradeOrderDO.getUserRemark(), "我是备注");  
172 - assertNull(tradeOrderDO.getRemark());  
173 - assertFalse(tradeOrderDO.getPayStatus());  
174 - assertNull(tradeOrderDO.getPayTime());  
175 - assertEquals(tradeOrderDO.getTotalPrice(), 230);  
176 - assertEquals(tradeOrderDO.getDiscountPrice(), 0);  
177 - assertEquals(tradeOrderDO.getAdjustPrice(), 0);  
178 - assertEquals(tradeOrderDO.getPayPrice(), 80);  
179 - assertEquals(tradeOrderDO.getPayOrderId(), 1000L);  
180 - assertNull(tradeOrderDO.getPayChannelCode());  
181 - assertNull(tradeOrderDO.getLogisticsId());  
182 - assertNull(tradeOrderDO.getDeliveryTime());  
183 - assertNull(tradeOrderDO.getReceiveTime());  
184 - assertEquals(tradeOrderDO.getReceiverName(), "芋艿");  
185 - assertEquals(tradeOrderDO.getReceiverMobile(), "15601691300");  
186 - assertEquals(tradeOrderDO.getReceiverAreaId(), 3306);  
187 - assertEquals(tradeOrderDO.getReceiverDetailAddress(), "土豆村");  
188 - assertEquals(tradeOrderDO.getRefundStatus(), TradeOrderRefundStatusEnum.NONE.getStatus());  
189 - assertEquals(tradeOrderDO.getRefundPrice(), 0);  
190 - assertEquals(tradeOrderDO.getCouponPrice(), 30);  
191 - assertEquals(tradeOrderDO.getPointPrice(), 10);  
192 - // 断言 TradeOrderItemDO 订单(第 1 个)  
193 - List<TradeOrderItemDO> tradeOrderItemDOs = tradeOrderItemMapper.selectList();  
194 - assertEquals(tradeOrderItemDOs.size(), 2);  
195 - TradeOrderItemDO tradeOrderItemDO01 = tradeOrderItemDOs.get(0);  
196 - assertNotNull(tradeOrderItemDO01.getId());  
197 - assertEquals(tradeOrderItemDO01.getUserId(), userId);  
198 - assertEquals(tradeOrderItemDO01.getOrderId(), order.getId());  
199 - assertEquals(tradeOrderItemDO01.getSpuId(), 11L);  
200 - assertEquals(tradeOrderItemDO01.getSkuId(), 1L);  
201 - assertEquals(tradeOrderItemDO01.getProperties().size(), 1);  
202 - assertEquals(tradeOrderItemDO01.getProperties().get(0).getPropertyId(), 111L);  
203 - assertEquals(tradeOrderItemDO01.getProperties().get(0).getValueId(), 222L);  
204 - //assertEquals(tradeOrderItemDO01.getSpuName(), sku01.getSpuName()); TODO 找不到spuName  
205 - assertEquals(tradeOrderItemDO01.getPicUrl(), sku01.getPicUrl());  
206 - assertEquals(tradeOrderItemDO01.getCount(), 3);  
207 -// assertEquals(tradeOrderItemDO01.getOriginalPrice(), 150);  
208 - assertEquals(tradeOrderItemDO01.getPrice(), 50);  
209 - assertEquals(tradeOrderItemDO01.getDiscountPrice(), 20);  
210 - assertEquals(tradeOrderItemDO01.getPayPrice(), 130);  
211 - assertEquals(tradeOrderItemDO01.getAfterSaleStatus(), TradeOrderItemAfterSaleStatusEnum.NONE.getStatus());  
212 - // 断言 TradeOrderItemDO 订单(第 2 个)  
213 - TradeOrderItemDO tradeOrderItemDO02 = tradeOrderItemDOs.get(1);  
214 - assertNotNull(tradeOrderItemDO02.getId());  
215 - assertEquals(tradeOrderItemDO02.getUserId(), userId);  
216 - assertEquals(tradeOrderItemDO02.getOrderId(), order.getId());  
217 - assertEquals(tradeOrderItemDO02.getSpuId(), 21L);  
218 - assertEquals(tradeOrderItemDO02.getSkuId(), 2L);  
219 - assertEquals(tradeOrderItemDO02.getProperties().size(), 1);  
220 - assertEquals(tradeOrderItemDO02.getProperties().get(0).getPropertyId(), 333L);  
221 - assertEquals(tradeOrderItemDO02.getProperties().get(0).getValueId(), 444L);  
222 - //assertEquals(tradeOrderItemDO02.getSpuName(), sku02.getSpuName()); TODO 找不到spuName  
223 - assertEquals(tradeOrderItemDO02.getPicUrl(), sku02.getPicUrl());  
224 - assertEquals(tradeOrderItemDO02.getCount(), 4);  
225 -// assertEquals(tradeOrderItemDO02.getOriginalPrice(), 80);  
226 - assertEquals(tradeOrderItemDO02.getPrice(), 20);  
227 - assertEquals(tradeOrderItemDO02.getDiscountPrice(), 40);  
228 - assertEquals(tradeOrderItemDO02.getPayPrice(), 40);  
229 - assertEquals(tradeOrderItemDO02.getAfterSaleStatus(), TradeOrderItemAfterSaleStatusEnum.NONE.getStatus());  
230 - // 校验调用  
231 - verify(productSkuApi).updateSkuStock(argThat(updateStockReqDTO -> {  
232 - assertEquals(updateStockReqDTO.getItems().size(), 2);  
233 - assertEquals(updateStockReqDTO.getItems().get(0).getId(), 1L);  
234 - assertEquals(updateStockReqDTO.getItems().get(0).getIncrCount(), 3);  
235 - assertEquals(updateStockReqDTO.getItems().get(1).getId(), 2L);  
236 - assertEquals(updateStockReqDTO.getItems().get(1).getIncrCount(), 4);  
237 - return true;  
238 - }));  
239 - verify(couponApi).useCoupon(argThat(reqDTO -> {  
240 - assertEquals(reqDTO.getId(), reqVO.getCouponId());  
241 - assertEquals(reqDTO.getUserId(), userId);  
242 - assertEquals(reqDTO.getOrderId(), order.getId());  
243 - return true;  
244 - }));  
245 - } 74 +// @Test
  75 +// public void testCreateTradeOrder_success() {
  76 +// // 准备参数
  77 +// Long userId = 100L;
  78 +// String userIp = "127.0.0.1";
  79 +//// AppTradeOrderCreateReqVO reqVO = new AppTradeOrderCreateReqVO()
  80 +//// .setAddressId(10L).setCouponId(101L).setRemark("我是备注").setFromCart(true)
  81 +//// .setItems(Arrays.asList(new AppTradeOrderCreateReqVO.Item().setSkuId(1L).setCount(3),
  82 +//// new AppTradeOrderCreateReqVO.Item().setSkuId(2L).setCount(4)));
  83 +// AppTradeOrderCreateReqVO reqVO = null;
  84 +// // TODO 芋艿:重新高下
  85 +// // mock 方法(商品 SKU 检查)
  86 +// ProductSkuRespDTO sku01 = randomPojo(ProductSkuRespDTO.class, o -> o.setId(1L).setSpuId(11L)
  87 +// .setPrice(50).setStock(100)
  88 +// .setProperties(singletonList(new ProductPropertyValueDetailRespDTO().setPropertyId(111L).setValueId(222L))));
  89 +// ProductSkuRespDTO sku02 = randomPojo(ProductSkuRespDTO.class, o -> o.setId(2L).setSpuId(21L)
  90 +// .setPrice(20).setStock(50))
  91 +// .setProperties(singletonList(new ProductPropertyValueDetailRespDTO().setPropertyId(333L).setValueId(444L)));
  92 +// when(productSkuApi.getSkuList(eq(asSet(1L, 2L)))).thenReturn(Arrays.asList(sku01, sku02));
  93 +// // mock 方法(商品 SPU 检查)
  94 +// ProductSpuRespDTO spu01 = randomPojo(ProductSpuRespDTO.class, o -> o.setId(11L)
  95 +// .setStatus(ProductSpuStatusEnum.ENABLE.getStatus()).setName("商品 1"));
  96 +// ProductSpuRespDTO spu02 = randomPojo(ProductSpuRespDTO.class, o -> o.setId(21L)
  97 +// .setStatus(ProductSpuStatusEnum.ENABLE.getStatus()));
  98 +// when(productSpuApi.getSpuList(eq(asSet(11L, 21L)))).thenReturn(Arrays.asList(spu01, spu02));
  99 +// // mock 方法(用户收件地址的校验)
  100 +// MemberAddressRespDTO addressRespDTO = new MemberAddressRespDTO().setId(10L).setUserId(userId).setName("芋艿")
  101 +// .setMobile("15601691300").setAreaId(3306).setDetailAddress("土豆村");
  102 +// when(addressApi.getAddress(eq(10L), eq(userId))).thenReturn(addressRespDTO);
  103 +// // mock 方法(价格计算)
  104 +// PriceCalculateRespDTO.OrderItem priceOrderItem01 = new PriceCalculateRespDTO.OrderItem()
  105 +// .setSpuId(11L).setSkuId(1L).setCount(3).setOriginalPrice(150).setOriginalUnitPrice(50)
  106 +// .setDiscountPrice(20).setPayPrice(130).setOrderPartPrice(7).setOrderDividePrice(35);
  107 +// PriceCalculateRespDTO.OrderItem priceOrderItem02 = new PriceCalculateRespDTO.OrderItem()
  108 +// .setSpuId(21L).setSkuId(2L).setCount(4).setOriginalPrice(80).setOriginalUnitPrice(20)
  109 +// .setDiscountPrice(40).setPayPrice(40).setOrderPartPrice(15).setOrderDividePrice(25);
  110 +// PriceCalculateRespDTO.Order priceOrder = new PriceCalculateRespDTO.Order()
  111 +// .setTotalPrice(230).setDiscountPrice(0).setCouponPrice(30)
  112 +// .setPointPrice(10).setDeliveryPrice(20).setPayPrice(80).setCouponId(101L).setCouponPrice(30)
  113 +// .setItems(Arrays.asList(priceOrderItem01, priceOrderItem02));
  114 +// when(priceApi.calculatePrice(argThat(priceCalculateReqDTO -> {
  115 +// assertEquals(priceCalculateReqDTO.getUserId(), 100L);
  116 +// assertEquals(priceCalculateReqDTO.getCouponId(), 101L);
  117 +// assertEquals(priceCalculateReqDTO.getItems().get(0).getSkuId(), 1L);
  118 +// assertEquals(priceCalculateReqDTO.getItems().get(0).getCount(), 3);
  119 +// assertEquals(priceCalculateReqDTO.getItems().get(1).getSkuId(), 2L);
  120 +// assertEquals(priceCalculateReqDTO.getItems().get(1).getCount(), 4);
  121 +// return true;
  122 +// }))).thenReturn(new PriceCalculateRespDTO().setOrder(priceOrder));
  123 +// // mock 方法(创建支付单)
  124 +// when(payOrderApi.createOrder(argThat(createReqDTO -> {
  125 +// assertEquals(createReqDTO.getAppId(), 888L);
  126 +// assertEquals(createReqDTO.getUserIp(), userIp);
  127 +// assertNotNull(createReqDTO.getMerchantOrderId()); // 由于 tradeOrderId 后生成,只能校验非空
  128 +// assertEquals(createReqDTO.getSubject(), "商品 1 等多件");
  129 +// assertNull(createReqDTO.getBody());
  130 +// assertEquals(createReqDTO.getPrice(), 80);
  131 +// assertNotNull(createReqDTO.getExpireTime());
  132 +// return true;
  133 +// }))).thenReturn(1000L);
  134 +//
  135 +// // 调用方法
  136 +// TradeOrderDO order = tradeOrderUpdateService.createOrder(userId, userIp, reqVO, null);
  137 +// // 断言 TradeOrderDO 订单
  138 +// List<TradeOrderDO> tradeOrderDOs = tradeOrderMapper.selectList();
  139 +// assertEquals(tradeOrderDOs.size(), 1);
  140 +// TradeOrderDO tradeOrderDO = tradeOrderDOs.get(0);
  141 +// assertEquals(tradeOrderDO.getId(), order.getId());
  142 +// assertNotNull(tradeOrderDO.getNo());
  143 +// assertEquals(tradeOrderDO.getType(), TradeOrderTypeEnum.NORMAL.getType());
  144 +// assertEquals(tradeOrderDO.getTerminal(), TerminalEnum.H5.getTerminal());
  145 +// assertEquals(tradeOrderDO.getUserId(), userId);
  146 +// assertEquals(tradeOrderDO.getUserIp(), userIp);
  147 +// assertEquals(tradeOrderDO.getStatus(), TradeOrderStatusEnum.UNPAID.getStatus());
  148 +// assertEquals(tradeOrderDO.getProductCount(), 7);
  149 +// assertNull(tradeOrderDO.getFinishTime());
  150 +// assertNull(tradeOrderDO.getCancelTime());
  151 +// assertNull(tradeOrderDO.getCancelType());
  152 +// assertEquals(tradeOrderDO.getUserRemark(), "我是备注");
  153 +// assertNull(tradeOrderDO.getRemark());
  154 +// assertFalse(tradeOrderDO.getPayStatus());
  155 +// assertNull(tradeOrderDO.getPayTime());
  156 +// assertEquals(tradeOrderDO.getTotalPrice(), 230);
  157 +// assertEquals(tradeOrderDO.getDiscountPrice(), 0);
  158 +// assertEquals(tradeOrderDO.getAdjustPrice(), 0);
  159 +// assertEquals(tradeOrderDO.getPayPrice(), 80);
  160 +// assertEquals(tradeOrderDO.getPayOrderId(), 1000L);
  161 +// assertNull(tradeOrderDO.getPayChannelCode());
  162 +// assertNull(tradeOrderDO.getLogisticsId());
  163 +// assertNull(tradeOrderDO.getDeliveryTime());
  164 +// assertNull(tradeOrderDO.getReceiveTime());
  165 +// assertEquals(tradeOrderDO.getReceiverName(), "芋艿");
  166 +// assertEquals(tradeOrderDO.getReceiverMobile(), "15601691300");
  167 +// assertEquals(tradeOrderDO.getReceiverAreaId(), 3306);
  168 +// assertEquals(tradeOrderDO.getReceiverDetailAddress(), "土豆村");
  169 +// assertEquals(tradeOrderDO.getRefundStatus(), TradeOrderRefundStatusEnum.NONE.getStatus());
  170 +// assertEquals(tradeOrderDO.getRefundPrice(), 0);
  171 +// assertEquals(tradeOrderDO.getCouponPrice(), 30);
  172 +// assertEquals(tradeOrderDO.getPointPrice(), 10);
  173 +// // 断言 TradeOrderItemDO 订单(第 1 个)
  174 +// List<TradeOrderItemDO> tradeOrderItemDOs = tradeOrderItemMapper.selectList();
  175 +// assertEquals(tradeOrderItemDOs.size(), 2);
  176 +// TradeOrderItemDO tradeOrderItemDO01 = tradeOrderItemDOs.get(0);
  177 +// assertNotNull(tradeOrderItemDO01.getId());
  178 +// assertEquals(tradeOrderItemDO01.getUserId(), userId);
  179 +// assertEquals(tradeOrderItemDO01.getOrderId(), order.getId());
  180 +// assertEquals(tradeOrderItemDO01.getSpuId(), 11L);
  181 +// assertEquals(tradeOrderItemDO01.getSkuId(), 1L);
  182 +// assertEquals(tradeOrderItemDO01.getProperties().size(), 1);
  183 +// assertEquals(tradeOrderItemDO01.getProperties().get(0).getPropertyId(), 111L);
  184 +// assertEquals(tradeOrderItemDO01.getProperties().get(0).getValueId(), 222L);
  185 +// //assertEquals(tradeOrderItemDO01.getSpuName(), sku01.getSpuName()); TODO 找不到spuName
  186 +// assertEquals(tradeOrderItemDO01.getPicUrl(), sku01.getPicUrl());
  187 +// assertEquals(tradeOrderItemDO01.getCount(), 3);
  188 +//// assertEquals(tradeOrderItemDO01.getOriginalPrice(), 150);
  189 +// assertEquals(tradeOrderItemDO01.getPrice(), 50);
  190 +// assertEquals(tradeOrderItemDO01.getDiscountPrice(), 20);
  191 +// assertEquals(tradeOrderItemDO01.getPayPrice(), 130);
  192 +// assertEquals(tradeOrderItemDO01.getAfterSaleStatus(), TradeOrderItemAfterSaleStatusEnum.NONE.getStatus());
  193 +// // 断言 TradeOrderItemDO 订单(第 2 个)
  194 +// TradeOrderItemDO tradeOrderItemDO02 = tradeOrderItemDOs.get(1);
  195 +// assertNotNull(tradeOrderItemDO02.getId());
  196 +// assertEquals(tradeOrderItemDO02.getUserId(), userId);
  197 +// assertEquals(tradeOrderItemDO02.getOrderId(), order.getId());
  198 +// assertEquals(tradeOrderItemDO02.getSpuId(), 21L);
  199 +// assertEquals(tradeOrderItemDO02.getSkuId(), 2L);
  200 +// assertEquals(tradeOrderItemDO02.getProperties().size(), 1);
  201 +// assertEquals(tradeOrderItemDO02.getProperties().get(0).getPropertyId(), 333L);
  202 +// assertEquals(tradeOrderItemDO02.getProperties().get(0).getValueId(), 444L);
  203 +// //assertEquals(tradeOrderItemDO02.getSpuName(), sku02.getSpuName()); TODO 找不到spuName
  204 +// assertEquals(tradeOrderItemDO02.getPicUrl(), sku02.getPicUrl());
  205 +// assertEquals(tradeOrderItemDO02.getCount(), 4);
  206 +//// assertEquals(tradeOrderItemDO02.getOriginalPrice(), 80);
  207 +// assertEquals(tradeOrderItemDO02.getPrice(), 20);
  208 +// assertEquals(tradeOrderItemDO02.getDiscountPrice(), 40);
  209 +// assertEquals(tradeOrderItemDO02.getPayPrice(), 40);
  210 +// assertEquals(tradeOrderItemDO02.getAfterSaleStatus(), TradeOrderItemAfterSaleStatusEnum.NONE.getStatus());
  211 +// // 校验调用
  212 +// verify(productSkuApi).updateSkuStock(argThat(updateStockReqDTO -> {
  213 +// assertEquals(updateStockReqDTO.getItems().size(), 2);
  214 +// assertEquals(updateStockReqDTO.getItems().get(0).getId(), 1L);
  215 +// assertEquals(updateStockReqDTO.getItems().get(0).getIncrCount(), 3);
  216 +// assertEquals(updateStockReqDTO.getItems().get(1).getId(), 2L);
  217 +// assertEquals(updateStockReqDTO.getItems().get(1).getIncrCount(), 4);
  218 +// return true;
  219 +// }));
  220 +// verify(couponApi).useCoupon(argThat(reqDTO -> {
  221 +// assertEquals(reqDTO.getId(), reqVO.getCouponId());
  222 +// assertEquals(reqDTO.getUserId(), userId);
  223 +// assertEquals(reqDTO.getOrderId(), order.getId());
  224 +// return true;
  225 +// }));
  226 +// }
246 227
247 @Test 228 @Test
248 public void testUpdateOrderPaid() { 229 public void testUpdateOrderPaid() {
yudao-module-mall/yudao-module-trade-biz/src/test/java/cn/iocoder/yudao/module/trade/service/price/calculator/TradeDeliveryPriceCalculatorTest.java
@@ -2,8 +2,8 @@ package cn.iocoder.yudao.module.trade.service.price.calculator; @@ -2,8 +2,8 @@ package cn.iocoder.yudao.module.trade.service.price.calculator;
2 2
3 import cn.hutool.core.map.MapUtil; 3 import cn.hutool.core.map.MapUtil;
4 import cn.iocoder.yudao.framework.test.core.ut.BaseMockitoUnitTest; 4 import cn.iocoder.yudao.framework.test.core.ut.BaseMockitoUnitTest;
5 -import cn.iocoder.yudao.module.member.api.address.AddressApi;  
6 -import cn.iocoder.yudao.module.member.api.address.dto.AddressRespDTO; 5 +import cn.iocoder.yudao.module.member.api.address.MemberAddressApi;
  6 +import cn.iocoder.yudao.module.member.api.address.dto.MemberAddressRespDTO;
7 import cn.iocoder.yudao.module.trade.dal.dataobject.config.TradeConfigDO; 7 import cn.iocoder.yudao.module.trade.dal.dataobject.config.TradeConfigDO;
8 import cn.iocoder.yudao.module.trade.enums.delivery.DeliveryExpressChargeModeEnum; 8 import cn.iocoder.yudao.module.trade.enums.delivery.DeliveryExpressChargeModeEnum;
9 import cn.iocoder.yudao.module.trade.enums.delivery.DeliveryTypeEnum; 9 import cn.iocoder.yudao.module.trade.enums.delivery.DeliveryTypeEnum;
@@ -38,7 +38,7 @@ public class TradeDeliveryPriceCalculatorTest extends BaseMockitoUnitTest { @@ -38,7 +38,7 @@ public class TradeDeliveryPriceCalculatorTest extends BaseMockitoUnitTest {
38 private TradeDeliveryPriceCalculator calculator; 38 private TradeDeliveryPriceCalculator calculator;
39 39
40 @Mock 40 @Mock
41 - private AddressApi addressApi; 41 + private MemberAddressApi addressApi;
42 42
43 @Mock 43 @Mock
44 private DeliveryExpressTemplateService deliveryExpressTemplateService; 44 private DeliveryExpressTemplateService deliveryExpressTemplateService;
@@ -80,7 +80,7 @@ public class TradeDeliveryPriceCalculatorTest extends BaseMockitoUnitTest { @@ -80,7 +80,7 @@ public class TradeDeliveryPriceCalculatorTest extends BaseMockitoUnitTest {
80 TradePriceCalculatorHelper.recountAllPrice(resultBO); 80 TradePriceCalculatorHelper.recountAllPrice(resultBO);
81 81
82 // 准备收件地址数据 82 // 准备收件地址数据
83 - AddressRespDTO addressResp = randomPojo(AddressRespDTO.class, item -> item.setAreaId(10)); 83 + MemberAddressRespDTO addressResp = randomPojo(MemberAddressRespDTO.class, item -> item.setAreaId(10));
84 when(addressApi.getAddress(eq(10L), eq(1L))).thenReturn(addressResp); 84 when(addressApi.getAddress(eq(10L), eq(1L))).thenReturn(addressResp);
85 85
86 // 准备运费模板费用配置数据 86 // 准备运费模板费用配置数据
yudao-module-member/yudao-module-member-api/src/main/java/cn/iocoder/yudao/module/member/api/address/AddressApi.java renamed to yudao-module-member/yudao-module-member-api/src/main/java/cn/iocoder/yudao/module/member/api/address/MemberAddressApi.java
1 package cn.iocoder.yudao.module.member.api.address; 1 package cn.iocoder.yudao.module.member.api.address;
2 2
3 -import cn.iocoder.yudao.module.member.api.address.dto.AddressRespDTO; 3 +import cn.iocoder.yudao.module.member.api.address.dto.MemberAddressRespDTO;
4 4
5 /** 5 /**
6 * 用户收件地址 API 接口 6 * 用户收件地址 API 接口
7 * 7 *
8 * @author 芋道源码 8 * @author 芋道源码
9 */ 9 */
10 -public interface AddressApi { 10 +public interface MemberAddressApi {
11 11
12 /** 12 /**
13 * 获得用户收件地址 13 * 获得用户收件地址
@@ -16,7 +16,7 @@ public interface AddressApi { @@ -16,7 +16,7 @@ public interface AddressApi {
16 * @param userId 用户编号 16 * @param userId 用户编号
17 * @return 用户收件地址 17 * @return 用户收件地址
18 */ 18 */
19 - AddressRespDTO getAddress(Long id, Long userId); 19 + MemberAddressRespDTO getAddress(Long id, Long userId);
20 20
21 /** 21 /**
22 * 获得用户默认收件地址 22 * 获得用户默认收件地址
@@ -24,6 +24,6 @@ public interface AddressApi { @@ -24,6 +24,6 @@ public interface AddressApi {
24 * @param userId 用户编号 24 * @param userId 用户编号
25 * @return 用户收件地址 25 * @return 用户收件地址
26 */ 26 */
27 - AddressRespDTO getDefaultAddress(Long userId); 27 + MemberAddressRespDTO getDefaultAddress(Long userId);
28 28
29 } 29 }
yudao-module-member/yudao-module-member-api/src/main/java/cn/iocoder/yudao/module/member/api/address/dto/AddressRespDTO.java renamed to yudao-module-member/yudao-module-member-api/src/main/java/cn/iocoder/yudao/module/member/api/address/dto/MemberAddressRespDTO.java
@@ -8,7 +8,7 @@ import lombok.Data; @@ -8,7 +8,7 @@ import lombok.Data;
8 * @author 芋道源码 8 * @author 芋道源码
9 */ 9 */
10 @Data 10 @Data
11 -public class AddressRespDTO { 11 +public class MemberAddressRespDTO {
12 12
13 /** 13 /**
14 * 编号 14 * 编号
yudao-module-member/yudao-module-member-api/src/main/java/cn/iocoder/yudao/module/member/api/user/MemberUserApi.java
@@ -38,7 +38,8 @@ public interface MemberUserApi { @@ -38,7 +38,8 @@ public interface MemberUserApi {
38 * @return 会员用户 Map 38 * @return 会员用户 Map
39 */ 39 */
40 default Map<Long, MemberUserRespDTO> getUserMap(Collection<Long> ids) { 40 default Map<Long, MemberUserRespDTO> getUserMap(Collection<Long> ids) {
41 - return convertMap(getUserList(ids), MemberUserRespDTO::getId); 41 + List<MemberUserRespDTO> list = getUserList(ids);
  42 + return convertMap(list, MemberUserRespDTO::getId);
42 } 43 }
43 44
44 /** 45 /**
yudao-module-member/yudao-module-member-api/src/main/java/cn/iocoder/yudao/module/member/message/package-info.java 0 → 100644
  1 +/**
  2 + * 消息队列的消息
  3 + */
  4 +package cn.iocoder.yudao.module.member.message;
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/mq/message/coupon/UserCreateMessage.java renamed to yudao-module-member/yudao-module-member-api/src/main/java/cn/iocoder/yudao/module/member/message/user/MemberUserCreateMessage.java
1 -package cn.iocoder.yudao.module.promotion.mq.message.coupon; 1 +package cn.iocoder.yudao.module.member.message.user;
2 2
3 -import cn.iocoder.yudao.framework.mq.core.stream.AbstractStreamMessage;  
4 import lombok.Data; 3 import lombok.Data;
5 -import lombok.EqualsAndHashCode;  
6 4
7 import javax.validation.constraints.NotNull; 5 import javax.validation.constraints.NotNull;
8 6
@@ -12,8 +10,7 @@ import javax.validation.constraints.NotNull; @@ -12,8 +10,7 @@ import javax.validation.constraints.NotNull;
12 * @author owen 10 * @author owen
13 */ 11 */
14 @Data 12 @Data
15 -@EqualsAndHashCode(callSuper = true)  
16 -public class UserCreateMessage extends AbstractStreamMessage { 13 +public class MemberUserCreateMessage {
17 14
18 /** 15 /**
19 * 用户编号 16 * 用户编号
@@ -21,9 +18,4 @@ public class UserCreateMessage extends AbstractStreamMessage { @@ -21,9 +18,4 @@ public class UserCreateMessage extends AbstractStreamMessage {
21 @NotNull(message = "用户编号不能为空") 18 @NotNull(message = "用户编号不能为空")
22 private Long userId; 19 private Long userId;
23 20
24 - @Override  
25 - public String getStreamKey() {  
26 - return "member.create.send";  
27 - }  
28 -  
29 } 21 }
yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/api/address/AddressApiImpl.java renamed to yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/api/address/MemberAddressApiImpl.java
1 package cn.iocoder.yudao.module.member.api.address; 1 package cn.iocoder.yudao.module.member.api.address;
2 2
3 -import cn.iocoder.yudao.module.member.api.address.dto.AddressRespDTO; 3 +import cn.iocoder.yudao.module.member.api.address.dto.MemberAddressRespDTO;
4 import cn.iocoder.yudao.module.member.convert.address.AddressConvert; 4 import cn.iocoder.yudao.module.member.convert.address.AddressConvert;
5 import cn.iocoder.yudao.module.member.service.address.AddressService; 5 import cn.iocoder.yudao.module.member.service.address.AddressService;
6 import org.springframework.stereotype.Service; 6 import org.springframework.stereotype.Service;
@@ -15,18 +15,18 @@ import javax.annotation.Resource; @@ -15,18 +15,18 @@ import javax.annotation.Resource;
15 */ 15 */
16 @Service 16 @Service
17 @Validated 17 @Validated
18 -public class AddressApiImpl implements AddressApi { 18 +public class MemberAddressApiImpl implements MemberAddressApi {
19 19
20 @Resource 20 @Resource
21 private AddressService addressService; 21 private AddressService addressService;
22 22
23 @Override 23 @Override
24 - public AddressRespDTO getAddress(Long id, Long userId) { 24 + public MemberAddressRespDTO getAddress(Long id, Long userId) {
25 return AddressConvert.INSTANCE.convert02(addressService.getAddress(userId, id)); 25 return AddressConvert.INSTANCE.convert02(addressService.getAddress(userId, id));
26 } 26 }
27 27
28 @Override 28 @Override
29 - public AddressRespDTO getDefaultAddress(Long userId) { 29 + public MemberAddressRespDTO getDefaultAddress(Long userId) {
30 return AddressConvert.INSTANCE.convert02(addressService.getDefaultUserAddress(userId)); 30 return AddressConvert.INSTANCE.convert02(addressService.getDefaultUserAddress(userId));
31 } 31 }
32 32
yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/controller/admin/point/MemberPointRecordController.java
@@ -2,13 +2,13 @@ package cn.iocoder.yudao.module.member.controller.admin.point; @@ -2,13 +2,13 @@ package cn.iocoder.yudao.module.member.controller.admin.point;
2 2
3 import cn.iocoder.yudao.framework.common.pojo.CommonResult; 3 import cn.iocoder.yudao.framework.common.pojo.CommonResult;
4 import cn.iocoder.yudao.framework.common.pojo.PageResult; 4 import cn.iocoder.yudao.framework.common.pojo.PageResult;
5 -import cn.iocoder.yudao.module.member.api.user.MemberUserApi;  
6 -import cn.iocoder.yudao.module.member.api.user.dto.MemberUserRespDTO;  
7 import cn.iocoder.yudao.module.member.controller.admin.point.vo.recrod.MemberPointRecordPageReqVO; 5 import cn.iocoder.yudao.module.member.controller.admin.point.vo.recrod.MemberPointRecordPageReqVO;
8 import cn.iocoder.yudao.module.member.controller.admin.point.vo.recrod.MemberPointRecordRespVO; 6 import cn.iocoder.yudao.module.member.controller.admin.point.vo.recrod.MemberPointRecordRespVO;
9 import cn.iocoder.yudao.module.member.convert.point.MemberPointRecordConvert; 7 import cn.iocoder.yudao.module.member.convert.point.MemberPointRecordConvert;
10 import cn.iocoder.yudao.module.member.dal.dataobject.point.MemberPointRecordDO; 8 import cn.iocoder.yudao.module.member.dal.dataobject.point.MemberPointRecordDO;
  9 +import cn.iocoder.yudao.module.member.dal.dataobject.user.MemberUserDO;
11 import cn.iocoder.yudao.module.member.service.point.MemberPointRecordService; 10 import cn.iocoder.yudao.module.member.service.point.MemberPointRecordService;
  11 +import cn.iocoder.yudao.module.member.service.user.MemberUserService;
12 import io.swagger.v3.oas.annotations.Operation; 12 import io.swagger.v3.oas.annotations.Operation;
13 import io.swagger.v3.oas.annotations.tags.Tag; 13 import io.swagger.v3.oas.annotations.tags.Tag;
14 import org.springframework.security.access.prepost.PreAuthorize; 14 import org.springframework.security.access.prepost.PreAuthorize;
@@ -35,7 +35,7 @@ public class MemberPointRecordController { @@ -35,7 +35,7 @@ public class MemberPointRecordController {
35 private MemberPointRecordService pointRecordService; 35 private MemberPointRecordService pointRecordService;
36 36
37 @Resource 37 @Resource
38 - private MemberUserApi memberUserApi; 38 + private MemberUserService memberUserService;
39 39
40 @GetMapping("/page") 40 @GetMapping("/page")
41 @Operation(summary = "获得用户积分记录分页") 41 @Operation(summary = "获得用户积分记录分页")
@@ -48,7 +48,7 @@ public class MemberPointRecordController { @@ -48,7 +48,7 @@ public class MemberPointRecordController {
48 } 48 }
49 49
50 // 拼接结果返回 50 // 拼接结果返回
51 - List<MemberUserRespDTO> users = memberUserApi.getUserList( 51 + List<MemberUserDO> users = memberUserService.getUserList(
52 convertSet(pageResult.getList(), MemberPointRecordDO::getUserId)); 52 convertSet(pageResult.getList(), MemberPointRecordDO::getUserId));
53 return success(MemberPointRecordConvert.INSTANCE.convertPage(pageResult, users)); 53 return success(MemberPointRecordConvert.INSTANCE.convertPage(pageResult, users));
54 } 54 }
yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/controller/admin/signin/MemberSignInRecordController.java
@@ -2,13 +2,13 @@ package cn.iocoder.yudao.module.member.controller.admin.signin; @@ -2,13 +2,13 @@ package cn.iocoder.yudao.module.member.controller.admin.signin;
2 2
3 import cn.iocoder.yudao.framework.common.pojo.CommonResult; 3 import cn.iocoder.yudao.framework.common.pojo.CommonResult;
4 import cn.iocoder.yudao.framework.common.pojo.PageResult; 4 import cn.iocoder.yudao.framework.common.pojo.PageResult;
5 -import cn.iocoder.yudao.module.member.api.user.MemberUserApi;  
6 -import cn.iocoder.yudao.module.member.api.user.dto.MemberUserRespDTO;  
7 import cn.iocoder.yudao.module.member.controller.admin.signin.vo.record.MemberSignInRecordPageReqVO; 5 import cn.iocoder.yudao.module.member.controller.admin.signin.vo.record.MemberSignInRecordPageReqVO;
8 import cn.iocoder.yudao.module.member.controller.admin.signin.vo.record.MemberSignInRecordRespVO; 6 import cn.iocoder.yudao.module.member.controller.admin.signin.vo.record.MemberSignInRecordRespVO;
9 import cn.iocoder.yudao.module.member.convert.signin.MemberSignInRecordConvert; 7 import cn.iocoder.yudao.module.member.convert.signin.MemberSignInRecordConvert;
10 import cn.iocoder.yudao.module.member.dal.dataobject.signin.MemberSignInRecordDO; 8 import cn.iocoder.yudao.module.member.dal.dataobject.signin.MemberSignInRecordDO;
  9 +import cn.iocoder.yudao.module.member.dal.dataobject.user.MemberUserDO;
11 import cn.iocoder.yudao.module.member.service.signin.MemberSignInRecordService; 10 import cn.iocoder.yudao.module.member.service.signin.MemberSignInRecordService;
  11 +import cn.iocoder.yudao.module.member.service.user.MemberUserService;
12 import io.swagger.v3.oas.annotations.Operation; 12 import io.swagger.v3.oas.annotations.Operation;
13 import io.swagger.v3.oas.annotations.tags.Tag; 13 import io.swagger.v3.oas.annotations.tags.Tag;
14 import org.springframework.security.access.prepost.PreAuthorize; 14 import org.springframework.security.access.prepost.PreAuthorize;
@@ -35,7 +35,7 @@ public class MemberSignInRecordController { @@ -35,7 +35,7 @@ public class MemberSignInRecordController {
35 private MemberSignInRecordService signInRecordService; 35 private MemberSignInRecordService signInRecordService;
36 36
37 @Resource 37 @Resource
38 - private MemberUserApi memberUserApi; 38 + private MemberUserService memberUserService;
39 39
40 @GetMapping("/page") 40 @GetMapping("/page")
41 @Operation(summary = "获得签到记录分页") 41 @Operation(summary = "获得签到记录分页")
@@ -48,7 +48,7 @@ public class MemberSignInRecordController { @@ -48,7 +48,7 @@ public class MemberSignInRecordController {
48 } 48 }
49 49
50 // 拼接结果返回 50 // 拼接结果返回
51 - List<MemberUserRespDTO> users = memberUserApi.getUserList( 51 + List<MemberUserDO> users = memberUserService.getUserList(
52 convertSet(pageResult.getList(), MemberSignInRecordDO::getUserId)); 52 convertSet(pageResult.getList(), MemberSignInRecordDO::getUserId));
53 return success(MemberSignInRecordConvert.INSTANCE.convertPage(pageResult, users)); 53 return success(MemberSignInRecordConvert.INSTANCE.convertPage(pageResult, users));
54 } 54 }
yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/controller/app/auth/AppAuthController.http
@@ -4,7 +4,7 @@ Content-Type: application/json @@ -4,7 +4,7 @@ Content-Type: application/json
4 tenant-id: {{appTenentId}} 4 tenant-id: {{appTenentId}}
5 5
6 { 6 {
7 - "mobile": "15601691300", 7 + "mobile": "15601691388",
8 "password": "admin123" 8 "password": "admin123"
9 } 9 }
10 10
@@ -14,7 +14,7 @@ Content-Type: application/json @@ -14,7 +14,7 @@ Content-Type: application/json
14 tenant-id: {{appTenentId}} 14 tenant-id: {{appTenentId}}
15 15
16 { 16 {
17 - "mobile": "15601691399", 17 + "mobile": "15601691388",
18 "scene": 1 18 "scene": 1
19 } 19 }
20 20
@@ -22,9 +22,10 @@ tenant-id: {{appTenentId}} @@ -22,9 +22,10 @@ tenant-id: {{appTenentId}}
22 POST {{appApi}}/member/auth/sms-login 22 POST {{appApi}}/member/auth/sms-login
23 Content-Type: application/json 23 Content-Type: application/json
24 tenant-id: {{appTenentId}} 24 tenant-id: {{appTenentId}}
  25 +terminal: 30
25 26
26 { 27 {
27 - "mobile": "15601691301", 28 + "mobile": "15601691388",
28 "code": 9999 29 "code": 9999
29 } 30 }
30 31
yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/convert/address/AddressConvert.java
1 package cn.iocoder.yudao.module.member.convert.address; 1 package cn.iocoder.yudao.module.member.convert.address;
2 2
3 import cn.iocoder.yudao.framework.ip.core.utils.AreaUtils; 3 import cn.iocoder.yudao.framework.ip.core.utils.AreaUtils;
4 -import cn.iocoder.yudao.module.member.api.address.dto.AddressRespDTO; 4 +import cn.iocoder.yudao.module.member.api.address.dto.MemberAddressRespDTO;
5 import cn.iocoder.yudao.module.member.controller.admin.address.vo.AddressRespVO; 5 import cn.iocoder.yudao.module.member.controller.admin.address.vo.AddressRespVO;
6 import cn.iocoder.yudao.module.member.controller.app.address.vo.AppAddressCreateReqVO; 6 import cn.iocoder.yudao.module.member.controller.app.address.vo.AppAddressCreateReqVO;
7 import cn.iocoder.yudao.module.member.controller.app.address.vo.AppAddressRespVO; 7 import cn.iocoder.yudao.module.member.controller.app.address.vo.AppAddressRespVO;
@@ -33,7 +33,7 @@ public interface AddressConvert { @@ -33,7 +33,7 @@ public interface AddressConvert {
33 33
34 List<AppAddressRespVO> convertList(List<MemberAddressDO> list); 34 List<AppAddressRespVO> convertList(List<MemberAddressDO> list);
35 35
36 - AddressRespDTO convert02(MemberAddressDO bean); 36 + MemberAddressRespDTO convert02(MemberAddressDO bean);
37 37
38 @Named("convertAreaIdToAreaName") 38 @Named("convertAreaIdToAreaName")
39 default String convertAreaIdToAreaName(Integer areaId) { 39 default String convertAreaIdToAreaName(Integer areaId) {
yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/convert/point/MemberPointRecordConvert.java
@@ -2,10 +2,10 @@ package cn.iocoder.yudao.module.member.convert.point; @@ -2,10 +2,10 @@ package cn.iocoder.yudao.module.member.convert.point;
2 2
3 import cn.iocoder.yudao.framework.common.pojo.PageResult; 3 import cn.iocoder.yudao.framework.common.pojo.PageResult;
4 import cn.iocoder.yudao.framework.common.util.collection.MapUtils; 4 import cn.iocoder.yudao.framework.common.util.collection.MapUtils;
5 -import cn.iocoder.yudao.module.member.api.user.dto.MemberUserRespDTO;  
6 import cn.iocoder.yudao.module.member.controller.admin.point.vo.recrod.MemberPointRecordRespVO; 5 import cn.iocoder.yudao.module.member.controller.admin.point.vo.recrod.MemberPointRecordRespVO;
7 import cn.iocoder.yudao.module.member.controller.app.point.vo.AppMemberPointRecordRespVO; 6 import cn.iocoder.yudao.module.member.controller.app.point.vo.AppMemberPointRecordRespVO;
8 import cn.iocoder.yudao.module.member.dal.dataobject.point.MemberPointRecordDO; 7 import cn.iocoder.yudao.module.member.dal.dataobject.point.MemberPointRecordDO;
  8 +import cn.iocoder.yudao.module.member.dal.dataobject.user.MemberUserDO;
9 import org.mapstruct.Mapper; 9 import org.mapstruct.Mapper;
10 import org.mapstruct.factory.Mappers; 10 import org.mapstruct.factory.Mappers;
11 11
@@ -24,10 +24,10 @@ public interface MemberPointRecordConvert { @@ -24,10 +24,10 @@ public interface MemberPointRecordConvert {
24 24
25 MemberPointRecordConvert INSTANCE = Mappers.getMapper(MemberPointRecordConvert.class); 25 MemberPointRecordConvert INSTANCE = Mappers.getMapper(MemberPointRecordConvert.class);
26 26
27 - default PageResult<MemberPointRecordRespVO> convertPage(PageResult<MemberPointRecordDO> pageResult, List<MemberUserRespDTO> users) { 27 + default PageResult<MemberPointRecordRespVO> convertPage(PageResult<MemberPointRecordDO> pageResult, List<MemberUserDO> users) {
28 PageResult<MemberPointRecordRespVO> voPageResult = convertPage(pageResult); 28 PageResult<MemberPointRecordRespVO> voPageResult = convertPage(pageResult);
29 // user 拼接 29 // user 拼接
30 - Map<Long, MemberUserRespDTO> userMap = convertMap(users, MemberUserRespDTO::getId); 30 + Map<Long, MemberUserDO> userMap = convertMap(users, MemberUserDO::getId);
31 voPageResult.getList().forEach(record -> MapUtils.findAndThen(userMap, record.getUserId(), 31 voPageResult.getList().forEach(record -> MapUtils.findAndThen(userMap, record.getUserId(),
32 memberUserRespDTO -> record.setNickname(memberUserRespDTO.getNickname()))); 32 memberUserRespDTO -> record.setNickname(memberUserRespDTO.getNickname())));
33 return voPageResult; 33 return voPageResult;
yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/convert/signin/MemberSignInRecordConvert.java
@@ -4,11 +4,11 @@ import cn.hutool.core.collection.CollUtil; @@ -4,11 +4,11 @@ import cn.hutool.core.collection.CollUtil;
4 import cn.hutool.core.util.ObjUtil; 4 import cn.hutool.core.util.ObjUtil;
5 import cn.iocoder.yudao.framework.common.pojo.PageResult; 5 import cn.iocoder.yudao.framework.common.pojo.PageResult;
6 import cn.iocoder.yudao.framework.common.util.collection.MapUtils; 6 import cn.iocoder.yudao.framework.common.util.collection.MapUtils;
7 -import cn.iocoder.yudao.module.member.api.user.dto.MemberUserRespDTO;  
8 import cn.iocoder.yudao.module.member.controller.admin.signin.vo.record.MemberSignInRecordRespVO; 7 import cn.iocoder.yudao.module.member.controller.admin.signin.vo.record.MemberSignInRecordRespVO;
9 import cn.iocoder.yudao.module.member.controller.app.signin.vo.record.AppMemberSignInRecordRespVO; 8 import cn.iocoder.yudao.module.member.controller.app.signin.vo.record.AppMemberSignInRecordRespVO;
10 import cn.iocoder.yudao.module.member.dal.dataobject.signin.MemberSignInConfigDO; 9 import cn.iocoder.yudao.module.member.dal.dataobject.signin.MemberSignInConfigDO;
11 import cn.iocoder.yudao.module.member.dal.dataobject.signin.MemberSignInRecordDO; 10 import cn.iocoder.yudao.module.member.dal.dataobject.signin.MemberSignInRecordDO;
  11 +import cn.iocoder.yudao.module.member.dal.dataobject.user.MemberUserDO;
12 import org.mapstruct.Mapper; 12 import org.mapstruct.Mapper;
13 import org.mapstruct.factory.Mappers; 13 import org.mapstruct.factory.Mappers;
14 14
@@ -28,10 +28,10 @@ public interface MemberSignInRecordConvert { @@ -28,10 +28,10 @@ public interface MemberSignInRecordConvert {
28 28
29 MemberSignInRecordConvert INSTANCE = Mappers.getMapper(MemberSignInRecordConvert.class); 29 MemberSignInRecordConvert INSTANCE = Mappers.getMapper(MemberSignInRecordConvert.class);
30 30
31 - default PageResult<MemberSignInRecordRespVO> convertPage(PageResult<MemberSignInRecordDO> pageResult, List<MemberUserRespDTO> users) { 31 + default PageResult<MemberSignInRecordRespVO> convertPage(PageResult<MemberSignInRecordDO> pageResult, List<MemberUserDO> users) {
32 PageResult<MemberSignInRecordRespVO> voPageResult = convertPage(pageResult); 32 PageResult<MemberSignInRecordRespVO> voPageResult = convertPage(pageResult);
33 // user 拼接 33 // user 拼接
34 - Map<Long, MemberUserRespDTO> userMap = convertMap(users, MemberUserRespDTO::getId); 34 + Map<Long, MemberUserDO> userMap = convertMap(users, MemberUserDO::getId);
35 voPageResult.getList().forEach(record -> MapUtils.findAndThen(userMap, record.getUserId(), 35 voPageResult.getList().forEach(record -> MapUtils.findAndThen(userMap, record.getUserId(),
36 memberUserRespDTO -> record.setNickname(memberUserRespDTO.getNickname()))); 36 memberUserRespDTO -> record.setNickname(memberUserRespDTO.getNickname())));
37 return voPageResult; 37 return voPageResult;
yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/mq/consumer/package-info.java 0 → 100644
  1 +/**
  2 + * 消息队列的消费者
  3 + */
  4 +package cn.iocoder.yudao.module.member.mq.consumer;
yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/mq/message/package-info.java 0 → 100644
  1 +/**
  2 + * 消息队列的消息
  3 + */
  4 +package cn.iocoder.yudao.module.member.mq.message;
yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/mq/message/user/UserCreateMessage.java deleted
1 -package cn.iocoder.yudao.module.member.mq.message.user;  
2 -  
3 -import cn.iocoder.yudao.framework.mq.core.stream.AbstractStreamMessage;  
4 -import lombok.Data;  
5 -import lombok.EqualsAndHashCode;  
6 -  
7 -import javax.validation.constraints.NotNull;  
8 -  
9 -/**  
10 - * 会员用户创建消息  
11 - *  
12 - * @author owen  
13 - */  
14 -@Data  
15 -@EqualsAndHashCode(callSuper = true)  
16 -public class UserCreateMessage extends AbstractStreamMessage {  
17 -  
18 - /**  
19 - * 用户编号  
20 - */  
21 - @NotNull(message = "用户编号不能为空")  
22 - private Long userId;  
23 -  
24 - @Override  
25 - public String getStreamKey() {  
26 - return "member.create.send";  
27 - }  
28 -  
29 -}  
yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/mq/producer/package-info.java 0 → 100644
  1 +/**
  2 + * 消息队列的生产者
  3 + */
  4 +package cn.iocoder.yudao.module.member.mq.producer;
yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/mq/producer/user/UserCreateProducer.java renamed to yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/mq/producer/user/MemberUserProducer.java
1 package cn.iocoder.yudao.module.member.mq.producer.user; 1 package cn.iocoder.yudao.module.member.mq.producer.user;
2 2
3 -import cn.iocoder.yudao.framework.mq.core.RedisMQTemplate;  
4 -import cn.iocoder.yudao.module.member.mq.message.user.UserCreateMessage; 3 +import cn.iocoder.yudao.module.member.message.user.MemberUserCreateMessage;
5 import lombok.extern.slf4j.Slf4j; 4 import lombok.extern.slf4j.Slf4j;
  5 +import org.springframework.context.ApplicationContext;
6 import org.springframework.stereotype.Component; 6 import org.springframework.stereotype.Component;
7 7
8 import javax.annotation.Resource; 8 import javax.annotation.Resource;
9 9
10 /** 10 /**
11 - * 会员用户创建 Producer 11 + * 会员用户 Producer
12 * 12 *
13 * @author owen 13 * @author owen
14 */ 14 */
15 @Slf4j 15 @Slf4j
16 @Component 16 @Component
17 -public class UserCreateProducer { 17 +public class MemberUserProducer {
18 18
19 @Resource 19 @Resource
20 - private RedisMQTemplate redisMQTemplate; 20 + private ApplicationContext applicationContext;
21 21
22 /** 22 /**
23 - * 发送 {@link UserCreateMessage} 消息 23 + * 发送 {@link MemberUserCreateMessage} 消息
24 * 24 *
25 * @param userId 用户编号 25 * @param userId 用户编号
26 */ 26 */
27 public void sendUserCreateMessage(Long userId) { 27 public void sendUserCreateMessage(Long userId) {
28 - redisMQTemplate.send(new UserCreateMessage().setUserId(userId)); 28 + applicationContext.publishEvent(new MemberUserCreateMessage().setUserId(userId));
29 } 29 }
30 30
31 } 31 }
yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/service/signin/MemberSignInRecordServiceImpl.java
@@ -7,18 +7,18 @@ import cn.iocoder.yudao.framework.common.pojo.PageParam; @@ -7,18 +7,18 @@ import cn.iocoder.yudao.framework.common.pojo.PageParam;
7 import cn.iocoder.yudao.framework.common.pojo.PageResult; 7 import cn.iocoder.yudao.framework.common.pojo.PageResult;
8 import cn.iocoder.yudao.framework.common.util.date.DateUtils; 8 import cn.iocoder.yudao.framework.common.util.date.DateUtils;
9 import cn.iocoder.yudao.framework.common.util.object.ObjectUtils; 9 import cn.iocoder.yudao.framework.common.util.object.ObjectUtils;
10 -import cn.iocoder.yudao.module.member.api.user.MemberUserApi;  
11 -import cn.iocoder.yudao.module.member.api.user.dto.MemberUserRespDTO;  
12 import cn.iocoder.yudao.module.member.controller.admin.signin.vo.record.MemberSignInRecordPageReqVO; 10 import cn.iocoder.yudao.module.member.controller.admin.signin.vo.record.MemberSignInRecordPageReqVO;
13 import cn.iocoder.yudao.module.member.controller.app.signin.vo.record.AppMemberSignInRecordSummaryRespVO; 11 import cn.iocoder.yudao.module.member.controller.app.signin.vo.record.AppMemberSignInRecordSummaryRespVO;
14 import cn.iocoder.yudao.module.member.convert.signin.MemberSignInRecordConvert; 12 import cn.iocoder.yudao.module.member.convert.signin.MemberSignInRecordConvert;
15 import cn.iocoder.yudao.module.member.dal.dataobject.signin.MemberSignInConfigDO; 13 import cn.iocoder.yudao.module.member.dal.dataobject.signin.MemberSignInConfigDO;
16 import cn.iocoder.yudao.module.member.dal.dataobject.signin.MemberSignInRecordDO; 14 import cn.iocoder.yudao.module.member.dal.dataobject.signin.MemberSignInRecordDO;
  15 +import cn.iocoder.yudao.module.member.dal.dataobject.user.MemberUserDO;
17 import cn.iocoder.yudao.module.member.dal.mysql.signin.MemberSignInRecordMapper; 16 import cn.iocoder.yudao.module.member.dal.mysql.signin.MemberSignInRecordMapper;
18 import cn.iocoder.yudao.module.member.enums.MemberExperienceBizTypeEnum; 17 import cn.iocoder.yudao.module.member.enums.MemberExperienceBizTypeEnum;
19 import cn.iocoder.yudao.module.member.enums.point.MemberPointBizTypeEnum; 18 import cn.iocoder.yudao.module.member.enums.point.MemberPointBizTypeEnum;
20 import cn.iocoder.yudao.module.member.service.level.MemberLevelService; 19 import cn.iocoder.yudao.module.member.service.level.MemberLevelService;
21 import cn.iocoder.yudao.module.member.service.point.MemberPointRecordService; 20 import cn.iocoder.yudao.module.member.service.point.MemberPointRecordService;
  21 +import cn.iocoder.yudao.module.member.service.user.MemberUserService;
22 import org.apache.commons.lang3.StringUtils; 22 import org.apache.commons.lang3.StringUtils;
23 import org.springframework.stereotype.Service; 23 import org.springframework.stereotype.Service;
24 import org.springframework.transaction.annotation.Transactional; 24 import org.springframework.transaction.annotation.Transactional;
@@ -53,7 +53,7 @@ public class MemberSignInRecordServiceImpl implements MemberSignInRecordService @@ -53,7 +53,7 @@ public class MemberSignInRecordServiceImpl implements MemberSignInRecordService
53 private MemberLevelService memberLevelService; 53 private MemberLevelService memberLevelService;
54 54
55 @Resource 55 @Resource
56 - private MemberUserApi memberUserApi; 56 + private MemberUserService memberUserService;
57 57
58 @Override 58 @Override
59 public AppMemberSignInRecordSummaryRespVO getSignInRecordSummary(Long userId) { 59 public AppMemberSignInRecordSummaryRespVO getSignInRecordSummary(Long userId) {
@@ -126,12 +126,12 @@ public class MemberSignInRecordServiceImpl implements MemberSignInRecordService @@ -126,12 +126,12 @@ public class MemberSignInRecordServiceImpl implements MemberSignInRecordService
126 // 根据用户昵称查询出用户ids 126 // 根据用户昵称查询出用户ids
127 Set<Long> userIds = null; 127 Set<Long> userIds = null;
128 if (StringUtils.isNotBlank(pageReqVO.getNickname())) { 128 if (StringUtils.isNotBlank(pageReqVO.getNickname())) {
129 - List<MemberUserRespDTO> users = memberUserApi.getUserListByNickname(pageReqVO.getNickname()); 129 + List<MemberUserDO> users = memberUserService.getUserListByNickname(pageReqVO.getNickname());
130 // 如果查询用户结果为空直接返回无需继续查询 130 // 如果查询用户结果为空直接返回无需继续查询
131 if (CollUtil.isEmpty(users)) { 131 if (CollUtil.isEmpty(users)) {
132 return PageResult.empty(); 132 return PageResult.empty();
133 } 133 }
134 - userIds = convertSet(users, MemberUserRespDTO::getId); 134 + userIds = convertSet(users, MemberUserDO::getId);
135 } 135 }
136 // 分页查询 136 // 分页查询
137 return signInRecordMapper.selectPage(pageReqVO, userIds); 137 return signInRecordMapper.selectPage(pageReqVO, userIds);
yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/service/user/MemberUserServiceImpl.java
@@ -7,7 +7,6 @@ import cn.hutool.core.util.ObjectUtil; @@ -7,7 +7,6 @@ import cn.hutool.core.util.ObjectUtil;
7 import cn.hutool.core.util.StrUtil; 7 import cn.hutool.core.util.StrUtil;
8 import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; 8 import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
9 import cn.iocoder.yudao.framework.common.pojo.PageResult; 9 import cn.iocoder.yudao.framework.common.pojo.PageResult;
10 -import cn.iocoder.yudao.module.infra.api.file.FileApi;  
11 import cn.iocoder.yudao.module.member.controller.admin.user.vo.MemberUserPageReqVO; 10 import cn.iocoder.yudao.module.member.controller.admin.user.vo.MemberUserPageReqVO;
12 import cn.iocoder.yudao.module.member.controller.admin.user.vo.MemberUserUpdateReqVO; 11 import cn.iocoder.yudao.module.member.controller.admin.user.vo.MemberUserUpdateReqVO;
13 import cn.iocoder.yudao.module.member.controller.app.user.vo.AppMemberUserResetPasswordReqVO; 12 import cn.iocoder.yudao.module.member.controller.app.user.vo.AppMemberUserResetPasswordReqVO;
@@ -18,7 +17,7 @@ import cn.iocoder.yudao.module.member.convert.auth.AuthConvert; @@ -18,7 +17,7 @@ import cn.iocoder.yudao.module.member.convert.auth.AuthConvert;
18 import cn.iocoder.yudao.module.member.convert.user.MemberUserConvert; 17 import cn.iocoder.yudao.module.member.convert.user.MemberUserConvert;
19 import cn.iocoder.yudao.module.member.dal.dataobject.user.MemberUserDO; 18 import cn.iocoder.yudao.module.member.dal.dataobject.user.MemberUserDO;
20 import cn.iocoder.yudao.module.member.dal.mysql.user.MemberUserMapper; 19 import cn.iocoder.yudao.module.member.dal.mysql.user.MemberUserMapper;
21 -import cn.iocoder.yudao.module.member.mq.producer.user.UserCreateProducer; 20 +import cn.iocoder.yudao.module.member.mq.producer.user.MemberUserProducer;
22 import cn.iocoder.yudao.module.system.api.sms.SmsCodeApi; 21 import cn.iocoder.yudao.module.system.api.sms.SmsCodeApi;
23 import cn.iocoder.yudao.module.system.api.sms.dto.code.SmsCodeUseReqDTO; 22 import cn.iocoder.yudao.module.system.api.sms.dto.code.SmsCodeUseReqDTO;
24 import cn.iocoder.yudao.module.system.enums.sms.SmsSceneEnum; 23 import cn.iocoder.yudao.module.system.enums.sms.SmsSceneEnum;
@@ -29,7 +28,6 @@ import org.springframework.stereotype.Service; @@ -29,7 +28,6 @@ import org.springframework.stereotype.Service;
29 import org.springframework.transaction.annotation.Transactional; 28 import org.springframework.transaction.annotation.Transactional;
30 import org.springframework.transaction.support.TransactionSynchronization; 29 import org.springframework.transaction.support.TransactionSynchronization;
31 import org.springframework.transaction.support.TransactionSynchronizationManager; 30 import org.springframework.transaction.support.TransactionSynchronizationManager;
32 -import org.springframework.transaction.support.TransactionTemplate;  
33 31
34 import javax.annotation.Resource; 32 import javax.annotation.Resource;
35 import javax.validation.Valid; 33 import javax.validation.Valid;
@@ -55,18 +53,13 @@ public class MemberUserServiceImpl implements MemberUserService { @@ -55,18 +53,13 @@ public class MemberUserServiceImpl implements MemberUserService {
55 private MemberUserMapper memberUserMapper; 53 private MemberUserMapper memberUserMapper;
56 54
57 @Resource 55 @Resource
58 - private FileApi fileApi;  
59 - @Resource  
60 private SmsCodeApi smsCodeApi; 56 private SmsCodeApi smsCodeApi;
61 57
62 @Resource 58 @Resource
63 private PasswordEncoder passwordEncoder; 59 private PasswordEncoder passwordEncoder;
64 60
65 @Resource 61 @Resource
66 - private UserCreateProducer registerCouponProducer;  
67 -  
68 - @Resource  
69 - private TransactionTemplate transactionTemplate; 62 + private MemberUserProducer memberUserProducer;
70 63
71 @Override 64 @Override
72 public MemberUserDO getUserByMobile(String mobile) { 65 public MemberUserDO getUserByMobile(String mobile) {
@@ -107,7 +100,7 @@ public class MemberUserServiceImpl implements MemberUserService { @@ -107,7 +100,7 @@ public class MemberUserServiceImpl implements MemberUserService {
107 100
108 @Override 101 @Override
109 public void afterCommit() { 102 public void afterCommit() {
110 - registerCouponProducer.sendUserCreateMessage(user.getId()); 103 + memberUserProducer.sendUserCreateMessage(user.getId());
111 } 104 }
112 105
113 }); 106 });
yudao-module-member/yudao-module-member-biz/src/test/java/cn/iocoder/yudao/module/member/service/address/AddressServiceImplTest.java renamed to yudao-module-member/yudao-module-member-biz/src/test/java/cn/iocoder/yudao/module/member/service/address/MemberAddressServiceImplTest.java
@@ -24,7 +24,7 @@ import static org.junit.jupiter.api.Assertions.assertNull; @@ -24,7 +24,7 @@ import static org.junit.jupiter.api.Assertions.assertNull;
24 * @author 芋道源码 24 * @author 芋道源码
25 */ 25 */
26 @Import(AddressServiceImpl.class) 26 @Import(AddressServiceImpl.class)
27 -public class AddressServiceImplTest extends BaseDbUnitTest { 27 +public class MemberAddressServiceImplTest extends BaseDbUnitTest {
28 28
29 @Resource 29 @Resource
30 private AddressServiceImpl addressService; 30 private AddressServiceImpl addressService;
yudao-module-pay/yudao-module-pay-api/src/main/java/cn/iocoder/yudao/module/pay/api/notify/dto/PayTransferNotifyReqDTO.java 0 → 100644
  1 +package cn.iocoder.yudao.module.pay.api.notify.dto;
  2 +
  3 +import lombok.Data;
  4 +
  5 +import javax.validation.constraints.NotEmpty;
  6 +import javax.validation.constraints.NotNull;
  7 +
  8 +/**
  9 + * 转账单的通知 Request DTO
  10 + *
  11 + * @author jason
  12 + */
  13 +@Data
  14 +public class PayTransferNotifyReqDTO {
  15 +
  16 + /**
  17 + * 商户转账单号
  18 + */
  19 + @NotEmpty(message = "商户转账单号不能为空")
  20 + private String merchantTransferId;
  21 +
  22 + /**
  23 + * 转账订单编号
  24 + */
  25 + @NotNull(message = "转账订单编号不能为空")
  26 + private Long payTransferId;
  27 +}
yudao-module-pay/yudao-module-pay-api/src/main/java/cn/iocoder/yudao/module/pay/api/transfer/dto/PayTransferCreateReqDTO.java
@@ -11,6 +11,8 @@ import javax.validation.constraints.NotNull; @@ -11,6 +11,8 @@ import javax.validation.constraints.NotNull;
11 import java.util.Map; 11 import java.util.Map;
12 12
13 /** 13 /**
  14 + * 转账单创建 Request DTO
  15 + *
14 * @author jason 16 * @author jason
15 */ 17 */
16 @Data 18 @Data
yudao-module-pay/yudao-module-pay-api/src/main/java/cn/iocoder/yudao/module/pay/enums/ErrorCodeConstants.java
@@ -65,12 +65,13 @@ public interface ErrorCodeConstants { @@ -65,12 +65,13 @@ public interface ErrorCodeConstants {
65 65
66 // ========== 转账模块 1-007-009-000 ========== 66 // ========== 转账模块 1-007-009-000 ==========
67 ErrorCode PAY_TRANSFER_SUBMIT_CHANNEL_ERROR = new ErrorCode(1_007_009_000, "发起转账报错,错误码:{},错误提示:{}"); 67 ErrorCode PAY_TRANSFER_SUBMIT_CHANNEL_ERROR = new ErrorCode(1_007_009_000, "发起转账报错,错误码:{},错误提示:{}");
68 - ErrorCode PAY_TRANSFER_NOT_FOUND = new ErrorCode(1_007_009_001, "转账交易单不存在");  
69 - ErrorCode PAY_TRANSFER_STATUS_IS_SUCCESS = new ErrorCode(1_007_009_002, "转账单已成功转账");  
70 - ErrorCode PAY_TRANSFER_EXISTS = new ErrorCode(1_007_009_003, "已经存在转账单");  
71 - ErrorCode PAY_MERCHANT_TRANSFER_EXISTS = new ErrorCode(1_007_009_004, "该笔业务的转账已经存在,请查询转账订单相关状态"); 68 + ErrorCode PAY_TRANSFER_NOT_FOUND = new ErrorCode(1_007_009_001, "转账单不存在");
  69 + ErrorCode PAY_SAME_MERCHANT_TRANSFER_TYPE_NOT_MATCH = new ErrorCode(1_007_009_002, "两次相同转账请求的类型不匹配");
  70 + ErrorCode PAY_SAME_MERCHANT_TRANSFER_PRICE_NOT_MATCH = new ErrorCode(1_007_009_003, "两次相同转账请求的金额不匹配");
  71 + ErrorCode PAY_MERCHANT_TRANSFER_EXISTS = new ErrorCode(1_007_009_004, "该笔业务的转账已经发起,请查询转账订单相关状态");
72 ErrorCode PAY_TRANSFER_STATUS_IS_NOT_WAITING = new ErrorCode(1_007_009_005, "转账单不处于待转账"); 72 ErrorCode PAY_TRANSFER_STATUS_IS_NOT_WAITING = new ErrorCode(1_007_009_005, "转账单不处于待转账");
73 ErrorCode PAY_TRANSFER_STATUS_IS_NOT_PENDING = new ErrorCode(1_007_009_006, "转账单不处于待转账或转账中"); 73 ErrorCode PAY_TRANSFER_STATUS_IS_NOT_PENDING = new ErrorCode(1_007_009_006, "转账单不处于待转账或转账中");
  74 +
74 // ========== 示例订单 1-007-900-000 ========== 75 // ========== 示例订单 1-007-900-000 ==========
75 ErrorCode DEMO_ORDER_NOT_FOUND = new ErrorCode(1_007_900_000, "示例订单不存在"); 76 ErrorCode DEMO_ORDER_NOT_FOUND = new ErrorCode(1_007_900_000, "示例订单不存在");
76 ErrorCode DEMO_ORDER_UPDATE_PAID_STATUS_NOT_UNPAID = new ErrorCode(1_007_900_001, "示例订单更新支付状态失败,订单不是【未支付】状态"); 77 ErrorCode DEMO_ORDER_UPDATE_PAID_STATUS_NOT_UNPAID = new ErrorCode(1_007_900_001, "示例订单更新支付状态失败,订单不是【未支付】状态");
@@ -84,4 +85,8 @@ public interface ErrorCodeConstants { @@ -84,4 +85,8 @@ public interface ErrorCodeConstants {
84 ErrorCode DEMO_ORDER_REFUND_FAIL_REFUND_ORDER_ID_ERROR = new ErrorCode(1_007_900_009, "发起退款失败,退款单编号不匹配"); 85 ErrorCode DEMO_ORDER_REFUND_FAIL_REFUND_ORDER_ID_ERROR = new ErrorCode(1_007_900_009, "发起退款失败,退款单编号不匹配");
85 ErrorCode DEMO_ORDER_REFUND_FAIL_REFUND_PRICE_NOT_MATCH = new ErrorCode(1_007_900_010, "发起退款失败,退款单金额不匹配"); 86 ErrorCode DEMO_ORDER_REFUND_FAIL_REFUND_PRICE_NOT_MATCH = new ErrorCode(1_007_900_010, "发起退款失败,退款单金额不匹配");
86 87
  88 + // ========== 示例转账订单 1-007-901-001 ==========
  89 + ErrorCode DEMO_TRANSFER_NOT_FOUND = new ErrorCode(1_007_901_001, "示例转账单不存在");
  90 + ErrorCode DEMO_TRANSFER_FAIL_TRANSFER_ID_ERROR = new ErrorCode(1_007_901_002, "转账失败,转账单编号不匹配");
  91 + ErrorCode DEMO_TRANSFER_FAIL_PRICE_NOT_MATCH = new ErrorCode(1_007_901_003, "转账失败,转账单金额不匹配");
87 } 92 }
yudao-module-pay/yudao-module-pay-api/src/main/java/cn/iocoder/yudao/module/pay/enums/notify/PayNotifyTypeEnum.java
@@ -14,6 +14,7 @@ public enum PayNotifyTypeEnum { @@ -14,6 +14,7 @@ public enum PayNotifyTypeEnum {
14 14
15 ORDER(1, "支付单"), 15 ORDER(1, "支付单"),
16 REFUND(2, "退款单"), 16 REFUND(2, "退款单"),
  17 + TRANSFER(3, "转账单")
17 ; 18 ;
18 19
19 /** 20 /**
yudao-module-pay/yudao-module-pay-api/src/main/java/cn/iocoder/yudao/module/pay/enums/transfer/PayTransferStatusEnum.java
@@ -40,9 +40,13 @@ public enum PayTransferStatusEnum { @@ -40,9 +40,13 @@ public enum PayTransferStatusEnum {
40 public static boolean isClosed(Integer status) { 40 public static boolean isClosed(Integer status) {
41 return Objects.equals(status, CLOSED.getStatus()); 41 return Objects.equals(status, CLOSED.getStatus());
42 } 42 }
  43 +
43 public static boolean isWaiting(Integer status) { 44 public static boolean isWaiting(Integer status) {
44 return Objects.equals(status, WAITING.getStatus()); 45 return Objects.equals(status, WAITING.getStatus());
45 } 46 }
  47 + public static boolean isInProgress(Integer status) {
  48 + return Objects.equals(status, IN_PROGRESS.getStatus());
  49 + }
46 50
47 /** 51 /**
48 * 是否处于待转账或者转账中的状态 52 * 是否处于待转账或者转账中的状态
yudao-module-pay/yudao-module-pay-api/src/main/java/cn/iocoder/yudao/module/pay/enums/member/PayWalletBizTypeEnum.java renamed to yudao-module-pay/yudao-module-pay-api/src/main/java/cn/iocoder/yudao/module/pay/enums/wallet/PayWalletBizTypeEnum.java
1 -package cn.iocoder.yudao.module.pay.enums.member; 1 +package cn.iocoder.yudao.module.pay.enums.wallet;
2 2
3 import cn.iocoder.yudao.framework.common.core.IntArrayValuable; 3 import cn.iocoder.yudao.framework.common.core.IntArrayValuable;
4 import lombok.AllArgsConstructor; 4 import lombok.AllArgsConstructor;
yudao-module-pay/yudao-module-pay-api/src/main/java/cn/iocoder/yudao/module/pay/package-info.java deleted
1 -package cn.iocoder.yudao.module.pay;  
yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/controller/admin/demo/PayDemoOrderController.java
@@ -6,8 +6,8 @@ import cn.iocoder.yudao.framework.common.pojo.PageResult; @@ -6,8 +6,8 @@ import cn.iocoder.yudao.framework.common.pojo.PageResult;
6 import cn.iocoder.yudao.framework.operatelog.core.annotations.OperateLog; 6 import cn.iocoder.yudao.framework.operatelog.core.annotations.OperateLog;
7 import cn.iocoder.yudao.module.pay.api.notify.dto.PayOrderNotifyReqDTO; 7 import cn.iocoder.yudao.module.pay.api.notify.dto.PayOrderNotifyReqDTO;
8 import cn.iocoder.yudao.module.pay.api.notify.dto.PayRefundNotifyReqDTO; 8 import cn.iocoder.yudao.module.pay.api.notify.dto.PayRefundNotifyReqDTO;
9 -import cn.iocoder.yudao.module.pay.controller.admin.demo.vo.PayDemoOrderCreateReqVO;  
10 -import cn.iocoder.yudao.module.pay.controller.admin.demo.vo.PayDemoOrderRespVO; 9 +import cn.iocoder.yudao.module.pay.controller.admin.demo.vo.order.PayDemoOrderCreateReqVO;
  10 +import cn.iocoder.yudao.module.pay.controller.admin.demo.vo.order.PayDemoOrderRespVO;
11 import cn.iocoder.yudao.module.pay.convert.demo.PayDemoOrderConvert; 11 import cn.iocoder.yudao.module.pay.convert.demo.PayDemoOrderConvert;
12 import cn.iocoder.yudao.module.pay.dal.dataobject.demo.PayDemoOrderDO; 12 import cn.iocoder.yudao.module.pay.dal.dataobject.demo.PayDemoOrderDO;
13 import cn.iocoder.yudao.module.pay.service.demo.PayDemoOrderService; 13 import cn.iocoder.yudao.module.pay.service.demo.PayDemoOrderService;
yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/controller/admin/demo/PayDemoTransferController.java
@@ -3,6 +3,8 @@ package cn.iocoder.yudao.module.pay.controller.admin.demo; @@ -3,6 +3,8 @@ package cn.iocoder.yudao.module.pay.controller.admin.demo;
3 import cn.iocoder.yudao.framework.common.pojo.CommonResult; 3 import cn.iocoder.yudao.framework.common.pojo.CommonResult;
4 import cn.iocoder.yudao.framework.common.pojo.PageParam; 4 import cn.iocoder.yudao.framework.common.pojo.PageParam;
5 import cn.iocoder.yudao.framework.common.pojo.PageResult; 5 import cn.iocoder.yudao.framework.common.pojo.PageResult;
  6 +import cn.iocoder.yudao.framework.operatelog.core.annotations.OperateLog;
  7 +import cn.iocoder.yudao.module.pay.api.notify.dto.PayTransferNotifyReqDTO;
6 import cn.iocoder.yudao.module.pay.controller.admin.demo.vo.transfer.PayDemoTransferCreateReqVO; 8 import cn.iocoder.yudao.module.pay.controller.admin.demo.vo.transfer.PayDemoTransferCreateReqVO;
7 import cn.iocoder.yudao.module.pay.controller.admin.demo.vo.transfer.PayDemoTransferRespVO; 9 import cn.iocoder.yudao.module.pay.controller.admin.demo.vo.transfer.PayDemoTransferRespVO;
8 import cn.iocoder.yudao.module.pay.convert.demo.PayDemoTransferConvert; 10 import cn.iocoder.yudao.module.pay.convert.demo.PayDemoTransferConvert;
@@ -14,6 +16,7 @@ import org.springframework.validation.annotation.Validated; @@ -14,6 +16,7 @@ import org.springframework.validation.annotation.Validated;
14 import org.springframework.web.bind.annotation.*; 16 import org.springframework.web.bind.annotation.*;
15 17
16 import javax.annotation.Resource; 18 import javax.annotation.Resource;
  19 +import javax.annotation.security.PermitAll;
17 import javax.validation.Valid; 20 import javax.validation.Valid;
18 21
19 import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; 22 import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
@@ -33,9 +36,19 @@ public class PayDemoTransferController { @@ -33,9 +36,19 @@ public class PayDemoTransferController {
33 } 36 }
34 37
35 @GetMapping("/page") 38 @GetMapping("/page")
36 - @Operation(summary = "获得示例订单分页") 39 + @Operation(summary = "获得示例转账订单分页")
37 public CommonResult<PageResult<PayDemoTransferRespVO>> getDemoTransferPage(@Valid PageParam pageVO) { 40 public CommonResult<PageResult<PayDemoTransferRespVO>> getDemoTransferPage(@Valid PageParam pageVO) {
38 PageResult<PayDemoTransferDO> pageResult = demoTransferService.getDemoTransferPage(pageVO); 41 PageResult<PayDemoTransferDO> pageResult = demoTransferService.getDemoTransferPage(pageVO);
39 return success(PayDemoTransferConvert.INSTANCE.convertPage(pageResult)); 42 return success(PayDemoTransferConvert.INSTANCE.convertPage(pageResult));
40 } 43 }
  44 +
  45 + @PostMapping("/update-status")
  46 + @Operation(summary = "更新示例转账订单的转账状态") // 由 pay-module 转账服务,进行回调
  47 + @PermitAll // 无需登录,安全由 PayDemoTransferService 内部校验实现
  48 + @OperateLog(enable = false) // 禁用操作日志,因为没有操作人
  49 + public CommonResult<Boolean> updateDemoTransferStatus(@RequestBody PayTransferNotifyReqDTO notifyReqDTO) {
  50 + demoTransferService.updateDemoTransferStatus(Long.valueOf(notifyReqDTO.getMerchantTransferId()),
  51 + notifyReqDTO.getPayTransferId());
  52 + return success(true);
  53 + }
41 } 54 }
yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/controller/admin/demo/vo/PayDemoOrderCreateReqVO.java renamed to yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/controller/admin/demo/vo/order/PayDemoOrderCreateReqVO.java
1 -package cn.iocoder.yudao.module.pay.controller.admin.demo.vo; 1 +package cn.iocoder.yudao.module.pay.controller.admin.demo.vo.order;
2 2
3 -import lombok.*;  
4 import io.swagger.v3.oas.annotations.media.Schema; 3 import io.swagger.v3.oas.annotations.media.Schema;
  4 +import lombok.Data;
5 5
6 -import javax.validation.constraints.NotEmpty;  
7 import javax.validation.constraints.NotNull; 6 import javax.validation.constraints.NotNull;
8 7
9 @Schema(description = "管理后台 - 示例订单创建 Request VO") 8 @Schema(description = "管理后台 - 示例订单创建 Request VO")
yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/controller/admin/demo/vo/PayDemoOrderRespVO.java renamed to yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/controller/admin/demo/vo/order/PayDemoOrderRespVO.java
1 -package cn.iocoder.yudao.module.pay.controller.admin.demo.vo; 1 +package cn.iocoder.yudao.module.pay.controller.admin.demo.vo.order;
2 2
3 import io.swagger.v3.oas.annotations.media.Schema; 3 import io.swagger.v3.oas.annotations.media.Schema;
4 import lombok.*; 4 import lombok.*;
yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/controller/admin/transfer/PayTransferController.java
1 package cn.iocoder.yudao.module.pay.controller.admin.transfer; 1 package cn.iocoder.yudao.module.pay.controller.admin.transfer;
2 2
3 import cn.iocoder.yudao.framework.common.pojo.CommonResult; 3 import cn.iocoder.yudao.framework.common.pojo.CommonResult;
4 -import cn.iocoder.yudao.module.pay.controller.admin.transfer.vo.PayTransferCreateReqVO;  
5 -import cn.iocoder.yudao.module.pay.controller.admin.transfer.vo.PayTransferCreateRespVO; 4 +import cn.iocoder.yudao.framework.common.pojo.PageResult;
  5 +import cn.iocoder.yudao.module.pay.controller.admin.transfer.vo.*;
  6 +import cn.iocoder.yudao.module.pay.convert.transfer.PayTransferConvert;
6 import cn.iocoder.yudao.module.pay.dal.dataobject.transfer.PayTransferDO; 7 import cn.iocoder.yudao.module.pay.dal.dataobject.transfer.PayTransferDO;
7 import cn.iocoder.yudao.module.pay.service.transfer.PayTransferService; 8 import cn.iocoder.yudao.module.pay.service.transfer.PayTransferService;
8 import io.swagger.v3.oas.annotations.Operation; 9 import io.swagger.v3.oas.annotations.Operation;
9 import io.swagger.v3.oas.annotations.tags.Tag; 10 import io.swagger.v3.oas.annotations.tags.Tag;
  11 +import org.springframework.security.access.prepost.PreAuthorize;
10 import org.springframework.validation.annotation.Validated; 12 import org.springframework.validation.annotation.Validated;
11 -import org.springframework.web.bind.annotation.PostMapping;  
12 -import org.springframework.web.bind.annotation.RequestBody;  
13 -import org.springframework.web.bind.annotation.RequestMapping;  
14 -import org.springframework.web.bind.annotation.RestController; 13 +import org.springframework.web.bind.annotation.*;
15 14
16 import javax.annotation.Resource; 15 import javax.annotation.Resource;
17 import javax.validation.Valid; 16 import javax.validation.Valid;
@@ -30,10 +29,24 @@ public class PayTransferController { @@ -30,10 +29,24 @@ public class PayTransferController {
30 29
31 @PostMapping("/create") 30 @PostMapping("/create")
32 @Operation(summary = "创建转账单,发起转账") 31 @Operation(summary = "创建转账单,发起转账")
33 - // TODO @jason:权限的设置, 管理后台页面加的时候加一下 32 + @PreAuthorize("@ss.hasPermission('pay:transfer:create')")
34 public CommonResult<PayTransferCreateRespVO> createPayTransfer(@Valid @RequestBody PayTransferCreateReqVO reqVO) { 33 public CommonResult<PayTransferCreateRespVO> createPayTransfer(@Valid @RequestBody PayTransferCreateReqVO reqVO) {
35 PayTransferDO payTransfer = payTransferService.createTransfer(reqVO, getClientIP()); 34 PayTransferDO payTransfer = payTransferService.createTransfer(reqVO, getClientIP());
36 return success(new PayTransferCreateRespVO().setId(payTransfer.getId()).setStatus(payTransfer.getStatus())); 35 return success(new PayTransferCreateRespVO().setId(payTransfer.getId()).setStatus(payTransfer.getStatus()));
37 } 36 }
38 37
  38 + @GetMapping("/get")
  39 + @Operation(summary = "获得转账订单")
  40 + @PreAuthorize("@ss.hasPermission('pay:transfer:query')")
  41 + public CommonResult<PayTransferRespVO> getTransfer(@RequestParam("id") Long id) {
  42 + return success(PayTransferConvert.INSTANCE.convert(payTransferService.getTransfer(id)));
  43 + }
  44 +
  45 + @GetMapping("/page")
  46 + @Operation(summary = "获得转账订单分页")
  47 + @PreAuthorize("@ss.hasPermission('pay:transfer:query')")
  48 + public CommonResult<PageResult<PayTransferPageItemRespVO>> getTransferPage(@Valid PayTransferPageReqVO pageVO) {
  49 + PageResult<PayTransferDO> pageResult = payTransferService.getTransferPage(pageVO);
  50 + return success(PayTransferConvert.INSTANCE.convertPage(pageResult));
  51 + }
39 } 52 }
yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/controller/admin/transfer/vo/PayTransferPageItemRespVO.java 0 → 100644
  1 +package cn.iocoder.yudao.module.pay.controller.admin.transfer.vo;
  2 +
  3 +import io.swagger.v3.oas.annotations.media.Schema;
  4 +import lombok.Data;
  5 +
  6 +import java.time.LocalDateTime;
  7 +
  8 +/**
  9 + * @author jason
  10 + */
  11 +@Schema(description = "管理后台 - 转账单分页项 Response VO")
  12 +@Data
  13 +public class PayTransferPageItemRespVO {
  14 +
  15 + @Schema(description = "编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "2931")
  16 + private Long id;
  17 +
  18 + @Schema(description = "转账单号", requiredMode = Schema.RequiredMode.REQUIRED)
  19 + private String no;
  20 +
  21 + @Schema(description = "应用编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "12831")
  22 + private Long appId;
  23 +
  24 + @Schema(description = "转账渠道编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "24833")
  25 + private Long channelId;
  26 +
  27 + @Schema(description = "转账渠道编码", requiredMode = Schema.RequiredMode.REQUIRED)
  28 + private String channelCode;
  29 +
  30 + @Schema(description = "商户转账单编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "17481")
  31 + private String merchantTransferId;
  32 +
  33 + @Schema(description = "类型", requiredMode = Schema.RequiredMode.REQUIRED, example = "2")
  34 + private Integer type;
  35 +
  36 + @Schema(description = "转账状态", requiredMode = Schema.RequiredMode.REQUIRED, example = "2")
  37 + private Integer status;
  38 +
  39 + @Schema(description = "转账成功时间")
  40 + private LocalDateTime successTime;
  41 +
  42 + @Schema(description = "转账金额", requiredMode = Schema.RequiredMode.REQUIRED, example = "964")
  43 + private Integer price;
  44 +
  45 + @Schema(description = "转账标题", requiredMode = Schema.RequiredMode.REQUIRED)
  46 + private String subject;
  47 +
  48 + @Schema(description = "收款人姓名", example = "王五")
  49 + private String userName;
  50 +
  51 + @Schema(description = "支付宝登录号", example = "29245")
  52 + private String alipayLogonId;
  53 +
  54 + @Schema(description = "微信 openId", example = "26589")
  55 + private String openid;
  56 +
  57 + @Schema(description = "渠道转账单号")
  58 + private String channelTransferNo;
  59 +
  60 + @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED)
  61 + private LocalDateTime createTime;
  62 +}
yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/controller/admin/transfer/vo/PayTransferPageReqVO.java 0 → 100644
  1 +package cn.iocoder.yudao.module.pay.controller.admin.transfer.vo;
  2 +
  3 +import lombok.*;
  4 +import io.swagger.v3.oas.annotations.media.Schema;
  5 +import cn.iocoder.yudao.framework.common.pojo.PageParam;
  6 +import org.springframework.format.annotation.DateTimeFormat;
  7 +import java.time.LocalDateTime;
  8 +
  9 +import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND;
  10 +
  11 +@Schema(description = "管理后台 - 转账单分页 Request VO")
  12 +@Data
  13 +@EqualsAndHashCode(callSuper = true)
  14 +@ToString(callSuper = true)
  15 +public class PayTransferPageReqVO extends PageParam {
  16 +
  17 + @Schema(description = "转账单号")
  18 + private String no;
  19 +
  20 + @Schema(description = "应用编号", example = "12831")
  21 + private Long appId;
  22 +
  23 + @Schema(description = "渠道编码", example = "wx_app")
  24 + private String channelCode;
  25 +
  26 + @Schema(description = "商户转账单编号", example = "17481")
  27 + private String merchantTransferId;
  28 +
  29 + @Schema(description = "类型", example = "2")
  30 + private Integer type;
  31 +
  32 + @Schema(description = "转账状态", example = "2")
  33 + private Integer status;
  34 +
  35 + @Schema(description = "收款人姓名", example = "王五")
  36 + private String userName;
  37 +
  38 + @Schema(description = "渠道转账单号")
  39 + private String channelTransferNo;
  40 +
  41 + @Schema(description = "创建时间")
  42 + @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
  43 + private LocalDateTime[] createTime;
  44 +
  45 +}
yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/controller/admin/transfer/vo/PayTransferRespVO.java 0 → 100644
  1 +package cn.iocoder.yudao.module.pay.controller.admin.transfer.vo;
  2 +
  3 +import io.swagger.v3.oas.annotations.media.Schema;
  4 +import lombok.*;
  5 +import java.time.LocalDateTime;
  6 +import java.util.Map;
  7 +
  8 +@Schema(description = "管理后台 - 转账单 Response VO")
  9 +@Data
  10 +public class PayTransferRespVO {
  11 +
  12 + @Schema(description = "编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "2931")
  13 + private Long id;
  14 +
  15 + @Schema(description = "转账单号", requiredMode = Schema.RequiredMode.REQUIRED)
  16 + private String no;
  17 +
  18 + @Schema(description = "应用编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "12831")
  19 + private Long appId;
  20 +
  21 + @Schema(description = "转账渠道编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "24833")
  22 + private Long channelId;
  23 +
  24 + @Schema(description = "转账渠道编码", requiredMode = Schema.RequiredMode.REQUIRED)
  25 + private String channelCode;
  26 +
  27 + @Schema(description = "商户转账单编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "17481")
  28 + private String merchantTransferId;
  29 +
  30 + @Schema(description = "类型", requiredMode = Schema.RequiredMode.REQUIRED, example = "2")
  31 + private Integer type;
  32 +
  33 + @Schema(description = "转账状态", requiredMode = Schema.RequiredMode.REQUIRED, example = "2")
  34 + private Integer status;
  35 +
  36 + @Schema(description = "转账成功时间")
  37 + private LocalDateTime successTime;
  38 +
  39 + @Schema(description = "转账金额", requiredMode = Schema.RequiredMode.REQUIRED, example = "964")
  40 + private Integer price;
  41 +
  42 + @Schema(description = "转账标题", requiredMode = Schema.RequiredMode.REQUIRED)
  43 + private String subject;
  44 +
  45 + @Schema(description = "收款人姓名", example = "王五")
  46 + private String userName;
  47 +
  48 + @Schema(description = "支付宝登录号", example = "29245")
  49 + private String alipayLogonId;
  50 +
  51 + @Schema(description = "微信 openId", example = "26589")
  52 + private String openid;
  53 +
  54 + @Schema(description = "异步通知商户地址", requiredMode = Schema.RequiredMode.REQUIRED, example = "https://www.iocoder.cn")
  55 + private String notifyUrl;
  56 +
  57 + @Schema(description = "用户 IP", requiredMode = Schema.RequiredMode.REQUIRED)
  58 + private String userIp;
  59 +
  60 + @Schema(description = "渠道的额外参数")
  61 + private Map<String, String> channelExtras;
  62 +
  63 + @Schema(description = "渠道转账单号")
  64 + private String channelTransferNo;
  65 +
  66 + @Schema(description = "调用渠道的错误码")
  67 + private String channelErrorCode;
  68 +
  69 + @Schema(description = "调用渠道的错误提示")
  70 + private String channelErrorMsg;
  71 +
  72 + @Schema(description = "渠道的同步/异步通知的内容")
  73 + private String channelNotifyData;
  74 +
  75 + @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED)
  76 + private LocalDateTime createTime;
  77 +
  78 +}
yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/controller/admin/wallet/PayWalletController.java
@@ -4,7 +4,6 @@ import cn.hutool.core.collection.CollectionUtil; @@ -4,7 +4,6 @@ import cn.hutool.core.collection.CollectionUtil;
4 import cn.hutool.core.util.StrUtil; 4 import cn.hutool.core.util.StrUtil;
5 import cn.iocoder.yudao.framework.common.pojo.CommonResult; 5 import cn.iocoder.yudao.framework.common.pojo.CommonResult;
6 import cn.iocoder.yudao.framework.common.pojo.PageResult; 6 import cn.iocoder.yudao.framework.common.pojo.PageResult;
7 -import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils;  
8 import cn.iocoder.yudao.module.member.api.user.MemberUserApi; 7 import cn.iocoder.yudao.module.member.api.user.MemberUserApi;
9 import cn.iocoder.yudao.module.member.api.user.dto.MemberUserRespDTO; 8 import cn.iocoder.yudao.module.member.api.user.dto.MemberUserRespDTO;
10 import cn.iocoder.yudao.module.pay.controller.admin.wallet.vo.wallet.PayWalletPageReqVO; 9 import cn.iocoder.yudao.module.pay.controller.admin.wallet.vo.wallet.PayWalletPageReqVO;
@@ -26,12 +25,10 @@ import javax.annotation.Resource; @@ -26,12 +25,10 @@ import javax.annotation.Resource;
26 import javax.validation.Valid; 25 import javax.validation.Valid;
27 import java.util.List; 26 import java.util.List;
28 import java.util.Map; 27 import java.util.Map;
29 -import java.util.Set;  
30 28
31 import static cn.iocoder.yudao.framework.common.enums.UserTypeEnum.MEMBER; 29 import static cn.iocoder.yudao.framework.common.enums.UserTypeEnum.MEMBER;
32 import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; 30 import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
33 -import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertList;  
34 -import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertMap; 31 +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.*;
35 32
36 @Tag(name = "管理后台 - 用户钱包") 33 @Tag(name = "管理后台 - 用户钱包")
37 @RestController 34 @RestController
@@ -50,6 +47,7 @@ public class PayWalletController { @@ -50,6 +47,7 @@ public class PayWalletController {
50 @Operation(summary = "获得用户钱包明细") 47 @Operation(summary = "获得用户钱包明细")
51 public CommonResult<PayWalletRespVO> getWallet(PayWalletUserReqVO reqVO) { 48 public CommonResult<PayWalletRespVO> getWallet(PayWalletUserReqVO reqVO) {
52 PayWalletDO wallet = payWalletService.getOrCreateWallet(reqVO.getUserId(), MEMBER.getValue()); 49 PayWalletDO wallet = payWalletService.getOrCreateWallet(reqVO.getUserId(), MEMBER.getValue());
  50 + // TODO jason:如果为空,返回给前端只要 null 就可以了
53 MemberUserRespDTO memberUser = memberUserApi.getUser(reqVO.getUserId()); 51 MemberUserRespDTO memberUser = memberUserApi.getUser(reqVO.getUserId());
54 String nickname = memberUser == null ? "" : memberUser.getNickname(); 52 String nickname = memberUser == null ? "" : memberUser.getNickname();
55 String avatar = memberUser == null ? "" : memberUser.getAvatar(); 53 String avatar = memberUser == null ? "" : memberUser.getAvatar();
@@ -61,9 +59,8 @@ public class PayWalletController { @@ -61,9 +59,8 @@ public class PayWalletController {
61 @PreAuthorize("@ss.hasPermission('pay:wallet:query')") 59 @PreAuthorize("@ss.hasPermission('pay:wallet:query')")
62 public CommonResult<PageResult<PayWalletRespVO>> getWalletPage(@Valid PayWalletPageReqVO pageVO) { 60 public CommonResult<PageResult<PayWalletRespVO>> getWalletPage(@Valid PayWalletPageReqVO pageVO) {
63 if (StrUtil.isNotEmpty(pageVO.getNickname())) { 61 if (StrUtil.isNotEmpty(pageVO.getNickname())) {
64 - Set<Long> userIds = CollectionUtils.convertSet(memberUserApi.getUserListByNickname(pageVO.getNickname()),  
65 - MemberUserRespDTO::getId);  
66 - pageVO.setUserIds(userIds); 62 + List<MemberUserRespDTO> users = memberUserApi.getUserListByNickname(pageVO.getNickname());
  63 + pageVO.setUserIds(convertSet(users, MemberUserRespDTO::getId));
67 } 64 }
68 // TODO @jason:管理员也可以先查询下。。 65 // TODO @jason:管理员也可以先查询下。。
69 // 暂时支持查询 userType 会员类型。管理员类型还不知道使用场景 66 // 暂时支持查询 userType 会员类型。管理员类型还不知道使用场景
@@ -71,8 +68,8 @@ public class PayWalletController { @@ -71,8 +68,8 @@ public class PayWalletController {
71 if (CollectionUtil.isEmpty(pageResult.getList())) { 68 if (CollectionUtil.isEmpty(pageResult.getList())) {
72 return success(new PageResult<>(pageResult.getTotal())); 69 return success(new PageResult<>(pageResult.getTotal()));
73 } 70 }
74 - List<Long> userIds = convertList(pageResult.getList(), PayWalletDO::getUserId);  
75 - Map<Long, MemberUserRespDTO> userMap = convertMap(memberUserApi.getUserList(userIds),MemberUserRespDTO::getId); 71 + List<MemberUserRespDTO> users = memberUserApi.getUserList(convertList(pageResult.getList(), PayWalletDO::getUserId));
  72 + Map<Long, MemberUserRespDTO> userMap = convertMap(users, MemberUserRespDTO::getId);
76 return success(PayWalletConvert.INSTANCE.convertPage(pageResult, userMap)); 73 return success(PayWalletConvert.INSTANCE.convertPage(pageResult, userMap));
77 } 74 }
78 75
yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/convert/demo/PayDemoOrderConvert.java
1 package cn.iocoder.yudao.module.pay.convert.demo; 1 package cn.iocoder.yudao.module.pay.convert.demo;
2 2
3 import cn.iocoder.yudao.framework.common.pojo.PageResult; 3 import cn.iocoder.yudao.framework.common.pojo.PageResult;
4 -import cn.iocoder.yudao.module.pay.controller.admin.demo.vo.PayDemoOrderCreateReqVO;  
5 -import cn.iocoder.yudao.module.pay.controller.admin.demo.vo.PayDemoOrderRespVO; 4 +import cn.iocoder.yudao.module.pay.controller.admin.demo.vo.order.PayDemoOrderCreateReqVO;
  5 +import cn.iocoder.yudao.module.pay.controller.admin.demo.vo.order.PayDemoOrderRespVO;
6 import cn.iocoder.yudao.module.pay.dal.dataobject.demo.PayDemoOrderDO; 6 import cn.iocoder.yudao.module.pay.dal.dataobject.demo.PayDemoOrderDO;
7 import org.mapstruct.Mapper; 7 import org.mapstruct.Mapper;
8 import org.mapstruct.factory.Mappers; 8 import org.mapstruct.factory.Mappers;
yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/convert/transfer/PayTransferConvert.java
1 package cn.iocoder.yudao.module.pay.convert.transfer; 1 package cn.iocoder.yudao.module.pay.convert.transfer;
2 2
  3 +import cn.iocoder.yudao.framework.common.pojo.PageResult;
3 import cn.iocoder.yudao.framework.pay.core.client.dto.transfer.PayTransferUnifiedReqDTO; 4 import cn.iocoder.yudao.framework.pay.core.client.dto.transfer.PayTransferUnifiedReqDTO;
4 import cn.iocoder.yudao.module.pay.api.transfer.dto.PayTransferCreateReqDTO; 5 import cn.iocoder.yudao.module.pay.api.transfer.dto.PayTransferCreateReqDTO;
5 import cn.iocoder.yudao.module.pay.controller.admin.demo.vo.transfer.PayDemoTransferCreateReqVO; 6 import cn.iocoder.yudao.module.pay.controller.admin.demo.vo.transfer.PayDemoTransferCreateReqVO;
6 import cn.iocoder.yudao.module.pay.controller.admin.transfer.vo.PayTransferCreateReqVO; 7 import cn.iocoder.yudao.module.pay.controller.admin.transfer.vo.PayTransferCreateReqVO;
  8 +import cn.iocoder.yudao.module.pay.controller.admin.transfer.vo.PayTransferPageItemRespVO;
  9 +import cn.iocoder.yudao.module.pay.controller.admin.transfer.vo.PayTransferRespVO;
7 import cn.iocoder.yudao.module.pay.dal.dataobject.transfer.PayTransferDO; 10 import cn.iocoder.yudao.module.pay.dal.dataobject.transfer.PayTransferDO;
8 import org.mapstruct.Mapper; 11 import org.mapstruct.Mapper;
9 import org.mapstruct.factory.Mappers; 12 import org.mapstruct.factory.Mappers;
@@ -15,10 +18,13 @@ public interface PayTransferConvert { @@ -15,10 +18,13 @@ public interface PayTransferConvert {
15 18
16 PayTransferDO convert(PayTransferCreateReqDTO dto); 19 PayTransferDO convert(PayTransferCreateReqDTO dto);
17 20
18 - PayTransferUnifiedReqDTO convert2(PayTransferCreateReqDTO dto); 21 + PayTransferUnifiedReqDTO convert2(PayTransferDO dto);
19 22
20 PayTransferCreateReqDTO convert(PayTransferCreateReqVO vo); 23 PayTransferCreateReqDTO convert(PayTransferCreateReqVO vo);
21 24
22 PayTransferCreateReqDTO convert(PayDemoTransferCreateReqVO vo); 25 PayTransferCreateReqDTO convert(PayDemoTransferCreateReqVO vo);
23 26
  27 + PayTransferRespVO convert(PayTransferDO bean);
  28 +
  29 + PageResult<PayTransferPageItemRespVO> convertPage(PageResult<PayTransferDO> pageResult);
24 } 30 }
yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/dal/dataobject/app/PayAppDO.java
@@ -54,4 +54,9 @@ public class PayAppDO extends BaseDO { @@ -54,4 +54,9 @@ public class PayAppDO extends BaseDO {
54 */ 54 */
55 private String refundNotifyUrl; 55 private String refundNotifyUrl;
56 56
  57 + /**
  58 + * 转账结果的回调地址
  59 + */
  60 + private String transferNotifyUrl;
  61 +
57 } 62 }
yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/dal/dataobject/notify/PayNotifyTaskDO.java
@@ -67,6 +67,10 @@ public class PayNotifyTaskDO extends TenantBaseDO { @@ -67,6 +67,10 @@ public class PayNotifyTaskDO extends TenantBaseDO {
67 */ 67 */
68 private String merchantOrderId; 68 private String merchantOrderId;
69 /** 69 /**
  70 + * 商户转账单编号
  71 + */
  72 + private String merchantTransferId;
  73 + /**
70 * 通知状态 74 * 通知状态
71 * 75 *
72 * 外键 {@link PayNotifyStatusEnum} 76 * 外键 {@link PayNotifyStatusEnum}
yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/dal/dataobject/wallet/PayWalletTransactionDO.java
1 package cn.iocoder.yudao.module.pay.dal.dataobject.wallet; 1 package cn.iocoder.yudao.module.pay.dal.dataobject.wallet;
2 2
3 import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; 3 import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
4 -import cn.iocoder.yudao.module.pay.enums.member.PayWalletBizTypeEnum; 4 +import cn.iocoder.yudao.module.pay.enums.wallet.PayWalletBizTypeEnum;
5 import com.baomidou.mybatisplus.annotation.KeySequence; 5 import com.baomidou.mybatisplus.annotation.KeySequence;
6 import com.baomidou.mybatisplus.annotation.TableId; 6 import com.baomidou.mybatisplus.annotation.TableId;
7 import com.baomidou.mybatisplus.annotation.TableName; 7 import com.baomidou.mybatisplus.annotation.TableName;
yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/dal/mysql/transfer/PayTransferMapper.java
1 package cn.iocoder.yudao.module.pay.dal.mysql.transfer; 1 package cn.iocoder.yudao.module.pay.dal.mysql.transfer;
2 2
3 -import cn.iocoder.yudao.module.pay.dal.dataobject.transfer.PayTransferDO; 3 +import cn.iocoder.yudao.framework.common.pojo.PageResult;
4 import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; 4 import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX;
  5 +import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX;
  6 +import cn.iocoder.yudao.module.pay.controller.admin.transfer.vo.PayTransferPageReqVO;
  7 +import cn.iocoder.yudao.module.pay.dal.dataobject.transfer.PayTransferDO;
5 import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; 8 import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
6 import org.apache.ibatis.annotations.Mapper; 9 import org.apache.ibatis.annotations.Mapper;
7 10
@@ -23,6 +26,24 @@ public interface PayTransferMapper extends BaseMapperX&lt;PayTransferDO&gt; { @@ -23,6 +26,24 @@ public interface PayTransferMapper extends BaseMapperX&lt;PayTransferDO&gt; {
23 default PayTransferDO selectByNo(String no){ 26 default PayTransferDO selectByNo(String no){
24 return selectOne(PayTransferDO::getNo, no); 27 return selectOne(PayTransferDO::getNo, no);
25 } 28 }
  29 +
  30 + default PageResult<PayTransferDO> selectPage(PayTransferPageReqVO reqVO) {
  31 + return selectPage(reqVO, new LambdaQueryWrapperX<PayTransferDO>()
  32 + .eqIfPresent(PayTransferDO::getNo, reqVO.getNo())
  33 + .eqIfPresent(PayTransferDO::getAppId, reqVO.getAppId())
  34 + .eqIfPresent(PayTransferDO::getChannelCode, reqVO.getChannelCode())
  35 + .eqIfPresent(PayTransferDO::getMerchantTransferId, reqVO.getMerchantTransferId())
  36 + .eqIfPresent(PayTransferDO::getType, reqVO.getType())
  37 + .eqIfPresent(PayTransferDO::getStatus, reqVO.getStatus())
  38 + .likeIfPresent(PayTransferDO::getUserName, reqVO.getUserName())
  39 + .eqIfPresent(PayTransferDO::getChannelTransferNo, reqVO.getChannelTransferNo())
  40 + .betweenIfPresent(PayTransferDO::getCreateTime, reqVO.getCreateTime())
  41 + .orderByDesc(PayTransferDO::getId));
  42 + }
  43 +
  44 + default List<PayTransferDO> selectListByStatus(Integer status){
  45 + return selectList(PayTransferDO::getStatus, status);
  46 + }
26 } 47 }
27 48
28 49
yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/framework/pay/core/WalletPayClient.java
@@ -14,10 +14,11 @@ import cn.iocoder.yudao.framework.pay.core.client.impl.AbstractPayClient; @@ -14,10 +14,11 @@ import cn.iocoder.yudao.framework.pay.core.client.impl.AbstractPayClient;
14 import cn.iocoder.yudao.framework.pay.core.client.impl.NonePayClientConfig; 14 import cn.iocoder.yudao.framework.pay.core.client.impl.NonePayClientConfig;
15 import cn.iocoder.yudao.framework.pay.core.enums.channel.PayChannelEnum; 15 import cn.iocoder.yudao.framework.pay.core.enums.channel.PayChannelEnum;
16 import cn.iocoder.yudao.framework.pay.core.enums.refund.PayRefundStatusRespEnum; 16 import cn.iocoder.yudao.framework.pay.core.enums.refund.PayRefundStatusRespEnum;
  17 +import cn.iocoder.yudao.framework.pay.core.enums.transfer.PayTransferTypeEnum;
17 import cn.iocoder.yudao.module.pay.dal.dataobject.order.PayOrderExtensionDO; 18 import cn.iocoder.yudao.module.pay.dal.dataobject.order.PayOrderExtensionDO;
18 import cn.iocoder.yudao.module.pay.dal.dataobject.refund.PayRefundDO; 19 import cn.iocoder.yudao.module.pay.dal.dataobject.refund.PayRefundDO;
19 import cn.iocoder.yudao.module.pay.dal.dataobject.wallet.PayWalletTransactionDO; 20 import cn.iocoder.yudao.module.pay.dal.dataobject.wallet.PayWalletTransactionDO;
20 -import cn.iocoder.yudao.module.pay.enums.member.PayWalletBizTypeEnum; 21 +import cn.iocoder.yudao.module.pay.enums.wallet.PayWalletBizTypeEnum;
21 import cn.iocoder.yudao.module.pay.enums.order.PayOrderStatusEnum; 22 import cn.iocoder.yudao.module.pay.enums.order.PayOrderStatusEnum;
22 import cn.iocoder.yudao.module.pay.service.order.PayOrderService; 23 import cn.iocoder.yudao.module.pay.service.order.PayOrderService;
23 import cn.iocoder.yudao.module.pay.service.refund.PayRefundService; 24 import cn.iocoder.yudao.module.pay.service.refund.PayRefundService;
@@ -181,4 +182,9 @@ public class WalletPayClient extends AbstractPayClient&lt;NonePayClientConfig&gt; { @@ -181,4 +182,9 @@ public class WalletPayClient extends AbstractPayClient&lt;NonePayClientConfig&gt; {
181 throw new UnsupportedOperationException("待实现"); 182 throw new UnsupportedOperationException("待实现");
182 } 183 }
183 184
  185 + @Override
  186 + protected PayTransferRespDTO doGetTransfer(String outTradeNo, PayTransferTypeEnum type) {
  187 + throw new UnsupportedOperationException("待实现");
  188 + }
  189 +
184 } 190 }
yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/job/transfer/PayTransferSyncJob.java 0 → 100644
  1 +package cn.iocoder.yudao.module.pay.job.transfer;
  2 +
  3 +import cn.hutool.core.util.StrUtil;
  4 +import cn.iocoder.yudao.framework.quartz.core.handler.JobHandler;
  5 +import cn.iocoder.yudao.framework.tenant.core.job.TenantJob;
  6 +import cn.iocoder.yudao.module.pay.service.transfer.PayTransferService;
  7 +import org.springframework.stereotype.Component;
  8 +
  9 +import javax.annotation.Resource;
  10 +
  11 +/**
  12 + * 转账订单的同步 Job
  13 + *
  14 + * 由于转账订单的转账结果,有些渠道是异步通知进行同步的,考虑到异步通知可能会失败(小概率),所以需要定时进行同步。
  15 + *
  16 + * @author jason
  17 + */
  18 +@Component
  19 +public class PayTransferSyncJob implements JobHandler {
  20 +
  21 + @Resource
  22 + private PayTransferService transferService;
  23 +
  24 + @Override
  25 + @TenantJob
  26 + public String execute(String param) {
  27 + int count = transferService.syncTransfer();
  28 + return StrUtil.format("同步转账订单 {} 个", count);
  29 + }
  30 +}
yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/service/demo/PayDemoOrderService.java
@@ -2,7 +2,7 @@ package cn.iocoder.yudao.module.pay.service.demo; @@ -2,7 +2,7 @@ package cn.iocoder.yudao.module.pay.service.demo;
2 2
3 import cn.iocoder.yudao.framework.common.pojo.PageParam; 3 import cn.iocoder.yudao.framework.common.pojo.PageParam;
4 import cn.iocoder.yudao.framework.common.pojo.PageResult; 4 import cn.iocoder.yudao.framework.common.pojo.PageResult;
5 -import cn.iocoder.yudao.module.pay.controller.admin.demo.vo.PayDemoOrderCreateReqVO; 5 +import cn.iocoder.yudao.module.pay.controller.admin.demo.vo.order.PayDemoOrderCreateReqVO;
6 import cn.iocoder.yudao.module.pay.dal.dataobject.demo.PayDemoOrderDO; 6 import cn.iocoder.yudao.module.pay.dal.dataobject.demo.PayDemoOrderDO;
7 7
8 import javax.validation.Valid; 8 import javax.validation.Valid;
yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/service/demo/PayDemoOrderServiceImpl.java
@@ -9,7 +9,7 @@ import cn.iocoder.yudao.module.pay.api.order.dto.PayOrderRespDTO; @@ -9,7 +9,7 @@ import cn.iocoder.yudao.module.pay.api.order.dto.PayOrderRespDTO;
9 import cn.iocoder.yudao.module.pay.api.refund.PayRefundApi; 9 import cn.iocoder.yudao.module.pay.api.refund.PayRefundApi;
10 import cn.iocoder.yudao.module.pay.api.refund.dto.PayRefundCreateReqDTO; 10 import cn.iocoder.yudao.module.pay.api.refund.dto.PayRefundCreateReqDTO;
11 import cn.iocoder.yudao.module.pay.api.refund.dto.PayRefundRespDTO; 11 import cn.iocoder.yudao.module.pay.api.refund.dto.PayRefundRespDTO;
12 -import cn.iocoder.yudao.module.pay.controller.admin.demo.vo.PayDemoOrderCreateReqVO; 12 +import cn.iocoder.yudao.module.pay.controller.admin.demo.vo.order.PayDemoOrderCreateReqVO;
13 import cn.iocoder.yudao.module.pay.dal.dataobject.demo.PayDemoOrderDO; 13 import cn.iocoder.yudao.module.pay.dal.dataobject.demo.PayDemoOrderDO;
14 import cn.iocoder.yudao.module.pay.dal.mysql.demo.PayDemoOrderMapper; 14 import cn.iocoder.yudao.module.pay.dal.mysql.demo.PayDemoOrderMapper;
15 import cn.iocoder.yudao.module.pay.enums.order.PayOrderStatusEnum; 15 import cn.iocoder.yudao.module.pay.enums.order.PayOrderStatusEnum;
yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/service/demo/PayDemoTransferService.java
@@ -28,4 +28,12 @@ public interface PayDemoTransferService { @@ -28,4 +28,12 @@ public interface PayDemoTransferService {
28 * @param pageVO 分页查询参数 28 * @param pageVO 分页查询参数
29 */ 29 */
30 PageResult<PayDemoTransferDO> getDemoTransferPage(PageParam pageVO); 30 PageResult<PayDemoTransferDO> getDemoTransferPage(PageParam pageVO);
  31 +
  32 + /**
  33 + * 更新转账业务示例订单的转账状态
  34 + *
  35 + * @param id 编号
  36 + * @param payTransferId 转账单编号
  37 + */
  38 + void updateDemoTransferStatus(Long id, Long payTransferId);
31 } 39 }
yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/service/demo/PayDemoTransferServiceImpl.java
1 package cn.iocoder.yudao.module.pay.service.demo; 1 package cn.iocoder.yudao.module.pay.service.demo;
2 2
  3 +import cn.hutool.core.util.ObjectUtil;
3 import cn.iocoder.yudao.framework.common.pojo.PageParam; 4 import cn.iocoder.yudao.framework.common.pojo.PageParam;
4 import cn.iocoder.yudao.framework.common.pojo.PageResult; 5 import cn.iocoder.yudao.framework.common.pojo.PageResult;
5 import cn.iocoder.yudao.module.pay.controller.admin.demo.vo.transfer.PayDemoTransferCreateReqVO; 6 import cn.iocoder.yudao.module.pay.controller.admin.demo.vo.transfer.PayDemoTransferCreateReqVO;
6 import cn.iocoder.yudao.module.pay.convert.demo.PayDemoTransferConvert; 7 import cn.iocoder.yudao.module.pay.convert.demo.PayDemoTransferConvert;
7 import cn.iocoder.yudao.module.pay.dal.dataobject.demo.PayDemoTransferDO; 8 import cn.iocoder.yudao.module.pay.dal.dataobject.demo.PayDemoTransferDO;
  9 +import cn.iocoder.yudao.module.pay.dal.dataobject.transfer.PayTransferDO;
8 import cn.iocoder.yudao.module.pay.dal.mysql.demo.PayDemoTransferMapper; 10 import cn.iocoder.yudao.module.pay.dal.mysql.demo.PayDemoTransferMapper;
  11 +import cn.iocoder.yudao.module.pay.enums.transfer.PayTransferStatusEnum;
  12 +import cn.iocoder.yudao.module.pay.service.transfer.PayTransferService;
9 import org.springframework.stereotype.Service; 13 import org.springframework.stereotype.Service;
10 import org.springframework.validation.annotation.Validated; 14 import org.springframework.validation.annotation.Validated;
11 15
12 import javax.annotation.Resource; 16 import javax.annotation.Resource;
13 import javax.validation.Valid; 17 import javax.validation.Valid;
14 import javax.validation.Validator; 18 import javax.validation.Validator;
  19 +import java.util.Objects;
15 20
  21 +import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
  22 +import static cn.iocoder.yudao.module.pay.enums.ErrorCodeConstants.*;
16 import static cn.iocoder.yudao.module.pay.enums.transfer.PayTransferStatusEnum.WAITING; 23 import static cn.iocoder.yudao.module.pay.enums.transfer.PayTransferStatusEnum.WAITING;
17 24
18 /** 25 /**
@@ -33,6 +40,8 @@ public class PayDemoTransferServiceImpl implements PayDemoTransferService { @@ -33,6 +40,8 @@ public class PayDemoTransferServiceImpl implements PayDemoTransferService {
33 @Resource 40 @Resource
34 private PayDemoTransferMapper demoTransferMapper; 41 private PayDemoTransferMapper demoTransferMapper;
35 @Resource 42 @Resource
  43 + private PayTransferService payTransferService;
  44 + @Resource
36 private Validator validator; 45 private Validator validator;
37 46
38 @Override 47 @Override
@@ -50,4 +59,41 @@ public class PayDemoTransferServiceImpl implements PayDemoTransferService { @@ -50,4 +59,41 @@ public class PayDemoTransferServiceImpl implements PayDemoTransferService {
50 public PageResult<PayDemoTransferDO> getDemoTransferPage(PageParam pageVO) { 59 public PageResult<PayDemoTransferDO> getDemoTransferPage(PageParam pageVO) {
51 return demoTransferMapper.selectPage(pageVO); 60 return demoTransferMapper.selectPage(pageVO);
52 } 61 }
  62 +
  63 + @Override
  64 + public void updateDemoTransferStatus(Long id, Long payTransferId) {
  65 + PayTransferDO payTransfer = validateDemoTransferStatusCanUpdate(id, payTransferId);
  66 + // 更新示例订单状态
  67 + if (payTransfer != null) {
  68 + demoTransferMapper.updateById(new PayDemoTransferDO().setId(id)
  69 + .setPayTransferId(payTransferId)
  70 + .setPayChannelCode(payTransfer.getChannelCode())
  71 + .setTransferStatus(payTransfer.getStatus())
  72 + .setTransferTime(payTransfer.getSuccessTime()));
  73 + }
  74 + }
  75 +
  76 + private PayTransferDO validateDemoTransferStatusCanUpdate(Long id, Long payTransferId) {
  77 + PayDemoTransferDO demoTransfer = demoTransferMapper.selectById(id);
  78 + if (demoTransfer == null) {
  79 + throw exception(DEMO_TRANSFER_NOT_FOUND);
  80 + }
  81 + if (PayTransferStatusEnum.isSuccess(demoTransfer.getTransferStatus())
  82 + || PayTransferStatusEnum.isClosed(demoTransfer.getTransferStatus())) {
  83 + // 无需更新返回 null
  84 + return null;
  85 + }
  86 + PayTransferDO transfer = payTransferService.getTransfer(payTransferId);
  87 + if (transfer == null) {
  88 + throw exception(PAY_TRANSFER_NOT_FOUND);
  89 + }
  90 + if (!Objects.equals(demoTransfer.getPrice(), transfer.getPrice())) {
  91 + throw exception(DEMO_TRANSFER_FAIL_PRICE_NOT_MATCH);
  92 + }
  93 + if (ObjectUtil.notEqual(transfer.getMerchantTransferId(), id.toString())) {
  94 + throw exception(DEMO_TRANSFER_FAIL_TRANSFER_ID_ERROR);
  95 + }
  96 + // TODO 校验账号
  97 + return transfer;
  98 + }
53 } 99 }
yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/service/notify/PayNotifyServiceImpl.java
@@ -13,11 +13,13 @@ import cn.iocoder.yudao.framework.common.util.json.JsonUtils; @@ -13,11 +13,13 @@ import cn.iocoder.yudao.framework.common.util.json.JsonUtils;
13 import cn.iocoder.yudao.framework.tenant.core.util.TenantUtils; 13 import cn.iocoder.yudao.framework.tenant.core.util.TenantUtils;
14 import cn.iocoder.yudao.module.pay.api.notify.dto.PayOrderNotifyReqDTO; 14 import cn.iocoder.yudao.module.pay.api.notify.dto.PayOrderNotifyReqDTO;
15 import cn.iocoder.yudao.module.pay.api.notify.dto.PayRefundNotifyReqDTO; 15 import cn.iocoder.yudao.module.pay.api.notify.dto.PayRefundNotifyReqDTO;
  16 +import cn.iocoder.yudao.module.pay.api.notify.dto.PayTransferNotifyReqDTO;
16 import cn.iocoder.yudao.module.pay.controller.admin.notify.vo.PayNotifyTaskPageReqVO; 17 import cn.iocoder.yudao.module.pay.controller.admin.notify.vo.PayNotifyTaskPageReqVO;
17 import cn.iocoder.yudao.module.pay.dal.dataobject.notify.PayNotifyLogDO; 18 import cn.iocoder.yudao.module.pay.dal.dataobject.notify.PayNotifyLogDO;
18 import cn.iocoder.yudao.module.pay.dal.dataobject.notify.PayNotifyTaskDO; 19 import cn.iocoder.yudao.module.pay.dal.dataobject.notify.PayNotifyTaskDO;
19 import cn.iocoder.yudao.module.pay.dal.dataobject.order.PayOrderDO; 20 import cn.iocoder.yudao.module.pay.dal.dataobject.order.PayOrderDO;
20 import cn.iocoder.yudao.module.pay.dal.dataobject.refund.PayRefundDO; 21 import cn.iocoder.yudao.module.pay.dal.dataobject.refund.PayRefundDO;
  22 +import cn.iocoder.yudao.module.pay.dal.dataobject.transfer.PayTransferDO;
21 import cn.iocoder.yudao.module.pay.dal.mysql.notify.PayNotifyLogMapper; 23 import cn.iocoder.yudao.module.pay.dal.mysql.notify.PayNotifyLogMapper;
22 import cn.iocoder.yudao.module.pay.dal.mysql.notify.PayNotifyTaskMapper; 24 import cn.iocoder.yudao.module.pay.dal.mysql.notify.PayNotifyTaskMapper;
23 import cn.iocoder.yudao.module.pay.dal.redis.notify.PayNotifyLockRedisDAO; 25 import cn.iocoder.yudao.module.pay.dal.redis.notify.PayNotifyLockRedisDAO;
@@ -25,6 +27,7 @@ import cn.iocoder.yudao.module.pay.enums.notify.PayNotifyStatusEnum; @@ -25,6 +27,7 @@ import cn.iocoder.yudao.module.pay.enums.notify.PayNotifyStatusEnum;
25 import cn.iocoder.yudao.module.pay.enums.notify.PayNotifyTypeEnum; 27 import cn.iocoder.yudao.module.pay.enums.notify.PayNotifyTypeEnum;
26 import cn.iocoder.yudao.module.pay.service.order.PayOrderService; 28 import cn.iocoder.yudao.module.pay.service.order.PayOrderService;
27 import cn.iocoder.yudao.module.pay.service.refund.PayRefundService; 29 import cn.iocoder.yudao.module.pay.service.refund.PayRefundService;
  30 +import cn.iocoder.yudao.module.pay.service.transfer.PayTransferService;
28 import com.google.common.annotations.VisibleForTesting; 31 import com.google.common.annotations.VisibleForTesting;
29 import lombok.extern.slf4j.Slf4j; 32 import lombok.extern.slf4j.Slf4j;
30 import org.springframework.context.annotation.Lazy; 33 import org.springframework.context.annotation.Lazy;
@@ -73,6 +76,9 @@ public class PayNotifyServiceImpl implements PayNotifyService { @@ -73,6 +76,9 @@ public class PayNotifyServiceImpl implements PayNotifyService {
73 @Resource 76 @Resource
74 @Lazy // 循环依赖,避免报错 77 @Lazy // 循环依赖,避免报错
75 private PayRefundService refundService; 78 private PayRefundService refundService;
  79 + @Resource
  80 + @Lazy // 循环依赖,避免报错
  81 + private PayTransferService transferService;
76 82
77 @Resource 83 @Resource
78 private PayNotifyTaskMapper notifyTaskMapper; 84 private PayNotifyTaskMapper notifyTaskMapper;
@@ -100,6 +106,10 @@ public class PayNotifyServiceImpl implements PayNotifyService { @@ -100,6 +106,10 @@ public class PayNotifyServiceImpl implements PayNotifyService {
100 PayRefundDO refundDO = refundService.getRefund(task.getDataId()); 106 PayRefundDO refundDO = refundService.getRefund(task.getDataId());
101 task.setAppId(refundDO.getAppId()) 107 task.setAppId(refundDO.getAppId())
102 .setMerchantOrderId(refundDO.getMerchantOrderId()).setNotifyUrl(refundDO.getNotifyUrl()); 108 .setMerchantOrderId(refundDO.getMerchantOrderId()).setNotifyUrl(refundDO.getNotifyUrl());
  109 + } else if (Objects.equals(task.getType(), PayNotifyTypeEnum.TRANSFER.getType())) {
  110 + PayTransferDO transfer = transferService.getTransfer(task.getDataId());
  111 + task.setAppId(transfer.getAppId()).setMerchantTransferId(transfer.getMerchantTransferId())
  112 + .setNotifyUrl(transfer.getNotifyUrl());
103 } 113 }
104 114
105 // 执行插入 115 // 执行插入
@@ -214,6 +224,9 @@ public class PayNotifyServiceImpl implements PayNotifyService { @@ -214,6 +224,9 @@ public class PayNotifyServiceImpl implements PayNotifyService {
214 } else if (Objects.equals(task.getType(), PayNotifyTypeEnum.REFUND.getType())) { 224 } else if (Objects.equals(task.getType(), PayNotifyTypeEnum.REFUND.getType())) {
215 request = PayRefundNotifyReqDTO.builder().merchantOrderId(task.getMerchantOrderId()) 225 request = PayRefundNotifyReqDTO.builder().merchantOrderId(task.getMerchantOrderId())
216 .payRefundId(task.getDataId()).build(); 226 .payRefundId(task.getDataId()).build();
  227 + } else if (Objects.equals(task.getType(), PayNotifyTypeEnum.TRANSFER.getType())) {
  228 + request = new PayTransferNotifyReqDTO().setMerchantTransferId(task.getMerchantTransferId())
  229 + .setPayTransferId(task.getDataId());
217 } else { 230 } else {
218 throw new RuntimeException("未知的通知任务类型:" + JsonUtils.toJsonString(task)); 231 throw new RuntimeException("未知的通知任务类型:" + JsonUtils.toJsonString(task));
219 } 232 }
yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/service/order/PayOrderServiceImpl.java
@@ -421,6 +421,7 @@ public class PayOrderServiceImpl implements PayOrderService { @@ -421,6 +421,7 @@ public class PayOrderServiceImpl implements PayOrderService {
421 return; 421 return;
422 } 422 }
423 423
  424 + // TODO 芋艿:应该 new 出来更新
424 order.setPrice(payPrice); 425 order.setPrice(payPrice);
425 orderMapper.updateById(order); 426 orderMapper.updateById(order);
426 } 427 }
yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/service/transfer/PayTransferService.java
1 package cn.iocoder.yudao.module.pay.service.transfer; 1 package cn.iocoder.yudao.module.pay.service.transfer;
2 2
  3 +import cn.iocoder.yudao.framework.common.pojo.PageResult;
3 import cn.iocoder.yudao.module.pay.api.transfer.dto.PayTransferCreateReqDTO; 4 import cn.iocoder.yudao.module.pay.api.transfer.dto.PayTransferCreateReqDTO;
4 import cn.iocoder.yudao.module.pay.controller.admin.transfer.vo.PayTransferCreateReqVO; 5 import cn.iocoder.yudao.module.pay.controller.admin.transfer.vo.PayTransferCreateReqVO;
  6 +import cn.iocoder.yudao.module.pay.controller.admin.transfer.vo.PayTransferPageReqVO;
5 import cn.iocoder.yudao.module.pay.dal.dataobject.transfer.PayTransferDO; 7 import cn.iocoder.yudao.module.pay.dal.dataobject.transfer.PayTransferDO;
6 8
7 import javax.validation.Valid; 9 import javax.validation.Valid;
@@ -38,4 +40,18 @@ public interface PayTransferService { @@ -38,4 +40,18 @@ public interface PayTransferService {
38 */ 40 */
39 PayTransferDO getTransfer(Long id); 41 PayTransferDO getTransfer(Long id);
40 42
  43 + /**
  44 + * 获得转账单分页
  45 + *
  46 + * @param pageReqVO 分页查询
  47 + * @return 转账单分页
  48 + */
  49 + PageResult<PayTransferDO> getTransferPage(PayTransferPageReqVO pageReqVO);
  50 +
  51 + /**
  52 + * 同步渠道转账单状态
  53 + *
  54 + * @return 同步到状态的转账数量,包括转账成功、转账失败、转账中的
  55 + */
  56 + int syncTransfer();
41 } 57 }
yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/service/transfer/PayTransferServiceImpl.java
1 package cn.iocoder.yudao.module.pay.service.transfer; 1 package cn.iocoder.yudao.module.pay.service.transfer;
2 2
3 import cn.hutool.core.collection.CollUtil; 3 import cn.hutool.core.collection.CollUtil;
  4 +import cn.hutool.core.util.ObjectUtil;
4 import cn.hutool.extra.spring.SpringUtil; 5 import cn.hutool.extra.spring.SpringUtil;
5 -import cn.iocoder.yudao.framework.common.exception.ServiceException; 6 +import cn.iocoder.yudao.framework.common.pojo.PageResult;
6 import cn.iocoder.yudao.framework.common.util.json.JsonUtils; 7 import cn.iocoder.yudao.framework.common.util.json.JsonUtils;
7 import cn.iocoder.yudao.framework.pay.core.client.PayClient; 8 import cn.iocoder.yudao.framework.pay.core.client.PayClient;
8 import cn.iocoder.yudao.framework.pay.core.client.dto.transfer.PayTransferRespDTO; 9 import cn.iocoder.yudao.framework.pay.core.client.dto.transfer.PayTransferRespDTO;
9 import cn.iocoder.yudao.framework.pay.core.client.dto.transfer.PayTransferUnifiedReqDTO; 10 import cn.iocoder.yudao.framework.pay.core.client.dto.transfer.PayTransferUnifiedReqDTO;
10 import cn.iocoder.yudao.framework.pay.core.enums.transfer.PayTransferStatusRespEnum; 11 import cn.iocoder.yudao.framework.pay.core.enums.transfer.PayTransferStatusRespEnum;
  12 +import cn.iocoder.yudao.framework.pay.core.enums.transfer.PayTransferTypeEnum;
  13 +import cn.iocoder.yudao.framework.tenant.core.util.TenantUtils;
11 import cn.iocoder.yudao.module.pay.api.transfer.dto.PayTransferCreateReqDTO; 14 import cn.iocoder.yudao.module.pay.api.transfer.dto.PayTransferCreateReqDTO;
12 import cn.iocoder.yudao.module.pay.controller.admin.transfer.vo.PayTransferCreateReqVO; 15 import cn.iocoder.yudao.module.pay.controller.admin.transfer.vo.PayTransferCreateReqVO;
  16 +import cn.iocoder.yudao.module.pay.controller.admin.transfer.vo.PayTransferPageReqVO;
  17 +import cn.iocoder.yudao.module.pay.dal.dataobject.app.PayAppDO;
13 import cn.iocoder.yudao.module.pay.dal.dataobject.channel.PayChannelDO; 18 import cn.iocoder.yudao.module.pay.dal.dataobject.channel.PayChannelDO;
14 import cn.iocoder.yudao.module.pay.dal.dataobject.transfer.PayTransferDO; 19 import cn.iocoder.yudao.module.pay.dal.dataobject.transfer.PayTransferDO;
15 import cn.iocoder.yudao.module.pay.dal.mysql.transfer.PayTransferMapper; 20 import cn.iocoder.yudao.module.pay.dal.mysql.transfer.PayTransferMapper;
16 import cn.iocoder.yudao.module.pay.dal.redis.no.PayNoRedisDAO; 21 import cn.iocoder.yudao.module.pay.dal.redis.no.PayNoRedisDAO;
  22 +import cn.iocoder.yudao.module.pay.enums.notify.PayNotifyTypeEnum;
  23 +import cn.iocoder.yudao.module.pay.enums.transfer.PayTransferStatusEnum;
17 import cn.iocoder.yudao.module.pay.service.app.PayAppService; 24 import cn.iocoder.yudao.module.pay.service.app.PayAppService;
18 import cn.iocoder.yudao.module.pay.service.channel.PayChannelService; 25 import cn.iocoder.yudao.module.pay.service.channel.PayChannelService;
  26 +import cn.iocoder.yudao.module.pay.service.notify.PayNotifyService;
19 import lombok.extern.slf4j.Slf4j; 27 import lombok.extern.slf4j.Slf4j;
20 import org.springframework.stereotype.Service; 28 import org.springframework.stereotype.Service;
21 import org.springframework.transaction.annotation.Transactional; 29 import org.springframework.transaction.annotation.Transactional;
22 30
23 import javax.annotation.Resource; 31 import javax.annotation.Resource;
24 import javax.validation.Validator; 32 import javax.validation.Validator;
25 -import java.util.Objects; 33 +import java.util.List;
26 34
27 import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; 35 import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
28 import static cn.iocoder.yudao.module.pay.convert.transfer.PayTransferConvert.INSTANCE; 36 import static cn.iocoder.yudao.module.pay.convert.transfer.PayTransferConvert.INSTANCE;
@@ -49,6 +57,8 @@ public class PayTransferServiceImpl implements PayTransferService { @@ -49,6 +57,8 @@ public class PayTransferServiceImpl implements PayTransferService {
49 @Resource 57 @Resource
50 private PayChannelService channelService; 58 private PayChannelService channelService;
51 @Resource 59 @Resource
  60 + private PayNotifyService notifyService;
  61 + @Resource
52 private PayNoRedisDAO noRedisDAO; 62 private PayNoRedisDAO noRedisDAO;
53 @Resource 63 @Resource
54 private Validator validator; 64 private Validator validator;
@@ -68,51 +78,60 @@ public class PayTransferServiceImpl implements PayTransferService { @@ -68,51 +78,60 @@ public class PayTransferServiceImpl implements PayTransferService {
68 78
69 @Override 79 @Override
70 public Long createTransfer(PayTransferCreateReqDTO reqDTO) { 80 public Long createTransfer(PayTransferCreateReqDTO reqDTO) {
71 - // 1.1 校验转账单是否可以提交  
72 - validateTransferCanCreate(reqDTO.getAppId(), reqDTO.getMerchantTransferId());  
73 - // 1.2 校验 App  
74 - appService.validPayApp(reqDTO.getAppId());  
75 - // 1.3 校验支付渠道是否有效 81 + // 1.1 校验 App
  82 + PayAppDO payApp = appService.validPayApp(reqDTO.getAppId());
  83 + // 1.2 校验支付渠道是否有效
76 PayChannelDO channel = channelService.validPayChannel(reqDTO.getAppId(), reqDTO.getChannelCode()); 84 PayChannelDO channel = channelService.validPayChannel(reqDTO.getAppId(), reqDTO.getChannelCode());
77 PayClient client = channelService.getPayClient(channel.getId()); 85 PayClient client = channelService.getPayClient(channel.getId());
78 if (client == null) { 86 if (client == null) {
79 log.error("[createTransfer][渠道编号({}) 找不到对应的支付客户端]", channel.getId()); 87 log.error("[createTransfer][渠道编号({}) 找不到对应的支付客户端]", channel.getId());
80 throw exception(CHANNEL_NOT_FOUND); 88 throw exception(CHANNEL_NOT_FOUND);
81 } 89 }
82 - // 2.创建转账单  
83 - String no = noRedisDAO.generate(TRANSFER_NO_PREFIX);  
84 - PayTransferDO transfer = INSTANCE.convert(reqDTO)  
85 - .setChannelId(channel.getId())  
86 - .setNo(no).setStatus(WAITING.getStatus())  
87 - .setNotifyUrl("http://127.0.0.1:48080/admin-api/pay/todo"); // TODO 需要加个transfer Notify url  
88 - transferMapper.insert(transfer);  
89 - PayTransferRespDTO unifiedTransferResp = null; 90 + // 1.3 校验转账单已经发起过转账。
  91 + PayTransferDO transfer = validateTransferCanCreate(reqDTO);
  92 +
  93 + if (transfer == null) {
  94 + // 2.不存在创建转账单. 否则允许使用相同的 no 再次发起转账
  95 + String no = noRedisDAO.generate(TRANSFER_NO_PREFIX);
  96 + transfer = INSTANCE.convert(reqDTO)
  97 + .setChannelId(channel.getId())
  98 + .setNo(no).setStatus(WAITING.getStatus())
  99 + .setNotifyUrl(payApp.getTransferNotifyUrl());
  100 + transferMapper.insert(transfer);
  101 + }
90 try { 102 try {
91 // 3. 调用三方渠道发起转账 103 // 3. 调用三方渠道发起转账
92 - PayTransferUnifiedReqDTO transferUnifiedReq = INSTANCE.convert2(reqDTO)  
93 - .setOutTransferNo(no);  
94 - unifiedTransferResp = client.unifiedTransfer(transferUnifiedReq);  
95 - } catch (ServiceException ex) {  
96 - // 业务异常.直接返回转账失败的结果  
97 - log.error("[createTransfer][转账 id({}) requestDTO({}) 发生业务异常]", transfer.getId(), reqDTO, ex);  
98 - unifiedTransferResp = PayTransferRespDTO.closedOf("", "", no, ex); 104 + PayTransferUnifiedReqDTO transferUnifiedReq = INSTANCE.convert2(transfer)
  105 + .setOutTransferNo(transfer.getNo());
  106 + PayTransferRespDTO unifiedTransferResp = client.unifiedTransfer(transferUnifiedReq);
  107 + // 4. 通知转账结果
  108 + getSelf().notifyTransfer(channel, unifiedTransferResp);
99 } catch (Throwable e) { 109 } catch (Throwable e) {
100 // 注意这里仅打印异常,不进行抛出。 110 // 注意这里仅打印异常,不进行抛出。
101 - // 原因是:虽然调用支付渠道进行转账发生异常(网络请求超时),实际转账成功。这个结果,后续通过转账回调、或者转账轮询可以拿到。  
102 - // TODO 需要加转账回调业务接口 和 转账轮询未实现  
103 - // 最终,在异常的情况下,支付中心会异步回调业务的转账回调接口,提供转账结果 111 + // 原因是:虽然调用支付渠道进行转账发生异常(网络请求超时),实际转账成功。这个结果,后续转账轮询可以拿到。
  112 + // 或者使用相同 no 再次发起转账请求
104 log.error("[createTransfer][转账 id({}) requestDTO({}) 发生异常]", transfer.getId(), reqDTO, e); 113 log.error("[createTransfer][转账 id({}) requestDTO({}) 发生异常]", transfer.getId(), reqDTO, e);
105 } 114 }
106 - if (Objects.nonNull(unifiedTransferResp)) {  
107 - // 4. 通知转账结果  
108 - getSelf().notifyTransfer(channel, unifiedTransferResp);  
109 - } 115 +
110 return transfer.getId(); 116 return transfer.getId();
111 } 117 }
112 118
113 - @Override  
114 - public PayTransferDO getTransfer(Long id) {  
115 - return transferMapper.selectById(id); 119 + private PayTransferDO validateTransferCanCreate(PayTransferCreateReqDTO dto) {
  120 + PayTransferDO transfer = transferMapper.selectByAppIdAndMerchantTransferId(dto.getAppId(), dto.getMerchantTransferId());
  121 + if (transfer != null) {
  122 + // 已经存在,并且状态不为等待状态。说明已经调用渠道转账并返回结果.
  123 + if (!PayTransferStatusEnum.isWaiting(transfer.getStatus())) {
  124 + throw exception(PAY_MERCHANT_TRANSFER_EXISTS);
  125 + }
  126 + if (ObjectUtil.notEqual(dto.getPrice(), transfer.getPrice())) {
  127 + throw exception(PAY_SAME_MERCHANT_TRANSFER_PRICE_NOT_MATCH);
  128 + }
  129 + if (ObjectUtil.notEqual(dto.getType(), transfer.getType())) {
  130 + throw exception(PAY_SAME_MERCHANT_TRANSFER_TYPE_NOT_MATCH);
  131 + }
  132 + }
  133 + // 如果状态为等待状态。不知道渠道转账是否发起成功。 允许使用相同的 no 再次发起转账,渠道会保证幂等
  134 + return transfer;
116 } 135 }
117 136
118 @Transactional(rollbackFor = Exception.class) 137 @Transactional(rollbackFor = Exception.class)
@@ -126,34 +145,48 @@ public class PayTransferServiceImpl implements PayTransferService { @@ -126,34 +145,48 @@ public class PayTransferServiceImpl implements PayTransferService {
126 if (PayTransferStatusRespEnum.isClosed(notify.getStatus())) { 145 if (PayTransferStatusRespEnum.isClosed(notify.getStatus())) {
127 notifyTransferClosed(channel, notify); 146 notifyTransferClosed(channel, notify);
128 } 147 }
  148 + // 转账处理中的回调
  149 + if (PayTransferStatusRespEnum.isInProgress(notify.getStatus())) {
  150 + notifyTransferInProgress(channel, notify);
  151 + }
129 // WAITING 状态无需处理 152 // WAITING 状态无需处理
130 - // TODO IN_PROGRESS 待处理  
131 } 153 }
132 154
133 - private void validateTransferCanCreate(Long appId, String merchantTransferId) {  
134 - PayTransferDO transfer = transferMapper.selectByAppIdAndMerchantTransferId(appId, merchantTransferId);  
135 - if (transfer != null) { // 是否存在  
136 - throw exception(PAY_MERCHANT_TRANSFER_EXISTS); 155 + private void notifyTransferInProgress(PayChannelDO channel, PayTransferRespDTO notify) {
  156 + // 1.校验
  157 + PayTransferDO transfer = transferMapper.selectByNo(notify.getOutTransferNo());
  158 + if (transfer == null) {
  159 + throw exception(PAY_TRANSFER_NOT_FOUND);
137 } 160 }
138 - }  
139 -  
140 - private void notifyTransferSuccess(PayChannelDO channel, PayTransferRespDTO notify) {  
141 - // 1. 更新 PayTransferDO 转账成功  
142 - Boolean transferred = updateTransferSuccess(channel, notify);  
143 - if (transferred) { 161 + if (isInProgress(transfer.getStatus())) { // 如果已经是转账中,直接返回,不用重复更新
144 return; 162 return;
145 } 163 }
146 - // 2. TODO 插入转账通知记录 164 + if (!isWaiting(transfer.getStatus())) {
  165 + throw exception(PAY_TRANSFER_STATUS_IS_NOT_WAITING);
  166 + }
  167 + // 2.更新
  168 + int updateCounts = transferMapper.updateByIdAndStatus(transfer.getId(),
  169 + CollUtil.newArrayList(WAITING.getStatus()),
  170 + new PayTransferDO().setStatus(IN_PROGRESS.getStatus()));
  171 + if (updateCounts == 0) {
  172 + throw exception(PAY_TRANSFER_STATUS_IS_NOT_WAITING);
  173 + }
  174 + log.info("[notifyTransferInProgress][transfer({}) 更新为转账进行中状态]", transfer.getId());
  175 +
  176 + // 3. 插入转账通知记录
  177 + notifyService.createPayNotifyTask(PayNotifyTypeEnum.TRANSFER.getType(),
  178 + transfer.getId());
147 } 179 }
148 180
149 - private Boolean updateTransferSuccess(PayChannelDO channel, PayTransferRespDTO notify) { 181 +
  182 + private void notifyTransferSuccess(PayChannelDO channel, PayTransferRespDTO notify) {
150 // 1.校验 183 // 1.校验
151 PayTransferDO transfer = transferMapper.selectByNo(notify.getOutTransferNo()); 184 PayTransferDO transfer = transferMapper.selectByNo(notify.getOutTransferNo());
152 if (transfer == null) { 185 if (transfer == null) {
153 throw exception(PAY_TRANSFER_NOT_FOUND); 186 throw exception(PAY_TRANSFER_NOT_FOUND);
154 } 187 }
155 if (isSuccess(transfer.getStatus())) { // 如果已成功,直接返回,不用重复更新 188 if (isSuccess(transfer.getStatus())) { // 如果已成功,直接返回,不用重复更新
156 - return Boolean.TRUE; 189 + return;
157 } 190 }
158 if (!isPendingStatus(transfer.getStatus())) { 191 if (!isPendingStatus(transfer.getStatus())) {
159 throw exception(PAY_TRANSFER_STATUS_IS_NOT_PENDING); 192 throw exception(PAY_TRANSFER_STATUS_IS_NOT_PENDING);
@@ -169,10 +202,13 @@ public class PayTransferServiceImpl implements PayTransferService { @@ -169,10 +202,13 @@ public class PayTransferServiceImpl implements PayTransferService {
169 throw exception(PAY_TRANSFER_STATUS_IS_NOT_PENDING); 202 throw exception(PAY_TRANSFER_STATUS_IS_NOT_PENDING);
170 } 203 }
171 log.info("[updateTransferSuccess][transfer({}) 更新为已转账]", transfer.getId()); 204 log.info("[updateTransferSuccess][transfer({}) 更新为已转账]", transfer.getId());
172 - return Boolean.FALSE; 205 +
  206 + // 3. 插入转账通知记录
  207 + notifyService.createPayNotifyTask(PayNotifyTypeEnum.TRANSFER.getType(),
  208 + transfer.getId());
173 } 209 }
174 210
175 - private void updateTransferClosed(PayChannelDO channel, PayTransferRespDTO notify) { 211 + private void notifyTransferClosed(PayChannelDO channel, PayTransferRespDTO notify) {
176 // 1.校验 212 // 1.校验
177 PayTransferDO transfer = transferMapper.selectByNo(notify.getOutTransferNo()); 213 PayTransferDO transfer = transferMapper.selectByNo(notify.getOutTransferNo());
178 if (transfer == null) { 214 if (transfer == null) {
@@ -185,6 +221,7 @@ public class PayTransferServiceImpl implements PayTransferService { @@ -185,6 +221,7 @@ public class PayTransferServiceImpl implements PayTransferService {
185 if (!isPendingStatus(transfer.getStatus())) { 221 if (!isPendingStatus(transfer.getStatus())) {
186 throw exception(PAY_TRANSFER_STATUS_IS_NOT_PENDING); 222 throw exception(PAY_TRANSFER_STATUS_IS_NOT_PENDING);
187 } 223 }
  224 +
188 // 2.更新 225 // 2.更新
189 int updateCount = transferMapper.updateByIdAndStatus(transfer.getId(), 226 int updateCount = transferMapper.updateByIdAndStatus(transfer.getId(),
190 CollUtil.newArrayList(WAITING.getStatus(), IN_PROGRESS.getStatus()), 227 CollUtil.newArrayList(WAITING.getStatus(), IN_PROGRESS.getStatus()),
@@ -196,11 +233,61 @@ public class PayTransferServiceImpl implements PayTransferService { @@ -196,11 +233,61 @@ public class PayTransferServiceImpl implements PayTransferService {
196 throw exception(PAY_TRANSFER_STATUS_IS_NOT_PENDING); 233 throw exception(PAY_TRANSFER_STATUS_IS_NOT_PENDING);
197 } 234 }
198 log.info("[updateTransferClosed][transfer({}) 更新为关闭状态]", transfer.getId()); 235 log.info("[updateTransferClosed][transfer({}) 更新为关闭状态]", transfer.getId());
  236 +
  237 + // 3. 插入转账通知记录
  238 + notifyService.createPayNotifyTask(PayNotifyTypeEnum.TRANSFER.getType(),
  239 + transfer.getId());
  240 +
199 } 241 }
200 242
201 - private void notifyTransferClosed(PayChannelDO channel, PayTransferRespDTO notify) {  
202 - // 更新 PayTransferDO 转账关闭  
203 - updateTransferClosed(channel, notify); 243 + @Override
  244 + public PayTransferDO getTransfer(Long id) {
  245 + return transferMapper.selectById(id);
  246 + }
  247 +
  248 + @Override
  249 + public PageResult<PayTransferDO> getTransferPage(PayTransferPageReqVO pageReqVO) {
  250 + return transferMapper.selectPage(pageReqVO);
  251 + }
  252 +
  253 + @Override
  254 + public int syncTransfer() {
  255 + List<PayTransferDO> list = transferMapper.selectListByStatus(WAITING.getStatus());
  256 + if (CollUtil.isEmpty(list)) {
  257 + return 0;
  258 + }
  259 + int count = 0;
  260 + for (PayTransferDO transfer : list) {
  261 + count += syncTransfer(transfer) ? 1 : 0;
  262 + }
  263 + return count;
  264 + }
  265 +
  266 + private boolean syncTransfer(PayTransferDO transfer) {
  267 + try {
  268 + // 1. 查询转账订单信息
  269 + PayClient payClient = channelService.getPayClient(transfer.getChannelId());
  270 + if (payClient == null) {
  271 + log.error("[syncTransfer][渠道编号({}) 找不到对应的支付客户端]", transfer.getChannelId());
  272 + return false;
  273 + }
  274 + PayTransferRespDTO resp = payClient.getTransfer(transfer.getNo(),
  275 + PayTransferTypeEnum.typeOf(transfer.getType()));
  276 +
  277 + // 2. 回调转账结果
  278 + notifyTransfer(transfer.getChannelId(), resp);
  279 + return true;
  280 + } catch (Throwable ex) {
  281 + log.error("[syncTransfer][transfer({}) 同步转账单状态异常]", transfer.getId(), ex);
  282 + return false;
  283 + }
  284 + }
  285 +
  286 + private void notifyTransfer(Long channelId, PayTransferRespDTO notify) {
  287 + // 校验渠道是否有效
  288 + PayChannelDO channel = channelService.validPayChannel(channelId);
  289 + // 通知转账结果给对应的业务
  290 + TenantUtils.execute(channel.getTenantId(), () -> getSelf().notifyTransfer(channel, notify));
204 } 291 }
205 292
206 /** 293 /**
yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/service/wallet/PayWalletRechargeServiceImpl.java
@@ -11,7 +11,7 @@ import cn.iocoder.yudao.module.pay.dal.dataobject.wallet.PayWalletDO; @@ -11,7 +11,7 @@ import cn.iocoder.yudao.module.pay.dal.dataobject.wallet.PayWalletDO;
11 import cn.iocoder.yudao.module.pay.dal.dataobject.wallet.PayWalletRechargeDO; 11 import cn.iocoder.yudao.module.pay.dal.dataobject.wallet.PayWalletRechargeDO;
12 import cn.iocoder.yudao.module.pay.dal.dataobject.wallet.PayWalletRechargePackageDO; 12 import cn.iocoder.yudao.module.pay.dal.dataobject.wallet.PayWalletRechargePackageDO;
13 import cn.iocoder.yudao.module.pay.dal.mysql.wallet.PayWalletRechargeMapper; 13 import cn.iocoder.yudao.module.pay.dal.mysql.wallet.PayWalletRechargeMapper;
14 -import cn.iocoder.yudao.module.pay.enums.member.PayWalletBizTypeEnum; 14 +import cn.iocoder.yudao.module.pay.enums.wallet.PayWalletBizTypeEnum;
15 import cn.iocoder.yudao.module.pay.enums.order.PayOrderStatusEnum; 15 import cn.iocoder.yudao.module.pay.enums.order.PayOrderStatusEnum;
16 import cn.iocoder.yudao.module.pay.enums.refund.PayRefundStatusEnum; 16 import cn.iocoder.yudao.module.pay.enums.refund.PayRefundStatusEnum;
17 import cn.iocoder.yudao.module.pay.service.order.PayOrderService; 17 import cn.iocoder.yudao.module.pay.service.order.PayOrderService;
@@ -64,6 +64,7 @@ public class PayWalletRechargeServiceImpl implements PayWalletRechargeService { @@ -64,6 +64,7 @@ public class PayWalletRechargeServiceImpl implements PayWalletRechargeService {
64 @Transactional(rollbackFor = Exception.class) 64 @Transactional(rollbackFor = Exception.class)
65 public PayWalletRechargeDO createWalletRecharge(Long userId, Integer userType, String userIp, 65 public PayWalletRechargeDO createWalletRecharge(Long userId, Integer userType, String userIp,
66 AppPayWalletRechargeCreateReqVO reqVO) { 66 AppPayWalletRechargeCreateReqVO reqVO) {
  67 +
67 // 1.1 计算充值金额 68 // 1.1 计算充值金额
68 int payPrice; 69 int payPrice;
69 int bonusPrice = 0; 70 int bonusPrice = 0;
yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/service/wallet/PayWalletService.java
@@ -4,7 +4,7 @@ import cn.iocoder.yudao.framework.common.pojo.PageResult; @@ -4,7 +4,7 @@ import cn.iocoder.yudao.framework.common.pojo.PageResult;
4 import cn.iocoder.yudao.module.pay.controller.admin.wallet.vo.wallet.PayWalletPageReqVO; 4 import cn.iocoder.yudao.module.pay.controller.admin.wallet.vo.wallet.PayWalletPageReqVO;
5 import cn.iocoder.yudao.module.pay.dal.dataobject.wallet.PayWalletDO; 5 import cn.iocoder.yudao.module.pay.dal.dataobject.wallet.PayWalletDO;
6 import cn.iocoder.yudao.module.pay.dal.dataobject.wallet.PayWalletTransactionDO; 6 import cn.iocoder.yudao.module.pay.dal.dataobject.wallet.PayWalletTransactionDO;
7 -import cn.iocoder.yudao.module.pay.enums.member.PayWalletBizTypeEnum; 7 +import cn.iocoder.yudao.module.pay.enums.wallet.PayWalletBizTypeEnum;
8 8
9 /** 9 /**
10 * 钱包 Service 接口 10 * 钱包 Service 接口
yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/service/wallet/PayWalletServiceImpl.java
@@ -8,7 +8,7 @@ import cn.iocoder.yudao.module.pay.dal.dataobject.refund.PayRefundDO; @@ -8,7 +8,7 @@ import cn.iocoder.yudao.module.pay.dal.dataobject.refund.PayRefundDO;
8 import cn.iocoder.yudao.module.pay.dal.dataobject.wallet.PayWalletDO; 8 import cn.iocoder.yudao.module.pay.dal.dataobject.wallet.PayWalletDO;
9 import cn.iocoder.yudao.module.pay.dal.dataobject.wallet.PayWalletTransactionDO; 9 import cn.iocoder.yudao.module.pay.dal.dataobject.wallet.PayWalletTransactionDO;
10 import cn.iocoder.yudao.module.pay.dal.mysql.wallet.PayWalletMapper; 10 import cn.iocoder.yudao.module.pay.dal.mysql.wallet.PayWalletMapper;
11 -import cn.iocoder.yudao.module.pay.enums.member.PayWalletBizTypeEnum; 11 +import cn.iocoder.yudao.module.pay.enums.wallet.PayWalletBizTypeEnum;
12 import cn.iocoder.yudao.module.pay.service.order.PayOrderService; 12 import cn.iocoder.yudao.module.pay.service.order.PayOrderService;
13 import cn.iocoder.yudao.module.pay.service.refund.PayRefundService; 13 import cn.iocoder.yudao.module.pay.service.refund.PayRefundService;
14 import cn.iocoder.yudao.module.pay.service.wallet.bo.WalletTransactionCreateReqBO; 14 import cn.iocoder.yudao.module.pay.service.wallet.bo.WalletTransactionCreateReqBO;
@@ -22,8 +22,8 @@ import java.time.LocalDateTime; @@ -22,8 +22,8 @@ import java.time.LocalDateTime;
22 22
23 import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; 23 import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
24 import static cn.iocoder.yudao.module.pay.enums.ErrorCodeConstants.*; 24 import static cn.iocoder.yudao.module.pay.enums.ErrorCodeConstants.*;
25 -import static cn.iocoder.yudao.module.pay.enums.member.PayWalletBizTypeEnum.PAYMENT;  
26 -import static cn.iocoder.yudao.module.pay.enums.member.PayWalletBizTypeEnum.PAYMENT_REFUND; 25 +import static cn.iocoder.yudao.module.pay.enums.wallet.PayWalletBizTypeEnum.PAYMENT;
  26 +import static cn.iocoder.yudao.module.pay.enums.wallet.PayWalletBizTypeEnum.PAYMENT_REFUND;
27 27
28 /** 28 /**
29 * 钱包 Service 实现类 29 * 钱包 Service 实现类
yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/service/wallet/PayWalletTransactionService.java
@@ -4,7 +4,7 @@ import cn.iocoder.yudao.framework.common.pojo.PageResult; @@ -4,7 +4,7 @@ import cn.iocoder.yudao.framework.common.pojo.PageResult;
4 import cn.iocoder.yudao.module.pay.controller.admin.wallet.vo.transaction.PayWalletTransactionPageReqVO; 4 import cn.iocoder.yudao.module.pay.controller.admin.wallet.vo.transaction.PayWalletTransactionPageReqVO;
5 import cn.iocoder.yudao.module.pay.controller.app.wallet.vo.transaction.AppPayWalletTransactionPageReqVO; 5 import cn.iocoder.yudao.module.pay.controller.app.wallet.vo.transaction.AppPayWalletTransactionPageReqVO;
6 import cn.iocoder.yudao.module.pay.dal.dataobject.wallet.PayWalletTransactionDO; 6 import cn.iocoder.yudao.module.pay.dal.dataobject.wallet.PayWalletTransactionDO;
7 -import cn.iocoder.yudao.module.pay.enums.member.PayWalletBizTypeEnum; 7 +import cn.iocoder.yudao.module.pay.enums.wallet.PayWalletBizTypeEnum;
8 import cn.iocoder.yudao.module.pay.service.wallet.bo.WalletTransactionCreateReqBO; 8 import cn.iocoder.yudao.module.pay.service.wallet.bo.WalletTransactionCreateReqBO;
9 9
10 import javax.validation.Valid; 10 import javax.validation.Valid;
yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/service/wallet/PayWalletTransactionServiceImpl.java
@@ -8,7 +8,7 @@ import cn.iocoder.yudao.module.pay.dal.dataobject.wallet.PayWalletDO; @@ -8,7 +8,7 @@ import cn.iocoder.yudao.module.pay.dal.dataobject.wallet.PayWalletDO;
8 import cn.iocoder.yudao.module.pay.dal.dataobject.wallet.PayWalletTransactionDO; 8 import cn.iocoder.yudao.module.pay.dal.dataobject.wallet.PayWalletTransactionDO;
9 import cn.iocoder.yudao.module.pay.dal.mysql.wallet.PayWalletTransactionMapper; 9 import cn.iocoder.yudao.module.pay.dal.mysql.wallet.PayWalletTransactionMapper;
10 import cn.iocoder.yudao.module.pay.dal.redis.no.PayNoRedisDAO; 10 import cn.iocoder.yudao.module.pay.dal.redis.no.PayNoRedisDAO;
11 -import cn.iocoder.yudao.module.pay.enums.member.PayWalletBizTypeEnum; 11 +import cn.iocoder.yudao.module.pay.enums.wallet.PayWalletBizTypeEnum;
12 import cn.iocoder.yudao.module.pay.service.wallet.bo.WalletTransactionCreateReqBO; 12 import cn.iocoder.yudao.module.pay.service.wallet.bo.WalletTransactionCreateReqBO;
13 import lombok.extern.slf4j.Slf4j; 13 import lombok.extern.slf4j.Slf4j;
14 import org.springframework.stereotype.Service; 14 import org.springframework.stereotype.Service;
yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/service/wallet/bo/WalletTransactionCreateReqBO.java
1 package cn.iocoder.yudao.module.pay.service.wallet.bo; 1 package cn.iocoder.yudao.module.pay.service.wallet.bo;
2 2
3 import cn.iocoder.yudao.framework.common.validation.InEnum; 3 import cn.iocoder.yudao.framework.common.validation.InEnum;
4 -import cn.iocoder.yudao.module.pay.enums.member.PayWalletBizTypeEnum; 4 +import cn.iocoder.yudao.module.pay.enums.wallet.PayWalletBizTypeEnum;
5 import lombok.Data; 5 import lombok.Data;
6 6
7 import javax.validation.constraints.NotEmpty; 7 import javax.validation.constraints.NotEmpty;
yudao-module-pay/yudao-module-pay-biz/src/test/java/cn/iocoder/yudao/module/pay/service/order/PayOrderServiceTest.java
@@ -3,7 +3,6 @@ package cn.iocoder.yudao.module.pay.service.order; @@ -3,7 +3,6 @@ package cn.iocoder.yudao.module.pay.service.order;
3 import cn.hutool.extra.spring.SpringUtil; 3 import cn.hutool.extra.spring.SpringUtil;
4 import cn.iocoder.yudao.framework.common.pojo.PageResult; 4 import cn.iocoder.yudao.framework.common.pojo.PageResult;
5 import cn.iocoder.yudao.framework.pay.core.client.PayClient; 5 import cn.iocoder.yudao.framework.pay.core.client.PayClient;
6 -import cn.iocoder.yudao.framework.pay.core.client.PayClientFactory;  
7 import cn.iocoder.yudao.framework.pay.core.client.dto.order.PayOrderRespDTO; 6 import cn.iocoder.yudao.framework.pay.core.client.dto.order.PayOrderRespDTO;
8 import cn.iocoder.yudao.framework.pay.core.enums.channel.PayChannelEnum; 7 import cn.iocoder.yudao.framework.pay.core.enums.channel.PayChannelEnum;
9 import cn.iocoder.yudao.framework.pay.core.enums.order.PayOrderDisplayModeEnum; 8 import cn.iocoder.yudao.framework.pay.core.enums.order.PayOrderDisplayModeEnum;
@@ -68,8 +67,6 @@ public class PayOrderServiceTest extends BaseDbAndRedisUnitTest { @@ -68,8 +67,6 @@ public class PayOrderServiceTest extends BaseDbAndRedisUnitTest {
68 private PayOrderExtensionMapper orderExtensionMapper; 67 private PayOrderExtensionMapper orderExtensionMapper;
69 68
70 @MockBean 69 @MockBean
71 - private PayClientFactory payClientFactory;  
72 - @MockBean  
73 private PayProperties properties; 70 private PayProperties properties;
74 @MockBean 71 @MockBean
75 private PayAppService appService; 72 private PayAppService appService;
@@ -351,7 +348,7 @@ public class PayOrderServiceTest extends BaseDbAndRedisUnitTest { @@ -351,7 +348,7 @@ public class PayOrderServiceTest extends BaseDbAndRedisUnitTest {
351 .thenReturn(channel); 348 .thenReturn(channel);
352 // mock 方法(client) 349 // mock 方法(client)
353 PayClient client = mock(PayClient.class); 350 PayClient client = mock(PayClient.class);
354 - when(payClientFactory.getPayClient(eq(10L))).thenReturn(client); 351 + when(channelService.getPayClient(eq(10L))).thenReturn(client);
355 // mock 方法() 352 // mock 方法()
356 PayOrderRespDTO unifiedOrderResp = randomPojo(PayOrderRespDTO.class, o -> 353 PayOrderRespDTO unifiedOrderResp = randomPojo(PayOrderRespDTO.class, o ->
357 o.setChannelErrorCode("001").setChannelErrorMsg("模拟异常")); 354 o.setChannelErrorCode("001").setChannelErrorMsg("模拟异常"));
@@ -405,7 +402,7 @@ public class PayOrderServiceTest extends BaseDbAndRedisUnitTest { @@ -405,7 +402,7 @@ public class PayOrderServiceTest extends BaseDbAndRedisUnitTest {
405 .thenReturn(channel); 402 .thenReturn(channel);
406 // mock 方法(client) 403 // mock 方法(client)
407 PayClient client = mock(PayClient.class); 404 PayClient client = mock(PayClient.class);
408 - when(payClientFactory.getPayClient(eq(10L))).thenReturn(client); 405 + when(channelService.getPayClient(eq(10L))).thenReturn(client);
409 // mock 方法(支付渠道的调用) 406 // mock 方法(支付渠道的调用)
410 PayOrderRespDTO unifiedOrderResp = randomPojo(PayOrderRespDTO.class, o -> o.setChannelErrorCode(null).setChannelErrorMsg(null) 407 PayOrderRespDTO unifiedOrderResp = randomPojo(PayOrderRespDTO.class, o -> o.setChannelErrorCode(null).setChannelErrorMsg(null)
411 .setDisplayMode(PayOrderDisplayModeEnum.URL.getMode()).setDisplayContent("tudou")); 408 .setDisplayMode(PayOrderDisplayModeEnum.URL.getMode()).setDisplayContent("tudou"));
@@ -463,7 +460,7 @@ public class PayOrderServiceTest extends BaseDbAndRedisUnitTest { @@ -463,7 +460,7 @@ public class PayOrderServiceTest extends BaseDbAndRedisUnitTest {
463 orderExtensionMapper.insert(orderExtension); 460 orderExtensionMapper.insert(orderExtension);
464 // mock 方法(PayClient 已支付) 461 // mock 方法(PayClient 已支付)
465 PayClient client = mock(PayClient.class); 462 PayClient client = mock(PayClient.class);
466 - when(payClientFactory.getPayClient(eq(orderExtension.getChannelId()))).thenReturn(client); 463 + when(channelService.getPayClient(eq(orderExtension.getChannelId()))).thenReturn(client);
467 when(client.getOrder(eq(orderExtension.getNo()))).thenReturn(randomPojo(PayOrderRespDTO.class, 464 when(client.getOrder(eq(orderExtension.getNo()))).thenReturn(randomPojo(PayOrderRespDTO.class,
468 o -> o.setStatus(PayOrderStatusEnum.SUCCESS.getStatus()))); 465 o -> o.setStatus(PayOrderStatusEnum.SUCCESS.getStatus())));
469 466
@@ -482,7 +479,7 @@ public class PayOrderServiceTest extends BaseDbAndRedisUnitTest { @@ -482,7 +479,7 @@ public class PayOrderServiceTest extends BaseDbAndRedisUnitTest {
482 orderExtensionMapper.insert(orderExtension); 479 orderExtensionMapper.insert(orderExtension);
483 // mock 方法(PayClient 已支付) 480 // mock 方法(PayClient 已支付)
484 PayClient client = mock(PayClient.class); 481 PayClient client = mock(PayClient.class);
485 - when(payClientFactory.getPayClient(eq(orderExtension.getChannelId()))).thenReturn(client); 482 + when(channelService.getPayClient(eq(orderExtension.getChannelId()))).thenReturn(client);
486 when(client.getOrder(eq(orderExtension.getNo()))).thenReturn(randomPojo(PayOrderRespDTO.class, 483 when(client.getOrder(eq(orderExtension.getNo()))).thenReturn(randomPojo(PayOrderRespDTO.class,
487 o -> o.setStatus(PayOrderStatusEnum.WAITING.getStatus()))); 484 o -> o.setStatus(PayOrderStatusEnum.WAITING.getStatus())));
488 485
@@ -639,7 +636,7 @@ public class PayOrderServiceTest extends BaseDbAndRedisUnitTest { @@ -639,7 +636,7 @@ public class PayOrderServiceTest extends BaseDbAndRedisUnitTest {
639 orderExtensionMapper.insert(orderExtension); 636 orderExtensionMapper.insert(orderExtension);
640 // 准备参数 637 // 准备参数
641 PayChannelDO channel = randomPojo(PayChannelDO.class, o -> o.setId(10L) 638 PayChannelDO channel = randomPojo(PayChannelDO.class, o -> o.setId(10L)
642 - .setFeeRate(0.1D)); 639 + .setFeeRate(10D));
643 PayOrderRespDTO notify = randomPojo(PayOrderRespDTO.class, 640 PayOrderRespDTO notify = randomPojo(PayOrderRespDTO.class,
644 o -> o.setStatus(PayOrderStatusRespEnum.SUCCESS.getStatus()) 641 o -> o.setStatus(PayOrderStatusRespEnum.SUCCESS.getStatus())
645 .setOutTradeNo("P110")); 642 .setOutTradeNo("P110"));
@@ -656,7 +653,7 @@ public class PayOrderServiceTest extends BaseDbAndRedisUnitTest { @@ -656,7 +653,7 @@ public class PayOrderServiceTest extends BaseDbAndRedisUnitTest {
656 .setChannelId(10L).setChannelCode(channel.getCode()) 653 .setChannelId(10L).setChannelCode(channel.getCode())
657 .setSuccessTime(notify.getSuccessTime()).setExtensionId(orderExtension.getId()).setNo(orderExtension.getNo()) 654 .setSuccessTime(notify.getSuccessTime()).setExtensionId(orderExtension.getId()).setNo(orderExtension.getNo())
658 .setChannelOrderNo(notify.getChannelOrderNo()).setChannelUserId(notify.getChannelUserId()) 655 .setChannelOrderNo(notify.getChannelOrderNo()).setChannelUserId(notify.getChannelUserId())
659 - .setChannelFeeRate(0.1D).setChannelFeePrice(1); 656 + .setChannelFeeRate(10D).setChannelFeePrice(1);
660 assertPojoEquals(order, orderMapper.selectOne(null), 657 assertPojoEquals(order, orderMapper.selectOne(null),
661 "updateTime", "updater"); 658 "updateTime", "updater");
662 // 断言,调用 659 // 断言,调用
@@ -874,7 +871,7 @@ public class PayOrderServiceTest extends BaseDbAndRedisUnitTest { @@ -874,7 +871,7 @@ public class PayOrderServiceTest extends BaseDbAndRedisUnitTest {
874 orderExtensionMapper.insert(orderExtension); 871 orderExtensionMapper.insert(orderExtension);
875 // mock 方法(PayClient) 872 // mock 方法(PayClient)
876 PayClient client = mock(PayClient.class); 873 PayClient client = mock(PayClient.class);
877 - when(payClientFactory.getPayClient(eq(10L))).thenReturn(client); 874 + when(channelService.getPayClient(eq(10L))).thenReturn(client);
878 // mock 方法(PayClient 异常) 875 // mock 方法(PayClient 异常)
879 when(client.getOrder(any())).thenThrow(new RuntimeException()); 876 when(client.getOrder(any())).thenThrow(new RuntimeException());
880 877
@@ -901,7 +898,7 @@ public class PayOrderServiceTest extends BaseDbAndRedisUnitTest { @@ -901,7 +898,7 @@ public class PayOrderServiceTest extends BaseDbAndRedisUnitTest {
901 orderExtensionMapper.insert(orderExtension); 898 orderExtensionMapper.insert(orderExtension);
902 // mock 方法(PayClient) 899 // mock 方法(PayClient)
903 PayClient client = mock(PayClient.class); 900 PayClient client = mock(PayClient.class);
904 - when(payClientFactory.getPayClient(eq(10L))).thenReturn(client); 901 + when(channelService.getPayClient(eq(10L))).thenReturn(client);
905 // mock 方法(PayClient 成功返回) 902 // mock 方法(PayClient 成功返回)
906 PayOrderRespDTO respDTO = randomPojo(PayOrderRespDTO.class, 903 PayOrderRespDTO respDTO = randomPojo(PayOrderRespDTO.class,
907 o -> o.setStatus(PayOrderStatusEnum.SUCCESS.getStatus())); 904 o -> o.setStatus(PayOrderStatusEnum.SUCCESS.getStatus()));
@@ -935,7 +932,7 @@ public class PayOrderServiceTest extends BaseDbAndRedisUnitTest { @@ -935,7 +932,7 @@ public class PayOrderServiceTest extends BaseDbAndRedisUnitTest {
935 orderExtensionMapper.insert(orderExtension); 932 orderExtensionMapper.insert(orderExtension);
936 // mock 方法(PayClient) 933 // mock 方法(PayClient)
937 PayClient client = mock(PayClient.class); 934 PayClient client = mock(PayClient.class);
938 - when(payClientFactory.getPayClient(eq(10L))).thenReturn(client); 935 + when(channelService.getPayClient(eq(10L))).thenReturn(client);
939 // mock 方法(PayClient 成功返回) 936 // mock 方法(PayClient 成功返回)
940 PayOrderRespDTO respDTO = randomPojo(PayOrderRespDTO.class, 937 PayOrderRespDTO respDTO = randomPojo(PayOrderRespDTO.class,
941 o -> o.setStatus(PayOrderStatusEnum.CLOSED.getStatus())); 938 o -> o.setStatus(PayOrderStatusEnum.CLOSED.getStatus()));
@@ -966,7 +963,7 @@ public class PayOrderServiceTest extends BaseDbAndRedisUnitTest { @@ -966,7 +963,7 @@ public class PayOrderServiceTest extends BaseDbAndRedisUnitTest {
966 orderExtensionMapper.insert(orderExtension); 963 orderExtensionMapper.insert(orderExtension);
967 // mock 方法(PayClient) 964 // mock 方法(PayClient)
968 PayClient client = mock(PayClient.class); 965 PayClient client = mock(PayClient.class);
969 - when(payClientFactory.getPayClient(eq(10L))).thenReturn(client); 966 + when(channelService.getPayClient(eq(10L))).thenReturn(client);
970 967
971 // 调用 968 // 调用
972 int count = orderService.expireOrder(); 969 int count = orderService.expireOrder();
@@ -1013,7 +1010,7 @@ public class PayOrderServiceTest extends BaseDbAndRedisUnitTest { @@ -1013,7 +1010,7 @@ public class PayOrderServiceTest extends BaseDbAndRedisUnitTest {
1013 orderExtensionMapper.insert(orderExtension); 1010 orderExtensionMapper.insert(orderExtension);
1014 // mock 方法(PayClient) 1011 // mock 方法(PayClient)
1015 PayClient client = mock(PayClient.class); 1012 PayClient client = mock(PayClient.class);
1016 - when(payClientFactory.getPayClient(eq(10L))).thenReturn(client); 1013 + when(channelService.getPayClient(eq(10L))).thenReturn(client);
1017 // mock 方法(PayClient 退款返回) 1014 // mock 方法(PayClient 退款返回)
1018 PayOrderRespDTO respDTO = randomPojo(PayOrderRespDTO.class, 1015 PayOrderRespDTO respDTO = randomPojo(PayOrderRespDTO.class,
1019 o -> o.setStatus(PayOrderStatusEnum.REFUND.getStatus())); 1016 o -> o.setStatus(PayOrderStatusEnum.REFUND.getStatus()));
@@ -1047,7 +1044,7 @@ public class PayOrderServiceTest extends BaseDbAndRedisUnitTest { @@ -1047,7 +1044,7 @@ public class PayOrderServiceTest extends BaseDbAndRedisUnitTest {
1047 orderExtensionMapper.insert(orderExtension); 1044 orderExtensionMapper.insert(orderExtension);
1048 // mock 方法(PayClient) 1045 // mock 方法(PayClient)
1049 PayClient client = mock(PayClient.class); 1046 PayClient client = mock(PayClient.class);
1050 - when(payClientFactory.getPayClient(eq(10L))).thenReturn(client); 1047 + when(channelService.getPayClient(eq(10L))).thenReturn(client);
1051 // mock 方法(PayClient 成功返回) 1048 // mock 方法(PayClient 成功返回)
1052 PayOrderRespDTO respDTO = randomPojo(PayOrderRespDTO.class, 1049 PayOrderRespDTO respDTO = randomPojo(PayOrderRespDTO.class,
1053 o -> o.setStatus(PayOrderStatusEnum.SUCCESS.getStatus())); 1050 o -> o.setStatus(PayOrderStatusEnum.SUCCESS.getStatus()));
@@ -1081,7 +1078,7 @@ public class PayOrderServiceTest extends BaseDbAndRedisUnitTest { @@ -1081,7 +1078,7 @@ public class PayOrderServiceTest extends BaseDbAndRedisUnitTest {
1081 orderExtensionMapper.insert(orderExtension); 1078 orderExtensionMapper.insert(orderExtension);
1082 // mock 方法(PayClient) 1079 // mock 方法(PayClient)
1083 PayClient client = mock(PayClient.class); 1080 PayClient client = mock(PayClient.class);
1084 - when(payClientFactory.getPayClient(eq(10L))).thenReturn(client); 1081 + when(channelService.getPayClient(eq(10L))).thenReturn(client);
1085 // mock 方法(PayClient 关闭返回) 1082 // mock 方法(PayClient 关闭返回)
1086 PayOrderRespDTO respDTO = randomPojo(PayOrderRespDTO.class, 1083 PayOrderRespDTO respDTO = randomPojo(PayOrderRespDTO.class,
1087 o -> o.setStatus(PayOrderStatusEnum.CLOSED.getStatus())); 1084 o -> o.setStatus(PayOrderStatusEnum.CLOSED.getStatus()));
yudao-module-pay/yudao-module-pay-biz/src/test/java/cn/iocoder/yudao/module/pay/service/refund/PayRefundServiceTest.java
@@ -3,7 +3,6 @@ package cn.iocoder.yudao.module.pay.service.refund; @@ -3,7 +3,6 @@ package cn.iocoder.yudao.module.pay.service.refund;
3 import cn.hutool.extra.spring.SpringUtil; 3 import cn.hutool.extra.spring.SpringUtil;
4 import cn.iocoder.yudao.framework.common.pojo.PageResult; 4 import cn.iocoder.yudao.framework.common.pojo.PageResult;
5 import cn.iocoder.yudao.framework.pay.core.client.PayClient; 5 import cn.iocoder.yudao.framework.pay.core.client.PayClient;
6 -import cn.iocoder.yudao.framework.pay.core.client.PayClientFactory;  
7 import cn.iocoder.yudao.framework.pay.core.client.dto.refund.PayRefundRespDTO; 6 import cn.iocoder.yudao.framework.pay.core.client.dto.refund.PayRefundRespDTO;
8 import cn.iocoder.yudao.framework.pay.core.client.dto.refund.PayRefundUnifiedReqDTO; 7 import cn.iocoder.yudao.framework.pay.core.client.dto.refund.PayRefundUnifiedReqDTO;
9 import cn.iocoder.yudao.framework.pay.core.enums.channel.PayChannelEnum; 8 import cn.iocoder.yudao.framework.pay.core.enums.channel.PayChannelEnum;
@@ -67,8 +66,6 @@ public class PayRefundServiceTest extends BaseDbAndRedisUnitTest { @@ -67,8 +66,6 @@ public class PayRefundServiceTest extends BaseDbAndRedisUnitTest {
67 @MockBean 66 @MockBean
68 private PayProperties payProperties; 67 private PayProperties payProperties;
69 @MockBean 68 @MockBean
70 - private PayClientFactory payClientFactory;  
71 - @MockBean  
72 private PayOrderService orderService; 69 private PayOrderService orderService;
73 @MockBean 70 @MockBean
74 private PayAppService appService; 71 private PayAppService appService;
@@ -335,7 +332,7 @@ public class PayRefundServiceTest extends BaseDbAndRedisUnitTest { @@ -335,7 +332,7 @@ public class PayRefundServiceTest extends BaseDbAndRedisUnitTest {
335 when(channelService.validPayChannel(eq(1L))).thenReturn(channel); 332 when(channelService.validPayChannel(eq(1L))).thenReturn(channel);
336 // mock 方法(client) 333 // mock 方法(client)
337 PayClient client = mock(PayClient.class); 334 PayClient client = mock(PayClient.class);
338 - when(payClientFactory.getPayClient(eq(10L))).thenReturn(client); 335 + when(channelService.getPayClient(eq(10L))).thenReturn(client);
339 // mock 数据(refund 已存在) 336 // mock 数据(refund 已存在)
340 PayRefundDO refund = randomPojo(PayRefundDO.class, o -> 337 PayRefundDO refund = randomPojo(PayRefundDO.class, o ->
341 o.setAppId(1L).setMerchantRefundId("200")); 338 o.setAppId(1L).setMerchantRefundId("200"));
@@ -367,7 +364,7 @@ public class PayRefundServiceTest extends BaseDbAndRedisUnitTest { @@ -367,7 +364,7 @@ public class PayRefundServiceTest extends BaseDbAndRedisUnitTest {
367 when(channelService.validPayChannel(eq(10L))).thenReturn(channel); 364 when(channelService.validPayChannel(eq(10L))).thenReturn(channel);
368 // mock 方法(client) 365 // mock 方法(client)
369 PayClient client = mock(PayClient.class); 366 PayClient client = mock(PayClient.class);
370 - when(payClientFactory.getPayClient(eq(10L))).thenReturn(client); 367 + when(channelService.getPayClient(eq(10L))).thenReturn(client);
371 // mock 方法(client 调用发生异常) 368 // mock 方法(client 调用发生异常)
372 when(client.unifiedRefund(any(PayRefundUnifiedReqDTO.class))).thenThrow(new RuntimeException()); 369 when(client.unifiedRefund(any(PayRefundUnifiedReqDTO.class))).thenThrow(new RuntimeException());
373 370
@@ -411,7 +408,7 @@ public class PayRefundServiceTest extends BaseDbAndRedisUnitTest { @@ -411,7 +408,7 @@ public class PayRefundServiceTest extends BaseDbAndRedisUnitTest {
411 when(channelService.validPayChannel(eq(10L))).thenReturn(channel); 408 when(channelService.validPayChannel(eq(10L))).thenReturn(channel);
412 // mock 方法(client) 409 // mock 方法(client)
413 PayClient client = mock(PayClient.class); 410 PayClient client = mock(PayClient.class);
414 - when(payClientFactory.getPayClient(eq(10L))).thenReturn(client); 411 + when(channelService.getPayClient(eq(10L))).thenReturn(client);
415 // mock 方法(client 成功) 412 // mock 方法(client 成功)
416 PayRefundRespDTO refundRespDTO = randomPojo(PayRefundRespDTO.class); 413 PayRefundRespDTO refundRespDTO = randomPojo(PayRefundRespDTO.class);
417 when(client.unifiedRefund(argThat(unifiedReqDTO -> { 414 when(client.unifiedRefund(argThat(unifiedReqDTO -> {
@@ -668,7 +665,7 @@ public class PayRefundServiceTest extends BaseDbAndRedisUnitTest { @@ -668,7 +665,7 @@ public class PayRefundServiceTest extends BaseDbAndRedisUnitTest {
668 refundMapper.insert(refund); 665 refundMapper.insert(refund);
669 // mock 方法(client) 666 // mock 方法(client)
670 PayClient client = mock(PayClient.class); 667 PayClient client = mock(PayClient.class);
671 - when(payClientFactory.getPayClient(eq(10L))).thenReturn(client); 668 + when(channelService.getPayClient(eq(10L))).thenReturn(client);
672 // mock 方法(client 返回指定状态) 669 // mock 方法(client 返回指定状态)
673 PayRefundRespDTO respDTO = randomPojo(PayRefundRespDTO.class, o -> o.setStatus(status)); 670 PayRefundRespDTO respDTO = randomPojo(PayRefundRespDTO.class, o -> o.setStatus(status));
674 when(client.getRefund(eq("P110"), eq("R220"))).thenReturn(respDTO); 671 when(client.getRefund(eq("P110"), eq("R220"))).thenReturn(respDTO);
@@ -690,7 +687,7 @@ public class PayRefundServiceTest extends BaseDbAndRedisUnitTest { @@ -690,7 +687,7 @@ public class PayRefundServiceTest extends BaseDbAndRedisUnitTest {
690 refundMapper.insert(refund); 687 refundMapper.insert(refund);
691 // mock 方法(client) 688 // mock 方法(client)
692 PayClient client = mock(PayClient.class); 689 PayClient client = mock(PayClient.class);
693 - when(payClientFactory.getPayClient(eq(10L))).thenReturn(client); 690 + when(channelService.getPayClient(eq(10L))).thenReturn(client);
694 // mock 方法(client 抛出异常) 691 // mock 方法(client 抛出异常)
695 when(client.getRefund(eq("P110"), eq("R220"))).thenThrow(new RuntimeException()); 692 when(client.getRefund(eq("P110"), eq("R220"))).thenThrow(new RuntimeException());
696 693
yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/api/social/SocialClientApi.java
@@ -14,12 +14,12 @@ public interface SocialClientApi { @@ -14,12 +14,12 @@ public interface SocialClientApi {
14 /** 14 /**
15 * 获得社交平台的授权 URL 15 * 获得社交平台的授权 URL
16 * 16 *
17 - * @param type 社交平台的类型 {@link SocialTypeEnum} 17 + * @param socialType 社交平台的类型 {@link SocialTypeEnum}
18 * @param userType 用户类型 18 * @param userType 用户类型
19 * @param redirectUri 重定向 URL 19 * @param redirectUri 重定向 URL
20 * @return 社交平台的授权 URL 20 * @return 社交平台的授权 URL
21 */ 21 */
22 - String getAuthorizeUrl(Integer type, Integer userType, String redirectUri); 22 + String getAuthorizeUrl(Integer socialType, Integer userType, String redirectUri);
23 23
24 /** 24 /**
25 * 创建微信公众号 JS SDK 初始化所需的签名 25 * 创建微信公众号 JS SDK 初始化所需的签名
yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/api/social/SocialUserApi.java
@@ -35,12 +35,12 @@ public interface SocialUserApi { @@ -35,12 +35,12 @@ public interface SocialUserApi {
35 * 在认证信息不正确的情况下,也会抛出 {@link ServiceException} 业务异常 35 * 在认证信息不正确的情况下,也会抛出 {@link ServiceException} 业务异常
36 * 36 *
37 * @param userType 用户类型 37 * @param userType 用户类型
38 - * @param type 社交平台的类型 38 + * @param socialType 社交平台的类型
39 * @param code 授权码 39 * @param code 授权码
40 * @param state state 40 * @param state state
41 * @return 社交用户 41 * @return 社交用户
42 */ 42 */
43 - SocialUserRespDTO getSocialUser(Integer userType, Integer type, 43 + SocialUserRespDTO getSocialUser(Integer userType, Integer socialType,
44 String code, String state); 44 String code, String state);
45 45
46 } 46 }
yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/enums/ErrorCodeConstants.java
@@ -116,10 +116,11 @@ public interface ErrorCodeConstants { @@ -116,10 +116,11 @@ public interface ErrorCodeConstants {
116 116
117 // ========== 社交用户 1-002-018-000 ========== 117 // ========== 社交用户 1-002-018-000 ==========
118 ErrorCode SOCIAL_USER_AUTH_FAILURE = new ErrorCode(1_002_018_000, "社交授权失败,原因是:{}"); 118 ErrorCode SOCIAL_USER_AUTH_FAILURE = new ErrorCode(1_002_018_000, "社交授权失败,原因是:{}");
119 - ErrorCode SOCIAL_USER_UNBIND_NOT_SELF = new ErrorCode(1_002_018_001, "社交解绑失败,非当前用户绑定");  
120 - ErrorCode SOCIAL_USER_NOT_FOUND = new ErrorCode(1_002_018_002, "社交授权失败,找不到对应的用户"); 119 + ErrorCode SOCIAL_USER_NOT_FOUND = new ErrorCode(1_002_018_001, "社交授权失败,找不到对应的用户");
121 120
122 - ErrorCode SOCIAL_APP_WEIXIN_MINI_APP_PHONE_CODE_ERROR = new ErrorCode(1_002_018_103, "获得手机号失败"); 121 + ErrorCode SOCIAL_CLIENT_WEIXIN_MINI_APP_PHONE_CODE_ERROR = new ErrorCode(1_002_018_200, "获得手机号失败");
  122 + ErrorCode SOCIAL_CLIENT_NOT_EXISTS = new ErrorCode(1_002_018_201, "社交客户端不存在");
  123 + ErrorCode SOCIAL_CLIENT_UNIQUE = new ErrorCode(1_002_018_201, "社交客户端已存在配置");
123 124
124 // ========== 系统敏感词 1-002-019-000 ========= 125 // ========== 系统敏感词 1-002-019-000 =========
125 ErrorCode SENSITIVE_WORD_NOT_EXISTS = new ErrorCode(1_002_019_000, "系统敏感词在所有标签中都不存在"); 126 ErrorCode SENSITIVE_WORD_NOT_EXISTS = new ErrorCode(1_002_019_000, "系统敏感词在所有标签中都不存在");
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/api/social/SocialClientApiImpl.java
@@ -24,8 +24,8 @@ public class SocialClientApiImpl implements SocialClientApi { @@ -24,8 +24,8 @@ public class SocialClientApiImpl implements SocialClientApi {
24 private SocialClientService socialClientService; 24 private SocialClientService socialClientService;
25 25
26 @Override 26 @Override
27 - public String getAuthorizeUrl(Integer type, Integer userType, String redirectUri) {  
28 - return socialClientService.getAuthorizeUrl(type, userType, redirectUri); 27 + public String getAuthorizeUrl(Integer socialType, Integer userType, String redirectUri) {
  28 + return socialClientService.getAuthorizeUrl(socialType, userType, redirectUri);
29 } 29 }
30 30
31 @Override 31 @Override
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/api/social/SocialUserApiImpl.java
@@ -33,8 +33,8 @@ public class SocialUserApiImpl implements SocialUserApi { @@ -33,8 +33,8 @@ public class SocialUserApiImpl implements SocialUserApi {
33 } 33 }
34 34
35 @Override 35 @Override
36 - public SocialUserRespDTO getSocialUser(Integer userType, Integer type, String code, String state) {  
37 - return socialUserService.getSocialUser(userType, type, code, state); 36 + public SocialUserRespDTO getSocialUser(Integer userType, Integer socialType, String code, String state) {
  37 + return socialUserService.getSocialUser(userType, socialType, code, state);
38 } 38 }
39 39
40 } 40 }
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/auth/AuthController.java
@@ -148,7 +148,8 @@ public class AuthController { @@ -148,7 +148,8 @@ public class AuthController {
148 }) 148 })
149 public CommonResult<String> socialLogin(@RequestParam("type") Integer type, 149 public CommonResult<String> socialLogin(@RequestParam("type") Integer type,
150 @RequestParam("redirectUri") String redirectUri) { 150 @RequestParam("redirectUri") String redirectUri) {
151 - return success(socialClientService.getAuthorizeUrl(type, UserTypeEnum.ADMIN.getValue(), redirectUri)); 151 + return success(socialClientService.getAuthorizeUrl(
  152 + type, UserTypeEnum.ADMIN.getValue(), redirectUri));
152 } 153 }
153 154
154 @PostMapping("/social-login") 155 @PostMapping("/social-login")
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/sms/SmsTemplateController.http
@@ -6,9 +6,9 @@ tenant-id: {{adminTenentId}} @@ -6,9 +6,9 @@ tenant-id: {{adminTenentId}}
6 6
7 { 7 {
8 "templateCode": "test_01", 8 "templateCode": "test_01",
9 - "mobile": "156016913900",  
10 - "params": {  
11 - "key01": "value01",  
12 - "key02": "value02" 9 + "mobile": "15601691390",
  10 + "templateParams": {
  11 + "operation": "value01",
  12 + "code": "value02"
13 } 13 }
14 } 14 }
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/socail/SocialClientController.java 0 → 100644
  1 +package cn.iocoder.yudao.module.system.controller.admin.socail;
  2 +
  3 +import cn.iocoder.yudao.framework.common.pojo.CommonResult;
  4 +import cn.iocoder.yudao.framework.common.pojo.PageResult;
  5 +import cn.iocoder.yudao.module.system.controller.admin.socail.vo.client.SocialClientCreateReqVO;
  6 +import cn.iocoder.yudao.module.system.controller.admin.socail.vo.client.SocialClientPageReqVO;
  7 +import cn.iocoder.yudao.module.system.controller.admin.socail.vo.client.SocialClientRespVO;
  8 +import cn.iocoder.yudao.module.system.controller.admin.socail.vo.client.SocialClientUpdateReqVO;
  9 +import cn.iocoder.yudao.module.system.convert.social.SocialClientConvert;
  10 +import cn.iocoder.yudao.module.system.dal.dataobject.social.SocialClientDO;
  11 +import cn.iocoder.yudao.module.system.service.social.SocialClientService;
  12 +import io.swagger.v3.oas.annotations.Operation;
  13 +import io.swagger.v3.oas.annotations.Parameter;
  14 +import io.swagger.v3.oas.annotations.tags.Tag;
  15 +import org.springframework.security.access.prepost.PreAuthorize;
  16 +import org.springframework.validation.annotation.Validated;
  17 +import org.springframework.web.bind.annotation.*;
  18 +
  19 +import javax.annotation.Resource;
  20 +import javax.validation.Valid;
  21 +
  22 +import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
  23 +
  24 +@Tag(name = "管理后台 - 社交客户端")
  25 +@RestController
  26 +@RequestMapping("/system/social-client")
  27 +@Validated
  28 +public class SocialClientController {
  29 +
  30 + @Resource
  31 + private SocialClientService socialClientService;
  32 +
  33 + @PostMapping("/create")
  34 + @Operation(summary = "创建社交客户端")
  35 + @PreAuthorize("@ss.hasPermission('system:social-client:create')")
  36 + public CommonResult<Long> createSocialClient(@Valid @RequestBody SocialClientCreateReqVO createReqVO) {
  37 + return success(socialClientService.createSocialClient(createReqVO));
  38 + }
  39 +
  40 + @PutMapping("/update")
  41 + @Operation(summary = "更新社交客户端")
  42 + @PreAuthorize("@ss.hasPermission('system:social-client:update')")
  43 + public CommonResult<Boolean> updateSocialClient(@Valid @RequestBody SocialClientUpdateReqVO updateReqVO) {
  44 + socialClientService.updateSocialClient(updateReqVO);
  45 + return success(true);
  46 + }
  47 +
  48 + @DeleteMapping("/delete")
  49 + @Operation(summary = "删除社交客户端")
  50 + @Parameter(name = "id", description = "编号", required = true)
  51 + @PreAuthorize("@ss.hasPermission('system:social-client:delete')")
  52 + public CommonResult<Boolean> deleteSocialClient(@RequestParam("id") Long id) {
  53 + socialClientService.deleteSocialClient(id);
  54 + return success(true);
  55 + }
  56 +
  57 + @GetMapping("/get")
  58 + @Operation(summary = "获得社交客户端")
  59 + @Parameter(name = "id", description = "编号", required = true, example = "1024")
  60 + @PreAuthorize("@ss.hasPermission('system:social-client:query')")
  61 + public CommonResult<SocialClientRespVO> getSocialClient(@RequestParam("id") Long id) {
  62 + SocialClientDO socialClient = socialClientService.getSocialClient(id);
  63 + return success(SocialClientConvert.INSTANCE.convert(socialClient));
  64 + }
  65 +
  66 + @GetMapping("/page")
  67 + @Operation(summary = "获得社交客户端分页")
  68 + @PreAuthorize("@ss.hasPermission('system:social-client:query')")
  69 + public CommonResult<PageResult<SocialClientRespVO>> getSocialClientPage(@Valid SocialClientPageReqVO pageVO) {
  70 + PageResult<SocialClientDO> pageResult = socialClientService.getSocialClientPage(pageVO);
  71 + return success(SocialClientConvert.INSTANCE.convertPage(pageResult));
  72 + }
  73 +
  74 +}
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/socail/SocialUserController.java
@@ -2,18 +2,25 @@ package cn.iocoder.yudao.module.system.controller.admin.socail; @@ -2,18 +2,25 @@ package cn.iocoder.yudao.module.system.controller.admin.socail;
2 2
3 import cn.iocoder.yudao.framework.common.enums.UserTypeEnum; 3 import cn.iocoder.yudao.framework.common.enums.UserTypeEnum;
4 import cn.iocoder.yudao.framework.common.pojo.CommonResult; 4 import cn.iocoder.yudao.framework.common.pojo.CommonResult;
  5 +import cn.iocoder.yudao.framework.common.pojo.PageResult;
5 import cn.iocoder.yudao.module.system.controller.admin.socail.vo.SocialUserBindReqVO; 6 import cn.iocoder.yudao.module.system.controller.admin.socail.vo.SocialUserBindReqVO;
6 import cn.iocoder.yudao.module.system.controller.admin.socail.vo.SocialUserUnbindReqVO; 7 import cn.iocoder.yudao.module.system.controller.admin.socail.vo.SocialUserUnbindReqVO;
  8 +import cn.iocoder.yudao.module.system.controller.admin.socail.vo.user.SocialUserPageReqVO;
  9 +import cn.iocoder.yudao.module.system.controller.admin.socail.vo.user.SocialUserRespVO;
7 import cn.iocoder.yudao.module.system.convert.social.SocialUserConvert; 10 import cn.iocoder.yudao.module.system.convert.social.SocialUserConvert;
  11 +import cn.iocoder.yudao.module.system.dal.dataobject.social.SocialUserDO;
8 import cn.iocoder.yudao.module.system.service.social.SocialUserService; 12 import cn.iocoder.yudao.module.system.service.social.SocialUserService;
9 -import io.swagger.v3.oas.annotations.tags.Tag;  
10 import io.swagger.v3.oas.annotations.Operation; 13 import io.swagger.v3.oas.annotations.Operation;
  14 +import io.swagger.v3.oas.annotations.Parameter;
  15 +import io.swagger.v3.oas.annotations.tags.Tag;
  16 +import org.springframework.security.access.prepost.PreAuthorize;
11 import org.springframework.validation.annotation.Validated; 17 import org.springframework.validation.annotation.Validated;
12 import org.springframework.web.bind.annotation.*; 18 import org.springframework.web.bind.annotation.*;
13 19
14 import javax.annotation.Resource; 20 import javax.annotation.Resource;
15 import javax.validation.Valid; 21 import javax.validation.Valid;
16 22
  23 +import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
17 import static cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils.getLoginUserId; 24 import static cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils.getLoginUserId;
18 25
19 @Tag(name = "管理后台 - 社交用户") 26 @Tag(name = "管理后台 - 社交用户")
@@ -39,4 +46,23 @@ public class SocialUserController { @@ -39,4 +46,23 @@ public class SocialUserController {
39 return CommonResult.success(true); 46 return CommonResult.success(true);
40 } 47 }
41 48
  49 + // ==================== 社交用户 CRUD ====================
  50 +
  51 + @GetMapping("/get")
  52 + @Operation(summary = "获得社交用户")
  53 + @Parameter(name = "id", description = "编号", required = true, example = "1024")
  54 + @PreAuthorize("@ss.hasPermission('system:social-user:query')")
  55 + public CommonResult<SocialUserRespVO> getSocialUser(@RequestParam("id") Long id) {
  56 + SocialUserDO socialUser = socialUserService.getSocialUser(id);
  57 + return success(SocialUserConvert.INSTANCE.convert(socialUser));
  58 + }
  59 +
  60 + @GetMapping("/page")
  61 + @Operation(summary = "获得社交用户分页")
  62 + @PreAuthorize("@ss.hasPermission('system:social-user:query')")
  63 + public CommonResult<PageResult<SocialUserRespVO>> getSocialUserPage(@Valid SocialUserPageReqVO pageVO) {
  64 + PageResult<SocialUserDO> pageResult = socialUserService.getSocialUserPage(pageVO);
  65 + return success(SocialUserConvert.INSTANCE.convertPage(pageResult));
  66 + }
  67 +
42 } 68 }
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/socail/vo/client/SocialClientBaseVO.java 0 → 100644
  1 +package cn.iocoder.yudao.module.system.controller.admin.socail.vo.client;
  2 +
  3 +import cn.hutool.core.util.StrUtil;
  4 +import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
  5 +import cn.iocoder.yudao.framework.common.enums.UserTypeEnum;
  6 +import cn.iocoder.yudao.framework.common.validation.InEnum;
  7 +import cn.iocoder.yudao.module.system.enums.social.SocialTypeEnum;
  8 +import com.fasterxml.jackson.annotation.JsonIgnore;
  9 +import io.swagger.v3.oas.annotations.media.Schema;
  10 +import lombok.Data;
  11 +
  12 +import javax.validation.constraints.AssertTrue;
  13 +import javax.validation.constraints.NotNull;
  14 +import java.util.Objects;
  15 +
  16 +/**
  17 + * 社交客户端 Base VO,提供给添加、修改、详细的子 VO 使用
  18 + * 如果子 VO 存在差异的字段,请不要添加到这里,影响 Swagger 文档生成
  19 + */
  20 +@Data
  21 +public class SocialClientBaseVO {
  22 +
  23 + @Schema(description = "应用名", requiredMode = Schema.RequiredMode.REQUIRED, example = "yudao商城")
  24 + @NotNull(message = "应用名不能为空")
  25 + private String name;
  26 +
  27 + @Schema(description = "社交平台的类型", requiredMode = Schema.RequiredMode.REQUIRED, example = "31")
  28 + @NotNull(message = "社交平台的类型不能为空")
  29 + @InEnum(SocialTypeEnum.class)
  30 + private Integer socialType;
  31 +
  32 + @Schema(description = "用户类型", requiredMode = Schema.RequiredMode.REQUIRED, example = "2")
  33 + @NotNull(message = "用户类型不能为空")
  34 + @InEnum(UserTypeEnum.class)
  35 + private Integer userType;
  36 +
  37 + @Schema(description = "客户端编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "wwd411c69a39ad2e54")
  38 + @NotNull(message = "客户端编号不能为空")
  39 + private String clientId;
  40 +
  41 + @Schema(description = "客户端密钥", requiredMode = Schema.RequiredMode.REQUIRED, example = "1wTb7hYxnpT2TUbIeHGXGo7T0odav1ic10mLdyyATOw")
  42 + @NotNull(message = "客户端密钥不能为空")
  43 + private String clientSecret;
  44 +
  45 + @Schema(description = "授权方的网页应用编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "2000045")
  46 + private String agentId;
  47 +
  48 + @Schema(description = "状态", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
  49 + @NotNull(message = "状态不能为空")
  50 + @InEnum(CommonStatusEnum.class)
  51 + private Integer status;
  52 +
  53 + @SuppressWarnings("RedundantIfStatement")
  54 + @AssertTrue(message = "agentId 不能为空")
  55 + @JsonIgnore
  56 + public boolean isAgentIdValid() {
  57 + // 如果是企业微信,必须填写 agentId 属性
  58 + if (Objects.equals(socialType, SocialTypeEnum.WECHAT_ENTERPRISE.getType())
  59 + && StrUtil.isEmpty(agentId)) {
  60 + return false;
  61 + }
  62 + return true;
  63 + }
  64 +
  65 +}
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/socail/vo/client/SocialClientCreateReqVO.java 0 → 100644
  1 +package cn.iocoder.yudao.module.system.controller.admin.socail.vo.client;
  2 +
  3 +import io.swagger.v3.oas.annotations.media.Schema;
  4 +import lombok.Data;
  5 +import lombok.EqualsAndHashCode;
  6 +import lombok.ToString;
  7 +
  8 +@Schema(description = "管理后台 - 社交客户端创建 Request VO")
  9 +@Data
  10 +@EqualsAndHashCode(callSuper = true)
  11 +@ToString(callSuper = true)
  12 +public class SocialClientCreateReqVO extends SocialClientBaseVO {
  13 +
  14 +}
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/socail/vo/client/SocialClientPageReqVO.java 0 → 100644
  1 +package cn.iocoder.yudao.module.system.controller.admin.socail.vo.client;
  2 +
  3 +import cn.iocoder.yudao.framework.common.pojo.PageParam;
  4 +import io.swagger.v3.oas.annotations.media.Schema;
  5 +import lombok.Data;
  6 +import lombok.EqualsAndHashCode;
  7 +import lombok.ToString;
  8 +
  9 +@Schema(description = "管理后台 - 社交客户端分页 Request VO")
  10 +@Data
  11 +@EqualsAndHashCode(callSuper = true)
  12 +@ToString(callSuper = true)
  13 +public class SocialClientPageReqVO extends PageParam {
  14 +
  15 + @Schema(description = "应用名", example = "yudao商城")
  16 + private String name;
  17 +
  18 + @Schema(description = "社交平台的类型", example = "31")
  19 + private Integer socialType;
  20 +
  21 + @Schema(description = "用户类型", example = "2")
  22 + private Integer userType;
  23 +
  24 + @Schema(description = "客户端编号", example = "145442115")
  25 + private String clientId;
  26 +
  27 + @Schema(description = "状态", example = "1")
  28 + private Integer status;
  29 +
  30 +}
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/socail/vo/client/SocialClientRespVO.java 0 → 100644
  1 +package cn.iocoder.yudao.module.system.controller.admin.socail.vo.client;
  2 +
  3 +import io.swagger.v3.oas.annotations.media.Schema;
  4 +import lombok.Data;
  5 +import lombok.EqualsAndHashCode;
  6 +import lombok.ToString;
  7 +
  8 +import java.time.LocalDateTime;
  9 +
  10 +@Schema(description = "管理后台 - 社交客户端 Response VO")
  11 +@Data
  12 +@EqualsAndHashCode(callSuper = true)
  13 +@ToString(callSuper = true)
  14 +public class SocialClientRespVO extends SocialClientBaseVO {
  15 +
  16 + @Schema(description = "编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "27162")
  17 + private Long id;
  18 +
  19 + @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED)
  20 + private LocalDateTime createTime;
  21 +
  22 +}
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/socail/vo/client/SocialClientUpdateReqVO.java 0 → 100644
  1 +package cn.iocoder.yudao.module.system.controller.admin.socail.vo.client;
  2 +
  3 +import io.swagger.v3.oas.annotations.media.Schema;
  4 +import lombok.Data;
  5 +import lombok.EqualsAndHashCode;
  6 +import lombok.ToString;
  7 +
  8 +import javax.validation.constraints.NotNull;
  9 +
  10 +@Schema(description = "管理后台 - 社交客户端更新 Request VO")
  11 +@Data
  12 +@EqualsAndHashCode(callSuper = true)
  13 +@ToString(callSuper = true)
  14 +public class SocialClientUpdateReqVO extends SocialClientBaseVO {
  15 +
  16 + @Schema(description = "编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "27162")
  17 + @NotNull(message = "编号不能为空")
  18 + private Long id;
  19 +
  20 +}
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/socail/vo/user/SocialUserBaseVO.java 0 → 100644
  1 +package cn.iocoder.yudao.module.system.controller.admin.socail.vo.user;
  2 +
  3 +import io.swagger.v3.oas.annotations.media.Schema;
  4 +import lombok.Data;
  5 +
  6 +import javax.validation.constraints.NotNull;
  7 +
  8 +/**
  9 + * 社交用户 Base VO,提供给添加、修改、详细的子 VO 使用
  10 + * 如果子 VO 存在差异的字段,请不要添加到这里,影响 Swagger 文档生成
  11 + */
  12 +@Data
  13 +public class SocialUserBaseVO {
  14 +
  15 + @Schema(description = "社交平台的类型", requiredMode = Schema.RequiredMode.REQUIRED, example = "30")
  16 + @NotNull(message = "社交平台的类型不能为空")
  17 + private Integer type;
  18 +
  19 + @Schema(description = "社交 openid", requiredMode = Schema.RequiredMode.REQUIRED, example = "666")
  20 + @NotNull(message = "社交 openid不能为空")
  21 + private String openid;
  22 +
  23 + @Schema(description = "社交 token", requiredMode = Schema.RequiredMode.REQUIRED, example = "666")
  24 + private String token;
  25 +
  26 + @Schema(description = "原始 Token 数据,一般是 JSON 格式", requiredMode = Schema.RequiredMode.REQUIRED, example = "{}")
  27 + private String rawTokenInfo;
  28 +
  29 + @Schema(description = "用户昵称", requiredMode = Schema.RequiredMode.REQUIRED, example = "芋艿")
  30 + @NotNull(message = "用户昵称不能为空")
  31 + private String nickname;
  32 +
  33 + @Schema(description = "用户头像", example = "https://www.iocoder.cn/xxx.png")
  34 + private String avatar;
  35 +
  36 + @Schema(description = "原始用户数据,一般是 JSON 格式", requiredMode = Schema.RequiredMode.REQUIRED, example = "{}")
  37 + private String rawUserInfo;
  38 +
  39 + @Schema(description = "最后一次的认证 code", requiredMode = Schema.RequiredMode.REQUIRED, example = "666666")
  40 + private String code;
  41 +
  42 + @Schema(description = "最后一次的认证 state", requiredMode = Schema.RequiredMode.REQUIRED, example = "123456")
  43 + private String state;
  44 +
  45 +}
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/socail/vo/user/SocialUserPageReqVO.java 0 → 100644
  1 +package cn.iocoder.yudao.module.system.controller.admin.socail.vo.user;
  2 +
  3 +import cn.iocoder.yudao.framework.common.pojo.PageParam;
  4 +import io.swagger.v3.oas.annotations.media.Schema;
  5 +import lombok.Data;
  6 +import lombok.EqualsAndHashCode;
  7 +import lombok.ToString;
  8 +import org.springframework.format.annotation.DateTimeFormat;
  9 +
  10 +import java.time.LocalDateTime;
  11 +
  12 +import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND;
  13 +
  14 +@Schema(description = "管理后台 - 社交用户分页 Request VO")
  15 +@Data
  16 +@EqualsAndHashCode(callSuper = true)
  17 +@ToString(callSuper = true)
  18 +public class SocialUserPageReqVO extends PageParam {
  19 +
  20 + @Schema(description = "社交平台的类型", example = "30")
  21 + private Integer type;
  22 +
  23 + @Schema(description = "用户昵称", example = "李四")
  24 + private String nickname;
  25 +
  26 + @Schema(description = "社交 openid", example = "oz-Jdt0kd_jdhUxJHQdBJMlOFN7w\n")
  27 + private String openid;
  28 +
  29 + @Schema(description = "创建时间")
  30 + @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
  31 + private LocalDateTime[] createTime;
  32 +
  33 +}
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/socail/vo/user/SocialUserRespVO.java 0 → 100644
  1 +package cn.iocoder.yudao.module.system.controller.admin.socail.vo.user;
  2 +
  3 +import io.swagger.v3.oas.annotations.media.Schema;
  4 +import lombok.Data;
  5 +import lombok.EqualsAndHashCode;
  6 +import lombok.ToString;
  7 +
  8 +import java.time.LocalDateTime;
  9 +
  10 +@Schema(description = "管理后台 - 社交用户 Response VO")
  11 +@Data
  12 +@EqualsAndHashCode(callSuper = true)
  13 +@ToString(callSuper = true)
  14 +public class SocialUserRespVO extends SocialUserBaseVO {
  15 +
  16 + @Schema(description = "主键(自增策略)", requiredMode = Schema.RequiredMode.REQUIRED, example = "14569")
  17 + private Long id;
  18 +
  19 + @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED)
  20 + private LocalDateTime createTime;
  21 +
  22 + @Schema(description = "更新时间", requiredMode = Schema.RequiredMode.REQUIRED)
  23 + private LocalDateTime updateTime;
  24 +
  25 +}
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/convert/dict/DictDataConvert.java
@@ -31,5 +31,4 @@ public interface DictDataConvert { @@ -31,5 +31,4 @@ public interface DictDataConvert {
31 31
32 List<AppDictDataRespVO> convertList03(List<DictDataDO> list); 32 List<AppDictDataRespVO> convertList03(List<DictDataDO> list);
33 33
34 - List<DictDataRespDTO> convertList04(List<DictDataDO> list);  
35 } 34 }
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/convert/social/SocialClientConvert.java
1 package cn.iocoder.yudao.module.system.convert.social; 1 package cn.iocoder.yudao.module.system.convert.social;
2 2
3 import cn.binarywang.wx.miniapp.bean.WxMaPhoneNumberInfo; 3 import cn.binarywang.wx.miniapp.bean.WxMaPhoneNumberInfo;
  4 +import cn.iocoder.yudao.framework.common.pojo.PageResult;
4 import cn.iocoder.yudao.module.system.api.social.dto.SocialWxJsapiSignatureRespDTO; 5 import cn.iocoder.yudao.module.system.api.social.dto.SocialWxJsapiSignatureRespDTO;
5 import cn.iocoder.yudao.module.system.api.social.dto.SocialWxPhoneNumberInfoRespDTO; 6 import cn.iocoder.yudao.module.system.api.social.dto.SocialWxPhoneNumberInfoRespDTO;
  7 +import cn.iocoder.yudao.module.system.controller.admin.socail.vo.client.SocialClientCreateReqVO;
  8 +import cn.iocoder.yudao.module.system.controller.admin.socail.vo.client.SocialClientRespVO;
  9 +import cn.iocoder.yudao.module.system.controller.admin.socail.vo.client.SocialClientUpdateReqVO;
  10 +import cn.iocoder.yudao.module.system.dal.dataobject.social.SocialClientDO;
6 import me.chanjar.weixin.common.bean.WxJsapiSignature; 11 import me.chanjar.weixin.common.bean.WxJsapiSignature;
7 import org.mapstruct.Mapper; 12 import org.mapstruct.Mapper;
8 import org.mapstruct.factory.Mappers; 13 import org.mapstruct.factory.Mappers;
9 14
  15 +import java.util.List;
  16 +
10 @Mapper 17 @Mapper
11 public interface SocialClientConvert { 18 public interface SocialClientConvert {
12 19
@@ -16,4 +23,16 @@ public interface SocialClientConvert { @@ -16,4 +23,16 @@ public interface SocialClientConvert {
16 23
17 SocialWxPhoneNumberInfoRespDTO convert(WxMaPhoneNumberInfo bean); 24 SocialWxPhoneNumberInfoRespDTO convert(WxMaPhoneNumberInfo bean);
18 25
  26 + SocialClientDO convert(SocialClientCreateReqVO bean);
  27 +
  28 + SocialClientDO convert(SocialClientUpdateReqVO bean);
  29 +
  30 + SocialClientRespVO convert(SocialClientDO bean);
  31 +
  32 + List<SocialClientRespVO> convertList(List<SocialClientDO> list);
  33 +
  34 + PageResult<SocialClientRespVO> convertPage(PageResult<SocialClientDO> page);
  35 +
  36 +
  37 +
19 } 38 }
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/convert/social/SocialUserConvert.java
1 package cn.iocoder.yudao.module.system.convert.social; 1 package cn.iocoder.yudao.module.system.convert.social;
2 2
  3 +import cn.iocoder.yudao.framework.common.pojo.PageResult;
3 import cn.iocoder.yudao.module.system.api.social.dto.SocialUserBindReqDTO; 4 import cn.iocoder.yudao.module.system.api.social.dto.SocialUserBindReqDTO;
4 import cn.iocoder.yudao.module.system.api.social.dto.SocialUserUnbindReqDTO; 5 import cn.iocoder.yudao.module.system.api.social.dto.SocialUserUnbindReqDTO;
5 import cn.iocoder.yudao.module.system.controller.admin.socail.vo.SocialUserBindReqVO; 6 import cn.iocoder.yudao.module.system.controller.admin.socail.vo.SocialUserBindReqVO;
6 import cn.iocoder.yudao.module.system.controller.admin.socail.vo.SocialUserUnbindReqVO; 7 import cn.iocoder.yudao.module.system.controller.admin.socail.vo.SocialUserUnbindReqVO;
  8 +import cn.iocoder.yudao.module.system.controller.admin.socail.vo.user.SocialUserRespVO;
  9 +import cn.iocoder.yudao.module.system.dal.dataobject.social.SocialUserDO;
7 import org.mapstruct.Mapper; 10 import org.mapstruct.Mapper;
  11 +import org.mapstruct.Mapping;
8 import org.mapstruct.factory.Mappers; 12 import org.mapstruct.factory.Mappers;
9 13
  14 +import java.util.List;
  15 +
10 @Mapper 16 @Mapper
11 public interface SocialUserConvert { 17 public interface SocialUserConvert {
12 18
13 SocialUserConvert INSTANCE = Mappers.getMapper(SocialUserConvert.class); 19 SocialUserConvert INSTANCE = Mappers.getMapper(SocialUserConvert.class);
14 20
  21 + @Mapping(target = "socialType", source = "reqVO.type")
15 SocialUserBindReqDTO convert(Long userId, Integer userType, SocialUserBindReqVO reqVO); 22 SocialUserBindReqDTO convert(Long userId, Integer userType, SocialUserBindReqVO reqVO);
16 23
17 SocialUserUnbindReqDTO convert(Long userId, Integer userType, SocialUserUnbindReqVO reqVO); 24 SocialUserUnbindReqDTO convert(Long userId, Integer userType, SocialUserUnbindReqVO reqVO);
18 25
  26 + SocialUserRespVO convert(SocialUserDO bean);
  27 +
  28 + List<SocialUserRespVO> convertList(List<SocialUserDO> list);
  29 +
  30 + PageResult<SocialUserRespVO> convertPage(PageResult<SocialUserDO> page);
  31 +
19 } 32 }
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/dataobject/social/SocialClientDO.java
@@ -65,4 +65,12 @@ public class SocialClientDO extends TenantBaseDO { @@ -65,4 +65,12 @@ public class SocialClientDO extends TenantBaseDO {
65 */ 65 */
66 private String clientSecret; 66 private String clientSecret;
67 67
  68 + /**
  69 + * 代理编号
  70 + *
  71 + * 目前只有部分“社交类型”在使用:
  72 + * 1. 企业微信:对应授权方的网页应用 ID
  73 + */
  74 + private String agentId;
  75 +
68 } 76 }
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/mysql/social/SocialClientMapper.java
1 package cn.iocoder.yudao.module.system.dal.mysql.social; 1 package cn.iocoder.yudao.module.system.dal.mysql.social;
2 2
  3 +import cn.iocoder.yudao.framework.common.pojo.PageResult;
3 import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; 4 import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX;
  5 +import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX;
  6 +import cn.iocoder.yudao.module.system.controller.admin.socail.vo.client.SocialClientPageReqVO;
4 import cn.iocoder.yudao.module.system.dal.dataobject.social.SocialClientDO; 7 import cn.iocoder.yudao.module.system.dal.dataobject.social.SocialClientDO;
5 import org.apache.ibatis.annotations.Mapper; 8 import org.apache.ibatis.annotations.Mapper;
6 9
@@ -12,4 +15,14 @@ public interface SocialClientMapper extends BaseMapperX&lt;SocialClientDO&gt; { @@ -12,4 +15,14 @@ public interface SocialClientMapper extends BaseMapperX&lt;SocialClientDO&gt; {
12 SocialClientDO::getUserType, userType); 15 SocialClientDO::getUserType, userType);
13 } 16 }
14 17
  18 + default PageResult<SocialClientDO> selectPage(SocialClientPageReqVO reqVO) {
  19 + return selectPage(reqVO, new LambdaQueryWrapperX<SocialClientDO>()
  20 + .likeIfPresent(SocialClientDO::getName, reqVO.getName())
  21 + .eqIfPresent(SocialClientDO::getSocialType, reqVO.getSocialType())
  22 + .eqIfPresent(SocialClientDO::getUserType, reqVO.getUserType())
  23 + .eqIfPresent(SocialClientDO::getClientId, reqVO.getClientId())
  24 + .eqIfPresent(SocialClientDO::getStatus, reqVO.getStatus())
  25 + .orderByDesc(SocialClientDO::getId));
  26 + }
  27 +
15 } 28 }
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/mysql/social/SocialUserMapper.java
1 package cn.iocoder.yudao.module.system.dal.mysql.social; 1 package cn.iocoder.yudao.module.system.dal.mysql.social;
2 2
3 -import cn.iocoder.yudao.module.system.dal.dataobject.social.SocialUserDO; 3 +import cn.iocoder.yudao.framework.common.pojo.PageResult;
4 import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; 4 import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX;
  5 +import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX;
  6 +import cn.iocoder.yudao.module.system.controller.admin.socail.vo.user.SocialUserPageReqVO;
  7 +import cn.iocoder.yudao.module.system.dal.dataobject.social.SocialUserDO;
5 import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; 8 import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
6 -import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;  
7 import org.apache.ibatis.annotations.Mapper; 9 import org.apache.ibatis.annotations.Mapper;
8 10
9 -import java.util.Collection;  
10 -import java.util.List;  
11 -  
12 @Mapper 11 @Mapper
13 public interface SocialUserMapper extends BaseMapperX<SocialUserDO> { 12 public interface SocialUserMapper extends BaseMapperX<SocialUserDO> {
14 13
@@ -25,4 +24,13 @@ public interface SocialUserMapper extends BaseMapperX&lt;SocialUserDO&gt; { @@ -25,4 +24,13 @@ public interface SocialUserMapper extends BaseMapperX&lt;SocialUserDO&gt; {
25 .eq(SocialUserDO::getOpenid, openid)); 24 .eq(SocialUserDO::getOpenid, openid));
26 } 25 }
27 26
  27 + default PageResult<SocialUserDO> selectPage(SocialUserPageReqVO reqVO) {
  28 + return selectPage(reqVO, new LambdaQueryWrapperX<SocialUserDO>()
  29 + .eqIfPresent(SocialUserDO::getType, reqVO.getType())
  30 + .likeIfPresent(SocialUserDO::getNickname, reqVO.getNickname())
  31 + .likeIfPresent(SocialUserDO::getOpenid, reqVO.getOpenid())
  32 + .betweenIfPresent(SocialUserDO::getCreateTime, reqVO.getCreateTime())
  33 + .orderByDesc(SocialUserDO::getId));
  34 + }
  35 +
28 } 36 }
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/mq/consumer/mail/MailSendConsumer.java
1 package cn.iocoder.yudao.module.system.mq.consumer.mail; 1 package cn.iocoder.yudao.module.system.mq.consumer.mail;
2 2
3 -import cn.iocoder.yudao.framework.mq.core.stream.AbstractStreamMessageListener;  
4 import cn.iocoder.yudao.module.system.mq.message.mail.MailSendMessage; 3 import cn.iocoder.yudao.module.system.mq.message.mail.MailSendMessage;
5 -import cn.iocoder.yudao.module.system.mq.message.sms.SmsSendMessage;  
6 import cn.iocoder.yudao.module.system.service.mail.MailSendService; 4 import cn.iocoder.yudao.module.system.service.mail.MailSendService;
7 import lombok.extern.slf4j.Slf4j; 5 import lombok.extern.slf4j.Slf4j;
  6 +import org.springframework.context.event.EventListener;
  7 +import org.springframework.scheduling.annotation.Async;
8 import org.springframework.stereotype.Component; 8 import org.springframework.stereotype.Component;
9 9
10 import javax.annotation.Resource; 10 import javax.annotation.Resource;
@@ -16,12 +16,13 @@ import javax.annotation.Resource; @@ -16,12 +16,13 @@ import javax.annotation.Resource;
16 */ 16 */
17 @Component 17 @Component
18 @Slf4j 18 @Slf4j
19 -public class MailSendConsumer extends AbstractStreamMessageListener<MailSendMessage> { 19 +public class MailSendConsumer {
20 20
21 @Resource 21 @Resource
22 private MailSendService mailSendService; 22 private MailSendService mailSendService;
23 23
24 - @Override 24 + @EventListener
  25 + @Async // Spring Event 默认在 Producer 发送的线程,通过 @Async 实现异步
25 public void onMessage(MailSendMessage message) { 26 public void onMessage(MailSendMessage message) {
26 log.info("[onMessage][消息内容({})]", message); 27 log.info("[onMessage][消息内容({})]", message);
27 mailSendService.doSendMail(message); 28 mailSendService.doSendMail(message);
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/mq/consumer/sms/SmsSendConsumer.java
@@ -2,8 +2,9 @@ package cn.iocoder.yudao.module.system.mq.consumer.sms; @@ -2,8 +2,9 @@ package cn.iocoder.yudao.module.system.mq.consumer.sms;
2 2
3 import cn.iocoder.yudao.module.system.mq.message.sms.SmsSendMessage; 3 import cn.iocoder.yudao.module.system.mq.message.sms.SmsSendMessage;
4 import cn.iocoder.yudao.module.system.service.sms.SmsSendService; 4 import cn.iocoder.yudao.module.system.service.sms.SmsSendService;
5 -import cn.iocoder.yudao.framework.mq.core.stream.AbstractStreamMessageListener;  
6 import lombok.extern.slf4j.Slf4j; 5 import lombok.extern.slf4j.Slf4j;
  6 +import org.springframework.context.event.EventListener;
  7 +import org.springframework.scheduling.annotation.Async;
7 import org.springframework.stereotype.Component; 8 import org.springframework.stereotype.Component;
8 9
9 import javax.annotation.Resource; 10 import javax.annotation.Resource;
@@ -15,12 +16,13 @@ import javax.annotation.Resource; @@ -15,12 +16,13 @@ import javax.annotation.Resource;
15 */ 16 */
16 @Component 17 @Component
17 @Slf4j 18 @Slf4j
18 -public class SmsSendConsumer extends AbstractStreamMessageListener<SmsSendMessage> { 19 +public class SmsSendConsumer {
19 20
20 @Resource 21 @Resource
21 private SmsSendService smsSendService; 22 private SmsSendService smsSendService;
22 23
23 - @Override 24 + @EventListener
  25 + @Async // Spring Event 默认在 Producer 发送的线程,通过 @Async 实现异步
24 public void onMessage(SmsSendMessage message) { 26 public void onMessage(SmsSendMessage message) {
25 log.info("[onMessage][消息内容({})]", message); 27 log.info("[onMessage][消息内容({})]", message);
26 smsSendService.doSendSms(message); 28 smsSendService.doSendSms(message);
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/mq/message/mail/MailSendMessage.java
1 package cn.iocoder.yudao.module.system.mq.message.mail; 1 package cn.iocoder.yudao.module.system.mq.message.mail;
2 2
3 -import cn.iocoder.yudao.framework.mq.core.stream.AbstractStreamMessage;  
4 import lombok.Data; 3 import lombok.Data;
5 -import lombok.EqualsAndHashCode;  
6 4
7 import javax.validation.constraints.NotEmpty; 5 import javax.validation.constraints.NotEmpty;
8 import javax.validation.constraints.NotNull; 6 import javax.validation.constraints.NotNull;
@@ -13,8 +11,7 @@ import javax.validation.constraints.NotNull; @@ -13,8 +11,7 @@ import javax.validation.constraints.NotNull;
13 * @author 芋道源码 11 * @author 芋道源码
14 */ 12 */
15 @Data 13 @Data
16 -@EqualsAndHashCode(callSuper = true)  
17 -public class MailSendMessage extends AbstractStreamMessage { 14 +public class MailSendMessage {
18 15
19 /** 16 /**
20 * 邮件日志编号 17 * 邮件日志编号
@@ -47,9 +44,4 @@ public class MailSendMessage extends AbstractStreamMessage { @@ -47,9 +44,4 @@ public class MailSendMessage extends AbstractStreamMessage {
47 @NotEmpty(message = "邮件内容不能为空") 44 @NotEmpty(message = "邮件内容不能为空")
48 private String content; 45 private String content;
49 46
50 - @Override  
51 - public String getStreamKey() {  
52 - return "system.mail.send";  
53 - }  
54 -  
55 } 47 }
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/mq/message/sms/SmsSendMessage.java
1 package cn.iocoder.yudao.module.system.mq.message.sms; 1 package cn.iocoder.yudao.module.system.mq.message.sms;
2 2
3 import cn.iocoder.yudao.framework.common.core.KeyValue; 3 import cn.iocoder.yudao.framework.common.core.KeyValue;
4 -import cn.iocoder.yudao.framework.mq.core.stream.AbstractStreamMessage;  
5 import lombok.Data; 4 import lombok.Data;
6 -import lombok.EqualsAndHashCode;  
7 5
8 import javax.validation.constraints.NotNull; 6 import javax.validation.constraints.NotNull;
9 import java.util.List; 7 import java.util.List;
@@ -14,8 +12,7 @@ import java.util.List; @@ -14,8 +12,7 @@ import java.util.List;
14 * @author 芋道源码 12 * @author 芋道源码
15 */ 13 */
16 @Data 14 @Data
17 -@EqualsAndHashCode(callSuper = true)  
18 -public class SmsSendMessage extends AbstractStreamMessage { 15 +public class SmsSendMessage {
19 16
20 /** 17 /**
21 * 短信日志编号 18 * 短信日志编号
@@ -42,9 +39,4 @@ public class SmsSendMessage extends AbstractStreamMessage { @@ -42,9 +39,4 @@ public class SmsSendMessage extends AbstractStreamMessage {
42 */ 39 */
43 private List<KeyValue<String, Object>> templateParams; 40 private List<KeyValue<String, Object>> templateParams;
44 41
45 - @Override  
46 - public String getStreamKey() {  
47 - return "system.sms.send";  
48 - }  
49 -  
50 } 42 }
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/mq/producer/mail/MailProducer.java
1 package cn.iocoder.yudao.module.system.mq.producer.mail; 1 package cn.iocoder.yudao.module.system.mq.producer.mail;
2 2
3 -import cn.iocoder.yudao.framework.mq.core.RedisMQTemplate;  
4 import cn.iocoder.yudao.module.system.mq.message.mail.MailSendMessage; 3 import cn.iocoder.yudao.module.system.mq.message.mail.MailSendMessage;
5 import lombok.extern.slf4j.Slf4j; 4 import lombok.extern.slf4j.Slf4j;
  5 +import org.springframework.context.ApplicationContext;
6 import org.springframework.stereotype.Component; 6 import org.springframework.stereotype.Component;
7 7
8 import javax.annotation.Resource; 8 import javax.annotation.Resource;
@@ -18,7 +18,7 @@ import javax.annotation.Resource; @@ -18,7 +18,7 @@ import javax.annotation.Resource;
18 public class MailProducer { 18 public class MailProducer {
19 19
20 @Resource 20 @Resource
21 - private RedisMQTemplate redisMQTemplate; 21 + private ApplicationContext applicationContext;
22 22
23 /** 23 /**
24 * 发送 {@link MailSendMessage} 消息 24 * 发送 {@link MailSendMessage} 消息
@@ -35,7 +35,7 @@ public class MailProducer { @@ -35,7 +35,7 @@ public class MailProducer {
35 MailSendMessage message = new MailSendMessage() 35 MailSendMessage message = new MailSendMessage()
36 .setLogId(sendLogId).setMail(mail).setAccountId(accountId) 36 .setLogId(sendLogId).setMail(mail).setAccountId(accountId)
37 .setNickname(nickname).setTitle(title).setContent(content); 37 .setNickname(nickname).setTitle(title).setContent(content);
38 - redisMQTemplate.send(message); 38 + applicationContext.publishEvent(message);
39 } 39 }
40 40
41 } 41 }
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/mq/producer/sms/SmsProducer.java
1 package cn.iocoder.yudao.module.system.mq.producer.sms; 1 package cn.iocoder.yudao.module.system.mq.producer.sms;
2 2
3 import cn.iocoder.yudao.framework.common.core.KeyValue; 3 import cn.iocoder.yudao.framework.common.core.KeyValue;
4 -import cn.iocoder.yudao.framework.mq.core.RedisMQTemplate;  
5 import cn.iocoder.yudao.module.system.mq.message.sms.SmsSendMessage; 4 import cn.iocoder.yudao.module.system.mq.message.sms.SmsSendMessage;
6 import lombok.extern.slf4j.Slf4j; 5 import lombok.extern.slf4j.Slf4j;
  6 +import org.springframework.context.ApplicationContext;
7 import org.springframework.stereotype.Component; 7 import org.springframework.stereotype.Component;
8 8
9 import javax.annotation.Resource; 9 import javax.annotation.Resource;
@@ -20,7 +20,7 @@ import java.util.List; @@ -20,7 +20,7 @@ import java.util.List;
20 public class SmsProducer { 20 public class SmsProducer {
21 21
22 @Resource 22 @Resource
23 - private RedisMQTemplate redisMQTemplate; 23 + private ApplicationContext applicationContext;
24 24
25 /** 25 /**
26 * 发送 {@link SmsSendMessage} 消息 26 * 发送 {@link SmsSendMessage} 消息
@@ -35,7 +35,7 @@ public class SmsProducer { @@ -35,7 +35,7 @@ public class SmsProducer {
35 Long channelId, String apiTemplateId, List<KeyValue<String, Object>> templateParams) { 35 Long channelId, String apiTemplateId, List<KeyValue<String, Object>> templateParams) {
36 SmsSendMessage message = new SmsSendMessage().setLogId(logId).setMobile(mobile); 36 SmsSendMessage message = new SmsSendMessage().setLogId(logId).setMobile(mobile);
37 message.setChannelId(channelId).setApiTemplateId(apiTemplateId).setTemplateParams(templateParams); 37 message.setChannelId(channelId).setApiTemplateId(apiTemplateId).setTemplateParams(templateParams);
38 - redisMQTemplate.send(message); 38 + applicationContext.publishEvent(message);
39 } 39 }
40 40
41 } 41 }
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/sensitiveword/SensitiveWordService.java
@@ -91,8 +91,8 @@ public interface SensitiveWordService { @@ -91,8 +91,8 @@ public interface SensitiveWordService {
91 * 判断文本是否包含敏感词 91 * 判断文本是否包含敏感词
92 * 92 *
93 * @param text 文本 93 * @param text 文本
94 - * @param tags 表述数组  
95 - * @return 是否包含 94 + * @param tags 标签数组
  95 + * @return 是否包含敏感词
96 */ 96 */
97 boolean isTextValid(String text, List<String> tags); 97 boolean isTextValid(String text, List<String> tags);
98 98
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/sensitiveword/SensitiveWordServiceImpl.java
@@ -258,6 +258,7 @@ public class SensitiveWordServiceImpl implements SensitiveWordService { @@ -258,6 +258,7 @@ public class SensitiveWordServiceImpl implements SensitiveWordService {
258 if (trie == null) { 258 if (trie == null) {
259 continue; 259 continue;
260 } 260 }
  261 + // 如果有一个标签不合法,则返回 false 不合法
261 if (!trie.isValid(text)) { 262 if (!trie.isValid(text)) {
262 return false; 263 return false;
263 } 264 }
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/sms/SmsTemplateServiceImpl.java
@@ -5,7 +5,6 @@ import cn.hutool.core.util.StrUtil; @@ -5,7 +5,6 @@ import cn.hutool.core.util.StrUtil;
5 import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; 5 import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
6 import cn.iocoder.yudao.framework.common.pojo.PageResult; 6 import cn.iocoder.yudao.framework.common.pojo.PageResult;
7 import cn.iocoder.yudao.framework.sms.core.client.SmsClient; 7 import cn.iocoder.yudao.framework.sms.core.client.SmsClient;
8 -import cn.iocoder.yudao.framework.sms.core.client.SmsClientFactory;  
9 import cn.iocoder.yudao.framework.sms.core.client.SmsCommonResult; 8 import cn.iocoder.yudao.framework.sms.core.client.SmsCommonResult;
10 import cn.iocoder.yudao.framework.sms.core.client.dto.SmsTemplateRespDTO; 9 import cn.iocoder.yudao.framework.sms.core.client.dto.SmsTemplateRespDTO;
11 import cn.iocoder.yudao.module.system.controller.admin.sms.vo.template.SmsTemplateCreateReqVO; 10 import cn.iocoder.yudao.module.system.controller.admin.sms.vo.template.SmsTemplateCreateReqVO;
@@ -53,9 +52,6 @@ public class SmsTemplateServiceImpl implements SmsTemplateService { @@ -53,9 +52,6 @@ public class SmsTemplateServiceImpl implements SmsTemplateService {
53 @Resource 52 @Resource
54 private SmsChannelService smsChannelService; 53 private SmsChannelService smsChannelService;
55 54
56 - @Resource  
57 - private SmsClientFactory smsClientFactory;  
58 -  
59 @Override 55 @Override
60 public Long createSmsTemplate(SmsTemplateCreateReqVO createReqVO) { 56 public Long createSmsTemplate(SmsTemplateCreateReqVO createReqVO) {
61 // 校验短信渠道 57 // 校验短信渠道
@@ -173,7 +169,7 @@ public class SmsTemplateServiceImpl implements SmsTemplateService { @@ -173,7 +169,7 @@ public class SmsTemplateServiceImpl implements SmsTemplateService {
173 @VisibleForTesting 169 @VisibleForTesting
174 void validateApiTemplate(Long channelId, String apiTemplateId) { 170 void validateApiTemplate(Long channelId, String apiTemplateId) {
175 // 获得短信模板 171 // 获得短信模板
176 - SmsClient smsClient = smsClientFactory.getSmsClient(channelId); 172 + SmsClient smsClient = smsChannelService.getSmsClient(channelId);
177 Assert.notNull(smsClient, String.format("短信客户端(%d) 不存在", channelId)); 173 Assert.notNull(smsClient, String.format("短信客户端(%d) 不存在", channelId));
178 SmsCommonResult<SmsTemplateRespDTO> templateResult = smsClient.getSmsTemplate(apiTemplateId); 174 SmsCommonResult<SmsTemplateRespDTO> templateResult = smsClient.getSmsTemplate(apiTemplateId);
179 // 校验短信模板是否正确 175 // 校验短信模板是否正确
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/social/SocialClientService.java
1 package cn.iocoder.yudao.module.system.service.social; 1 package cn.iocoder.yudao.module.system.service.social;
2 2
3 import cn.binarywang.wx.miniapp.bean.WxMaPhoneNumberInfo; 3 import cn.binarywang.wx.miniapp.bean.WxMaPhoneNumberInfo;
  4 +import cn.iocoder.yudao.framework.common.pojo.PageResult;
  5 +import cn.iocoder.yudao.module.system.controller.admin.socail.vo.client.SocialClientCreateReqVO;
  6 +import cn.iocoder.yudao.module.system.controller.admin.socail.vo.client.SocialClientPageReqVO;
  7 +import cn.iocoder.yudao.module.system.controller.admin.socail.vo.client.SocialClientUpdateReqVO;
  8 +import cn.iocoder.yudao.module.system.dal.dataobject.social.SocialClientDO;
4 import cn.iocoder.yudao.module.system.enums.social.SocialTypeEnum; 9 import cn.iocoder.yudao.module.system.enums.social.SocialTypeEnum;
5 import com.xingyuv.jushauth.model.AuthUser; 10 import com.xingyuv.jushauth.model.AuthUser;
6 import me.chanjar.weixin.common.bean.WxJsapiSignature; 11 import me.chanjar.weixin.common.bean.WxJsapiSignature;
7 12
  13 +import javax.validation.Valid;
  14 +
8 /** 15 /**
9 * 社交应用 Service 接口 16 * 社交应用 Service 接口
10 * 17 *
@@ -55,4 +62,44 @@ public interface SocialClientService { @@ -55,4 +62,44 @@ public interface SocialClientService {
55 */ 62 */
56 WxMaPhoneNumberInfo getWxMaPhoneNumberInfo(Integer userType, String phoneCode); 63 WxMaPhoneNumberInfo getWxMaPhoneNumberInfo(Integer userType, String phoneCode);
57 64
  65 + // =================== 客户端管理 ===================
  66 +
  67 + /**
  68 + * 创建社交客户端
  69 + *
  70 + * @param createReqVO 创建信息
  71 + * @return 编号
  72 + */
  73 + Long createSocialClient(@Valid SocialClientCreateReqVO createReqVO);
  74 +
  75 + /**
  76 + * 更新社交客户端
  77 + *
  78 + * @param updateReqVO 更新信息
  79 + */
  80 + void updateSocialClient(@Valid SocialClientUpdateReqVO updateReqVO);
  81 +
  82 + /**
  83 + * 删除社交客户端
  84 + *
  85 + * @param id 编号
  86 + */
  87 + void deleteSocialClient(Long id);
  88 +
  89 + /**
  90 + * 获得社交客户端
  91 + *
  92 + * @param id 编号
  93 + * @return 社交客户端
  94 + */
  95 + SocialClientDO getSocialClient(Long id);
  96 +
  97 + /**
  98 + * 获得社交客户端分页
  99 + *
  100 + * @param pageReqVO 分页查询
  101 + * @return 社交客户端分页
  102 + */
  103 + PageResult<SocialClientDO> getSocialClientPage(SocialClientPageReqVO pageReqVO);
  104 +
58 } 105 }
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/social/SocialClientServiceImpl.java
@@ -6,16 +6,23 @@ import cn.binarywang.wx.miniapp.bean.WxMaPhoneNumberInfo; @@ -6,16 +6,23 @@ import cn.binarywang.wx.miniapp.bean.WxMaPhoneNumberInfo;
6 import cn.binarywang.wx.miniapp.config.impl.WxMaRedisBetterConfigImpl; 6 import cn.binarywang.wx.miniapp.config.impl.WxMaRedisBetterConfigImpl;
7 import cn.hutool.core.bean.BeanUtil; 7 import cn.hutool.core.bean.BeanUtil;
8 import cn.hutool.core.lang.Assert; 8 import cn.hutool.core.lang.Assert;
  9 +import cn.hutool.core.util.ObjUtil;
9 import cn.hutool.core.util.ReflectUtil; 10 import cn.hutool.core.util.ReflectUtil;
10 import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; 11 import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
  12 +import cn.iocoder.yudao.framework.common.pojo.PageResult;
11 import cn.iocoder.yudao.framework.common.util.cache.CacheUtils; 13 import cn.iocoder.yudao.framework.common.util.cache.CacheUtils;
12 import cn.iocoder.yudao.framework.common.util.http.HttpUtils; 14 import cn.iocoder.yudao.framework.common.util.http.HttpUtils;
13 import cn.iocoder.yudao.framework.social.core.YudaoAuthRequestFactory; 15 import cn.iocoder.yudao.framework.social.core.YudaoAuthRequestFactory;
  16 +import cn.iocoder.yudao.module.system.controller.admin.socail.vo.client.SocialClientCreateReqVO;
  17 +import cn.iocoder.yudao.module.system.controller.admin.socail.vo.client.SocialClientPageReqVO;
  18 +import cn.iocoder.yudao.module.system.controller.admin.socail.vo.client.SocialClientUpdateReqVO;
  19 +import cn.iocoder.yudao.module.system.convert.social.SocialClientConvert;
14 import cn.iocoder.yudao.module.system.dal.dataobject.social.SocialClientDO; 20 import cn.iocoder.yudao.module.system.dal.dataobject.social.SocialClientDO;
15 import cn.iocoder.yudao.module.system.dal.mysql.social.SocialClientMapper; 21 import cn.iocoder.yudao.module.system.dal.mysql.social.SocialClientMapper;
16 import cn.iocoder.yudao.module.system.enums.social.SocialTypeEnum; 22 import cn.iocoder.yudao.module.system.enums.social.SocialTypeEnum;
17 import com.binarywang.spring.starter.wxjava.miniapp.properties.WxMaProperties; 23 import com.binarywang.spring.starter.wxjava.miniapp.properties.WxMaProperties;
18 import com.binarywang.spring.starter.wxjava.mp.properties.WxMpProperties; 24 import com.binarywang.spring.starter.wxjava.mp.properties.WxMpProperties;
  25 +import com.google.common.annotations.VisibleForTesting;
19 import com.google.common.cache.CacheLoader; 26 import com.google.common.cache.CacheLoader;
20 import com.google.common.cache.LoadingCache; 27 import com.google.common.cache.LoadingCache;
21 import com.xingyuv.jushauth.config.AuthConfig; 28 import com.xingyuv.jushauth.config.AuthConfig;
@@ -41,8 +48,7 @@ import java.util.Objects; @@ -41,8 +48,7 @@ import java.util.Objects;
41 48
42 import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; 49 import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
43 import static cn.iocoder.yudao.framework.common.util.json.JsonUtils.toJsonString; 50 import static cn.iocoder.yudao.framework.common.util.json.JsonUtils.toJsonString;
44 -import static cn.iocoder.yudao.module.system.enums.ErrorCodeConstants.SOCIAL_APP_WEIXIN_MINI_APP_PHONE_CODE_ERROR;  
45 -import static cn.iocoder.yudao.module.system.enums.ErrorCodeConstants.SOCIAL_USER_AUTH_FAILURE; 51 +import static cn.iocoder.yudao.module.system.enums.ErrorCodeConstants.*;
46 52
47 /** 53 /**
48 * 社交应用 Service 实现类 54 * 社交应用 Service 实现类
@@ -151,6 +157,9 @@ public class SocialClientServiceImpl implements SocialClientService { @@ -151,6 +157,9 @@ public class SocialClientServiceImpl implements SocialClientService {
151 // 2.2 修改对应的 clientId + clientSecret 密钥 157 // 2.2 修改对应的 clientId + clientSecret 密钥
152 newAuthConfig.setClientId(client.getClientId()); 158 newAuthConfig.setClientId(client.getClientId());
153 newAuthConfig.setClientSecret(client.getClientSecret()); 159 newAuthConfig.setClientSecret(client.getClientSecret());
  160 + if (client.getAgentId() != null) { // 如果有 agentId 则修改 agentId
  161 + newAuthConfig.setAgentId(client.getAgentId());
  162 + }
154 // 2.3 设置会 request 里,进行后续使用 163 // 2.3 设置会 request 里,进行后续使用
155 ReflectUtil.setFieldValue(request, "config", newAuthConfig); 164 ReflectUtil.setFieldValue(request, "config", newAuthConfig);
156 } 165 }
@@ -213,7 +222,7 @@ public class SocialClientServiceImpl implements SocialClientService { @@ -213,7 +222,7 @@ public class SocialClientServiceImpl implements SocialClientService {
213 return service.getUserService().getPhoneNoInfo(phoneCode); 222 return service.getUserService().getPhoneNoInfo(phoneCode);
214 } catch (WxErrorException e) { 223 } catch (WxErrorException e) {
215 log.error("[getPhoneNoInfo][userType({}) phoneCode({}) 获得手机号失败]", userType, phoneCode, e); 224 log.error("[getPhoneNoInfo][userType({}) phoneCode({}) 获得手机号失败]", userType, phoneCode, e);
216 - throw exception(SOCIAL_APP_WEIXIN_MINI_APP_PHONE_CODE_ERROR); 225 + throw exception(SOCIAL_CLIENT_WEIXIN_MINI_APP_PHONE_CODE_ERROR);
217 } 226 }
218 } 227 }
219 228
@@ -255,4 +264,76 @@ public class SocialClientServiceImpl implements SocialClientService { @@ -255,4 +264,76 @@ public class SocialClientServiceImpl implements SocialClientService {
255 return service; 264 return service;
256 } 265 }
257 266
  267 + // =================== 客户端管理 ===================
  268 +
  269 + @Override
  270 + public Long createSocialClient(SocialClientCreateReqVO createReqVO) {
  271 + // 校验重复
  272 + validateSocialClientUnique(null, createReqVO.getUserType(), createReqVO.getSocialType());
  273 +
  274 + // 插入
  275 + SocialClientDO socialClient = SocialClientConvert.INSTANCE.convert(createReqVO);
  276 + socialClientMapper.insert(socialClient);
  277 + // 返回
  278 + return socialClient.getId();
  279 + }
  280 +
  281 + @Override
  282 + public void updateSocialClient(SocialClientUpdateReqVO updateReqVO) {
  283 + // 校验存在
  284 + validateSocialClientExists(updateReqVO.getId());
  285 + // 校验重复
  286 + validateSocialClientUnique(updateReqVO.getId(), updateReqVO.getUserType(), updateReqVO.getSocialType());
  287 +
  288 + // 更新
  289 + SocialClientDO updateObj = SocialClientConvert.INSTANCE.convert(updateReqVO);
  290 + socialClientMapper.updateById(updateObj);
  291 + }
  292 +
  293 + @Override
  294 + public void deleteSocialClient(Long id) {
  295 + // 校验存在
  296 + validateSocialClientExists(id);
  297 + // 删除
  298 + socialClientMapper.deleteById(id);
  299 + }
  300 +
  301 + private void validateSocialClientExists(Long id) {
  302 + if (socialClientMapper.selectById(id) == null) {
  303 + throw exception(SOCIAL_CLIENT_NOT_EXISTS);
  304 + }
  305 + }
  306 +
  307 + /**
  308 + * 校验社交应用是否重复,需要保证 userType + socialType 唯一
  309 + *
  310 + * 原因是,不同端(userType)选择某个社交登录(socialType)时,需要通过 {@link #buildAuthRequest(Integer, Integer)} 构建对应的请求
  311 + *
  312 + * @param id 编号
  313 + * @param userType 用户类型
  314 + * @param socialType 社交类型
  315 + */
  316 + @VisibleForTesting
  317 + private void validateSocialClientUnique(Long id, Integer userType, Integer socialType) {
  318 + SocialClientDO client = socialClientMapper.selectBySocialTypeAndUserType(
  319 + socialType, userType);
  320 + if (client == null) {
  321 + return;
  322 + }
  323 + if (id == null // 新增时,说明重复
  324 + || ObjUtil.notEqual(id, client.getId())) { // 更新时,如果 id 不一致,说明重复
  325 + throw exception(SOCIAL_CLIENT_UNIQUE);
  326 + }
  327 + }
  328 +
  329 + @Override
  330 + public SocialClientDO getSocialClient(Long id) {
  331 + return socialClientMapper.selectById(id);
  332 + }
  333 +
  334 + @Override
  335 + public PageResult<SocialClientDO> getSocialClientPage(SocialClientPageReqVO pageReqVO) {
  336 + return socialClientMapper.selectPage(pageReqVO);
  337 + }
  338 +
258 } 339 }
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/social/SocialUserService.java
1 package cn.iocoder.yudao.module.system.service.social; 1 package cn.iocoder.yudao.module.system.service.social;
2 2
3 import cn.iocoder.yudao.framework.common.exception.ServiceException; 3 import cn.iocoder.yudao.framework.common.exception.ServiceException;
  4 +import cn.iocoder.yudao.framework.common.pojo.PageResult;
4 import cn.iocoder.yudao.module.system.api.social.dto.SocialUserBindReqDTO; 5 import cn.iocoder.yudao.module.system.api.social.dto.SocialUserBindReqDTO;
5 import cn.iocoder.yudao.module.system.api.social.dto.SocialUserRespDTO; 6 import cn.iocoder.yudao.module.system.api.social.dto.SocialUserRespDTO;
  7 +import cn.iocoder.yudao.module.system.controller.admin.socail.vo.user.SocialUserPageReqVO;
6 import cn.iocoder.yudao.module.system.dal.dataobject.social.SocialUserDO; 8 import cn.iocoder.yudao.module.system.dal.dataobject.social.SocialUserDO;
7 import cn.iocoder.yudao.module.system.enums.social.SocialTypeEnum; 9 import cn.iocoder.yudao.module.system.enums.social.SocialTypeEnum;
8 10
@@ -19,7 +21,7 @@ public interface SocialUserService { @@ -19,7 +21,7 @@ public interface SocialUserService {
19 /** 21 /**
20 * 获得指定用户的社交用户列表 22 * 获得指定用户的社交用户列表
21 * 23 *
22 - * @param userId 用户编号 24 + * @param userId 用户编号
23 * @param userType 用户类型 25 * @param userType 用户类型
24 * @return 社交用户列表 26 * @return 社交用户列表
25 */ 27 */
@@ -38,10 +40,10 @@ public interface SocialUserService { @@ -38,10 +40,10 @@ public interface SocialUserService {
38 * 40 *
39 * @param userId 用户编号 41 * @param userId 用户编号
40 * @param userType 全局用户类型 42 * @param userType 全局用户类型
41 - * @param type 社交平台的类型 {@link SocialTypeEnum} 43 + * @param socialType 社交平台的类型 {@link SocialTypeEnum}
42 * @param openid 社交平台的 openid 44 * @param openid 社交平台的 openid
43 */ 45 */
44 - void unbindSocialUser(Long userId, Integer userType, Integer type, String openid); 46 + void unbindSocialUser(Long userId, Integer userType, Integer socialType, String openid);
45 47
46 /** 48 /**
47 * 获得社交用户 49 * 获得社交用户
@@ -49,11 +51,29 @@ public interface SocialUserService { @@ -49,11 +51,29 @@ public interface SocialUserService {
49 * 在认证信息不正确的情况下,也会抛出 {@link ServiceException} 业务异常 51 * 在认证信息不正确的情况下,也会抛出 {@link ServiceException} 业务异常
50 * 52 *
51 * @param userType 用户类型 53 * @param userType 用户类型
52 - * @param type 社交平台的类型 54 + * @param socialType 社交平台的类型
53 * @param code 授权码 55 * @param code 授权码
54 * @param state state 56 * @param state state
55 * @return 社交用户 57 * @return 社交用户
56 */ 58 */
57 - SocialUserRespDTO getSocialUser(Integer userType, Integer type, String code, String state); 59 + SocialUserRespDTO getSocialUser(Integer userType, Integer socialType, String code, String state);
  60 +
  61 + // ==================== 社交用户 CRUD ====================
  62 +
  63 + /**
  64 + * 获得社交用户
  65 + *
  66 + * @param id 编号
  67 + * @return 社交用户
  68 + */
  69 + SocialUserDO getSocialUser(Long id);
  70 +
  71 + /**
  72 + * 获得社交用户分页
  73 + *
  74 + * @param pageReqVO 分页查询
  75 + * @return 社交用户分页
  76 + */
  77 + PageResult<SocialUserDO> getSocialUserPage(SocialUserPageReqVO pageReqVO);
58 78
59 } 79 }
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/social/SocialUserServiceImpl.java
1 package cn.iocoder.yudao.module.system.service.social; 1 package cn.iocoder.yudao.module.system.service.social;
2 2
3 import cn.hutool.core.collection.CollUtil; 3 import cn.hutool.core.collection.CollUtil;
  4 +import cn.hutool.core.collection.ListUtil;
4 import cn.hutool.core.lang.Assert; 5 import cn.hutool.core.lang.Assert;
5 import cn.iocoder.yudao.framework.common.exception.ServiceException; 6 import cn.iocoder.yudao.framework.common.exception.ServiceException;
  7 +import cn.iocoder.yudao.framework.common.pojo.PageResult;
6 import cn.iocoder.yudao.module.system.api.social.dto.SocialUserBindReqDTO; 8 import cn.iocoder.yudao.module.system.api.social.dto.SocialUserBindReqDTO;
7 import cn.iocoder.yudao.module.system.api.social.dto.SocialUserRespDTO; 9 import cn.iocoder.yudao.module.system.api.social.dto.SocialUserRespDTO;
  10 +import cn.iocoder.yudao.module.system.controller.admin.socail.vo.user.SocialUserPageReqVO;
  11 +import cn.iocoder.yudao.module.system.convert.social.SocialUserConvert;
8 import cn.iocoder.yudao.module.system.dal.dataobject.social.SocialUserBindDO; 12 import cn.iocoder.yudao.module.system.dal.dataobject.social.SocialUserBindDO;
9 import cn.iocoder.yudao.module.system.dal.dataobject.social.SocialUserDO; 13 import cn.iocoder.yudao.module.system.dal.dataobject.social.SocialUserDO;
10 import cn.iocoder.yudao.module.system.dal.mysql.social.SocialUserBindMapper; 14 import cn.iocoder.yudao.module.system.dal.mysql.social.SocialUserBindMapper;
@@ -18,14 +22,14 @@ import org.springframework.validation.annotation.Validated; @@ -18,14 +22,14 @@ import org.springframework.validation.annotation.Validated;
18 22
19 import javax.annotation.Resource; 23 import javax.annotation.Resource;
20 import javax.validation.constraints.NotNull; 24 import javax.validation.constraints.NotNull;
  25 +import java.util.Collection;
21 import java.util.Collections; 26 import java.util.Collections;
22 import java.util.List; 27 import java.util.List;
23 28
24 import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; 29 import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
25 import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet; 30 import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet;
26 import static cn.iocoder.yudao.framework.common.util.json.JsonUtils.toJsonString; 31 import static cn.iocoder.yudao.framework.common.util.json.JsonUtils.toJsonString;
27 -import static cn.iocoder.yudao.module.system.enums.ErrorCodeConstants.AUTH_THIRD_LOGIN_NOT_BIND;  
28 -import static cn.iocoder.yudao.module.system.enums.ErrorCodeConstants.SOCIAL_USER_NOT_FOUND; 32 +import static cn.iocoder.yudao.module.system.enums.ErrorCodeConstants.*;
29 33
30 /** 34 /**
31 * 社交用户 Service 实现类 35 * 社交用户 Service 实现类
@@ -80,9 +84,9 @@ public class SocialUserServiceImpl implements SocialUserService { @@ -80,9 +84,9 @@ public class SocialUserServiceImpl implements SocialUserService {
80 } 84 }
81 85
82 @Override 86 @Override
83 - public void unbindSocialUser(Long userId, Integer userType, Integer type, String openid) { 87 + public void unbindSocialUser(Long userId, Integer userType, Integer socialType, String openid) {
84 // 获得 openid 对应的 SocialUserDO 社交用户 88 // 获得 openid 对应的 SocialUserDO 社交用户
85 - SocialUserDO socialUser = socialUserMapper.selectByTypeAndOpenid(type, openid); 89 + SocialUserDO socialUser = socialUserMapper.selectByTypeAndOpenid(socialType, openid);
86 if (socialUser == null) { 90 if (socialUser == null) {
87 throw exception(SOCIAL_USER_NOT_FOUND); 91 throw exception(SOCIAL_USER_NOT_FOUND);
88 } 92 }
@@ -92,9 +96,9 @@ public class SocialUserServiceImpl implements SocialUserService { @@ -92,9 +96,9 @@ public class SocialUserServiceImpl implements SocialUserService {
92 } 96 }
93 97
94 @Override 98 @Override
95 - public SocialUserRespDTO getSocialUser(Integer userType, Integer type, String code, String state) { 99 + public SocialUserRespDTO getSocialUser(Integer userType, Integer socialType, String code, String state) {
96 // 获得社交用户 100 // 获得社交用户
97 - SocialUserDO socialUser = authSocialUser(type, userType, code, state); 101 + SocialUserDO socialUser = authSocialUser(socialType, userType, code, state);
98 Assert.notNull(socialUser, "社交用户不能为空"); 102 Assert.notNull(socialUser, "社交用户不能为空");
99 103
100 // 如果未绑定的社交用户,则无法自动登录,进行报错 104 // 如果未绑定的社交用户,则无法自动登录,进行报错
@@ -113,8 +117,8 @@ public class SocialUserServiceImpl implements SocialUserService { @@ -113,8 +117,8 @@ public class SocialUserServiceImpl implements SocialUserService {
113 * 117 *
114 * @param socialType 社交平台的类型 {@link SocialTypeEnum} 118 * @param socialType 社交平台的类型 {@link SocialTypeEnum}
115 * @param userType 用户类型 119 * @param userType 用户类型
116 - * @param code 授权码  
117 - * @param state state 120 + * @param code 授权码
  121 + * @param state state
118 * @return 授权用户 122 * @return 授权用户
119 */ 123 */
120 @NotNull 124 @NotNull
@@ -146,4 +150,16 @@ public class SocialUserServiceImpl implements SocialUserService { @@ -146,4 +150,16 @@ public class SocialUserServiceImpl implements SocialUserService {
146 return socialUser; 150 return socialUser;
147 } 151 }
148 152
  153 + // ==================== 社交用户 CRUD ====================
  154 +
  155 + @Override
  156 + public SocialUserDO getSocialUser(Long id) {
  157 + return socialUserMapper.selectById(id);
  158 + }
  159 +
  160 + @Override
  161 + public PageResult<SocialUserDO> getSocialUserPage(SocialUserPageReqVO pageReqVO) {
  162 + return socialUserMapper.selectPage(pageReqVO);
  163 + }
  164 +
149 } 165 }
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/util/collection/SimpleTrie.java
@@ -30,9 +30,10 @@ public class SimpleTrie { @@ -30,9 +30,10 @@ public class SimpleTrie {
30 * @param strs 字符串数组 30 * @param strs 字符串数组
31 */ 31 */
32 public SimpleTrie(Collection<String> strs) { 32 public SimpleTrie(Collection<String> strs) {
33 - children = new HashMap<>(); 33 + // 排序,优先使用较短的前缀
  34 + strs = CollUtil.sort(strs, String::compareTo);
34 // 构建树 35 // 构建树
35 - CollUtil.sort(strs, String::compareTo); // 排序,优先使用较短的前缀 36 + children = new HashMap<>();
36 for (String str : strs) { 37 for (String str : strs) {
37 Map<Character, Object> child = children; 38 Map<Character, Object> child = children;
38 // 遍历每个字符 39 // 遍历每个字符
@@ -56,11 +57,11 @@ public class SimpleTrie { @@ -56,11 +57,11 @@ public class SimpleTrie {
56 * 验证文本是否合法,即不包含敏感词 57 * 验证文本是否合法,即不包含敏感词
57 * 58 *
58 * @param text 文本 59 * @param text 文本
59 - * @return 是否 ok 60 + * @return 是否 true-合法 false-不合法
60 */ 61 */
61 public boolean isValid(String text) { 62 public boolean isValid(String text) {
62 // 遍历 text,使用每一个 [i, n) 段的字符串,使用 children 前缀树匹配,是否包含敏感词 63 // 遍历 text,使用每一个 [i, n) 段的字符串,使用 children 前缀树匹配,是否包含敏感词
63 - for (int i = 0; i < text.length() - 1; i++) { 64 + for (int i = 0; i < text.length(); i++) {
64 Map<Character, Object> child = (Map<Character, Object>) children.get(text.charAt(i)); 65 Map<Character, Object> child = (Map<Character, Object>) children.get(text.charAt(i));
65 if (child == null) { 66 if (child == null) {
66 continue; 67 continue;
@@ -74,14 +75,17 @@ public class SimpleTrie { @@ -74,14 +75,17 @@ public class SimpleTrie {
74 } 75 }
75 76
76 /** 77 /**
77 - * 验证文本从指定位置开始,是否包含某个敏感词 78 + * 验证文本从指定位置开始,是否不包含某个敏感词
78 * 79 *
79 * @param text 文本 80 * @param text 文本
80 * @param index 开始位置 81 * @param index 开始位置
81 * @param child 节点(当前遍历到的) 82 * @param child 节点(当前遍历到的)
82 - * @return 是否包含 83 + * @return 是否不包含 true-不包含 false-包含
83 */ 84 */
84 private boolean recursion(String text, int index, Map<Character, Object> child) { 85 private boolean recursion(String text, int index, Map<Character, Object> child) {
  86 + if (child.containsKey(CHARACTER_END)) {
  87 + return false;
  88 + }
85 if (index == text.length()) { 89 if (index == text.length()) {
86 return true; 90 return true;
87 } 91 }
@@ -99,7 +103,7 @@ public class SimpleTrie { @@ -99,7 +103,7 @@ public class SimpleTrie {
99 */ 103 */
100 public List<String> validate(String text) { 104 public List<String> validate(String text) {
101 Set<String> results = new HashSet<>(); 105 Set<String> results = new HashSet<>();
102 - for (int i = 0; i < text.length() - 1; i++) { 106 + for (int i = 0; i < text.length(); i++) {
103 Character c = text.charAt(i); 107 Character c = text.charAt(i);
104 Map<Character, Object> child = (Map<Character, Object>) children.get(c); 108 Map<Character, Object> child = (Map<Character, Object>) children.get(c);
105 if (child == null) { 109 if (child == null) {
@@ -127,6 +131,9 @@ public class SimpleTrie { @@ -127,6 +131,9 @@ public class SimpleTrie {
127 */ 131 */
128 @SuppressWarnings("unchecked") 132 @SuppressWarnings("unchecked")
129 private static boolean recursionWithResult(String text, int index, Map<Character, Object> child, StringBuilder result) { 133 private static boolean recursionWithResult(String text, int index, Map<Character, Object> child, StringBuilder result) {
  134 + if (child.containsKey(CHARACTER_END)) {
  135 + return false;
  136 + }
130 if (index == text.length()) { 137 if (index == text.length()) {
131 return true; 138 return true;
132 } 139 }
yudao-module-system/yudao-module-system-biz/src/test/java/cn/iocoder/yudao/module/system/service/sensitiveword/SensitiveWordServiceImplTest.java
@@ -56,20 +56,28 @@ public class SensitiveWordServiceImplTest extends BaseDbUnitTest { @@ -56,20 +56,28 @@ public class SensitiveWordServiceImplTest extends BaseDbUnitTest {
56 SensitiveWordDO wordDO2 = randomPojo(SensitiveWordDO.class, o -> o.setName("笨蛋") 56 SensitiveWordDO wordDO2 = randomPojo(SensitiveWordDO.class, o -> o.setName("笨蛋")
57 .setTags(singletonList("蔬菜")).setStatus(CommonStatusEnum.ENABLE.getStatus())); 57 .setTags(singletonList("蔬菜")).setStatus(CommonStatusEnum.ENABLE.getStatus()));
58 sensitiveWordMapper.insert(wordDO2); 58 sensitiveWordMapper.insert(wordDO2);
  59 + SensitiveWordDO wordDO3 = randomPojo(SensitiveWordDO.class, o -> o.setName("白")
  60 + .setTags(singletonList("测试")).setStatus(CommonStatusEnum.ENABLE.getStatus()));
  61 + sensitiveWordMapper.insert(wordDO3);
  62 + SensitiveWordDO wordDO4 = randomPojo(SensitiveWordDO.class, o -> o.setName("白痴")
  63 + .setTags(singletonList("测试")).setStatus(CommonStatusEnum.ENABLE.getStatus()));
  64 + sensitiveWordMapper.insert(wordDO4);
59 65
60 // 调用 66 // 调用
61 sensitiveWordService.initLocalCache(); 67 sensitiveWordService.initLocalCache();
62 // 断言 sensitiveWordTagsCache 缓存 68 // 断言 sensitiveWordTagsCache 缓存
63 - assertEquals(SetUtils.asSet("论坛", "蔬菜"), sensitiveWordService.getSensitiveWordTagSet()); 69 + assertEquals(SetUtils.asSet("论坛", "蔬菜", "测试"), sensitiveWordService.getSensitiveWordTagSet());
64 // 断言 sensitiveWordCache 70 // 断言 sensitiveWordCache
65 - assertEquals(2, sensitiveWordService.getSensitiveWordCache().size()); 71 + assertEquals(4, sensitiveWordService.getSensitiveWordCache().size());
66 assertPojoEquals(wordDO1, sensitiveWordService.getSensitiveWordCache().get(0)); 72 assertPojoEquals(wordDO1, sensitiveWordService.getSensitiveWordCache().get(0));
67 assertPojoEquals(wordDO2, sensitiveWordService.getSensitiveWordCache().get(1)); 73 assertPojoEquals(wordDO2, sensitiveWordService.getSensitiveWordCache().get(1));
  74 + assertPojoEquals(wordDO3, sensitiveWordService.getSensitiveWordCache().get(2));
68 // 断言 tagSensitiveWordTries 缓存 75 // 断言 tagSensitiveWordTries 缓存
69 assertNotNull(sensitiveWordService.getDefaultSensitiveWordTrie()); 76 assertNotNull(sensitiveWordService.getDefaultSensitiveWordTrie());
70 - assertEquals(2, sensitiveWordService.getTagSensitiveWordTries().size()); 77 + assertEquals(3, sensitiveWordService.getTagSensitiveWordTries().size());
71 assertNotNull(sensitiveWordService.getTagSensitiveWordTries().get("论坛")); 78 assertNotNull(sensitiveWordService.getTagSensitiveWordTries().get("论坛"));
72 assertNotNull(sensitiveWordService.getTagSensitiveWordTries().get("蔬菜")); 79 assertNotNull(sensitiveWordService.getTagSensitiveWordTries().get("蔬菜"));
  80 + assertNotNull(sensitiveWordService.getTagSensitiveWordTries().get("测试"));
73 } 81 }
74 82
75 @Test 83 @Test
@@ -231,11 +239,17 @@ public class SensitiveWordServiceImplTest extends BaseDbUnitTest { @@ -231,11 +239,17 @@ public class SensitiveWordServiceImplTest extends BaseDbUnitTest {
231 testInitLocalCache(); 239 testInitLocalCache();
232 // 准备参数 240 // 准备参数
233 String text = "你是傻瓜,你是笨蛋"; 241 String text = "你是傻瓜,你是笨蛋";
234 -  
235 // 调用 242 // 调用
236 List<String> result = sensitiveWordService.validateText(text, null); 243 List<String> result = sensitiveWordService.validateText(text, null);
237 // 断言 244 // 断言
238 assertEquals(Arrays.asList("傻瓜", "笨蛋"), result); 245 assertEquals(Arrays.asList("傻瓜", "笨蛋"), result);
  246 +
  247 + // 准备参数
  248 + String text2 = "你是傻瓜,你是笨蛋,你是白";
  249 + // 调用
  250 + List<String> result2 = sensitiveWordService.validateText(text2, null);
  251 + // 断言
  252 + assertEquals(Arrays.asList("傻瓜", "笨蛋","白"), result2);
239 } 253 }
240 254
241 @Test 255 @Test
@@ -243,11 +257,18 @@ public class SensitiveWordServiceImplTest extends BaseDbUnitTest { @@ -243,11 +257,18 @@ public class SensitiveWordServiceImplTest extends BaseDbUnitTest {
243 testInitLocalCache(); 257 testInitLocalCache();
244 // 准备参数 258 // 准备参数
245 String text = "你是傻瓜,你是笨蛋"; 259 String text = "你是傻瓜,你是笨蛋";
246 -  
247 // 调用 260 // 调用
248 List<String> result = sensitiveWordService.validateText(text, singletonList("论坛")); 261 List<String> result = sensitiveWordService.validateText(text, singletonList("论坛"));
249 // 断言 262 // 断言
250 assertEquals(singletonList("傻瓜"), result); 263 assertEquals(singletonList("傻瓜"), result);
  264 +
  265 +
  266 + // 准备参数
  267 + String text2 = "你是白";
  268 + // 调用
  269 + List<String> result2 = sensitiveWordService.validateText(text2, singletonList("测试"));
  270 + // 断言
  271 + assertEquals(singletonList("白"), result2);
251 } 272 }
252 273
253 @Test 274 @Test
@@ -255,9 +276,13 @@ public class SensitiveWordServiceImplTest extends BaseDbUnitTest { @@ -255,9 +276,13 @@ public class SensitiveWordServiceImplTest extends BaseDbUnitTest {
255 testInitLocalCache(); 276 testInitLocalCache();
256 // 准备参数 277 // 准备参数
257 String text = "你是傻瓜,你是笨蛋"; 278 String text = "你是傻瓜,你是笨蛋";
258 -  
259 // 调用,断言 279 // 调用,断言
260 assertFalse(sensitiveWordService.isTextValid(text, null)); 280 assertFalse(sensitiveWordService.isTextValid(text, null));
  281 +
  282 + // 准备参数
  283 + String text2 = "你是白";
  284 + // 调用,断言
  285 + assertFalse(sensitiveWordService.isTextValid(text2, null));
261 } 286 }
262 287
263 @Test 288 @Test
@@ -265,9 +290,13 @@ public class SensitiveWordServiceImplTest extends BaseDbUnitTest { @@ -265,9 +290,13 @@ public class SensitiveWordServiceImplTest extends BaseDbUnitTest {
265 testInitLocalCache(); 290 testInitLocalCache();
266 // 准备参数 291 // 准备参数
267 String text = "你是傻瓜,你是笨蛋"; 292 String text = "你是傻瓜,你是笨蛋";
268 -  
269 // 调用,断言 293 // 调用,断言
270 assertFalse(sensitiveWordService.isTextValid(text, singletonList("论坛"))); 294 assertFalse(sensitiveWordService.isTextValid(text, singletonList("论坛")));
  295 +
  296 + // 准备参数
  297 + String text2 = "你是白";
  298 + // 调用,断言
  299 + assertFalse(sensitiveWordService.isTextValid(text2, singletonList("测试")));
271 } 300 }
272 301
273 } 302 }
yudao-module-system/yudao-module-system-biz/src/test/java/cn/iocoder/yudao/module/system/service/sms/SmsTemplateServiceImplTest.java
@@ -6,7 +6,6 @@ import cn.iocoder.yudao.framework.common.pojo.PageResult; @@ -6,7 +6,6 @@ import cn.iocoder.yudao.framework.common.pojo.PageResult;
6 import cn.iocoder.yudao.framework.common.util.collection.ArrayUtils; 6 import cn.iocoder.yudao.framework.common.util.collection.ArrayUtils;
7 import cn.iocoder.yudao.framework.common.util.object.ObjectUtils; 7 import cn.iocoder.yudao.framework.common.util.object.ObjectUtils;
8 import cn.iocoder.yudao.framework.sms.core.client.SmsClient; 8 import cn.iocoder.yudao.framework.sms.core.client.SmsClient;
9 -import cn.iocoder.yudao.framework.sms.core.client.SmsClientFactory;  
10 import cn.iocoder.yudao.framework.sms.core.client.SmsCommonResult; 9 import cn.iocoder.yudao.framework.sms.core.client.SmsCommonResult;
11 import cn.iocoder.yudao.framework.sms.core.client.dto.SmsTemplateRespDTO; 10 import cn.iocoder.yudao.framework.sms.core.client.dto.SmsTemplateRespDTO;
12 import cn.iocoder.yudao.framework.test.core.ut.BaseDbUnitTest; 11 import cn.iocoder.yudao.framework.test.core.ut.BaseDbUnitTest;
@@ -36,7 +35,7 @@ import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.*; @@ -36,7 +35,7 @@ import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.*;
36 import static cn.iocoder.yudao.module.system.enums.ErrorCodeConstants.*; 35 import static cn.iocoder.yudao.module.system.enums.ErrorCodeConstants.*;
37 import static org.junit.jupiter.api.Assertions.*; 36 import static org.junit.jupiter.api.Assertions.*;
38 import static org.mockito.ArgumentMatchers.eq; 37 import static org.mockito.ArgumentMatchers.eq;
39 -import static org.mockito.Mockito.*; 38 +import static org.mockito.Mockito.when;
40 39
41 @Import(SmsTemplateServiceImpl.class) 40 @Import(SmsTemplateServiceImpl.class)
42 public class SmsTemplateServiceImplTest extends BaseDbUnitTest { 41 public class SmsTemplateServiceImplTest extends BaseDbUnitTest {
@@ -50,8 +49,6 @@ public class SmsTemplateServiceImplTest extends BaseDbUnitTest { @@ -50,8 +49,6 @@ public class SmsTemplateServiceImplTest extends BaseDbUnitTest {
50 @MockBean 49 @MockBean
51 private SmsChannelService smsChannelService; 50 private SmsChannelService smsChannelService;
52 @MockBean 51 @MockBean
53 - private SmsClientFactory smsClientFactory;  
54 - @MockBean  
55 private SmsClient smsClient; 52 private SmsClient smsClient;
56 53
57 @Test 54 @Test
@@ -82,7 +79,7 @@ public class SmsTemplateServiceImplTest extends BaseDbUnitTest { @@ -82,7 +79,7 @@ public class SmsTemplateServiceImplTest extends BaseDbUnitTest {
82 }); 79 });
83 when(smsChannelService.getSmsChannel(eq(channelDO.getId()))).thenReturn(channelDO); 80 when(smsChannelService.getSmsChannel(eq(channelDO.getId()))).thenReturn(channelDO);
84 // mock 获得 API 短信模板成功 81 // mock 获得 API 短信模板成功
85 - when(smsClientFactory.getSmsClient(eq(reqVO.getChannelId()))).thenReturn(smsClient); 82 + when(smsChannelService.getSmsClient(eq(reqVO.getChannelId()))).thenReturn(smsClient);
86 when(smsClient.getSmsTemplate(eq(reqVO.getApiTemplateId()))).thenReturn(randomPojo(SmsCommonResult.class, SmsTemplateRespDTO.class, 83 when(smsClient.getSmsTemplate(eq(reqVO.getApiTemplateId()))).thenReturn(randomPojo(SmsCommonResult.class, SmsTemplateRespDTO.class,
87 o -> o.setCode(GlobalErrorCodeConstants.SUCCESS.getCode()))); 84 o -> o.setCode(GlobalErrorCodeConstants.SUCCESS.getCode())));
88 85
@@ -117,7 +114,7 @@ public class SmsTemplateServiceImplTest extends BaseDbUnitTest { @@ -117,7 +114,7 @@ public class SmsTemplateServiceImplTest extends BaseDbUnitTest {
117 }); 114 });
118 when(smsChannelService.getSmsChannel(eq(channelDO.getId()))).thenReturn(channelDO); 115 when(smsChannelService.getSmsChannel(eq(channelDO.getId()))).thenReturn(channelDO);
119 // mock 获得 API 短信模板成功 116 // mock 获得 API 短信模板成功
120 - when(smsClientFactory.getSmsClient(eq(reqVO.getChannelId()))).thenReturn(smsClient); 117 + when(smsChannelService.getSmsClient(eq(reqVO.getChannelId()))).thenReturn(smsClient);
121 when(smsClient.getSmsTemplate(eq(reqVO.getApiTemplateId()))).thenReturn(randomPojo(SmsCommonResult.class, SmsTemplateRespDTO.class, 118 when(smsClient.getSmsTemplate(eq(reqVO.getApiTemplateId()))).thenReturn(randomPojo(SmsCommonResult.class, SmsTemplateRespDTO.class,
122 o -> o.setCode(GlobalErrorCodeConstants.SUCCESS.getCode()))); 119 o -> o.setCode(GlobalErrorCodeConstants.SUCCESS.getCode())));
123 120
yudao-module-system/yudao-module-system-biz/src/test/java/cn/iocoder/yudao/module/system/service/social/SocialClientServiceImplTest.java 0 → 100644
  1 +package cn.iocoder.yudao.module.system.service.social;
  2 +
  3 +import cn.iocoder.yudao.framework.common.pojo.PageResult;
  4 +import cn.iocoder.yudao.framework.test.core.ut.BaseDbUnitTest;
  5 +import cn.iocoder.yudao.module.system.controller.admin.socail.vo.client.SocialClientCreateReqVO;
  6 +import cn.iocoder.yudao.module.system.controller.admin.socail.vo.client.SocialClientPageReqVO;
  7 +import cn.iocoder.yudao.module.system.controller.admin.socail.vo.client.SocialClientUpdateReqVO;
  8 +import cn.iocoder.yudao.module.system.dal.dataobject.social.SocialClientDO;
  9 +import cn.iocoder.yudao.module.system.dal.mysql.social.SocialClientMapper;
  10 +import org.junit.jupiter.api.Disabled;
  11 +import org.junit.jupiter.api.Test;
  12 +import org.springframework.context.annotation.Import;
  13 +
  14 +import javax.annotation.Resource;
  15 +
  16 +import static cn.iocoder.yudao.framework.common.util.object.ObjectUtils.cloneIgnoreId;
  17 +import static cn.iocoder.yudao.framework.test.core.util.AssertUtils.assertPojoEquals;
  18 +import static cn.iocoder.yudao.framework.test.core.util.AssertUtils.assertServiceException;
  19 +import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.randomLongId;
  20 +import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.randomPojo;
  21 +import static cn.iocoder.yudao.module.system.enums.ErrorCodeConstants.SOCIAL_CLIENT_NOT_EXISTS;
  22 +import static org.junit.jupiter.api.Assertions.*;
  23 +
  24 +// TODO 芋艿:单测后续补充下;
  25 +/**
  26 + * {@link SocialClientServiceImpl} 的单元测试类
  27 + *
  28 + * @author 芋道源码
  29 + */
  30 +@Import(SocialClientServiceImpl.class)
  31 +@Disabled
  32 +public class SocialClientServiceImplTest extends BaseDbUnitTest {
  33 +
  34 + @Resource
  35 + private SocialClientServiceImpl socialClientService;
  36 +
  37 + @Resource
  38 + private SocialClientMapper socialClientMapper;
  39 +
  40 + @Test
  41 + public void testCreateSocialClient_success() {
  42 + // 准备参数
  43 + SocialClientCreateReqVO reqVO = randomPojo(SocialClientCreateReqVO.class);
  44 +
  45 + // 调用
  46 + Long socialClientId = socialClientService.createSocialClient(reqVO);
  47 + // 断言
  48 + assertNotNull(socialClientId);
  49 + // 校验记录的属性是否正确
  50 + SocialClientDO socialClient = socialClientMapper.selectById(socialClientId);
  51 + assertPojoEquals(reqVO, socialClient);
  52 + }
  53 +
  54 + @Test
  55 + public void testUpdateSocialClient_success() {
  56 + // mock 数据
  57 + SocialClientDO dbSocialClient = randomPojo(SocialClientDO.class);
  58 + socialClientMapper.insert(dbSocialClient);// @Sql: 先插入出一条存在的数据
  59 + // 准备参数
  60 + SocialClientUpdateReqVO reqVO = randomPojo(SocialClientUpdateReqVO.class, o -> {
  61 + o.setId(dbSocialClient.getId()); // 设置更新的 ID
  62 + });
  63 +
  64 + // 调用
  65 + socialClientService.updateSocialClient(reqVO);
  66 + // 校验是否更新正确
  67 + SocialClientDO socialClient = socialClientMapper.selectById(reqVO.getId()); // 获取最新的
  68 + assertPojoEquals(reqVO, socialClient);
  69 + }
  70 +
  71 + @Test
  72 + public void testUpdateSocialClient_notExists() {
  73 + // 准备参数
  74 + SocialClientUpdateReqVO reqVO = randomPojo(SocialClientUpdateReqVO.class);
  75 +
  76 + // 调用, 并断言异常
  77 + assertServiceException(() -> socialClientService.updateSocialClient(reqVO), SOCIAL_CLIENT_NOT_EXISTS);
  78 + }
  79 +
  80 + @Test
  81 + public void testDeleteSocialClient_success() {
  82 + // mock 数据
  83 + SocialClientDO dbSocialClient = randomPojo(SocialClientDO.class);
  84 + socialClientMapper.insert(dbSocialClient);// @Sql: 先插入出一条存在的数据
  85 + // 准备参数
  86 + Long id = dbSocialClient.getId();
  87 +
  88 + // 调用
  89 + socialClientService.deleteSocialClient(id);
  90 + // 校验数据不存在了
  91 + assertNull(socialClientMapper.selectById(id));
  92 + }
  93 +
  94 + @Test
  95 + public void testDeleteSocialClient_notExists() {
  96 + // 准备参数
  97 + Long id = randomLongId();
  98 +
  99 + // 调用, 并断言异常
  100 + assertServiceException(() -> socialClientService.deleteSocialClient(id), SOCIAL_CLIENT_NOT_EXISTS);
  101 + }
  102 +
  103 + @Test
  104 + @Disabled // TODO 请修改 null 为需要的值,然后删除 @Disabled 注解
  105 + public void testGetSocialClientPage() {
  106 + // mock 数据
  107 + SocialClientDO dbSocialClient = randomPojo(SocialClientDO.class, o -> { // 等会查询到
  108 + o.setName(null);
  109 + o.setSocialType(null);
  110 + o.setUserType(null);
  111 + o.setClientId(null);
  112 + o.setClientSecret(null);
  113 + o.setStatus(null);
  114 + o.setCreateTime(null);
  115 + });
  116 + socialClientMapper.insert(dbSocialClient);
  117 + // 测试 name 不匹配
  118 + socialClientMapper.insert(cloneIgnoreId(dbSocialClient, o -> o.setName(null)));
  119 + // 测试 socialType 不匹配
  120 + socialClientMapper.insert(cloneIgnoreId(dbSocialClient, o -> o.setSocialType(null)));
  121 + // 测试 userType 不匹配
  122 + socialClientMapper.insert(cloneIgnoreId(dbSocialClient, o -> o.setUserType(null)));
  123 + // 测试 clientId 不匹配
  124 + socialClientMapper.insert(cloneIgnoreId(dbSocialClient, o -> o.setClientId(null)));
  125 + // 测试 clientSecret 不匹配
  126 + socialClientMapper.insert(cloneIgnoreId(dbSocialClient, o -> o.setClientSecret(null)));
  127 + // 测试 status 不匹配
  128 + socialClientMapper.insert(cloneIgnoreId(dbSocialClient, o -> o.setStatus(null)));
  129 + // 测试 createTime 不匹配
  130 + socialClientMapper.insert(cloneIgnoreId(dbSocialClient, o -> o.setCreateTime(null)));
  131 + // 准备参数
  132 + SocialClientPageReqVO reqVO = new SocialClientPageReqVO();
  133 + reqVO.setName(null);
  134 + reqVO.setSocialType(null);
  135 + reqVO.setUserType(null);
  136 + reqVO.setClientId(null);
  137 + reqVO.setStatus(null);
  138 +
  139 + // 调用
  140 + PageResult<SocialClientDO> pageResult = socialClientService.getSocialClientPage(reqVO);
  141 + // 断言
  142 + assertEquals(1, pageResult.getTotal());
  143 + assertEquals(1, pageResult.getList().size());
  144 + assertPojoEquals(dbSocialClient, pageResult.getList().get(0));
  145 + }
  146 +
  147 +}
yudao-module-system/yudao-module-system-biz/src/test/resources/sql/clean.sql
@@ -17,6 +17,7 @@ DELETE FROM &quot;system_sms_template&quot;; @@ -17,6 +17,7 @@ DELETE FROM &quot;system_sms_template&quot;;
17 DELETE FROM "system_sms_log"; 17 DELETE FROM "system_sms_log";
18 DELETE FROM "system_sms_code"; 18 DELETE FROM "system_sms_code";
19 DELETE FROM "system_error_code"; 19 DELETE FROM "system_error_code";
  20 +DELETE FROM "system_social_client";
20 DELETE FROM "system_social_user"; 21 DELETE FROM "system_social_user";
21 DELETE FROM "system_social_user_bind"; 22 DELETE FROM "system_social_user_bind";
22 DELETE FROM "system_tenant"; 23 DELETE FROM "system_tenant";
yudao-module-system/yudao-module-system-biz/src/test/resources/sql/create_tables.sql
@@ -354,8 +354,25 @@ CREATE TABLE IF NOT EXISTS &quot;system_error_code&quot; ( @@ -354,8 +354,25 @@ CREATE TABLE IF NOT EXISTS &quot;system_error_code&quot; (
354 PRIMARY KEY ("id") 354 PRIMARY KEY ("id")
355 ) COMMENT '错误码表'; 355 ) COMMENT '错误码表';
356 356
  357 +CREATE TABLE IF NOT EXISTS "system_social_client" (
  358 + "id" bigint NOT NULL GENERATED BY DEFAULT AS IDENTITY,
  359 + "name" varchar(255) NOT NULL,
  360 + "social_type" int NOT NULL,
  361 + "user_type" int NOT NULL,
  362 + "client_id" varchar(255) NOT NULL,
  363 + "client_secret" varchar(255) NOT NULL,
  364 + "status" int NOT NULL,
  365 + "creator" varchar(64) DEFAULT '',
  366 + "create_time" datetime NOT NULL DEFAULT CURRENT_TIMESTAMP,
  367 + "updater" varchar(64) DEFAULT '',
  368 + "update_time" datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
  369 + "deleted" bit NOT NULL DEFAULT FALSE,
  370 + "tenant_id" bigint NOT NULL,
  371 + PRIMARY KEY ("id")
  372 +) COMMENT '社交客户端表';
  373 +
357 CREATE TABLE IF NOT EXISTS "system_social_user" ( 374 CREATE TABLE IF NOT EXISTS "system_social_user" (
358 - "id" number NOT NULL GENERATED BY DEFAULT AS IDENTITY, 375 + "id" bigint NOT NULL GENERATED BY DEFAULT AS IDENTITY,
359 "type" tinyint NOT NULL, 376 "type" tinyint NOT NULL,
360 "openid" varchar(64) NOT NULL, 377 "openid" varchar(64) NOT NULL,
361 "token" varchar(256) DEFAULT NULL, 378 "token" varchar(256) DEFAULT NULL,
@@ -374,7 +391,7 @@ CREATE TABLE IF NOT EXISTS &quot;system_social_user&quot; ( @@ -374,7 +391,7 @@ CREATE TABLE IF NOT EXISTS &quot;system_social_user&quot; (
374 ) COMMENT '社交用户'; 391 ) COMMENT '社交用户';
375 392
376 CREATE TABLE IF NOT EXISTS "system_social_user_bind" ( 393 CREATE TABLE IF NOT EXISTS "system_social_user_bind" (
377 - "id" number NOT NULL GENERATED BY DEFAULT AS IDENTITY, 394 + "id" bigint NOT NULL GENERATED BY DEFAULT AS IDENTITY,
378 "user_id" bigint NOT NULL, 395 "user_id" bigint NOT NULL,
379 "user_type" tinyint NOT NULL, 396 "user_type" tinyint NOT NULL,
380 "social_type" tinyint NOT NULL, 397 "social_type" tinyint NOT NULL,
yudao-server/pom.xml
@@ -63,13 +63,13 @@ @@ -63,13 +63,13 @@
63 </dependency> 63 </dependency>
64 64
65 <!-- 微信公众号模块。默认注释,保证编译速度 --> 65 <!-- 微信公众号模块。默认注释,保证编译速度 -->
66 - <dependency>  
67 - <groupId>cn.iocoder.boot</groupId>  
68 - <artifactId>yudao-module-mp-biz</artifactId>  
69 - <version>${revision}</version>  
70 - </dependency> 66 +<!-- <dependency>-->
  67 +<!-- <groupId>cn.iocoder.boot</groupId>-->
  68 +<!-- <artifactId>yudao-module-mp-biz</artifactId>-->
  69 +<!-- <version>${revision}</version>-->
  70 +<!-- </dependency>-->
71 71
72 -<!-- 商城相关模块。默认注释,保证编译速度--> 72 + <!-- 商城相关模块。默认注释,保证编译速度-->
73 <dependency> 73 <dependency>
74 <groupId>cn.iocoder.boot</groupId> 74 <groupId>cn.iocoder.boot</groupId>
75 <artifactId>yudao-module-promotion-biz</artifactId> 75 <artifactId>yudao-module-promotion-biz</artifactId>
yudao-server/src/main/resources/application-dev.yaml
@@ -94,6 +94,23 @@ spring: @@ -94,6 +94,23 @@ spring:
94 jdbc: # 使用 JDBC 的 JobStore 的时候,JDBC 的配置 94 jdbc: # 使用 JDBC 的 JobStore 的时候,JDBC 的配置
95 initialize-schema: NEVER # 是否自动使用 SQL 初始化 Quartz 表结构。这里设置成 never ,我们手动创建表结构。 95 initialize-schema: NEVER # 是否自动使用 SQL 初始化 Quartz 表结构。这里设置成 never ,我们手动创建表结构。
96 96
  97 +--- #################### 消息队列相关 ####################
  98 +
  99 +# rocketmq 配置项,对应 RocketMQProperties 配置类
  100 +rocketmq:
  101 + name-server: 127.0.0.1:9876 # RocketMQ Namesrv
  102 +
  103 +spring:
  104 + # RabbitMQ 配置项,对应 RabbitProperties 配置类
  105 + rabbitmq:
  106 + host: 127.0.0.1 # RabbitMQ 服务的地址
  107 + port: 5672 # RabbitMQ 服务的端口
  108 + username: guest # RabbitMQ 服务的账号
  109 + password: guest # RabbitMQ 服务的密码
  110 + # Kafka 配置项,对应 KafkaProperties 配置类
  111 + kafka:
  112 + bootstrap-servers: 127.0.0.1:9092 # 指定 Kafka Broker 地址,可以设置多个,以逗号分隔
  113 +
97 --- #################### 服务保障相关配置 #################### 114 --- #################### 服务保障相关配置 ####################
98 115
99 # Lock4j 配置项 116 # Lock4j 配置项
yudao-server/src/main/resources/application-local.yaml
@@ -109,6 +109,23 @@ spring: @@ -109,6 +109,23 @@ spring:
109 jdbc: # 使用 JDBC 的 JobStore 的时候,JDBC 的配置 109 jdbc: # 使用 JDBC 的 JobStore 的时候,JDBC 的配置
110 initialize-schema: NEVER # 是否自动使用 SQL 初始化 Quartz 表结构。这里设置成 never ,我们手动创建表结构。 110 initialize-schema: NEVER # 是否自动使用 SQL 初始化 Quartz 表结构。这里设置成 never ,我们手动创建表结构。
111 111
  112 +--- #################### 消息队列相关 ####################
  113 +
  114 +# rocketmq 配置项,对应 RocketMQProperties 配置类
  115 +rocketmq:
  116 + name-server: 127.0.0.1:9876 # RocketMQ Namesrv
  117 +
  118 +spring:
  119 + # RabbitMQ 配置项,对应 RabbitProperties 配置类
  120 + rabbitmq:
  121 + host: 127.0.0.1 # RabbitMQ 服务的地址
  122 + port: 5672 # RabbitMQ 服务的端口
  123 + username: guest # RabbitMQ 服务的账号
  124 + password: guest # RabbitMQ 服务的密码
  125 + # Kafka 配置项,对应 KafkaProperties 配置类
  126 + kafka:
  127 + bootstrap-servers: 127.0.0.1:9092 # 指定 Kafka Broker 地址,可以设置多个,以逗号分隔
  128 +
112 --- #################### 服务保障相关配置 #################### 129 --- #################### 服务保障相关配置 ####################
113 130
114 # Lock4j 配置项 131 # Lock4j 配置项
yudao-server/src/main/resources/application.yaml
@@ -106,6 +106,32 @@ aj: @@ -106,6 +106,32 @@ aj:
106 req-check-minute-limit: 60 # check 接口一分钟内请求数限制 106 req-check-minute-limit: 60 # check 接口一分钟内请求数限制
107 req-verify-minute-limit: 60 # verify 接口一分钟内请求数限制 107 req-verify-minute-limit: 60 # verify 接口一分钟内请求数限制
108 108
  109 +--- #################### 消息队列相关 ####################
  110 +
  111 +# rocketmq 配置项,对应 RocketMQProperties 配置类
  112 +rocketmq:
  113 + # Producer 配置项
  114 + producer:
  115 + group: ${spring.application.name}_PRODUCER # 生产者分组
  116 +
  117 +spring:
  118 + # Kafka 配置项,对应 KafkaProperties 配置类
  119 + kafka:
  120 + # Kafka Producer 配置项
  121 + producer:
  122 + acks: 1 # 0-不应答。1-leader 应答。all-所有 leader 和 follower 应答。
  123 + retries: 3 # 发送失败时,重试发送的次数
  124 + value-serializer: org.springframework.kafka.support.serializer.JsonSerializer # 消息的 value 的序列化
  125 + # Kafka Consumer 配置项
  126 + consumer:
  127 + auto-offset-reset: earliest # 设置消费者分组最初的消费进度为 earliest 。可参考博客 https://blog.csdn.net/lishuangzhe7047/article/details/74530417 理解
  128 + value-deserializer: org.springframework.kafka.support.serializer.JsonDeserializer
  129 + properties:
  130 + spring.json.trusted.packages: '*'
  131 + # Kafka Consumer Listener 监听器配置
  132 + listener:
  133 + missing-topics-fatal: false # 消费监听接口监听的主题不存在时,默认会报错。所以通过设置为 false ,解决报错
  134 +
109 --- #################### 芋道相关配置 #################### 135 --- #################### 芋道相关配置 ####################
110 136
111 yudao: 137 yudao:
@@ -145,12 +171,6 @@ yudao: @@ -145,12 +171,6 @@ yudao:
145 - cn.iocoder.yudao.module.pay.enums.ErrorCodeConstants 171 - cn.iocoder.yudao.module.pay.enums.ErrorCodeConstants
146 - cn.iocoder.yudao.module.system.enums.ErrorCodeConstants 172 - cn.iocoder.yudao.module.system.enums.ErrorCodeConstants
147 - cn.iocoder.yudao.module.mp.enums.ErrorCodeConstants 173 - cn.iocoder.yudao.module.mp.enums.ErrorCodeConstants
148 - mq:  
149 - redis:  
150 - pubsub:  
151 - enable: false # 是否开启 Redis pubsub 广播消费,默认为 true。这里设置成 false,可以按需开启  
152 - stream:  
153 - enable: false # 是否开启 Redis stream 集群消费,默认为 true。这里设置成 false,可以按需开启  
154 tenant: # 多租户相关配置项 174 tenant: # 多租户相关配置项
155 enable: true 175 enable: true
156 ignore-urls: 176 ignore-urls:
yudao-server/src/main/resources/static/MP_verify_DKOvVzFP7vPwwHx2.txt deleted
1 -DKOvVzFP7vPwwHx2  
2 \ No newline at end of file 0 \ No newline at end of file
yudao-server/src/main/resources/static/READMD.md deleted
1 -## 微信公众号  
2 -  
3 -参考文章:https://www.yuque.com/docs/share/0e2966dd-89f8-4b69-980d-b876168725df  
4 -  
5 -① 访问 social-login.html 选择【微信公众号】  
6 -  
7 -② 微信公众号授权完成后,跳转回 social-login2.html,输入手机号 + 密码,进行绑定  
8 -  
9 -## 微信小程序  
10 -  
11 -参考文章:https://www.yuque.com/docs/share/88e3d30a-6830-45fc-8c25-dae485aef3aa  
12 -  
13 -① 暂时使用 mini-program-test 项目  
yudao-server/src/main/resources/static/pay_wx_pub.html deleted
1 -<!DOCTYPE html>  
2 -<html>  
3 -<head>  
4 - <meta charset="UTF-8">  
5 - <meta name="viewport" content="width=device-width, initial-scale=1, user-scalable=no"/>  
6 - <title>支付测试页</title>  
7 - <script src="https://cdn.bootcdn.net/ajax/libs/jquery/3.6.0/jquery.js"></script>  
8 - <script src="http://res.wx.qq.com/open/js/jweixin-1.6.0.js"></script>  
9 -</head>  
10 -<body>  
11 -<div>点击如下按钮,发起支付的测试</div>  
12 -<div>  
13 - <button id="wx_pub">微信公众号</button>  
14 -</div>  
15 -</body>  
16 -<script>  
17 - let shopOrderId = undefined;  
18 - let payOrderId = undefined;  
19 - let server = 'http://127.0.0.1:48080';  
20 - // let server = 'http://niubi.natapp1.cc';  
21 - // TODO openid  
22 - let openid = "ockUAwIZ-0OeMZl9ogcZ4ILrGba0";  
23 - $(function() {  
24 - // 获得 JsapiTicket  
25 - // 参考 https://developers.weixin.qq.com/doc/offiaccount/OA_Web_Apps/JS-SDK.html 文档  
26 - $.ajax({  
27 - url: server + "/app-api/wx/mp/create-jsapi-signature?url=" + document.location.href,  
28 - method: 'POST',  
29 - headers: {  
30 - 'tenant-id': 1  
31 - },  
32 - success: function( result ) {  
33 - if (result.code !== 0) {  
34 - alert('获取 JsapiTicket 失败,原因:' + result.msg)  
35 - return;  
36 - }  
37 - var jsapiTicket = result.data;  
38 - jsapiTicket.jsApiList = ['chooseWXPay'];  
39 - jsapiTicket.debug = false;  
40 -  
41 - // 初始化 JS  
42 - wx.config(jsapiTicket);  
43 - }  
44 - });  
45 -  
46 - // 自动发起商城订单编号  
47 - $.ajax({  
48 - url: server + "/app-api/shop/order/create",  
49 - method: 'POST',  
50 - success: function( result ) {  
51 - if (result.code !== 0) {  
52 - alert('创建商城订单失败,原因:' + result.msg)  
53 - return;  
54 - }  
55 - shopOrderId = result.data.id;  
56 - payOrderId = result.data.payOrderId;  
57 - console.log("商城订单:" + shopOrderId)  
58 - console.log("支付订单:" + payOrderId)  
59 - }  
60 - })  
61 - })  
62 -  
63 - // 微信公众号  
64 - $( "#wx_pub").on( "click", function() {  
65 - if (typeof WeixinJSBridge == "undefined") {  
66 - // if (document.addEventListener) {  
67 - // document.addEventListener('WeixinJSBridgeReady', onBridgeReady, false);  
68 - // } else if (document.attachEvent) {  
69 - // document.attachEvent('WeixinJSBridgeReady', onBridgeReady);  
70 - // document.attachEvent('onWeixinJSBridgeReady', onBridgeReady);  
71 - // }  
72 - alert('微信支付,只支持在微信客户端中使用!');  
73 - return;  
74 - }  
75 - if (navigator.userAgent.indexOf('wechatdevtools') >= 0) {  
76 - alert('微信支付,无法在微信开发者工具中使用!请使用微信客户端!');  
77 - return;  
78 - }  
79 -  
80 - // 提交支付  
81 - // 参考 https://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=7_7&index=6 文档  
82 - // 参考 https://segmentfault.com/a/1190000020704650 文档  
83 - $.ajax({  
84 - url: server + "/app-api/pay/order/submit",  
85 - method: 'POST',  
86 - dataType: "json",  
87 - contentType: "application/json",  
88 - data: JSON.stringify({  
89 - "id": payOrderId,  
90 - "channelCode": 'wx_pub',  
91 - "channelExtras": {  
92 - "openid": openid  
93 - }  
94 - }),  
95 - success: function( result ) {  
96 - if (result.code !== 0) {  
97 - alert('提交支付订单失败,原因:' + result.msg)  
98 - return;  
99 - }  
100 - alert('点击确定,开始微信支付');  
101 - // 开始调用微信支付  
102 - let data = result.data.invokeResponse;  
103 - wx.chooseWXPay({  
104 - timestamp: data.timeStamp,  
105 - nonceStr: data.nonceStr,  
106 - package: data.packageValue,  
107 - signType: data.signType,  
108 - paySign: data.paySign,  
109 - success: function (res) {  
110 - alert(JSON.stringify(res));  
111 - },  
112 - error: function(e) {  
113 - alert(JSON.stringify(e));  
114 - }  
115 - });  
116 - }  
117 - })  
118 - });  
119 -</script>  
120 -</html>  
yudao-ui-admin/package.json
1 { 1 {
2 "name": "yudao-ui-admin", 2 "name": "yudao-ui-admin",
3 - "version": "1.8.0-snapshot", 3 + "version": "1.8.3-snapshot",
4 "description": "芋道管理系统", 4 "description": "芋道管理系统",
5 "author": "芋道", 5 "author": "芋道",
6 "license": "MIT", 6 "license": "MIT",