Commit f462ac7f9688b7f9195d552f16c2937a92ea9afe
Merge remote-tracking branch 'yudao/feature/mall_product' into feature/mall_product
Showing
96 changed files
with
1384 additions
and
359 deletions
sql/mysql/mall.sql
0 → 100644
sql/mysql/pay_wallet.sql
| ... | ... | @@ -77,7 +77,7 @@ ALTER TABLE `pay_channel` |
| 77 | 77 | MODIFY COLUMN `config` text CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '支付渠道配置' AFTER `app_id`; |
| 78 | 78 | |
| 79 | 79 | -- ---------------------------- |
| 80 | --- 套餐充值表 | |
| 80 | +-- 充值套餐表 | |
| 81 | 81 | -- ---------------------------- |
| 82 | 82 | DROP TABLE IF EXISTS `pay_wallet_recharge_package`; |
| 83 | 83 | CREATE TABLE `pay_wallet_recharge_package` |
| ... | ... | @@ -94,7 +94,7 @@ CREATE TABLE `pay_wallet_recharge_package` |
| 94 | 94 | `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除', |
| 95 | 95 | `tenant_id` bigint NOT NULL DEFAULT 0 COMMENT '租户编号', |
| 96 | 96 | PRIMARY KEY (`id`) USING BTREE |
| 97 | -) ENGINE=InnoDB COMMENT='套餐充值表'; | |
| 97 | +) ENGINE=InnoDB COMMENT='充值套餐表'; | |
| 98 | 98 | |
| 99 | 99 | -- ---------------------------- |
| 100 | 100 | -- Table structure for pay_wallet_recharge | ... | ... |
sql/mysql/ruoyi-vue-pro.sql
| ... | ... | @@ -11,7 +11,7 @@ |
| 11 | 11 | Target Server Version : 80034 |
| 12 | 12 | File Encoding : 65001 |
| 13 | 13 | |
| 14 | - Date: 17/10/2023 23:22:59 | |
| 14 | + Date: 18/10/2023 23:33:15 | |
| 15 | 15 | */ |
| 16 | 16 | |
| 17 | 17 | SET NAMES utf8mb4; |
| ... | ... | @@ -384,7 +384,7 @@ CREATE TABLE `infra_api_error_log` ( |
| 384 | 384 | `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除', |
| 385 | 385 | `tenant_id` bigint NOT NULL DEFAULT 0 COMMENT '租户编号', |
| 386 | 386 | PRIMARY KEY (`id`) USING BTREE |
| 387 | -) ENGINE = InnoDB AUTO_INCREMENT = 1735 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '系统异常日志'; | |
| 387 | +) ENGINE = InnoDB AUTO_INCREMENT = 1739 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '系统异常日志'; | |
| 388 | 388 | |
| 389 | 389 | -- ---------------------------- |
| 390 | 390 | -- Records of infra_api_error_log |
| ... | ... | @@ -422,7 +422,7 @@ CREATE TABLE `infra_codegen_column` ( |
| 422 | 422 | `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间', |
| 423 | 423 | `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除', |
| 424 | 424 | PRIMARY KEY (`id`) USING BTREE |
| 425 | -) ENGINE = InnoDB AUTO_INCREMENT = 1804 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '代码生成表字段定义'; | |
| 425 | +) ENGINE = InnoDB AUTO_INCREMENT = 1805 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '代码生成表字段定义'; | |
| 426 | 426 | |
| 427 | 427 | -- ---------------------------- |
| 428 | 428 | -- Records of infra_codegen_column |
| ... | ... | @@ -455,7 +455,7 @@ CREATE TABLE `infra_codegen_table` ( |
| 455 | 455 | `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间', |
| 456 | 456 | `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除', |
| 457 | 457 | PRIMARY KEY (`id`) USING BTREE |
| 458 | -) ENGINE = InnoDB AUTO_INCREMENT = 136 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '代码生成表定义'; | |
| 458 | +) ENGINE = InnoDB AUTO_INCREMENT = 137 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '代码生成表定义'; | |
| 459 | 459 | |
| 460 | 460 | -- ---------------------------- |
| 461 | 461 | -- Records of infra_codegen_table |
| ... | ... | @@ -615,7 +615,7 @@ CREATE TABLE `infra_job` ( |
| 615 | 615 | `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间', |
| 616 | 616 | `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除', |
| 617 | 617 | PRIMARY KEY (`id`) USING BTREE |
| 618 | -) ENGINE = InnoDB AUTO_INCREMENT = 27 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '定时任务表'; | |
| 618 | +) ENGINE = InnoDB AUTO_INCREMENT = 28 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '定时任务表'; | |
| 619 | 619 | |
| 620 | 620 | -- ---------------------------- |
| 621 | 621 | -- Records of infra_job |
| ... | ... | @@ -656,7 +656,7 @@ CREATE TABLE `infra_job_log` ( |
| 656 | 656 | `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间', |
| 657 | 657 | `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除', |
| 658 | 658 | PRIMARY KEY (`id`) USING BTREE |
| 659 | -) ENGINE = InnoDB AUTO_INCREMENT = 232 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '定时任务日志表'; | |
| 659 | +) ENGINE = InnoDB AUTO_INCREMENT = 233 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '定时任务日志表'; | |
| 660 | 660 | |
| 661 | 661 | -- ---------------------------- |
| 662 | 662 | -- Records of infra_job_log |
| ... | ... | @@ -709,7 +709,7 @@ CREATE TABLE `member_address` ( |
| 709 | 709 | `tenant_id` bigint NOT NULL DEFAULT 0 COMMENT '租户编号', |
| 710 | 710 | PRIMARY KEY (`id`) USING BTREE, |
| 711 | 711 | INDEX `idx_userId`(`user_id` ASC) USING BTREE |
| 712 | -) ENGINE = InnoDB AUTO_INCREMENT = 24 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_bin COMMENT = '用户收件地址'; | |
| 712 | +) ENGINE = InnoDB AUTO_INCREMENT = 25 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_bin COMMENT = '用户收件地址'; | |
| 713 | 713 | |
| 714 | 714 | -- ---------------------------- |
| 715 | 715 | -- Records of member_address |
| ... | ... | @@ -768,7 +768,7 @@ CREATE TABLE `member_experience_record` ( |
| 768 | 768 | PRIMARY KEY (`id`) USING BTREE, |
| 769 | 769 | INDEX `idx_user_id`(`user_id` ASC) USING BTREE COMMENT '会员经验记录-用户编号', |
| 770 | 770 | INDEX `idx_user_biz_type`(`user_id` ASC, `biz_type` ASC) USING BTREE COMMENT '会员经验记录-用户业务类型' |
| 771 | -) ENGINE = InnoDB AUTO_INCREMENT = 40 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '会员经验记录'; | |
| 771 | +) ENGINE = InnoDB AUTO_INCREMENT = 41 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '会员经验记录'; | |
| 772 | 772 | |
| 773 | 773 | -- ---------------------------- |
| 774 | 774 | -- Records of member_experience_record |
| ... | ... | @@ -883,7 +883,7 @@ CREATE TABLE `member_level_record` ( |
| 883 | 883 | `tenant_id` bigint NOT NULL DEFAULT 0 COMMENT '租户编号', |
| 884 | 884 | PRIMARY KEY (`id`) USING BTREE, |
| 885 | 885 | INDEX `idx_user_id`(`user_id` ASC) USING BTREE COMMENT '会员等级记录-用户编号' |
| 886 | -) ENGINE = InnoDB AUTO_INCREMENT = 19 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '会员等级记录'; | |
| 886 | +) ENGINE = InnoDB AUTO_INCREMENT = 20 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '会员等级记录'; | |
| 887 | 887 | |
| 888 | 888 | -- ---------------------------- |
| 889 | 889 | -- Records of member_level_record |
| ... | ... | @@ -913,7 +913,7 @@ CREATE TABLE `member_point_record` ( |
| 913 | 913 | PRIMARY KEY (`id`) USING BTREE, |
| 914 | 914 | INDEX `index_userId`(`user_id` ASC) USING BTREE, |
| 915 | 915 | INDEX `index_title`(`title` ASC) USING BTREE |
| 916 | -) ENGINE = InnoDB AUTO_INCREMENT = 59 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '用户积分记录'; | |
| 916 | +) ENGINE = InnoDB AUTO_INCREMENT = 60 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '用户积分记录'; | |
| 917 | 917 | |
| 918 | 918 | -- ---------------------------- |
| 919 | 919 | -- Records of member_point_record |
| ... | ... | @@ -1540,7 +1540,7 @@ CREATE TABLE `system_error_code` ( |
| 1540 | 1540 | `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间', |
| 1541 | 1541 | `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除', |
| 1542 | 1542 | PRIMARY KEY (`id`) USING BTREE |
| 1543 | -) ENGINE = InnoDB AUTO_INCREMENT = 5932 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '错误码表'; | |
| 1543 | +) ENGINE = InnoDB AUTO_INCREMENT = 5933 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '错误码表'; | |
| 1544 | 1544 | |
| 1545 | 1545 | -- ---------------------------- |
| 1546 | 1546 | -- Records of system_error_code |
| ... | ... | @@ -1569,7 +1569,7 @@ CREATE TABLE `system_login_log` ( |
| 1569 | 1569 | `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除', |
| 1570 | 1570 | `tenant_id` bigint NOT NULL DEFAULT 0 COMMENT '租户编号', |
| 1571 | 1571 | PRIMARY KEY (`id`) USING BTREE |
| 1572 | -) ENGINE = InnoDB AUTO_INCREMENT = 2582 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '系统访问记录'; | |
| 1572 | +) ENGINE = InnoDB AUTO_INCREMENT = 2599 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '系统访问记录'; | |
| 1573 | 1573 | |
| 1574 | 1574 | -- ---------------------------- |
| 1575 | 1575 | -- Records of system_login_log |
| ... | ... | @@ -1634,7 +1634,7 @@ CREATE TABLE `system_mail_log` ( |
| 1634 | 1634 | `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间', |
| 1635 | 1635 | `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除', |
| 1636 | 1636 | PRIMARY KEY (`id`) USING BTREE |
| 1637 | -) ENGINE = InnoDB AUTO_INCREMENT = 354 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '邮件日志表'; | |
| 1637 | +) ENGINE = InnoDB AUTO_INCREMENT = 355 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '邮件日志表'; | |
| 1638 | 1638 | |
| 1639 | 1639 | -- ---------------------------- |
| 1640 | 1640 | -- Records of system_mail_log |
| ... | ... | @@ -2283,7 +2283,7 @@ CREATE TABLE `system_notify_template` ( |
| 2283 | 2283 | `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间', |
| 2284 | 2284 | `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除', |
| 2285 | 2285 | PRIMARY KEY (`id`) USING BTREE |
| 2286 | -) ENGINE = InnoDB AUTO_INCREMENT = 5 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '站内信模板表'; | |
| 2286 | +) ENGINE = InnoDB AUTO_INCREMENT = 6 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '站内信模板表'; | |
| 2287 | 2287 | |
| 2288 | 2288 | -- ---------------------------- |
| 2289 | 2289 | -- Records of system_notify_template |
| ... | ... | @@ -2311,7 +2311,7 @@ CREATE TABLE `system_oauth2_access_token` ( |
| 2311 | 2311 | `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除', |
| 2312 | 2312 | `tenant_id` bigint NOT NULL DEFAULT 0 COMMENT '租户编号', |
| 2313 | 2313 | PRIMARY KEY (`id`) USING BTREE |
| 2314 | -) ENGINE = InnoDB AUTO_INCREMENT = 3056 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = 'OAuth2 访问令牌'; | |
| 2314 | +) ENGINE = InnoDB AUTO_INCREMENT = 3063 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = 'OAuth2 访问令牌'; | |
| 2315 | 2315 | |
| 2316 | 2316 | -- ---------------------------- |
| 2317 | 2317 | -- Records of system_oauth2_access_token |
| ... | ... | @@ -2433,7 +2433,7 @@ CREATE TABLE `system_oauth2_refresh_token` ( |
| 2433 | 2433 | `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除', |
| 2434 | 2434 | `tenant_id` bigint NOT NULL DEFAULT 0 COMMENT '租户编号', |
| 2435 | 2435 | PRIMARY KEY (`id`) USING BTREE |
| 2436 | -) ENGINE = InnoDB AUTO_INCREMENT = 1063 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = 'OAuth2 刷新令牌'; | |
| 2436 | +) ENGINE = InnoDB AUTO_INCREMENT = 1070 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = 'OAuth2 刷新令牌'; | |
| 2437 | 2437 | |
| 2438 | 2438 | -- ---------------------------- |
| 2439 | 2439 | -- Records of system_oauth2_refresh_token |
| ... | ... | @@ -3481,7 +3481,7 @@ CREATE TABLE `system_sms_code` ( |
| 3481 | 3481 | `tenant_id` bigint NOT NULL DEFAULT 0 COMMENT '租户编号', |
| 3482 | 3482 | PRIMARY KEY (`id`) USING BTREE, |
| 3483 | 3483 | INDEX `idx_mobile`(`mobile` ASC) USING BTREE COMMENT '手机号' |
| 3484 | -) ENGINE = InnoDB AUTO_INCREMENT = 530 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '手机验证码'; | |
| 3484 | +) ENGINE = InnoDB AUTO_INCREMENT = 531 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '手机验证码'; | |
| 3485 | 3485 | |
| 3486 | 3486 | -- ---------------------------- |
| 3487 | 3487 | -- Records of system_sms_code |
| ... | ... | @@ -3575,6 +3575,33 @@ INSERT INTO `system_sms_template` (`id`, `type`, `status`, `code`, `name`, `cont |
| 3575 | 3575 | COMMIT; |
| 3576 | 3576 | |
| 3577 | 3577 | -- ---------------------------- |
| 3578 | +-- Table structure for system_social_client | |
| 3579 | +-- ---------------------------- | |
| 3580 | +DROP TABLE IF EXISTS `system_social_client`; | |
| 3581 | +CREATE TABLE `system_social_client` ( | |
| 3582 | + `id` bigint NOT NULL AUTO_INCREMENT COMMENT '编号', | |
| 3583 | + `name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '应用名', | |
| 3584 | + `social_type` tinyint NOT NULL COMMENT '社交平台的类型', | |
| 3585 | + `user_type` tinyint NOT NULL COMMENT '用户类型', | |
| 3586 | + `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 '客户端密钥', | |
| 3588 | + `status` tinyint NOT NULL COMMENT '状态', | |
| 3589 | + `creator` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT '' COMMENT '创建者', | |
| 3590 | + `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', | |
| 3591 | + `updater` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT '' COMMENT '更新者', | |
| 3592 | + `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间', | |
| 3593 | + `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除', | |
| 3594 | + `tenant_id` bigint NOT NULL DEFAULT 0 COMMENT '租户编号', | |
| 3595 | + PRIMARY KEY (`id`) USING BTREE | |
| 3596 | +) ENGINE = InnoDB AUTO_INCREMENT = 43 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '社交客户端表'; | |
| 3597 | + | |
| 3598 | +-- ---------------------------- | |
| 3599 | +-- Records of system_social_client | |
| 3600 | +-- ---------------------------- | |
| 3601 | +BEGIN; | |
| 3602 | +COMMIT; | |
| 3603 | + | |
| 3604 | +-- ---------------------------- | |
| 3578 | 3605 | -- Table structure for system_social_user |
| 3579 | 3606 | -- ---------------------------- |
| 3580 | 3607 | DROP TABLE IF EXISTS `system_social_user`; |
| ... | ... | @@ -3596,7 +3623,7 @@ CREATE TABLE `system_social_user` ( |
| 3596 | 3623 | `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除', |
| 3597 | 3624 | `tenant_id` bigint NOT NULL DEFAULT 0 COMMENT '租户编号', |
| 3598 | 3625 | PRIMARY KEY (`id`) USING BTREE |
| 3599 | -) ENGINE = InnoDB AUTO_INCREMENT = 21 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '社交用户表'; | |
| 3626 | +) ENGINE = InnoDB AUTO_INCREMENT = 25 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '社交用户表'; | |
| 3600 | 3627 | |
| 3601 | 3628 | -- ---------------------------- |
| 3602 | 3629 | -- Records of system_social_user |
| ... | ... | @@ -3621,7 +3648,7 @@ CREATE TABLE `system_social_user_bind` ( |
| 3621 | 3648 | `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除', |
| 3622 | 3649 | `tenant_id` bigint NOT NULL DEFAULT 0 COMMENT '租户编号', |
| 3623 | 3650 | PRIMARY KEY (`id`) USING BTREE |
| 3624 | -) ENGINE = InnoDB AUTO_INCREMENT = 76 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '社交绑定表'; | |
| 3651 | +) ENGINE = InnoDB AUTO_INCREMENT = 79 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '社交绑定表'; | |
| 3625 | 3652 | |
| 3626 | 3653 | -- ---------------------------- |
| 3627 | 3654 | -- Records of system_social_user_bind |
| ... | ... | @@ -3797,7 +3824,7 @@ CREATE TABLE `system_users` ( |
| 3797 | 3824 | -- Records of system_users |
| 3798 | 3825 | -- ---------------------------- |
| 3799 | 3826 | BEGIN; |
| 3800 | -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-17 21:03:03', 'admin', '2021-01-05 17:03:47', NULL, '2023-10-17 21:03:03', b'0', 1); | |
| 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); | |
| 3801 | 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); |
| 3802 | 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); |
| 3803 | 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); |
| ... | ... | @@ -3805,7 +3832,7 @@ INSERT INTO `system_users` (`id`, `username`, `password`, `nickname`, `remark`, |
| 3805 | 3832 | 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 (108, 'admin108', '$2a$10$y6mfvKoNYL1GXWak8nYwVOH.kCWqjactkzdoIDgiKl93WN3Ejg.Lu', '芋艿', NULL, NULL, NULL, '', '15601691300', 0, '', 0, '', NULL, '1', '2022-02-20 23:00:50', '1', '2022-02-27 08:26:53', b'0', 119); |
| 3806 | 3833 | 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 (109, 'admin109', '$2a$10$JAqvH0tEc0I7dfDVBI7zyuB4E3j.uH6daIjV53.vUS6PknFkDJkuK', '芋艿', NULL, NULL, NULL, '', '15601691300', 0, '', 0, '', NULL, '1', '2022-02-20 23:11:50', '1', '2022-02-27 08:26:56', b'0', 120); |
| 3807 | 3834 | 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 (110, 'admin110', '$2a$10$mRMIYLDtRHlf6.9ipiqH1.Z.bh/R9dO9d5iHiGYPigi6r5KOoR2Wm', '小王', NULL, NULL, NULL, '', '15601691300', 0, '', 0, '127.0.0.1', '2022-09-25 22:47:33', '1', '2022-02-22 00:56:14', NULL, '2022-09-25 22:47:33', b'0', 121); |
| 3808 | -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 (111, 'test', '$2a$10$mExveopHUx9Q4QiLtAzhDeH3n4/QlNLzEsM4AqgxKrU.ciUZDXZCy', '测试用户', NULL, NULL, '[]', '', '', 0, '', 0, '', NULL, '110', '2022-02-23 13:14:33', '110', '2022-02-23 13:14:33', b'0', 121); | |
| 3835 | +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 (111, 'test', '$2a$10$mRMIYLDtRHlf6.9ipiqH1.Z.bh/R9dO9d5iHiGYPigi6r5KOoR2Wm', '测试用户', NULL, NULL, '[]', '', '', 0, '', 0, '0:0:0:0:0:0:0:1', '2023-10-18 23:31:51', '110', '2022-02-23 13:14:33', NULL, '2023-10-18 23:31:51', b'0', 121); | |
| 3809 | 3836 | 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 (112, 'newobject', '$2a$10$3alwklxqfq8/hKoW6oUV0OJp0IdQpBDauLy4633SpUjrRsStl6kMa', '新对象', NULL, 100, '[]', '', '', 1, '', 0, '0:0:0:0:0:0:0:1', '2023-02-10 13:48:13', '1', '2022-02-23 19:08:03', NULL, '2023-02-10 13:48:13', b'0', 1); |
| 3810 | 3837 | 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 (113, 'aoteman', '$2a$10$0acJOIk2D25/oC87nyclE..0lzeu9DtQ/n3geP4fkun/zIVRhHJIO', '芋道', NULL, NULL, NULL, '', '15601691300', 0, '', 0, '127.0.0.1', '2022-03-19 18:38:51', '1', '2022-03-07 21:37:58', NULL, '2022-03-19 18:38:51', b'0', 122); |
| 3811 | 3838 | 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 (114, 'hrmgr', '$2a$10$TR4eybBioGRhBmDBWkqWLO6NIh3mzYa8KBKDDB5woiGYFVlRAi.fu', 'hr 小姐姐', NULL, NULL, '[3]', '', '', 0, '', 0, '127.0.0.1', '2022-03-19 22:15:43', '1', '2022-03-19 21:50:58', NULL, '2022-03-19 22:15:43', b'0', 1); | ... | ... |
yudao-framework/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/dto/transfer/PayTransferUnifiedReqDTO.java
yudao-framework/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/impl/alipay/AlipayTransferClient.java
| ... | ... | @@ -22,6 +22,7 @@ import lombok.extern.slf4j.Slf4j; |
| 22 | 22 | import static cn.iocoder.yudao.framework.common.exception.enums.GlobalErrorCodeConstants.BAD_REQUEST; |
| 23 | 23 | import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception0; |
| 24 | 24 | |
| 25 | +// TODO @jason:看看能不能融合到 AbstractAlipayPayClient 中。 | |
| 25 | 26 | /** |
| 26 | 27 | * 支付宝转账的 PayClient 实现类 |
| 27 | 28 | * |
| ... | ... | @@ -29,6 +30,7 @@ import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionU |
| 29 | 30 | */ |
| 30 | 31 | @Slf4j |
| 31 | 32 | public class AlipayTransferClient extends AbstractAlipayPayClient { |
| 33 | + // TODO @jason:方法之间,要有空格噢 | |
| 32 | 34 | public AlipayTransferClient(Long channelId, AlipayPayClientConfig config) { |
| 33 | 35 | super(channelId, PayChannelEnum.ALIPAY_TRANSFER.getCode(), config); |
| 34 | 36 | } |
| ... | ... | @@ -49,16 +51,17 @@ public class AlipayTransferClient extends AbstractAlipayPayClient { |
| 49 | 51 | model.setOrderTitle(reqDTO.getTitle()); // 转账业务的标题,用于在支付宝用户的账单里显示。 |
| 50 | 52 | model.setOutBizNo(reqDTO.getOutTransferNo()); |
| 51 | 53 | model.setProductCode("TRANS_ACCOUNT_NO_PWD"); // 销售产品码。单笔无密转账固定为 TRANS_ACCOUNT_NO_PWD |
| 52 | - model.setBizScene("DIRECT_TRANSFER"); // 业务场景 单笔无密转账固定为 DIRECT_TRANSFER。 | |
| 54 | + model.setBizScene("DIRECT_TRANSFER"); // 业务场景 单笔无密转账固定为 DIRECT_TRANSFER | |
| 53 | 55 | model.setBusinessParams(JsonUtils.toJsonString(reqDTO.getChannelExtras())); |
| 54 | 56 | PayTransferTypeEnum transferType = PayTransferTypeEnum.ofType(reqDTO.getType()); |
| 55 | - switch(transferType){ | |
| 56 | - case WX_BALANCE : | |
| 57 | - case WALLET_BALANCE : { | |
| 57 | + switch(transferType) { | |
| 58 | + case WX_BALANCE: | |
| 59 | + case WALLET_BALANCE: { | |
| 58 | 60 | log.error("[doUnifiedTransfer],支付宝转账不支持的转账类型{}", transferType); |
| 59 | 61 | throw new UnsupportedOperationException(String.format("支付宝转账不支持转账类型: %s",transferType.getName())); |
| 60 | 62 | } |
| 61 | - case ALIPAY_BALANCE : { | |
| 63 | + // TODO @jason:是不是不用传递 transferType 参数哈?因为应该已经明确是支付宝啦? | |
| 64 | + case ALIPAY_BALANCE: { | |
| 62 | 65 | // ② 个性化的参数 |
| 63 | 66 | Participant payeeInfo = new Participant(); |
| 64 | 67 | payeeInfo.setIdentityType("ALIPAY_LOGON_ID"); |
| ... | ... | @@ -90,7 +93,7 @@ public class AlipayTransferClient extends AbstractAlipayPayClient { |
| 90 | 93 | return PayTransferRespDTO.successOf(response.getOrderId(), parseTime(response.getTransDate()), |
| 91 | 94 | response.getOutBizNo(), response); |
| 92 | 95 | } |
| 93 | - case BANK_CARD : { | |
| 96 | + case BANK_CARD: { | |
| 94 | 97 | Participant payeeInfo = new Participant(); |
| 95 | 98 | payeeInfo.setIdentityType("BANKCARD_ACCOUNT"); |
| 96 | 99 | throw new UnsupportedOperationException("待实现"); |
| ... | ... | @@ -100,4 +103,5 @@ public class AlipayTransferClient extends AbstractAlipayPayClient { |
| 100 | 103 | } |
| 101 | 104 | } |
| 102 | 105 | } |
| 106 | + | |
| 103 | 107 | } | ... | ... |
yudao-framework/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/impl/mock/MockPayClient.java
yudao-framework/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/enums/channel/PayChannelEnum.java
| ... | ... | @@ -28,6 +28,7 @@ public enum PayChannelEnum { |
| 28 | 28 | ALIPAY_APP("alipay_app", "支付宝App 支付", AlipayPayClientConfig.class), |
| 29 | 29 | ALIPAY_QR("alipay_qr", "支付宝扫码支付", AlipayPayClientConfig.class), |
| 30 | 30 | ALIPAY_BAR("alipay_bar", "支付宝条码支付", AlipayPayClientConfig.class), |
| 31 | + // TODO @jason:是不是按照微信聊的,合并回 ALIPAY_PC;因为支付宝、微信都是多种支付方式,选择其中的一种即可; | |
| 31 | 32 | ALIPAY_TRANSFER("alipay_transfer", "支付宝转账", AlipayPayClientConfig.class), |
| 32 | 33 | |
| 33 | 34 | MOCK("mock", "模拟支付", NonePayClientConfig.class), | ... | ... |
yudao-framework/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/enums/transfer/PayTransferStatusRespEnum.java
| ... | ... | @@ -18,10 +18,10 @@ public enum PayTransferStatusRespEnum { |
| 18 | 18 | |
| 19 | 19 | /** |
| 20 | 20 | * TODO 转账到银行卡. 会有T+0 T+1 到账的请情况。 还未实现 |
| 21 | + * TODO @jason:可以看看其它开源项目,针对这个场景,处理策略是怎么样的?例如说,每天主动轮询?这个状态的单子? | |
| 21 | 22 | */ |
| 22 | 23 | IN_PROGRESS(10, "转账进行中"), |
| 23 | 24 | |
| 24 | - | |
| 25 | 25 | SUCCESS(20, "转账成功"), |
| 26 | 26 | /** |
| 27 | 27 | * 转账关闭 (失败,或者其它情况) | ... | ... |
yudao-framework/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/enums/transfer/PayTransferTypeEnum.java
| ... | ... | @@ -15,6 +15,7 @@ import java.util.Arrays; |
| 15 | 15 | @AllArgsConstructor |
| 16 | 16 | @Getter |
| 17 | 17 | public enum PayTransferTypeEnum implements IntArrayValuable { |
| 18 | + | |
| 18 | 19 | ALIPAY_BALANCE(1, "支付宝余额"), |
| 19 | 20 | WX_BALANCE(2, "微信余额"), |
| 20 | 21 | BANK_CARD(3, "银行卡"), |
| ... | ... | @@ -33,7 +34,9 @@ public enum PayTransferTypeEnum implements IntArrayValuable { |
| 33 | 34 | return ARRAYS; |
| 34 | 35 | } |
| 35 | 36 | |
| 37 | + // TODO @jason:是不是 typeOf 更符合预期哈? | |
| 36 | 38 | public static PayTransferTypeEnum ofType(Integer type) { |
| 37 | 39 | return ArrayUtil.firstMatch(item -> item.getType().equals(type), values()); |
| 38 | 40 | } |
| 41 | + | |
| 39 | 42 | } | ... | ... |
yudao-framework/yudao-spring-boot-starter-mybatis/src/main/java/cn/iocoder/yudao/framework/mybatis/core/query/MPJLambdaWrapperX.java
0 → 100644
| 1 | +package cn.iocoder.yudao.framework.mybatis.core.query; | |
| 2 | + | |
| 3 | +import cn.hutool.core.util.ArrayUtil; | |
| 4 | +import cn.hutool.core.util.ObjectUtil; | |
| 5 | +import cn.iocoder.yudao.framework.common.util.collection.ArrayUtils; | |
| 6 | +import com.baomidou.mybatisplus.core.toolkit.support.SFunction; | |
| 7 | +import com.github.yulichang.toolkit.MPJWrappers; | |
| 8 | +import com.github.yulichang.wrapper.MPJLambdaWrapper; | |
| 9 | +import org.springframework.util.StringUtils; | |
| 10 | + | |
| 11 | +import java.util.Collection; | |
| 12 | +import java.util.function.Consumer; | |
| 13 | + | |
| 14 | +/** | |
| 15 | + * 拓展 MyBatis Plus Join QueryWrapper 类,主要增加如下功能: | |
| 16 | + * <p> | |
| 17 | + * 1. 拼接条件的方法,增加 xxxIfPresent 方法,用于判断值不存在的时候,不要拼接到条件中。 | |
| 18 | + * | |
| 19 | + * @param <T> 数据类型 | |
| 20 | + */ | |
| 21 | +public class MPJLambdaWrapperX<T> extends MPJLambdaWrapper<T> { | |
| 22 | + | |
| 23 | + public MPJLambdaWrapperX<T> likeIfPresent(SFunction<T, ?> column, String val) { | |
| 24 | + MPJWrappers.lambdaJoin().like(column, val); | |
| 25 | + if (StringUtils.hasText(val)) { | |
| 26 | + return (MPJLambdaWrapperX<T>) super.like(column, val); | |
| 27 | + } | |
| 28 | + return this; | |
| 29 | + } | |
| 30 | + | |
| 31 | + public MPJLambdaWrapperX<T> inIfPresent(SFunction<T, ?> column, Collection<?> values) { | |
| 32 | + if (ObjectUtil.isAllNotEmpty(values) && !ArrayUtil.isEmpty(values)) { | |
| 33 | + return (MPJLambdaWrapperX<T>) super.in(column, values); | |
| 34 | + } | |
| 35 | + return this; | |
| 36 | + } | |
| 37 | + | |
| 38 | + public MPJLambdaWrapperX<T> inIfPresent(SFunction<T, ?> column, Object... values) { | |
| 39 | + if (ObjectUtil.isAllNotEmpty(values) && !ArrayUtil.isEmpty(values)) { | |
| 40 | + return (MPJLambdaWrapperX<T>) super.in(column, values); | |
| 41 | + } | |
| 42 | + return this; | |
| 43 | + } | |
| 44 | + | |
| 45 | + public MPJLambdaWrapperX<T> eqIfPresent(SFunction<T, ?> column, Object val) { | |
| 46 | + if (ObjectUtil.isNotEmpty(val)) { | |
| 47 | + return (MPJLambdaWrapperX<T>) super.eq(column, val); | |
| 48 | + } | |
| 49 | + return this; | |
| 50 | + } | |
| 51 | + | |
| 52 | + public MPJLambdaWrapperX<T> neIfPresent(SFunction<T, ?> column, Object val) { | |
| 53 | + if (ObjectUtil.isNotEmpty(val)) { | |
| 54 | + return (MPJLambdaWrapperX<T>) super.ne(column, val); | |
| 55 | + } | |
| 56 | + return this; | |
| 57 | + } | |
| 58 | + | |
| 59 | + public MPJLambdaWrapperX<T> gtIfPresent(SFunction<T, ?> column, Object val) { | |
| 60 | + if (val != null) { | |
| 61 | + return (MPJLambdaWrapperX<T>) super.gt(column, val); | |
| 62 | + } | |
| 63 | + return this; | |
| 64 | + } | |
| 65 | + | |
| 66 | + public MPJLambdaWrapperX<T> geIfPresent(SFunction<T, ?> column, Object val) { | |
| 67 | + if (val != null) { | |
| 68 | + return (MPJLambdaWrapperX<T>) super.ge(column, val); | |
| 69 | + } | |
| 70 | + return this; | |
| 71 | + } | |
| 72 | + | |
| 73 | + public MPJLambdaWrapperX<T> ltIfPresent(SFunction<T, ?> column, Object val) { | |
| 74 | + if (val != null) { | |
| 75 | + return (MPJLambdaWrapperX<T>) super.lt(column, val); | |
| 76 | + } | |
| 77 | + return this; | |
| 78 | + } | |
| 79 | + | |
| 80 | + public MPJLambdaWrapperX<T> leIfPresent(SFunction<T, ?> column, Object val) { | |
| 81 | + if (val != null) { | |
| 82 | + return (MPJLambdaWrapperX<T>) super.le(column, val); | |
| 83 | + } | |
| 84 | + return this; | |
| 85 | + } | |
| 86 | + | |
| 87 | + public MPJLambdaWrapperX<T> betweenIfPresent(SFunction<T, ?> column, Object val1, Object val2) { | |
| 88 | + if (val1 != null && val2 != null) { | |
| 89 | + return (MPJLambdaWrapperX<T>) super.between(column, val1, val2); | |
| 90 | + } | |
| 91 | + if (val1 != null) { | |
| 92 | + return (MPJLambdaWrapperX<T>) ge(column, val1); | |
| 93 | + } | |
| 94 | + if (val2 != null) { | |
| 95 | + return (MPJLambdaWrapperX<T>) le(column, val2); | |
| 96 | + } | |
| 97 | + return this; | |
| 98 | + } | |
| 99 | + | |
| 100 | + public MPJLambdaWrapperX<T> betweenIfPresent(SFunction<T, ?> column, Object[] values) { | |
| 101 | + Object val1 = ArrayUtils.get(values, 0); | |
| 102 | + Object val2 = ArrayUtils.get(values, 1); | |
| 103 | + return betweenIfPresent(column, val1, val2); | |
| 104 | + } | |
| 105 | + | |
| 106 | + // ========== 重写父类方法,方便链式调用 ========== | |
| 107 | + | |
| 108 | + @Override | |
| 109 | + public <X> MPJLambdaWrapperX<T> eq(boolean condition, SFunction<X, ?> column, Object val) { | |
| 110 | + super.eq(condition, column, val); | |
| 111 | + return this; | |
| 112 | + } | |
| 113 | + | |
| 114 | + @Override | |
| 115 | + public <X> MPJLambdaWrapperX<T> eq(SFunction<X, ?> column, Object val) { | |
| 116 | + super.eq(column, val); | |
| 117 | + return this; | |
| 118 | + } | |
| 119 | + | |
| 120 | + @Override | |
| 121 | + public <X> MPJLambdaWrapperX<T> orderByDesc(SFunction<X, ?> column) { | |
| 122 | + //noinspection unchecked | |
| 123 | + super.orderByDesc(true, column); | |
| 124 | + return this; | |
| 125 | + } | |
| 126 | + | |
| 127 | + @Override | |
| 128 | + public MPJLambdaWrapperX<T> last(String lastSql) { | |
| 129 | + super.last(lastSql); | |
| 130 | + return this; | |
| 131 | + } | |
| 132 | + | |
| 133 | + @Override | |
| 134 | + public <X> MPJLambdaWrapperX<T> in(SFunction<X, ?> column, Collection<?> coll) { | |
| 135 | + super.in(column, coll); | |
| 136 | + return this; | |
| 137 | + } | |
| 138 | + | |
| 139 | + @Override | |
| 140 | + public MPJLambdaWrapperX<T> selectAll(Class<?> clazz) { | |
| 141 | + super.selectAll(clazz); | |
| 142 | + return this; | |
| 143 | + } | |
| 144 | + | |
| 145 | + @Override | |
| 146 | + public MPJLambdaWrapperX<T> selectAll(Class<?> clazz, String prefix) { | |
| 147 | + super.selectAll(clazz, prefix); | |
| 148 | + return this; | |
| 149 | + } | |
| 150 | + | |
| 151 | + @Override | |
| 152 | + public <S> MPJLambdaWrapperX<T> selectAs(SFunction<S, ?> column, String alias) { | |
| 153 | + super.selectAs(column, alias); | |
| 154 | + return this; | |
| 155 | + } | |
| 156 | + | |
| 157 | + @Override | |
| 158 | + public <E> MPJLambdaWrapperX<T> selectAs(String column, SFunction<E, ?> alias) { | |
| 159 | + super.selectAs(column, alias); | |
| 160 | + return this; | |
| 161 | + } | |
| 162 | + | |
| 163 | + @Override | |
| 164 | + public <S, X> MPJLambdaWrapperX<T> selectAs(SFunction<S, ?> column, SFunction<X, ?> alias) { | |
| 165 | + super.selectAs(column, alias); | |
| 166 | + return this; | |
| 167 | + } | |
| 168 | + | |
| 169 | + @Override | |
| 170 | + public <E, X> MPJLambdaWrapperX<T> selectAs(String index, SFunction<E, ?> column, SFunction<X, ?> alias) { | |
| 171 | + super.selectAs(index, column, alias); | |
| 172 | + return this; | |
| 173 | + } | |
| 174 | + | |
| 175 | + @Override | |
| 176 | + public <E> MPJLambdaWrapperX<T> selectAsClass(Class<E> source, Class<?> tag) { | |
| 177 | + super.selectAsClass(source, tag); | |
| 178 | + return this; | |
| 179 | + } | |
| 180 | + | |
| 181 | + @Override | |
| 182 | + public <E, F> MPJLambdaWrapperX<T> selectSub(Class<E> clazz, Consumer<MPJLambdaWrapper<E>> consumer, SFunction<F, ?> alias) { | |
| 183 | + super.selectSub(clazz, consumer, alias); | |
| 184 | + return this; | |
| 185 | + } | |
| 186 | + | |
| 187 | + @Override | |
| 188 | + public <E, F> MPJLambdaWrapperX<T> selectSub(Class<E> clazz, String st, Consumer<MPJLambdaWrapper<E>> consumer, SFunction<F, ?> alias) { | |
| 189 | + super.selectSub(clazz, st, consumer, alias); | |
| 190 | + return this; | |
| 191 | + } | |
| 192 | + | |
| 193 | + @Override | |
| 194 | + public <S> MPJLambdaWrapperX<T> selectCount(SFunction<S, ?> column) { | |
| 195 | + super.selectCount(column); | |
| 196 | + return this; | |
| 197 | + } | |
| 198 | + | |
| 199 | + @Override | |
| 200 | + public MPJLambdaWrapperX<T> selectCount(Object column, String alias) { | |
| 201 | + super.selectCount(column, alias); | |
| 202 | + return this; | |
| 203 | + } | |
| 204 | + | |
| 205 | + @Override | |
| 206 | + public <X> MPJLambdaWrapperX<T> selectCount(Object column, SFunction<X, ?> alias) { | |
| 207 | + super.selectCount(column, alias); | |
| 208 | + return this; | |
| 209 | + } | |
| 210 | + | |
| 211 | + @Override | |
| 212 | + public <S, X> MPJLambdaWrapperX<T> selectCount(SFunction<S, ?> column, String alias) { | |
| 213 | + super.selectCount(column, alias); | |
| 214 | + return this; | |
| 215 | + } | |
| 216 | + | |
| 217 | + @Override | |
| 218 | + public <S, X> MPJLambdaWrapperX<T> selectCount(SFunction<S, ?> column, SFunction<X, ?> alias) { | |
| 219 | + super.selectCount(column, alias); | |
| 220 | + return this; | |
| 221 | + } | |
| 222 | + | |
| 223 | + @Override | |
| 224 | + public <S> MPJLambdaWrapperX<T> selectSum(SFunction<S, ?> column) { | |
| 225 | + super.selectSum(column); | |
| 226 | + return this; | |
| 227 | + } | |
| 228 | + | |
| 229 | + @Override | |
| 230 | + public <S, X> MPJLambdaWrapperX<T> selectSum(SFunction<S, ?> column, String alias) { | |
| 231 | + super.selectSum(column, alias); | |
| 232 | + return this; | |
| 233 | + } | |
| 234 | + | |
| 235 | + @Override | |
| 236 | + public <S, X> MPJLambdaWrapperX<T> selectSum(SFunction<S, ?> column, SFunction<X, ?> alias) { | |
| 237 | + super.selectSum(column, alias); | |
| 238 | + return this; | |
| 239 | + } | |
| 240 | + | |
| 241 | + @Override | |
| 242 | + public <S> MPJLambdaWrapperX<T> selectMax(SFunction<S, ?> column) { | |
| 243 | + super.selectMax(column); | |
| 244 | + return this; | |
| 245 | + } | |
| 246 | + | |
| 247 | + @Override | |
| 248 | + public <S, X> MPJLambdaWrapperX<T> selectMax(SFunction<S, ?> column, String alias) { | |
| 249 | + super.selectMax(column, alias); | |
| 250 | + return this; | |
| 251 | + } | |
| 252 | + | |
| 253 | + @Override | |
| 254 | + public <S, X> MPJLambdaWrapperX<T> selectMax(SFunction<S, ?> column, SFunction<X, ?> alias) { | |
| 255 | + super.selectMax(column, alias); | |
| 256 | + return this; | |
| 257 | + } | |
| 258 | + | |
| 259 | + @Override | |
| 260 | + public <S> MPJLambdaWrapperX<T> selectMin(SFunction<S, ?> column) { | |
| 261 | + super.selectMin(column); | |
| 262 | + return this; | |
| 263 | + } | |
| 264 | + | |
| 265 | + @Override | |
| 266 | + public <S, X> MPJLambdaWrapperX<T> selectMin(SFunction<S, ?> column, String alias) { | |
| 267 | + super.selectMin(column, alias); | |
| 268 | + return this; | |
| 269 | + } | |
| 270 | + | |
| 271 | + @Override | |
| 272 | + public <S, X> MPJLambdaWrapperX<T> selectMin(SFunction<S, ?> column, SFunction<X, ?> alias) { | |
| 273 | + super.selectMin(column, alias); | |
| 274 | + return this; | |
| 275 | + } | |
| 276 | + | |
| 277 | + @Override | |
| 278 | + public <S> MPJLambdaWrapperX<T> selectAvg(SFunction<S, ?> column) { | |
| 279 | + super.selectAvg(column); | |
| 280 | + return this; | |
| 281 | + } | |
| 282 | + | |
| 283 | + @Override | |
| 284 | + public <S, X> MPJLambdaWrapperX<T> selectAvg(SFunction<S, ?> column, String alias) { | |
| 285 | + super.selectAvg(column, alias); | |
| 286 | + return this; | |
| 287 | + } | |
| 288 | + | |
| 289 | + @Override | |
| 290 | + public <S, X> MPJLambdaWrapperX<T> selectAvg(SFunction<S, ?> column, SFunction<X, ?> alias) { | |
| 291 | + super.selectAvg(column, alias); | |
| 292 | + return this; | |
| 293 | + } | |
| 294 | + | |
| 295 | + @Override | |
| 296 | + public <S> MPJLambdaWrapperX<T> selectLen(SFunction<S, ?> column) { | |
| 297 | + super.selectLen(column); | |
| 298 | + return this; | |
| 299 | + } | |
| 300 | + | |
| 301 | + @Override | |
| 302 | + public <S, X> MPJLambdaWrapperX<T> selectLen(SFunction<S, ?> column, String alias) { | |
| 303 | + super.selectLen(column, alias); | |
| 304 | + return this; | |
| 305 | + } | |
| 306 | + | |
| 307 | + @Override | |
| 308 | + public <S, X> MPJLambdaWrapperX<T> selectLen(SFunction<S, ?> column, SFunction<X, ?> alias) { | |
| 309 | + super.selectLen(column, alias); | |
| 310 | + return this; | |
| 311 | + } | |
| 312 | + | |
| 313 | +} | ... | ... |
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/app/activity/AppActivityController.java
| ... | ... | @@ -46,7 +46,7 @@ public class AppActivityController { |
| 46 | 46 | @Parameter(name = "spuId", description = "商品编号", required = true) |
| 47 | 47 | public CommonResult<List<AppActivityRespVO>> getActivityListBySpuId(@RequestParam("spuId") Long spuId) { |
| 48 | 48 | // 每种活动,只返回一个 |
| 49 | - return success(getAppActivityRespVOList(Collections.singletonList(spuId))); | |
| 49 | + return success(getAppActivityList(Collections.singletonList(spuId))); | |
| 50 | 50 | } |
| 51 | 51 | |
| 52 | 52 | @GetMapping("/list-by-spu-ids") |
| ... | ... | @@ -57,16 +57,17 @@ public class AppActivityController { |
| 57 | 57 | return success(MapUtil.empty()); |
| 58 | 58 | } |
| 59 | 59 | // 每种活动,只返回一个;key 为 SPU 编号 |
| 60 | - return success(convertMultiMap(getAppActivityRespVOList(spuIds), AppActivityRespVO::getSpuId)); | |
| 60 | + return success(convertMultiMap(getAppActivityList(spuIds), AppActivityRespVO::getSpuId)); | |
| 61 | 61 | } |
| 62 | 62 | |
| 63 | - private List<AppActivityRespVO> getAppActivityRespVOList(Collection<Long> spuIds) { | |
| 63 | + private List<AppActivityRespVO> getAppActivityList(Collection<Long> spuIds) { | |
| 64 | 64 | if (CollUtil.isEmpty(spuIds)) { |
| 65 | 65 | return new ArrayList<>(); |
| 66 | 66 | } |
| 67 | 67 | LocalDateTime now = LocalDateTime.now(); |
| 68 | 68 | List<AppActivityRespVO> activityList = new ArrayList<>(); |
| 69 | - // 拼团活动-获取开启的且开始的且没有结束的活动 | |
| 69 | + | |
| 70 | + // 1. 拼团活动 - 获取开启的且开始的且没有结束的活动 | |
| 70 | 71 | List<CombinationActivityDO> combinationActivities = combinationActivityService.getCombinationActivityBySpuIdsAndStatusAndDateTimeLt( |
| 71 | 72 | spuIds, CommonStatusEnum.ENABLE.getStatus(), now); |
| 72 | 73 | if (CollUtil.isNotEmpty(combinationActivities)) { |
| ... | ... | @@ -76,7 +77,8 @@ public class AppActivityController { |
| 76 | 77 | .setSpuId(item.getSpuId()).setStartTime(item.getStartTime()).setEndTime(item.getEndTime())); |
| 77 | 78 | }); |
| 78 | 79 | } |
| 79 | - // 秒杀活动-获取开启的且开始的且没有结束的活动 | |
| 80 | + | |
| 81 | + // 2. 秒杀活动 - 获取开启的且开始的且没有结束的活动 | |
| 80 | 82 | List<SeckillActivityDO> seckillActivities = seckillActivityService.getSeckillActivityBySpuIdsAndStatusAndDateTimeLt( |
| 81 | 83 | spuIds, CommonStatusEnum.ENABLE.getStatus(), now); |
| 82 | 84 | if (CollUtil.isNotEmpty(seckillActivities)) { |
| ... | ... | @@ -86,7 +88,8 @@ public class AppActivityController { |
| 86 | 88 | .setSpuId(item.getSpuId()).setStartTime(item.getStartTime()).setEndTime(item.getEndTime())); |
| 87 | 89 | }); |
| 88 | 90 | } |
| 89 | - // 砍价活动-获取开启的且开始的且没有结束的活动 | |
| 91 | + | |
| 92 | + // 3. 砍价活动 - 获取开启的且开始的且没有结束的活动 | |
| 90 | 93 | List<BargainActivityDO> bargainActivities = bargainActivityService.getBargainActivityBySpuIdsAndStatusAndDateTimeLt( |
| 91 | 94 | spuIds, CommonStatusEnum.ENABLE.getStatus(), now); |
| 92 | 95 | if (CollUtil.isNotEmpty(bargainActivities)) { | ... | ... |
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/app/article/AppArticleCategoryController.java
| ... | ... | @@ -32,7 +32,7 @@ public class AppArticleCategoryController { |
| 32 | 32 | public CommonResult<List<AppArticleCategoryRespVO>> getArticleCategoryList() { |
| 33 | 33 | List<ArticleCategoryDO> categoryList = articleCategoryService.getArticleCategoryListByStatus( |
| 34 | 34 | CommonStatusEnum.ENABLE.getStatus()); |
| 35 | - categoryList.sort(Comparator.comparing(ArticleCategoryDO::getSort).reversed()); // 按 sort 降序排列 | |
| 35 | + categoryList.sort(Comparator.comparing(ArticleCategoryDO::getSort)); // 按 sort 降序排列 | |
| 36 | 36 | return success(ArticleCategoryConvert.INSTANCE.convertList04(categoryList)); |
| 37 | 37 | } |
| 38 | 38 | ... | ... |
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/app/article/AppArticleController.java
| ... | ... | @@ -56,10 +56,12 @@ public class AppArticleController { |
| 56 | 56 | return success(ArticleConvert.INSTANCE.convert01(articleService.getArticle(id))); |
| 57 | 57 | } |
| 58 | 58 | |
| 59 | + // TODO @puhui999:add-browse-count 噢;前端 uniapp 也要接下;就是打开文章的时候,调用下这个接口; | |
| 59 | 60 | @PutMapping("/add-browseCount") |
| 60 | 61 | @Operation(summary = "增加文章浏览量") |
| 61 | 62 | @Parameter(name = "id", description = "文章编号", example = "1024") |
| 62 | 63 | public CommonResult<Boolean> addBrowseCount(@RequestParam("id") Long id) { |
| 64 | + // TODO @puhui999:addArticleBrowseCount | |
| 63 | 65 | articleService.addBrowseCount(id); |
| 64 | 66 | return success(true); |
| 65 | 67 | } | ... | ... |
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/convert/combination/CombinationActivityConvert.java
| ... | ... | @@ -204,9 +204,6 @@ public interface CombinationActivityConvert { |
| 204 | 204 | return respVO; |
| 205 | 205 | } |
| 206 | 206 | |
| 207 | - @Mapping(target = "id", ignore = true) | |
| 208 | - CombinationRecordDO convert5(CombinationRecordDO headRecord); | |
| 209 | - | |
| 210 | 207 | /** |
| 211 | 208 | * 转换生成虚拟成团虚拟记录 |
| 212 | 209 | * |
| ... | ... | @@ -214,21 +211,19 @@ public interface CombinationActivityConvert { |
| 214 | 211 | * @return 虚拟记录列表 |
| 215 | 212 | */ |
| 216 | 213 | default List<CombinationRecordDO> convertVirtualRecordList(CombinationRecordDO headRecord) { |
| 217 | - List<CombinationRecordDO> createRecords = new ArrayList<>(); | |
| 218 | - // 计算需要创建的虚拟成团记录数量 | |
| 219 | 214 | int count = headRecord.getUserSize() - headRecord.getUserCount(); |
| 215 | + List<CombinationRecordDO> createRecords = new ArrayList<>(count); | |
| 220 | 216 | for (int i = 0; i < count; i++) { |
| 221 | 217 | // 基础信息和团长保持一致 |
| 222 | 218 | CombinationRecordDO newRecord = convert5(headRecord); |
| 223 | 219 | // 虚拟信息 |
| 224 | - newRecord.setCount(0); | |
| 225 | - newRecord.setUserId(0L); | |
| 226 | - newRecord.setNickname(""); | |
| 227 | - newRecord.setAvatar(""); | |
| 228 | - newRecord.setOrderId(0L); | |
| 220 | + newRecord.setCount(0) // 会单独更新下,在后续的 Service 逻辑里 | |
| 221 | + .setUserId(0L).setNickname("").setAvatar("").setOrderId(0L); | |
| 229 | 222 | createRecords.add(newRecord); |
| 230 | 223 | } |
| 231 | 224 | return createRecords; |
| 232 | 225 | } |
| 226 | + @Mapping(target = "id", ignore = true) | |
| 227 | + CombinationRecordDO convert5(CombinationRecordDO headRecord); | |
| 233 | 228 | |
| 234 | 229 | } | ... | ... |
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/dal/mysql/bargain/BargainActivityMapper.java
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/article/ArticleServiceImpl.java
| ... | ... | @@ -10,7 +10,6 @@ import cn.iocoder.yudao.module.promotion.dal.dataobject.article.ArticleCategoryD |
| 10 | 10 | import cn.iocoder.yudao.module.promotion.dal.dataobject.article.ArticleDO; |
| 11 | 11 | import cn.iocoder.yudao.module.promotion.dal.mysql.article.ArticleMapper; |
| 12 | 12 | import org.springframework.stereotype.Service; |
| 13 | -import org.springframework.transaction.annotation.Transactional; | |
| 14 | 13 | import org.springframework.validation.annotation.Validated; |
| 15 | 14 | |
| 16 | 15 | import javax.annotation.Resource; |
| ... | ... | @@ -112,12 +111,10 @@ public class ArticleServiceImpl implements ArticleService { |
| 112 | 111 | } |
| 113 | 112 | |
| 114 | 113 | @Override |
| 115 | - @Transactional(rollbackFor = Exception.class) | |
| 116 | 114 | public void addBrowseCount(Long id) { |
| 117 | 115 | // 校验文章是否存在 |
| 118 | 116 | validateArticleExists(id); |
| 119 | - | |
| 120 | - // 增加浏览次数 TODO 先简单做,用户规模不大,只 +1 | |
| 117 | + // 增加浏览次数 | |
| 121 | 118 | articleMapper.updateBrowseCount(id); |
| 122 | 119 | } |
| 123 | 120 | ... | ... |
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/combination/CombinationRecordServiceImpl.java
| ... | ... | @@ -369,6 +369,7 @@ public class CombinationRecordServiceImpl implements CombinationRecordService { |
| 369 | 369 | keyValue.setValue(keyValue.getValue() + 1); |
| 370 | 370 | } |
| 371 | 371 | } catch (Exception ignored) { // 处理异常继续循环 |
| 372 | + // TODO @puhui999:拼团过期 or 虚拟成团 可以改成 expireCombinationRecord;因为找方法更容易一些; | |
| 372 | 373 | log.error("[拼团过期 or 虚拟成团][record({}) 处理异常,请进行处理!record 数据是:{}]", |
| 373 | 374 | record.getId(), JsonUtils.toJsonString(record)); |
| 374 | 375 | } |
| ... | ... | @@ -383,10 +384,10 @@ public class CombinationRecordServiceImpl implements CombinationRecordService { |
| 383 | 384 | */ |
| 384 | 385 | @Transactional(rollbackFor = Exception.class) |
| 385 | 386 | public void handleExpireRecord(CombinationRecordDO headRecord) { |
| 386 | - // 1.更新拼团记录 | |
| 387 | + // 1. 更新拼团记录 | |
| 387 | 388 | List<CombinationRecordDO> headAndRecords = updateBatchCombinationRecords(headRecord, |
| 388 | 389 | CombinationRecordStatusEnum.FAILED); |
| 389 | - // 2.订单取消 | |
| 390 | + // 2. 订单取消 | |
| 390 | 391 | headAndRecords.forEach(item -> tradeOrderApi.cancelPaidOrder(item.getUserId(), item.getOrderId())); |
| 391 | 392 | } |
| 392 | 393 | ... | ... |
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/order/TradeOrderController.java
| ... | ... | @@ -24,8 +24,11 @@ import org.springframework.web.bind.annotation.*; |
| 24 | 24 | import javax.annotation.Resource; |
| 25 | 25 | import java.util.List; |
| 26 | 26 | import java.util.Map; |
| 27 | +import java.util.Objects; | |
| 28 | +import java.util.Set; | |
| 27 | 29 | |
| 28 | 30 | import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; |
| 31 | +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertList; | |
| 29 | 32 | import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet; |
| 30 | 33 | |
| 31 | 34 | @Tag(name = "管理后台 - 交易订单") |
| ... | ... | @@ -56,7 +59,9 @@ public class TradeOrderController { |
| 56 | 59 | } |
| 57 | 60 | |
| 58 | 61 | // 查询用户信息 |
| 59 | - Map<Long, MemberUserRespDTO> userMap = memberUserApi.getUserMap(convertSet(pageResult.getList(), TradeOrderDO::getUserId)); | |
| 62 | + Set<Long> userIds = CollUtil.unionDistinct(convertList(pageResult.getList(), TradeOrderDO::getUserId), | |
| 63 | + convertList(pageResult.getList(), TradeOrderDO::getBrokerageUserId, Objects::nonNull)); | |
| 64 | + Map<Long, MemberUserRespDTO> userMap = memberUserApi.getUserMap(userIds); | |
| 60 | 65 | // 查询订单项 |
| 61 | 66 | List<TradeOrderItemDO> orderItems = tradeOrderQueryService.getOrderItemListByOrderId( |
| 62 | 67 | convertSet(pageResult.getList(), TradeOrderDO::getId)); |
| ... | ... | @@ -64,6 +69,13 @@ public class TradeOrderController { |
| 64 | 69 | return success(TradeOrderConvert.INSTANCE.convertPage(pageResult, orderItems, userMap)); |
| 65 | 70 | } |
| 66 | 71 | |
| 72 | + @GetMapping("/summary") | |
| 73 | + @Operation(summary = "获得交易订单统计") | |
| 74 | + @PreAuthorize("@ss.hasPermission('trade:order:query')") | |
| 75 | + public CommonResult<TradeOrderSummaryRespVO> getOrderSummary(TradeOrderPageReqVO reqVO) { | |
| 76 | + return success(tradeOrderQueryService.getOrderSummary(reqVO)); | |
| 77 | + } | |
| 78 | + | |
| 67 | 79 | @GetMapping("/get-detail") |
| 68 | 80 | @Operation(summary = "获得交易订单详情") |
| 69 | 81 | @Parameter(name = "id", description = "订单编号", required = true, example = "1") | ... | ... |
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/order/vo/TradeOrderBaseVO.java
| ... | ... | @@ -145,4 +145,7 @@ public class TradeOrderBaseVO { |
| 145 | 145 | @Schema(description = "VIP 减免金额", requiredMode = Schema.RequiredMode.REQUIRED, example = "888") |
| 146 | 146 | private Integer vipPrice; |
| 147 | 147 | |
| 148 | + @Schema(description = "推广人编号", example = "1") | |
| 149 | + private Long brokerageUserId; | |
| 150 | + | |
| 148 | 151 | } | ... | ... |
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/order/vo/TradeOrderPageItemRespVO.java
| 1 | 1 | package cn.iocoder.yudao.module.trade.controller.admin.order.vo; |
| 2 | 2 | |
| 3 | -import cn.iocoder.yudao.module.member.api.user.dto.MemberUserRespDTO; | |
| 3 | +import cn.iocoder.yudao.module.trade.controller.admin.base.member.user.MemberUserRespVO; | |
| 4 | 4 | import cn.iocoder.yudao.module.trade.controller.admin.base.product.property.ProductPropertyValueDetailRespVO; |
| 5 | 5 | import io.swagger.v3.oas.annotations.media.Schema; |
| 6 | 6 | import lombok.Data; |
| ... | ... | @@ -14,24 +14,20 @@ public class TradeOrderPageItemRespVO extends TradeOrderBaseVO { |
| 14 | 14 | @Schema(description = "收件人地区名字", requiredMode = Schema.RequiredMode.REQUIRED, example = "上海 上海市 普陀区") |
| 15 | 15 | private String receiverAreaName; |
| 16 | 16 | |
| 17 | - /** | |
| 18 | - * 订单项列表 | |
| 19 | - */ | |
| 17 | + @Schema(description = "订单项列表", requiredMode = Schema.RequiredMode.REQUIRED) | |
| 20 | 18 | private List<Item> items; |
| 21 | 19 | |
| 22 | - // TODO @xiaobai:使用 MemberUserRespVO 返回哈;DTO 不直接给前端 | |
| 23 | - /** | |
| 24 | - * 用户信息 | |
| 25 | - */ | |
| 26 | - private MemberUserRespDTO user; | |
| 20 | + @Schema(description = "用户信息", requiredMode = Schema.RequiredMode.REQUIRED) | |
| 21 | + private MemberUserRespVO user; | |
| 22 | + | |
| 23 | + @Schema(description = "推广人信息") | |
| 24 | + private MemberUserRespVO brokerageUser; | |
| 27 | 25 | |
| 28 | 26 | @Schema(description = "管理后台 - 交易订单的分页项的订单项目") |
| 29 | 27 | @Data |
| 30 | 28 | public static class Item extends TradeOrderItemBaseVO { |
| 31 | 29 | |
| 32 | - /** | |
| 33 | - * 属性数组 | |
| 34 | - */ | |
| 30 | + @Schema(description = "属性列表", requiredMode = Schema.RequiredMode.REQUIRED) | |
| 35 | 31 | private List<ProductPropertyValueDetailRespVO> properties; |
| 36 | 32 | |
| 37 | 33 | } | ... | ... |
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/order/vo/TradeOrderSummaryRespVO.java
0 → 100644
| 1 | +package cn.iocoder.yudao.module.trade.controller.admin.order.vo; | |
| 2 | + | |
| 3 | +import io.swagger.v3.oas.annotations.media.Schema; | |
| 4 | +import lombok.Data; | |
| 5 | + | |
| 6 | +@Schema(description = "管理后台 - 交易订单统计 Response VO") | |
| 7 | +@Data | |
| 8 | +public class TradeOrderSummaryRespVO { | |
| 9 | + | |
| 10 | + @Schema(description = "订单数量", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") | |
| 11 | + private Long orderCount; | |
| 12 | + | |
| 13 | + @Schema(description = "订单金额", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") | |
| 14 | + private Long orderPayPrice; | |
| 15 | + | |
| 16 | + @Schema(description = "退款单数", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") | |
| 17 | + private Long afterSaleCount; | |
| 18 | + | |
| 19 | + @Schema(description = "退款金额", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") | |
| 20 | + private Long afterSalePrice; | |
| 21 | + | |
| 22 | +} | ... | ... |
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/convert/order/TradeOrderConvert.java
| ... | ... | @@ -124,13 +124,17 @@ public interface TradeOrderConvert { |
| 124 | 124 | TradeOrderPageItemRespVO orderVO = convert(order, xOrderItems); |
| 125 | 125 | // 处理收货地址 |
| 126 | 126 | orderVO.setReceiverAreaName(AreaUtils.format(order.getReceiverAreaId())); |
| 127 | - // 增加用户昵称 | |
| 128 | - orderVO.setUser(memberUserMap.get(orderVO.getUserId())); | |
| 127 | + // 增加用户信息 | |
| 128 | + orderVO.setUser(convertUser(memberUserMap.get(orderVO.getUserId()))); | |
| 129 | + // 增加推广人信息 | |
| 130 | + orderVO.setBrokerageUser(convertUser(memberUserMap.get(orderVO.getBrokerageUserId()))); | |
| 129 | 131 | return orderVO; |
| 130 | 132 | }); |
| 131 | 133 | return new PageResult<>(orderVOs, pageResult.getTotal()); |
| 132 | 134 | } |
| 133 | 135 | |
| 136 | + MemberUserRespVO convertUser(MemberUserRespDTO memberUserRespDTO); | |
| 137 | + | |
| 134 | 138 | TradeOrderPageItemRespVO convert(TradeOrderDO order, List<TradeOrderItemDO> items); |
| 135 | 139 | |
| 136 | 140 | ProductPropertyValueDetailRespVO convert(ProductPropertyValueDetailRespDTO bean); | ... | ... |
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/dal/mysql/order/TradeOrderMapper.java
| ... | ... | @@ -3,6 +3,7 @@ package cn.iocoder.yudao.module.trade.dal.mysql.order; |
| 3 | 3 | import cn.iocoder.yudao.framework.common.pojo.PageResult; |
| 4 | 4 | import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; |
| 5 | 5 | import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX; |
| 6 | +import cn.iocoder.yudao.framework.mybatis.core.query.MPJLambdaWrapperX; | |
| 6 | 7 | import cn.iocoder.yudao.module.trade.controller.admin.order.vo.TradeOrderPageReqVO; |
| 7 | 8 | import cn.iocoder.yudao.module.trade.controller.app.order.vo.AppTradeOrderPageReqVO; |
| 8 | 9 | import cn.iocoder.yudao.module.trade.dal.dataobject.order.TradeOrderDO; |
| ... | ... | @@ -11,6 +12,7 @@ import org.apache.ibatis.annotations.Mapper; |
| 11 | 12 | |
| 12 | 13 | import java.time.LocalDateTime; |
| 13 | 14 | import java.util.List; |
| 15 | +import java.util.Map; | |
| 14 | 16 | import java.util.Set; |
| 15 | 17 | |
| 16 | 18 | @Mapper |
| ... | ... | @@ -42,6 +44,27 @@ public interface TradeOrderMapper extends BaseMapperX<TradeOrderDO> { |
| 42 | 44 | .orderByDesc(TradeOrderDO::getId)); |
| 43 | 45 | } |
| 44 | 46 | |
| 47 | + // TODO @疯狂:如果用 map 返回,要不这里直接用 TradeOrderSummaryRespVO 返回?也算合理,就当 sql 查询出这么个玩意~~ | |
| 48 | + default List<Map<String, Object>> selectOrderSummaryGroupByRefundStatus(TradeOrderPageReqVO reqVO, Set<Long> userIds) { | |
| 49 | + return selectMaps(new MPJLambdaWrapperX<TradeOrderDO>() | |
| 50 | + .selectAs(TradeOrderDO::getRefundStatus, TradeOrderDO::getRefundStatus) // 售后状态 | |
| 51 | + .selectCount(TradeOrderDO::getId, "count") // 售后状态对应的数量 | |
| 52 | + .selectSum(TradeOrderDO::getPayPrice, "price") // 售后状态对应的支付金额 | |
| 53 | + .likeIfPresent(TradeOrderDO::getNo, reqVO.getNo()) | |
| 54 | + .eqIfPresent(TradeOrderDO::getUserId, reqVO.getUserId()) | |
| 55 | + .eqIfPresent(TradeOrderDO::getDeliveryType, reqVO.getDeliveryType()) | |
| 56 | + .inIfPresent(TradeOrderDO::getUserId, userIds) | |
| 57 | + .eqIfPresent(TradeOrderDO::getType, reqVO.getType()) | |
| 58 | + .eqIfPresent(TradeOrderDO::getStatus, reqVO.getStatus()) | |
| 59 | + .eqIfPresent(TradeOrderDO::getPayChannelCode, reqVO.getPayChannelCode()) | |
| 60 | + .eqIfPresent(TradeOrderDO::getTerminal, reqVO.getTerminal()) | |
| 61 | + .eqIfPresent(TradeOrderDO::getLogisticsId, reqVO.getLogisticsId()) | |
| 62 | + .inIfPresent(TradeOrderDO::getPickUpStoreId, reqVO.getPickUpStoreIds()) | |
| 63 | + .likeIfPresent(TradeOrderDO::getPickUpVerifyCode, reqVO.getPickUpVerifyCode()) | |
| 64 | + .betweenIfPresent(TradeOrderDO::getCreateTime, reqVO.getCreateTime()) | |
| 65 | + .groupBy(TradeOrderDO::getRefundStatus)); // 按售后状态分组 | |
| 66 | + } | |
| 67 | + | |
| 45 | 68 | default PageResult<TradeOrderDO> selectPage(AppTradeOrderPageReqVO reqVO, Long userId) { |
| 46 | 69 | return selectPage(reqVO, new LambdaQueryWrapperX<TradeOrderDO>() |
| 47 | 70 | .eq(TradeOrderDO::getUserId, userId) |
| ... | ... | @@ -92,7 +115,7 @@ public interface TradeOrderMapper extends BaseMapperX<TradeOrderDO> { |
| 92 | 115 | default TradeOrderDO selectOneByPickUpVerifyCode(String pickUpVerifyCode) { |
| 93 | 116 | return selectOne(TradeOrderDO::getPickUpVerifyCode, pickUpVerifyCode); |
| 94 | 117 | } |
| 95 | - | |
| 118 | + | |
| 96 | 119 | default TradeOrderDO selectByUserIdAndCombinationActivityIdAndStatus(Long userId, Long combinationActivityId, Integer status) { |
| 97 | 120 | return selectOne(new LambdaQueryWrapperX<TradeOrderDO>() |
| 98 | 121 | .eq(TradeOrderDO::getUserId, userId) | ... | ... |
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/framework/order/core/aop/TradeOrderLogAspect.java
| ... | ... | @@ -58,10 +58,6 @@ public class TradeOrderLogAspect { |
| 58 | 58 | */ |
| 59 | 59 | private static final ThreadLocal<Map<String, Object>> EXTS = new ThreadLocal<>(); |
| 60 | 60 | |
| 61 | - public TradeOrderLogAspect() { | |
| 62 | - System.out.println(); | |
| 63 | - } | |
| 64 | - | |
| 65 | 61 | @Resource |
| 66 | 62 | private TradeOrderLogService orderLogService; |
| 67 | 63 | ... | ... |
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/order/TradeOrderQueryService.java
| ... | ... | @@ -2,6 +2,7 @@ package cn.iocoder.yudao.module.trade.service.order; |
| 2 | 2 | |
| 3 | 3 | import cn.iocoder.yudao.framework.common.pojo.PageResult; |
| 4 | 4 | import cn.iocoder.yudao.module.trade.controller.admin.order.vo.TradeOrderPageReqVO; |
| 5 | +import cn.iocoder.yudao.module.trade.controller.admin.order.vo.TradeOrderSummaryRespVO; | |
| 5 | 6 | import cn.iocoder.yudao.module.trade.controller.app.order.vo.AppTradeOrderPageReqVO; |
| 6 | 7 | import cn.iocoder.yudao.module.trade.dal.dataobject.order.TradeOrderDO; |
| 7 | 8 | import cn.iocoder.yudao.module.trade.dal.dataobject.order.TradeOrderItemDO; |
| ... | ... | @@ -65,6 +66,14 @@ public interface TradeOrderQueryService { |
| 65 | 66 | PageResult<TradeOrderDO> getOrderPage(TradeOrderPageReqVO reqVO); |
| 66 | 67 | |
| 67 | 68 | /** |
| 69 | + * 获得订单统计 | |
| 70 | + * | |
| 71 | + * @param reqVO 请求参数 | |
| 72 | + * @return 订单统计 | |
| 73 | + */ | |
| 74 | + TradeOrderSummaryRespVO getOrderSummary(TradeOrderPageReqVO reqVO); | |
| 75 | + | |
| 76 | + /** | |
| 68 | 77 | * 【会员】获得交易订单分页 |
| 69 | 78 | * |
| 70 | 79 | * @param userId 用户编号 | ... | ... |
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/order/TradeOrderQueryServiceImpl.java
| 1 | 1 | package cn.iocoder.yudao.module.trade.service.order; |
| 2 | 2 | |
| 3 | 3 | import cn.hutool.core.collection.CollUtil; |
| 4 | +import cn.hutool.core.map.MapUtil; | |
| 4 | 5 | import cn.hutool.core.util.ObjectUtil; |
| 5 | 6 | import cn.hutool.core.util.StrUtil; |
| 6 | 7 | import cn.hutool.extra.spring.SpringUtil; |
| ... | ... | @@ -8,6 +9,7 @@ import cn.iocoder.yudao.framework.common.pojo.PageResult; |
| 8 | 9 | import cn.iocoder.yudao.module.member.api.user.MemberUserApi; |
| 9 | 10 | import cn.iocoder.yudao.module.member.api.user.dto.MemberUserRespDTO; |
| 10 | 11 | import cn.iocoder.yudao.module.trade.controller.admin.order.vo.TradeOrderPageReqVO; |
| 12 | +import cn.iocoder.yudao.module.trade.controller.admin.order.vo.TradeOrderSummaryRespVO; | |
| 11 | 13 | import cn.iocoder.yudao.module.trade.controller.app.order.vo.AppTradeOrderPageReqVO; |
| 12 | 14 | import cn.iocoder.yudao.module.trade.dal.dataobject.delivery.DeliveryExpressDO; |
| 13 | 15 | import cn.iocoder.yudao.module.trade.dal.dataobject.order.TradeOrderDO; |
| ... | ... | @@ -15,6 +17,7 @@ import cn.iocoder.yudao.module.trade.dal.dataobject.order.TradeOrderItemDO; |
| 15 | 17 | import cn.iocoder.yudao.module.trade.dal.mysql.order.TradeOrderItemMapper; |
| 16 | 18 | import cn.iocoder.yudao.module.trade.dal.mysql.order.TradeOrderMapper; |
| 17 | 19 | import cn.iocoder.yudao.module.trade.dal.redis.RedisKeyConstants; |
| 20 | +import cn.iocoder.yudao.module.trade.enums.order.TradeOrderRefundStatusEnum; | |
| 18 | 21 | import cn.iocoder.yudao.module.trade.enums.order.TradeOrderStatusEnum; |
| 19 | 22 | import cn.iocoder.yudao.module.trade.framework.delivery.core.client.ExpressClientFactory; |
| 20 | 23 | import cn.iocoder.yudao.module.trade.framework.delivery.core.client.dto.ExpressTrackQueryReqDTO; |
| ... | ... | @@ -85,24 +88,57 @@ public class TradeOrderQueryServiceImpl implements TradeOrderQueryService { |
| 85 | 88 | |
| 86 | 89 | @Override |
| 87 | 90 | public PageResult<TradeOrderDO> getOrderPage(TradeOrderPageReqVO reqVO) { |
| 91 | + // 根据用户查询条件构建用户编号列表 | |
| 92 | + Set<Long> userIds = buildQueryConditionUserIds(reqVO); | |
| 93 | + if (userIds == null) { // 没查询到用户,说明肯定也没他的订单 | |
| 94 | + return PageResult.empty(); | |
| 95 | + } | |
| 96 | + // 分页查询 | |
| 97 | + return tradeOrderMapper.selectPage(reqVO, userIds); | |
| 98 | + } | |
| 99 | + | |
| 100 | + private Set<Long> buildQueryConditionUserIds(TradeOrderPageReqVO reqVO) { | |
| 88 | 101 | // 获得 userId 相关的查询 |
| 89 | 102 | Set<Long> userIds = new HashSet<>(); |
| 90 | 103 | if (StrUtil.isNotEmpty(reqVO.getUserMobile())) { |
| 91 | 104 | MemberUserRespDTO user = memberUserApi.getUserByMobile(reqVO.getUserMobile()); |
| 92 | 105 | if (user == null) { // 没查询到用户,说明肯定也没他的订单 |
| 93 | - return new PageResult<>(); | |
| 106 | + return null; | |
| 94 | 107 | } |
| 95 | 108 | userIds.add(user.getId()); |
| 96 | 109 | } |
| 97 | 110 | if (StrUtil.isNotEmpty(reqVO.getUserNickname())) { |
| 98 | 111 | List<MemberUserRespDTO> users = memberUserApi.getUserListByNickname(reqVO.getUserNickname()); |
| 99 | 112 | if (CollUtil.isEmpty(users)) { // 没查询到用户,说明肯定也没他的订单 |
| 100 | - return new PageResult<>(); | |
| 113 | + return null; | |
| 101 | 114 | } |
| 102 | 115 | userIds.addAll(convertSet(users, MemberUserRespDTO::getId)); |
| 103 | 116 | } |
| 104 | - // 分页查询 | |
| 105 | - return tradeOrderMapper.selectPage(reqVO, userIds); | |
| 117 | + return userIds; | |
| 118 | + } | |
| 119 | + | |
| 120 | + @Override | |
| 121 | + public TradeOrderSummaryRespVO getOrderSummary(TradeOrderPageReqVO reqVO) { | |
| 122 | + // 根据用户查询条件构建用户编号列表 | |
| 123 | + Set<Long> userIds = buildQueryConditionUserIds(reqVO); | |
| 124 | + if (userIds == null) { // 没查询到用户,说明肯定也没他的订单 | |
| 125 | + return new TradeOrderSummaryRespVO(); | |
| 126 | + } | |
| 127 | + // 查询每个售后状态对应的数量、金额 | |
| 128 | + List<Map<String, Object>> list = tradeOrderMapper.selectOrderSummaryGroupByRefundStatus(reqVO, null); | |
| 129 | + | |
| 130 | + TradeOrderSummaryRespVO vo = new TradeOrderSummaryRespVO().setAfterSaleCount(0L).setAfterSalePrice(0L); | |
| 131 | + for (Map<String, Object> map : list) { | |
| 132 | + Long count = MapUtil.getLong(map, "count", 0L); | |
| 133 | + Long price = MapUtil.getLong(map, "price", 0L); | |
| 134 | + // 未退款的计入订单,部分退款、全部退款计入售后 | |
| 135 | + if (TradeOrderRefundStatusEnum.NONE.getStatus().equals(MapUtil.getInt(map, "refundStatus"))) { | |
| 136 | + vo.setOrderCount(count).setOrderPayPrice(price); | |
| 137 | + } else { | |
| 138 | + vo.setAfterSaleCount(vo.getAfterSaleCount() + count).setAfterSalePrice(vo.getAfterSalePrice() + price); | |
| 139 | + } | |
| 140 | + } | |
| 141 | + return vo; | |
| 106 | 142 | } |
| 107 | 143 | |
| 108 | 144 | @Override | ... | ... |
yudao-module-member/yudao-module-member-api/src/main/java/cn/iocoder/yudao/module/member/enums/ErrorCodeConstants.java
| ... | ... | @@ -19,7 +19,6 @@ public interface ErrorCodeConstants { |
| 19 | 19 | ErrorCode AUTH_LOGIN_BAD_CREDENTIALS = new ErrorCode(1_004_003_000, "登录失败,账号密码不正确"); |
| 20 | 20 | ErrorCode AUTH_LOGIN_USER_DISABLED = new ErrorCode(1_004_003_001, "登录失败,账号被禁用"); |
| 21 | 21 | ErrorCode AUTH_THIRD_LOGIN_NOT_BIND = new ErrorCode(1_004_003_005, "未绑定账号,需要进行绑定"); |
| 22 | - ErrorCode AUTH_WEIXIN_MINI_APP_PHONE_CODE_ERROR = new ErrorCode(1_004_003_006, "获得手机号失败"); | |
| 23 | 22 | ErrorCode AUTH_MOBILE_USED = new ErrorCode(1_004_003_007, "手机号已经被使用"); |
| 24 | 23 | |
| 25 | 24 | // ========== 用户收件地址 1-004-004-000 ========== | ... | ... |
yudao-module-member/yudao-module-member-biz/pom.xml
| ... | ... | @@ -43,10 +43,6 @@ |
| 43 | 43 | <groupId>cn.iocoder.boot</groupId> |
| 44 | 44 | <artifactId>yudao-spring-boot-starter-biz-tenant</artifactId> |
| 45 | 45 | </dependency> |
| 46 | - <dependency> | |
| 47 | - <groupId>cn.iocoder.boot</groupId> | |
| 48 | - <artifactId>yudao-spring-boot-starter-biz-weixin</artifactId> | |
| 49 | - </dependency> | |
| 50 | 46 | |
| 51 | 47 | <!-- Web 相关 --> |
| 52 | 48 | <dependency> | ... | ... |
yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/controller/app/auth/AppAuthController.http
| ... | ... | @@ -59,3 +59,8 @@ tenant-id: {{appTenentId}} |
| 59 | 59 | POST {{appApi}}/member/auth/refresh-token?refreshToken=bc43d929094849a28b3a69f6e6940d70 |
| 60 | 60 | Content-Type: application/json |
| 61 | 61 | tenant-id: {{appTenentId}} |
| 62 | + | |
| 63 | +### 请求 /auth/create-weixin-jsapi-signature 接口 => 成功 | |
| 64 | +POST {{appApi}}/member/auth/create-weixin-jsapi-signature?url=http://www.iocoder.cn | |
| 65 | +Authorization: Bearer {{appToken}} | |
| 66 | +tenant-id: {{appTenentId}} | ... | ... |
yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/controller/app/auth/AppAuthController.java
| 1 | 1 | package cn.iocoder.yudao.module.member.controller.app.auth; |
| 2 | 2 | |
| 3 | 3 | import cn.hutool.core.util.StrUtil; |
| 4 | +import cn.iocoder.yudao.framework.common.enums.UserTypeEnum; | |
| 4 | 5 | import cn.iocoder.yudao.framework.common.pojo.CommonResult; |
| 5 | 6 | import cn.iocoder.yudao.framework.operatelog.core.annotations.OperateLog; |
| 6 | 7 | import cn.iocoder.yudao.framework.security.config.SecurityProperties; |
| 7 | 8 | import cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils; |
| 8 | 9 | import cn.iocoder.yudao.module.member.controller.app.auth.vo.*; |
| 10 | +import cn.iocoder.yudao.module.member.convert.auth.AuthConvert; | |
| 9 | 11 | import cn.iocoder.yudao.module.member.service.auth.MemberAuthService; |
| 12 | +import cn.iocoder.yudao.module.system.api.social.SocialClientApi; | |
| 13 | +import cn.iocoder.yudao.module.system.api.social.dto.SocialWxJsapiSignatureRespDTO; | |
| 10 | 14 | import io.swagger.v3.oas.annotations.Operation; |
| 11 | 15 | import io.swagger.v3.oas.annotations.Parameter; |
| 12 | 16 | import io.swagger.v3.oas.annotations.Parameters; |
| ... | ... | @@ -34,6 +38,9 @@ public class AppAuthController { |
| 34 | 38 | private MemberAuthService authService; |
| 35 | 39 | |
| 36 | 40 | @Resource |
| 41 | + private SocialClientApi socialClientApi; | |
| 42 | + | |
| 43 | + @Resource | |
| 37 | 44 | private SecurityProperties securityProperties; |
| 38 | 45 | |
| 39 | 46 | @PostMapping("/login") |
| ... | ... | @@ -109,4 +116,13 @@ public class AppAuthController { |
| 109 | 116 | return success(authService.weixinMiniAppLogin(reqVO)); |
| 110 | 117 | } |
| 111 | 118 | |
| 119 | + @PostMapping("/create-weixin-jsapi-signature") | |
| 120 | + @Operation(summary = "创建微信 JS SDK 初始化所需的签名", | |
| 121 | + description = "参考 https://developers.weixin.qq.com/doc/offiaccount/OA_Web_Apps/JS-SDK.html 文档") | |
| 122 | + public CommonResult<SocialWxJsapiSignatureRespDTO> createWeixinMpJsapiSignature(@RequestParam("url") String url) { | |
| 123 | + SocialWxJsapiSignatureRespDTO signature = socialClientApi.createWxMpJsapiSignature( | |
| 124 | + UserTypeEnum.MEMBER.getValue(), url); | |
| 125 | + return success(AuthConvert.INSTANCE.convert(signature)); | |
| 126 | + } | |
| 127 | + | |
| 112 | 128 | } | ... | ... |
yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/controller/app/auth/vo/AuthWeixinJsapiSignatureRespVO.java
0 → 100644
| 1 | +package cn.iocoder.yudao.module.member.controller.app.auth.vo; | |
| 2 | + | |
| 3 | +import io.swagger.v3.oas.annotations.media.Schema; | |
| 4 | +import lombok.AllArgsConstructor; | |
| 5 | +import lombok.Builder; | |
| 6 | +import lombok.Data; | |
| 7 | +import lombok.NoArgsConstructor; | |
| 8 | + | |
| 9 | +@Schema(description = "用户 APP - 微信公众号 JSAPI 签名 Response VO") | |
| 10 | +@Data | |
| 11 | +@NoArgsConstructor | |
| 12 | +@AllArgsConstructor | |
| 13 | +@Builder | |
| 14 | +public class AuthWeixinJsapiSignatureRespVO { | |
| 15 | + | |
| 16 | + @Schema(description = "微信公众号的 appId", requiredMode = Schema.RequiredMode.REQUIRED, example = "hello") | |
| 17 | + private String appId; | |
| 18 | + | |
| 19 | + @Schema(description = "匿名串", requiredMode = Schema.RequiredMode.REQUIRED, example = "world") | |
| 20 | + private String nonceStr; | |
| 21 | + | |
| 22 | + @Schema(description = "时间戳", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") | |
| 23 | + private Long timestamp; | |
| 24 | + | |
| 25 | + @Schema(description = "URL", requiredMode = Schema.RequiredMode.REQUIRED, example = "https://www.iocoder.cn") | |
| 26 | + private String url; | |
| 27 | + | |
| 28 | + @Schema(description = "签名", requiredMode = Schema.RequiredMode.REQUIRED, example = "阿巴阿巴") | |
| 29 | + private String signature; | |
| 30 | + | |
| 31 | +} | ... | ... |
yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/convert/auth/AuthConvert.java
| ... | ... | @@ -9,6 +9,7 @@ import cn.iocoder.yudao.module.system.api.sms.dto.code.SmsCodeUseReqDTO; |
| 9 | 9 | import cn.iocoder.yudao.module.system.api.sms.dto.code.SmsCodeValidateReqDTO; |
| 10 | 10 | import cn.iocoder.yudao.module.system.api.social.dto.SocialUserBindReqDTO; |
| 11 | 11 | import cn.iocoder.yudao.module.system.api.social.dto.SocialUserUnbindReqDTO; |
| 12 | +import cn.iocoder.yudao.module.system.api.social.dto.SocialWxJsapiSignatureRespDTO; | |
| 12 | 13 | import cn.iocoder.yudao.module.system.enums.sms.SmsSceneEnum; |
| 13 | 14 | import org.mapstruct.Mapper; |
| 14 | 15 | import org.mapstruct.factory.Mappers; |
| ... | ... | @@ -29,4 +30,6 @@ public interface AuthConvert { |
| 29 | 30 | |
| 30 | 31 | SmsCodeValidateReqDTO convert(AppAuthSmsValidateReqVO bean); |
| 31 | 32 | |
| 33 | + SocialWxJsapiSignatureRespDTO convert(SocialWxJsapiSignatureRespDTO bean); | |
| 34 | + | |
| 32 | 35 | } | ... | ... |
yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/service/auth/MemberAuthServiceImpl.java
| 1 | 1 | package cn.iocoder.yudao.module.member.service.auth; |
| 2 | 2 | |
| 3 | -import cn.binarywang.wx.miniapp.api.WxMaService; | |
| 4 | -import cn.binarywang.wx.miniapp.bean.WxMaPhoneNumberInfo; | |
| 5 | 3 | import cn.hutool.core.lang.Assert; |
| 6 | 4 | import cn.hutool.core.util.ObjectUtil; |
| 7 | 5 | import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; |
| ... | ... | @@ -19,9 +17,11 @@ import cn.iocoder.yudao.module.system.api.oauth2.OAuth2TokenApi; |
| 19 | 17 | import cn.iocoder.yudao.module.system.api.oauth2.dto.OAuth2AccessTokenCreateReqDTO; |
| 20 | 18 | import cn.iocoder.yudao.module.system.api.oauth2.dto.OAuth2AccessTokenRespDTO; |
| 21 | 19 | import cn.iocoder.yudao.module.system.api.sms.SmsCodeApi; |
| 20 | +import cn.iocoder.yudao.module.system.api.social.SocialClientApi; | |
| 22 | 21 | import cn.iocoder.yudao.module.system.api.social.SocialUserApi; |
| 23 | 22 | import cn.iocoder.yudao.module.system.api.social.dto.SocialUserBindReqDTO; |
| 24 | 23 | import cn.iocoder.yudao.module.system.api.social.dto.SocialUserRespDTO; |
| 24 | +import cn.iocoder.yudao.module.system.api.social.dto.SocialWxPhoneNumberInfoRespDTO; | |
| 25 | 25 | import cn.iocoder.yudao.module.system.enums.logger.LoginLogTypeEnum; |
| 26 | 26 | import cn.iocoder.yudao.module.system.enums.logger.LoginResultEnum; |
| 27 | 27 | import cn.iocoder.yudao.module.system.enums.oauth2.OAuth2ClientConstants; |
| ... | ... | @@ -56,10 +56,9 @@ public class MemberAuthServiceImpl implements MemberAuthService { |
| 56 | 56 | @Resource |
| 57 | 57 | private SocialUserApi socialUserApi; |
| 58 | 58 | @Resource |
| 59 | - private OAuth2TokenApi oauth2TokenApi; | |
| 60 | - | |
| 59 | + private SocialClientApi socialClientApi; | |
| 61 | 60 | @Resource |
| 62 | - private WxMaService wxMaService; | |
| 61 | + private OAuth2TokenApi oauth2TokenApi; | |
| 63 | 62 | |
| 64 | 63 | @Override |
| 65 | 64 | public AppAuthLoginRespVO login(AppAuthLoginReqVO reqVO) { |
| ... | ... | @@ -121,15 +120,13 @@ public class MemberAuthServiceImpl implements MemberAuthService { |
| 121 | 120 | @Override |
| 122 | 121 | public AppAuthLoginRespVO weixinMiniAppLogin(AppAuthWeixinMiniAppLoginReqVO reqVO) { |
| 123 | 122 | // 获得对应的手机号信息 |
| 124 | - // TODO @芋艿:需要弱化微信小程序的依赖,通过 system 获取手机号 | |
| 125 | - WxMaPhoneNumberInfo phoneNumberInfo; | |
| 126 | - try { | |
| 127 | - phoneNumberInfo = wxMaService.getUserService().getPhoneNoInfo(reqVO.getPhoneCode()); | |
| 128 | - } catch (Exception exception) { | |
| 129 | - throw exception(AUTH_WEIXIN_MINI_APP_PHONE_CODE_ERROR); | |
| 130 | - } | |
| 123 | + SocialWxPhoneNumberInfoRespDTO phoneNumberInfo = socialClientApi.getWxMaPhoneNumberInfo( | |
| 124 | + UserTypeEnum.MEMBER.getValue(), reqVO.getPhoneCode()); | |
| 125 | + Assert.notNull(phoneNumberInfo, "获得手机信息失败,结果为空"); | |
| 126 | + | |
| 131 | 127 | // 获得获得注册用户 |
| 132 | - MemberUserDO user = userService.createUserIfAbsent(phoneNumberInfo.getPurePhoneNumber(), getClientIP(), TerminalEnum.WECHAT_MINI_PROGRAM.getTerminal()); | |
| 128 | + MemberUserDO user = userService.createUserIfAbsent(phoneNumberInfo.getPurePhoneNumber(), | |
| 129 | + getClientIP(), TerminalEnum.WECHAT_MINI_PROGRAM.getTerminal()); | |
| 133 | 130 | Assert.notNull(user, "获取用户失败,结果为空"); |
| 134 | 131 | |
| 135 | 132 | // 绑定社交用户 |
| ... | ... | @@ -154,7 +151,7 @@ public class MemberAuthServiceImpl implements MemberAuthService { |
| 154 | 151 | |
| 155 | 152 | @Override |
| 156 | 153 | public String getSocialAuthorizeUrl(Integer type, String redirectUri) { |
| 157 | - return socialUserApi.getAuthorizeUrl(type, redirectUri); | |
| 154 | + return socialClientApi.getAuthorizeUrl(type, UserTypeEnum.MEMBER.getValue(), redirectUri); | |
| 158 | 155 | } |
| 159 | 156 | |
| 160 | 157 | private MemberUserDO login0(String mobile, String password) { | ... | ... |
yudao-module-pay/yudao-module-pay-api/src/main/java/cn/iocoder/yudao/module/pay/api/transfer/PayTransferApi.java
yudao-module-pay/yudao-module-pay-api/src/main/java/cn/iocoder/yudao/module/pay/api/transfer/dto/PayTransferCreateReqDTO.java
| ... | ... | @@ -23,6 +23,7 @@ public class PayTransferCreateReqDTO { |
| 23 | 23 | * 类型 |
| 24 | 24 | */ |
| 25 | 25 | @NotNull(message = "转账类型不能为空") |
| 26 | + // TODO @jason:枚举的校验 | |
| 26 | 27 | private Integer type; |
| 27 | 28 | |
| 28 | 29 | /** |
| ... | ... | @@ -34,9 +35,11 @@ public class PayTransferCreateReqDTO { |
| 34 | 35 | /** |
| 35 | 36 | * 转账金额,单位:分 |
| 36 | 37 | */ |
| 38 | + // TODO @jason:这个金额是不是非空哈 | |
| 37 | 39 | @Min(value = 1, message = "转账金额必须大于零") |
| 38 | 40 | private Integer price; |
| 39 | 41 | |
| 42 | + // TODO @jason:这个标题,是不是不允许空呀 | |
| 40 | 43 | /** |
| 41 | 44 | * 转账标题 |
| 42 | 45 | */ |
| ... | ... | @@ -44,4 +47,5 @@ public class PayTransferCreateReqDTO { |
| 44 | 47 | |
| 45 | 48 | @NotEmpty(message = "收款方信息不能为空") |
| 46 | 49 | private Map<String, String> payeeInfo; |
| 50 | + | |
| 47 | 51 | } | ... | ... |
yudao-module-pay/yudao-module-pay-api/src/main/java/cn/iocoder/yudao/module/pay/enums/ErrorCodeConstants.java
| ... | ... | @@ -27,8 +27,6 @@ public interface ErrorCodeConstants { |
| 27 | 27 | ErrorCode PAY_ORDER_IS_EXPIRED = new ErrorCode(1_007_002_003, "支付订单已经过期"); |
| 28 | 28 | ErrorCode PAY_ORDER_SUBMIT_CHANNEL_ERROR = new ErrorCode(1_007_002_004, "发起支付报错,错误码:{},错误提示:{}"); |
| 29 | 29 | ErrorCode PAY_ORDER_REFUND_FAIL_STATUS_ERROR = new ErrorCode(1_007_002_005, "支付订单退款失败,原因:状态不是已支付或已退款"); |
| 30 | - ErrorCode ORDER_UPDATE_PRICE_FAIL_PAID = new ErrorCode(1_007_002_006, "支付订单调价失败,原因:支付订单已付款,不能调价"); | |
| 31 | - ErrorCode ORDER_UPDATE_PRICE_FAIL_EQUAL = new ErrorCode(1_007_002_007, "支付订单调价失败,原因:价格没有变化"); | |
| 32 | 30 | |
| 33 | 31 | // ========== ORDER 模块(拓展单) 1-007-003-000 ========== |
| 34 | 32 | ErrorCode PAY_ORDER_EXTENSION_NOT_FOUND = new ErrorCode(1_007_003_000, "支付交易拓展单不存在"); |
| ... | ... | @@ -64,6 +62,7 @@ public interface ErrorCodeConstants { |
| 64 | 62 | ErrorCode WALLET_RECHARGE_PACKAGE_AND_PRICE_IS_EMPTY = new ErrorCode(1_007_008_011, "充值金额和充钱套餐不能同时为空"); |
| 65 | 63 | ErrorCode WALLET_RECHARGE_PACKAGE_NOT_FOUND = new ErrorCode(1_007_008_012, "钱包充值套餐不存在"); |
| 66 | 64 | ErrorCode WALLET_RECHARGE_PACKAGE_IS_DISABLE = new ErrorCode(1_007_008_013, "钱包充值套餐已禁用"); |
| 65 | + | |
| 67 | 66 | // ========== 转账模块 1-007-009-000 ========== |
| 68 | 67 | ErrorCode PAY_TRANSFER_SUBMIT_CHANNEL_ERROR = new ErrorCode(1_007_009_000, "发起转账报错,错误码:{},错误提示:{}"); |
| 69 | 68 | ErrorCode PAY_TRANSFER_ALIPAY_LOGIN_ID_IS_EMPTY = new ErrorCode(1_007_009_001, "支付宝登录 ID 不能为空"); | ... | ... |
yudao-module-pay/yudao-module-pay-api/src/main/java/cn/iocoder/yudao/module/pay/enums/transfer/PayTransferStatusEnum.java
| ... | ... | @@ -24,7 +24,13 @@ public enum PayTransferStatusEnum { |
| 24 | 24 | */ |
| 25 | 25 | CLOSED(30, "转账关闭"); |
| 26 | 26 | |
| 27 | + /** | |
| 28 | + * 状态 | |
| 29 | + */ | |
| 27 | 30 | private final Integer status; |
| 31 | + /** | |
| 32 | + * 状态名 | |
| 33 | + */ | |
| 28 | 34 | private final String name; |
| 29 | 35 | |
| 30 | 36 | public static boolean isSuccess(Integer status) { |
| ... | ... | @@ -45,4 +51,5 @@ public enum PayTransferStatusEnum { |
| 45 | 51 | public static boolean isPendingStatus(Integer status) { |
| 46 | 52 | return Objects.equals(status, WAITING.getStatus()) || Objects.equals(status, IN_PROGRESS.status); |
| 47 | 53 | } |
| 54 | + | |
| 48 | 55 | } | ... | ... |
yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/api/transfer/PayTransferApiImpl.java
| ... | ... | @@ -5,14 +5,18 @@ import org.springframework.stereotype.Service; |
| 5 | 5 | import org.springframework.validation.annotation.Validated; |
| 6 | 6 | |
| 7 | 7 | /** |
| 8 | + * 转账单 API 实现类 | |
| 9 | + * | |
| 8 | 10 | * @author jason |
| 9 | 11 | */ |
| 10 | 12 | @Service |
| 11 | 13 | @Validated |
| 12 | 14 | public class PayTransferApiImpl implements PayTransferApi { |
| 15 | + | |
| 13 | 16 | @Override |
| 14 | 17 | public Long createTransfer(PayTransferCreateReqDTO reqDTO) { |
| 15 | - | |
| 18 | + // TODO @jason:貌似没实现噢 | |
| 16 | 19 | return null; |
| 17 | 20 | } |
| 18 | -} | |
| 21 | + | |
| 22 | +} | |
| 19 | 23 | \ No newline at end of file | ... | ... |
yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/controller/admin/demo/vo/transfer/PayDemoTransferCreateReqVO.java
| ... | ... | @@ -17,6 +17,7 @@ import java.util.Map; |
| 17 | 17 | @Data |
| 18 | 18 | public class PayDemoTransferCreateReqVO { |
| 19 | 19 | |
| 20 | + // TODO @jason:这个字段,是不是叫 type 就好了。 | |
| 20 | 21 | @Schema(description = "转账类型", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") |
| 21 | 22 | @NotNull(message = "转账类型不能为空") |
| 22 | 23 | @InEnum(PayTransferTypeEnum.class) |
| ... | ... | @@ -26,7 +27,9 @@ public class PayDemoTransferCreateReqVO { |
| 26 | 27 | @Min(value = 1, message = "转账金额必须大于零") |
| 27 | 28 | private Integer price; |
| 28 | 29 | |
| 30 | + // TODO @jason:感觉这个动态字段,晚点改;可能要讨论下怎么搞好; | |
| 29 | 31 | @Schema(description = "收款方信息", requiredMode = Schema.RequiredMode.REQUIRED, example = "{'ALIPAY_LOGON_ID':'xxxx'}") |
| 30 | 32 | @NotEmpty(message = "收款方信息不能为空") |
| 31 | 33 | private Map<String, String> payeeInfo; |
| 34 | + | |
| 32 | 35 | } | ... | ... |
yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/controller/admin/transfer/PayTransferController.java
| ... | ... | @@ -29,8 +29,10 @@ public class PayTransferController { |
| 29 | 29 | |
| 30 | 30 | @PostMapping("/submit") |
| 31 | 31 | @Operation(summary = "提交转账订单") |
| 32 | + // TODO @jason:权限的设置 | |
| 32 | 33 | public CommonResult<PayTransferSubmitRespVO> submitPayTransfer(@Valid @RequestBody PayTransferSubmitReqVO reqVO) { |
| 33 | 34 | PayTransferSubmitRespVO respVO = payTransferService.submitTransfer(reqVO, getClientIP()); |
| 34 | 35 | return success(respVO); |
| 35 | 36 | } |
| 37 | + | |
| 36 | 38 | } | ... | ... |
yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/controller/admin/transfer/vo/PayTransferSubmitReqVO.java
yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/controller/admin/transfer/vo/PayTransferSubmitRespVO.java
yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/controller/admin/wallet/PayWalletRechargeController.java
yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/controller/admin/wallet/PayWalletTransactionController.java
| ... | ... | @@ -32,9 +32,11 @@ public class PayWalletTransactionController { |
| 32 | 32 | |
| 33 | 33 | @GetMapping("/page") |
| 34 | 34 | @Operation(summary = "获得钱包流水分页") |
| 35 | + // TODO @jason:权限校验,缺一个 | |
| 35 | 36 | public CommonResult<PageResult<PayWalletTransactionRespVO>> getWalletTransactionPage( |
| 36 | 37 | @Valid PayWalletTransactionPageReqVO pageReqVO) { |
| 37 | 38 | PageResult<PayWalletTransactionDO> result = payWalletTransactionService.getWalletTransactionPage(pageReqVO); |
| 38 | 39 | return success(PayWalletTransactionConvert.INSTANCE.convertPage2(result)); |
| 39 | 40 | } |
| 41 | + | |
| 40 | 42 | } | ... | ... |
yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/controller/admin/wallet/vo/rechargepackage/WalletRechargePackageBaseVO.java
yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/controller/admin/wallet/vo/rechargepackage/WalletRechargePackageCreateReqVO.java
| ... | ... | @@ -5,7 +5,7 @@ import lombok.Data; |
| 5 | 5 | import lombok.EqualsAndHashCode; |
| 6 | 6 | import lombok.ToString; |
| 7 | 7 | |
| 8 | -@Schema(description = "管理后台 - 套餐充值创建 Request VO") | |
| 8 | +@Schema(description = "管理后台 - 充值套餐创建 Request VO") | |
| 9 | 9 | @Data |
| 10 | 10 | @EqualsAndHashCode(callSuper = true) |
| 11 | 11 | @ToString(callSuper = true) | ... | ... |
yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/controller/admin/wallet/vo/rechargepackage/WalletRechargePackagePageReqVO.java
| ... | ... | @@ -11,7 +11,7 @@ import java.time.LocalDateTime; |
| 11 | 11 | |
| 12 | 12 | import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND; |
| 13 | 13 | |
| 14 | -@Schema(description = "管理后台 - 套餐充值分页 Request VO") | |
| 14 | +@Schema(description = "管理后台 - 充值套餐分页 Request VO") | |
| 15 | 15 | @Data |
| 16 | 16 | @EqualsAndHashCode(callSuper = true) |
| 17 | 17 | @ToString(callSuper = true) |
| ... | ... | @@ -20,6 +20,8 @@ public class WalletRechargePackagePageReqVO extends PageParam { |
| 20 | 20 | @Schema(description = "套餐名", example = "李四") |
| 21 | 21 | private String name; |
| 22 | 22 | |
| 23 | + // TODO @jason:payPrice 和 bonusPrice 可以去掉。。。一般太少检索啦; | |
| 24 | + | |
| 23 | 25 | @Schema(description = "支付金额", example = "16454") |
| 24 | 26 | private Integer payPrice; |
| 25 | 27 | ... | ... |
yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/controller/admin/wallet/vo/rechargepackage/WalletRechargePackageRespVO.java
| ... | ... | @@ -4,7 +4,7 @@ import io.swagger.v3.oas.annotations.media.Schema; |
| 4 | 4 | import lombok.*; |
| 5 | 5 | import java.time.LocalDateTime; |
| 6 | 6 | |
| 7 | -@Schema(description = "管理后台 - 套餐充值 Response VO") | |
| 7 | +@Schema(description = "管理后台 - 充值套餐 Response VO") | |
| 8 | 8 | @Data |
| 9 | 9 | @EqualsAndHashCode(callSuper = true) |
| 10 | 10 | @ToString(callSuper = true) | ... | ... |
yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/controller/admin/wallet/vo/rechargepackage/WalletRechargePackageUpdateReqVO.java
| ... | ... | @@ -7,7 +7,7 @@ import lombok.ToString; |
| 7 | 7 | |
| 8 | 8 | import javax.validation.constraints.NotNull; |
| 9 | 9 | |
| 10 | -@Schema(description = "管理后台 - 套餐充值更新 Request VO") | |
| 10 | +@Schema(description = "管理后台 - 充值套餐更新 Request VO") | |
| 11 | 11 | @Data |
| 12 | 12 | @EqualsAndHashCode(callSuper = true) |
| 13 | 13 | @ToString(callSuper = true) | ... | ... |
yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/controller/admin/wallet/vo/transaction/PayWalletTransactionPageReqVO.java
yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/controller/admin/wallet/vo/transaction/PayWalletTransactionRespVO.java
| ... | ... | @@ -29,4 +29,7 @@ public class PayWalletTransactionRespVO { |
| 29 | 29 | |
| 30 | 30 | @Schema(description = "交易时间", requiredMode = Schema.RequiredMode.REQUIRED) |
| 31 | 31 | private LocalDateTime createTime; |
| 32 | + | |
| 33 | + // TODO @jason:merchantOrderId 字段,需要在 PayWalletTransaction 存储下;然后,前端也返回下这个字段,界面也展示下商户名 | |
| 34 | + | |
| 32 | 35 | } | ... | ... |
yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/controller/admin/wallet/vo/wallet/PayWalletPageReqVO.java
| 1 | 1 | package cn.iocoder.yudao.module.pay.controller.admin.wallet.vo.wallet; |
| 2 | 2 | |
| 3 | +import cn.iocoder.yudao.framework.common.enums.UserTypeEnum; | |
| 4 | +import cn.iocoder.yudao.framework.common.validation.InEnum; | |
| 3 | 5 | import lombok.*; |
| 4 | 6 | import io.swagger.v3.oas.annotations.media.Schema; |
| 5 | 7 | import cn.iocoder.yudao.framework.common.pojo.PageParam; |
| ... | ... | @@ -18,6 +20,7 @@ public class PayWalletPageReqVO extends PageParam { |
| 18 | 20 | private Long userId; |
| 19 | 21 | |
| 20 | 22 | @Schema(description = "用户类型", example = "1") |
| 23 | + @InEnum(UserTypeEnum.class) | |
| 21 | 24 | private Integer userType; |
| 22 | 25 | |
| 23 | 26 | @Schema(description = "创建时间") | ... | ... |
yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/controller/admin/wallet/vo/wallet/PayWalletRespVO.java
yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/controller/app/wallet/vo/recharge/AppPayWalletRechargeCreateReqVO.java
| ... | ... | @@ -13,7 +13,9 @@ public class AppPayWalletRechargeCreateReqVO { |
| 13 | 13 | @Min(value = 1, message = "支付金额必须大于零") |
| 14 | 14 | private Integer payPrice; |
| 15 | 15 | |
| 16 | - | |
| 17 | 16 | @Schema(description = "充值套餐编号", example = "1024") |
| 18 | 17 | private Long packageId; |
| 18 | + | |
| 19 | + // TODO @jaosn:写个 AssertTrue 的校验方法,payPrice 和 packageId 必须二选一 | |
| 20 | + | |
| 19 | 21 | } | ... | ... |
yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/convert/wallet/PayWalletConvert.java
| ... | ... | @@ -14,7 +14,8 @@ public interface PayWalletConvert { |
| 14 | 14 | |
| 15 | 15 | AppPayWalletRespVO convert(PayWalletDO bean); |
| 16 | 16 | |
| 17 | - PayWalletRespVO convert02(PayWalletDO wallet); | |
| 17 | + PayWalletRespVO convert02(PayWalletDO bean); | |
| 18 | 18 | |
| 19 | 19 | PageResult<PayWalletRespVO> convertPage(PageResult<PayWalletDO> page); |
| 20 | + | |
| 20 | 21 | } | ... | ... |
yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/dal/dataobject/demo/PayDemoTransferDO.java
| ... | ... | @@ -20,6 +20,7 @@ import java.util.Map; |
| 20 | 20 | @KeySequence("pay_demo_transfer_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。 |
| 21 | 21 | @Data |
| 22 | 22 | public class PayDemoTransferDO extends BaseDO { |
| 23 | + | |
| 23 | 24 | /** |
| 24 | 25 | * 订单编号 |
| 25 | 26 | */ |
| ... | ... | @@ -41,6 +42,7 @@ public class PayDemoTransferDO extends BaseDO { |
| 41 | 42 | */ |
| 42 | 43 | private Integer type; |
| 43 | 44 | |
| 45 | + // TODO @jason:要不字段还是弄成正确的平铺开? | |
| 44 | 46 | /** |
| 45 | 47 | * 收款人信息,不同类型和渠道不同 |
| 46 | 48 | */ |
| ... | ... | @@ -66,4 +68,5 @@ public class PayDemoTransferDO extends BaseDO { |
| 66 | 68 | * 转账支付时间 |
| 67 | 69 | */ |
| 68 | 70 | private LocalDateTime transferTime; |
| 71 | + | |
| 69 | 72 | } |
| 70 | 73 | \ No newline at end of file | ... | ... |
yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/dal/dataobject/transfer/PayTransferDO.java
| 1 | 1 | package cn.iocoder.yudao.module.pay.dal.dataobject.transfer; |
| 2 | 2 | |
| 3 | 3 | import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; |
| 4 | +import cn.iocoder.yudao.framework.pay.core.enums.channel.PayChannelEnum; | |
| 5 | +import cn.iocoder.yudao.framework.pay.core.enums.transfer.PayTransferStatusRespEnum; | |
| 6 | +import cn.iocoder.yudao.framework.pay.core.enums.transfer.PayTransferTypeEnum; | |
| 7 | +import cn.iocoder.yudao.module.pay.dal.dataobject.app.PayAppDO; | |
| 8 | +import cn.iocoder.yudao.module.pay.dal.dataobject.channel.PayChannelDO; | |
| 4 | 9 | import com.baomidou.mybatisplus.annotation.KeySequence; |
| 5 | 10 | import com.baomidou.mybatisplus.annotation.TableField; |
| 6 | 11 | import com.baomidou.mybatisplus.annotation.TableId; |
| ... | ... | @@ -26,70 +31,76 @@ public class PayTransferDO extends BaseDO { |
| 26 | 31 | */ |
| 27 | 32 | @TableId |
| 28 | 33 | private Long id; |
| 29 | - | |
| 34 | + /** | |
| 35 | + * 应用编号 | |
| 36 | + * | |
| 37 | + * 关联 {@link PayAppDO#getId()} | |
| 38 | + */ | |
| 39 | + private Long appId; | |
| 40 | + /** | |
| 41 | + * 转账渠道编号 | |
| 42 | + * | |
| 43 | + * 关联 {@link PayChannelDO#getId()} | |
| 44 | + */ | |
| 45 | + private Long channelId; | |
| 46 | + /** | |
| 47 | + * 转账渠道编码 | |
| 48 | + * | |
| 49 | + * 枚举 {@link PayChannelEnum} | |
| 50 | + */ | |
| 51 | + private String channelCode; | |
| 30 | 52 | /** |
| 31 | 53 | * 类型 |
| 54 | + * | |
| 55 | + * 枚举 {@link PayTransferTypeEnum} | |
| 32 | 56 | */ |
| 33 | 57 | private Integer type; |
| 34 | 58 | |
| 35 | - /** | |
| 36 | - * 应用编号 | |
| 37 | - */ | |
| 38 | - private Long appId; | |
| 59 | + // ========== 商户相关字段 ========== | |
| 39 | 60 | |
| 40 | 61 | /** |
| 41 | 62 | * 商户订单编号 |
| 63 | + * | |
| 64 | + * 例如说,内部系统 A 的订单号,需要保证每个 PayAppDO 唯一 | |
| 42 | 65 | */ |
| 43 | 66 | private String merchantOrderId; |
| 44 | - | |
| 45 | - /** | |
| 46 | - * 转账金额,单位:分 | |
| 47 | - */ | |
| 48 | - private Integer price; | |
| 49 | - | |
| 67 | + // TODO @jason:这个字段,要不要改成 subject。。。和 payorderdo 保持一致;哈哈哈,我也忘记为啥当时选了这个名字了。。。 | |
| 50 | 68 | /** |
| 51 | 69 | * 转账标题 |
| 52 | 70 | */ |
| 53 | 71 | private String title; |
| 54 | 72 | |
| 73 | + // ========== 转账相关字段 ========== | |
| 55 | 74 | /** |
| 56 | - * 收款人信息,不同类型和渠道不同 | |
| 75 | + * 转账金额,单位:分 | |
| 57 | 76 | */ |
| 58 | - @TableField(typeHandler = JacksonTypeHandler.class) | |
| 59 | - private Map<String, String> payeeInfo; | |
| 60 | - | |
| 77 | + private Integer price; | |
| 61 | 78 | /** |
| 62 | 79 | * 转账状态 |
| 80 | + * | |
| 81 | + * 枚举 {@link PayTransferStatusRespEnum} | |
| 63 | 82 | */ |
| 64 | 83 | private Integer status; |
| 65 | - | |
| 66 | 84 | /** |
| 67 | 85 | * 订单转账成功时间 |
| 68 | - * | |
| 69 | 86 | */ |
| 70 | 87 | private LocalDateTime successTime; |
| 71 | - | |
| 72 | 88 | /** |
| 73 | 89 | * 转账成功的转账拓展单编号 |
| 74 | 90 | * |
| 75 | 91 | * 关联 {@link PayTransferExtensionDO#getId()} |
| 76 | 92 | */ |
| 77 | 93 | private Long extensionId; |
| 78 | - | |
| 79 | 94 | /** |
| 80 | 95 | * 转账成功的转账拓展单号 |
| 81 | 96 | * |
| 82 | 97 | * 关联 {@link PayTransferExtensionDO#getNo()} |
| 83 | 98 | */ |
| 84 | 99 | private String no; |
| 85 | - | |
| 86 | 100 | /** |
| 87 | - * 转账渠道编号 | |
| 101 | + * 收款人信息,不同类型和渠道不同 | |
| 88 | 102 | */ |
| 89 | - private Long channelId; | |
| 103 | + @TableField(typeHandler = JacksonTypeHandler.class) | |
| 104 | + private Map<String, String> payeeInfo; | |
| 90 | 105 | |
| 91 | - /** | |
| 92 | - * 转账渠道编码 | |
| 93 | - */ | |
| 94 | - private String channelCode; | |
| 95 | 106 | } |
| 96 | 107 | \ No newline at end of file | ... | ... |
yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/dal/dataobject/transfer/PayTransferExtensionDO.java
| ... | ... | @@ -10,6 +10,7 @@ import lombok.Data; |
| 10 | 10 | |
| 11 | 11 | import java.util.Map; |
| 12 | 12 | |
| 13 | +// TODO @jason:转账是不是类似 refund,不用拓展单呀?支付做拓展单的原因,是因为它存在不确定性,可以切换多种;转账和退款,都是明确方式的; | |
| 13 | 14 | /** |
| 14 | 15 | * 转账拓展单 DO |
| 15 | 16 | * |
| ... | ... | @@ -61,4 +62,5 @@ public class PayTransferExtensionDO extends BaseDO { |
| 61 | 62 | * 支付渠道异步通知的内容 |
| 62 | 63 | */ |
| 63 | 64 | private String channelNotifyData; |
| 65 | + | |
| 64 | 66 | } |
| 65 | 67 | \ No newline at end of file | ... | ... |
yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/dal/dataobject/wallet/PayWalletRechargeDO.java
| ... | ... | @@ -42,7 +42,6 @@ public class PayWalletRechargeDO extends BaseDO { |
| 42 | 42 | * 实际支付金额 |
| 43 | 43 | */ |
| 44 | 44 | private Integer payPrice; |
| 45 | - | |
| 46 | 45 | /** |
| 47 | 46 | * 钱包赠送金额 |
| 48 | 47 | */ |
| ... | ... | @@ -50,8 +49,10 @@ public class PayWalletRechargeDO extends BaseDO { |
| 50 | 49 | |
| 51 | 50 | /** |
| 52 | 51 | * 充值套餐编号 |
| 52 | + * | |
| 53 | + * 关联 {@link PayWalletRechargeDO#getPackageId()} 字段 | |
| 53 | 54 | */ |
| 54 | - private Long packageId; | |
| 55 | + private Long packageId; | |
| 55 | 56 | |
| 56 | 57 | /** |
| 57 | 58 | * 是否已支付 | ... | ... |
yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/dal/dataobject/wallet/PayWalletRechargePackageDO.java
yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/dal/mysql/demo/PayDemoTransferMapper.java
yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/dal/mysql/transfer/PayTransferExtensionMapper.java
| ... | ... | @@ -14,10 +14,11 @@ public interface PayTransferExtensionMapper extends BaseMapperX<PayTransferExten |
| 14 | 14 | return selectOne(PayTransferExtensionDO::getNo, no); |
| 15 | 15 | } |
| 16 | 16 | |
| 17 | - default int updateByIdAndStatus(Long id, List<Integer> status, PayTransferExtensionDO updateObj){ | |
| 17 | + default int updateByIdAndStatus(Long id, List<Integer> whereStatuses, PayTransferExtensionDO updateObj) { | |
| 18 | 18 | return update(updateObj, new LambdaQueryWrapper<PayTransferExtensionDO>() |
| 19 | - .eq(PayTransferExtensionDO::getId, id).in(PayTransferExtensionDO::getStatus, status)); | |
| 19 | + .eq(PayTransferExtensionDO::getId, id).in(PayTransferExtensionDO::getStatus, whereStatuses)); | |
| 20 | 20 | } |
| 21 | + | |
| 21 | 22 | } |
| 22 | 23 | |
| 23 | 24 | ... | ... |
yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/dal/mysql/transfer/PayTransferMapper.java
yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/dal/mysql/wallet/PayWalletMapper.java
| ... | ... | @@ -70,6 +70,7 @@ public interface PayWalletMapper extends BaseMapperX<PayWalletDO> { |
| 70 | 70 | |
| 71 | 71 | /** |
| 72 | 72 | * 冻结钱包部分余额 |
| 73 | + * | |
| 73 | 74 | * @param id 钱包 id |
| 74 | 75 | * @param price 冻结金额 |
| 75 | 76 | */ |
| ... | ... | @@ -84,6 +85,7 @@ public interface PayWalletMapper extends BaseMapperX<PayWalletDO> { |
| 84 | 85 | |
| 85 | 86 | /** |
| 86 | 87 | * 解冻钱包余额 |
| 88 | + * | |
| 87 | 89 | * @param id 钱包 id |
| 88 | 90 | * @param price 解冻金额 |
| 89 | 91 | */ |
| ... | ... | @@ -98,6 +100,7 @@ public interface PayWalletMapper extends BaseMapperX<PayWalletDO> { |
| 98 | 100 | |
| 99 | 101 | /** |
| 100 | 102 | * 当充值退款时, 更新钱包 |
| 103 | + * | |
| 101 | 104 | * @param id 钱包 id |
| 102 | 105 | * @param price 退款金额 |
| 103 | 106 | */ | ... | ... |
yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/dal/mysql/wallet/PayWalletRechargeMapper.java
| ... | ... | @@ -18,8 +18,4 @@ public interface PayWalletRechargeMapper extends BaseMapperX<PayWalletRechargeDO |
| 18 | 18 | .eq(PayWalletRechargeDO::getId, id).eq(PayWalletRechargeDO::getRefundStatus, whereRefundStatus)); |
| 19 | 19 | } |
| 20 | 20 | |
| 21 | -} | |
| 22 | - | |
| 23 | - | |
| 24 | - | |
| 25 | - | |
| 21 | +} | |
| 26 | 22 | \ No newline at end of file | ... | ... |
yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/dal/mysql/wallet/PayWalletRechargePackageMapper.java
| ... | ... | @@ -12,6 +12,7 @@ import org.apache.ibatis.annotations.Mapper; |
| 12 | 12 | public interface PayWalletRechargePackageMapper extends BaseMapperX<PayWalletRechargePackageDO> { |
| 13 | 13 | |
| 14 | 14 | default PageResult<PayWalletRechargePackageDO> selectPage(WalletRechargePackagePageReqVO reqVO) { |
| 15 | + // TODO @jason:排序按照充值金额 | |
| 15 | 16 | return selectPage(reqVO, new LambdaQueryWrapperX<PayWalletRechargePackageDO>() |
| 16 | 17 | .likeIfPresent(PayWalletRechargePackageDO::getName, reqVO.getName()) |
| 17 | 18 | .eqIfPresent(PayWalletRechargePackageDO::getPayPrice, reqVO.getPayPrice()) |
| ... | ... | @@ -20,8 +21,5 @@ public interface PayWalletRechargePackageMapper extends BaseMapperX<PayWalletRec |
| 20 | 21 | .betweenIfPresent(PayWalletRechargePackageDO::getCreateTime, reqVO.getCreateTime()) |
| 21 | 22 | .orderByDesc(PayWalletRechargePackageDO::getId)); |
| 22 | 23 | } |
| 23 | -} | |
| 24 | - | |
| 25 | - | |
| 26 | - | |
| 27 | 24 | |
| 25 | +} | |
| 28 | 26 | \ No newline at end of file | ... | ... |
yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/framework/pay/core/WalletPayClient.java
yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/service/demo/PayDemoTransferServiceImpl.java
| ... | ... | @@ -64,6 +64,7 @@ public class PayDemoTransferServiceImpl implements PayDemoTransferService { |
| 64 | 64 | return demoTransfer.getId(); |
| 65 | 65 | } |
| 66 | 66 | |
| 67 | + // TODO @jason:可以参考 AppBrokerageWithdrawCreateReqVO 搞下字段哈,进行校验 | |
| 67 | 68 | private void validatePayeeInfo(Integer transferType, Map<String, String> payeeInfo) { |
| 68 | 69 | PayTransferTypeEnum transferTypeEnum = ofType(transferType); |
| 69 | 70 | switch (transferTypeEnum) { |
| ... | ... | @@ -83,4 +84,5 @@ public class PayDemoTransferServiceImpl implements PayDemoTransferService { |
| 83 | 84 | } |
| 84 | 85 | } |
| 85 | 86 | } |
| 87 | + | |
| 86 | 88 | } | ... | ... |
yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/service/transfer/PayTransferService.java
| ... | ... | @@ -7,6 +7,8 @@ import cn.iocoder.yudao.module.pay.controller.admin.transfer.vo.PayTransferSubmi |
| 7 | 7 | import javax.validation.Valid; |
| 8 | 8 | |
| 9 | 9 | /** |
| 10 | + * 转账 Service 接口 | |
| 11 | + * | |
| 10 | 12 | * @author jason |
| 11 | 13 | */ |
| 12 | 14 | public interface PayTransferService { |
| ... | ... | @@ -29,4 +31,5 @@ public interface PayTransferService { |
| 29 | 31 | * @return 转账单编号 |
| 30 | 32 | */ |
| 31 | 33 | Long createTransfer(@Valid PayTransferCreateReqDTO reqDTO); |
| 34 | + | |
| 32 | 35 | } | ... | ... |
yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/service/transfer/PayTransferServiceImpl.java
| ... | ... | @@ -34,7 +34,10 @@ import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionU |
| 34 | 34 | import static cn.iocoder.yudao.module.pay.enums.ErrorCodeConstants.*; |
| 35 | 35 | import static cn.iocoder.yudao.module.pay.enums.transfer.PayTransferStatusEnum.*; |
| 36 | 36 | |
| 37 | +// TODO @jason:等彻底实现完,单测写写; | |
| 37 | 38 | /** |
| 39 | + * 转账 Service 实现类 | |
| 40 | + * | |
| 38 | 41 | * @author jason |
| 39 | 42 | */ |
| 40 | 43 | @Service |
| ... | ... | @@ -47,10 +50,12 @@ public class PayTransferServiceImpl implements PayTransferService { |
| 47 | 50 | private PayTransferMapper transferMapper; |
| 48 | 51 | @Resource |
| 49 | 52 | private PayTransferExtensionMapper transferExtensionMapper; |
| 53 | + | |
| 50 | 54 | @Resource |
| 51 | 55 | private PayAppService appService; |
| 52 | 56 | @Resource |
| 53 | 57 | private PayChannelService channelService; |
| 58 | + | |
| 54 | 59 | @Resource |
| 55 | 60 | private PayNoRedisDAO noRedisDAO; |
| 56 | 61 | |
| ... | ... | @@ -64,7 +69,7 @@ public class PayTransferServiceImpl implements PayTransferService { |
| 64 | 69 | PayChannelDO channel = validateChannelCanSubmit(transfer.getAppId(), reqVO.getChannelCode()); |
| 65 | 70 | PayClient client = channelService.getPayClient(channel.getId()); |
| 66 | 71 | |
| 67 | - // 2 新增转账拓展单 | |
| 72 | + // 2. 新增转账拓展单 | |
| 68 | 73 | String no = noRedisDAO.generate(TRANSFER_NO_PREFIX); |
| 69 | 74 | PayTransferExtensionDO transferExtension = new PayTransferExtensionDO().setNo(no) |
| 70 | 75 | .setTransferId(transfer.getId()).setChannelId(channel.getId()) |
| ... | ... | @@ -112,8 +117,9 @@ public class PayTransferServiceImpl implements PayTransferService { |
| 112 | 117 | notifyTransferClosed(channel, notify); |
| 113 | 118 | } |
| 114 | 119 | // WAITING 状态无需处理 |
| 115 | - // TODO IN_PROGRESS 待处理 | |
| 120 | + // TODO IN_PROGRESS 待处理 | |
| 116 | 121 | } |
| 122 | + | |
| 117 | 123 | private void notifyTransferSuccess(PayChannelDO channel, PayTransferRespDTO notify) { |
| 118 | 124 | // 1. 更新 PayTransferExtensionDO 转账成功 |
| 119 | 125 | PayTransferExtensionDO transferExtension = updateTransferExtensionSuccess(notify); |
| ... | ... | @@ -121,7 +127,7 @@ public class PayTransferServiceImpl implements PayTransferService { |
| 121 | 127 | // 2. 更新 PayTransferDO 转账成功 |
| 122 | 128 | Boolean transferred = updateTransferSuccess(channel,transferExtension, notify); |
| 123 | 129 | if (transferred) { |
| 124 | - return ; | |
| 130 | + return; | |
| 125 | 131 | } |
| 126 | 132 | // 3. TODO 插入转账通知记录 |
| 127 | 133 | } | ... | ... |
yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/service/wallet/PayWalletRechargePackageService.java
| ... | ... | @@ -31,7 +31,7 @@ public interface PayWalletRechargePackageService { |
| 31 | 31 | PayWalletRechargePackageDO validWalletRechargePackage(Long packageId); |
| 32 | 32 | |
| 33 | 33 | /** |
| 34 | - * 创建套餐充值 | |
| 34 | + * 创建充值套餐 | |
| 35 | 35 | * |
| 36 | 36 | * @param createReqVO 创建信息 |
| 37 | 37 | * @return 编号 |
| ... | ... | @@ -39,33 +39,25 @@ public interface PayWalletRechargePackageService { |
| 39 | 39 | Long createWalletRechargePackage(@Valid WalletRechargePackageCreateReqVO createReqVO); |
| 40 | 40 | |
| 41 | 41 | /** |
| 42 | - * 更新套餐充值 | |
| 42 | + * 更新充值套餐 | |
| 43 | 43 | * |
| 44 | 44 | * @param updateReqVO 更新信息 |
| 45 | 45 | */ |
| 46 | 46 | void updateWalletRechargePackage(@Valid WalletRechargePackageUpdateReqVO updateReqVO); |
| 47 | 47 | |
| 48 | - | |
| 49 | 48 | /** |
| 50 | - * 删除套餐充值 | |
| 49 | + * 删除充值套餐 | |
| 51 | 50 | * |
| 52 | 51 | * @param id 编号 |
| 53 | 52 | */ |
| 54 | 53 | void deleteWalletRechargePackage(Long id); |
| 55 | 54 | |
| 56 | 55 | /** |
| 57 | - * 获得套餐充值列表 | |
| 58 | - * | |
| 59 | - * @param ids 编号 | |
| 60 | - * @return 套餐充值列表 | |
| 61 | - */ | |
| 62 | - List<PayWalletRechargePackageDO> getWalletRechargePackageList(Collection<Long> ids); | |
| 63 | - | |
| 64 | - /** | |
| 65 | - * 获得套餐充值分页 | |
| 56 | + * 获得充值套餐分页 | |
| 66 | 57 | * |
| 67 | 58 | * @param pageReqVO 分页查询 |
| 68 | - * @return 套餐充值分页 | |
| 59 | + * @return 充值套餐分页 | |
| 69 | 60 | */ |
| 70 | 61 | PageResult<PayWalletRechargePackageDO> getWalletRechargePackagePage(WalletRechargePackagePageReqVO pageReqVO); |
| 62 | + | |
| 71 | 63 | } | ... | ... |
yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/service/wallet/PayWalletRechargePackageServiceImpl.java
| ... | ... | @@ -57,6 +57,7 @@ public class PayWalletRechargePackageServiceImpl implements PayWalletRechargePac |
| 57 | 57 | return walletRechargePackage.getId(); |
| 58 | 58 | } |
| 59 | 59 | |
| 60 | + // TODO @jason:校验下,套餐名唯一 | |
| 60 | 61 | @Override |
| 61 | 62 | public void updateWalletRechargePackage(WalletRechargePackageUpdateReqVO updateReqVO) { |
| 62 | 63 | // 校验存在 |
| ... | ... | @@ -81,14 +82,6 @@ public class PayWalletRechargePackageServiceImpl implements PayWalletRechargePac |
| 81 | 82 | } |
| 82 | 83 | |
| 83 | 84 | @Override |
| 84 | - public List<PayWalletRechargePackageDO> getWalletRechargePackageList(Collection<Long> ids) { | |
| 85 | - if (CollUtil.isEmpty(ids)) { | |
| 86 | - return ListUtil.empty(); | |
| 87 | - } | |
| 88 | - return walletRechargePackageMapper.selectBatchIds(ids); | |
| 89 | - } | |
| 90 | - | |
| 91 | - @Override | |
| 92 | 85 | public PageResult<PayWalletRechargePackageDO> getWalletRechargePackagePage(WalletRechargePackagePageReqVO pageReqVO) { |
| 93 | 86 | return walletRechargePackageMapper.selectPage(pageReqVO); |
| 94 | 87 | } | ... | ... |
yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/service/wallet/PayWalletRechargeServiceImpl.java
| ... | ... | @@ -44,7 +44,7 @@ import static cn.iocoder.yudao.module.pay.enums.refund.PayRefundStatusEnum.*; |
| 44 | 44 | public class PayWalletRechargeServiceImpl implements PayWalletRechargeService { |
| 45 | 45 | |
| 46 | 46 | /** |
| 47 | - * TODO 放到 配置文件中 | |
| 47 | + * TODO 芋艿:放到 payconfig | |
| 48 | 48 | */ |
| 49 | 49 | private static final Long WALLET_PAY_APP_ID = 8L; |
| 50 | 50 | |
| ... | ... | @@ -65,13 +65,14 @@ public class PayWalletRechargeServiceImpl implements PayWalletRechargeService { |
| 65 | 65 | @Transactional(rollbackFor = Exception.class) |
| 66 | 66 | public PayWalletRechargeDO createWalletRecharge(Long userId, Integer userType, |
| 67 | 67 | AppPayWalletRechargeCreateReqVO reqVO) { |
| 68 | - // 1.1 校验参数 | |
| 68 | + // 1.1 校验参数 TODO @jason:AppPayWalletRechargeCreateReqVO 看下校验; | |
| 69 | 69 | if (Objects.isNull(reqVO.getPayPrice()) && Objects.isNull(reqVO.getPackageId())) { |
| 70 | 70 | throw exception(WALLET_RECHARGE_PACKAGE_AND_PRICE_IS_EMPTY); |
| 71 | 71 | } |
| 72 | - // 1.2 新增钱包充值记录 | |
| 73 | - int payPrice ; | |
| 74 | - int bonusPrice = 0 ; | |
| 72 | + | |
| 73 | + // 1.1 计算充值金额 | |
| 74 | + int payPrice; | |
| 75 | + int bonusPrice = 0; | |
| 75 | 76 | if (Objects.nonNull(reqVO.getPackageId())) { |
| 76 | 77 | PayWalletRechargePackageDO rechargePackage = payWalletRechargePackageService.validWalletRechargePackage(reqVO.getPackageId()); |
| 77 | 78 | payPrice = rechargePackage.getPayPrice(); |
| ... | ... | @@ -79,23 +80,22 @@ public class PayWalletRechargeServiceImpl implements PayWalletRechargeService { |
| 79 | 80 | } else { |
| 80 | 81 | payPrice = reqVO.getPayPrice(); |
| 81 | 82 | } |
| 82 | - | |
| 83 | + // 1.2 插入充值记录 | |
| 83 | 84 | PayWalletDO wallet = payWalletService.getOrCreateWallet(userId, userType); |
| 84 | - PayWalletRechargeDO walletRecharge = INSTANCE.convert(wallet.getId(), payPrice, bonusPrice, reqVO.getPackageId()); | |
| 85 | - walletRechargeMapper.insert(walletRecharge); | |
| 85 | + PayWalletRechargeDO recharge = INSTANCE.convert(wallet.getId(), payPrice, bonusPrice, reqVO.getPackageId()); | |
| 86 | + walletRechargeMapper.insert(recharge); | |
| 86 | 87 | |
| 87 | 88 | // 2.1 创建支付单 |
| 88 | 89 | Long payOrderId = payOrderService.createOrder(new PayOrderCreateReqDTO() |
| 89 | - .setAppId(WALLET_PAY_APP_ID).setUserIp(getClientIP()) | |
| 90 | - .setMerchantOrderId(walletRecharge.getId().toString()) // 业务的订单编号 | |
| 91 | - .setSubject(WALLET_RECHARGE_ORDER_SUBJECT).setBody("").setPrice(walletRecharge.getPayPrice()) | |
| 92 | - .setExpireTime(addTime(Duration.ofHours(2L)))); | |
| 90 | + .setAppId(WALLET_PAY_APP_ID).setUserIp(getClientIP()) // TODO @jason:clientIp 从 controller 传递进来噢 | |
| 91 | + .setMerchantOrderId(recharge.getId().toString()) // 业务的订单编号 | |
| 92 | + .setSubject(WALLET_RECHARGE_ORDER_SUBJECT).setBody("") | |
| 93 | + .setPrice(recharge.getPayPrice()) | |
| 94 | + .setExpireTime(addTime(Duration.ofHours(2L)))); // TODO @芋艿:支付超时时间 | |
| 93 | 95 | // 2.2 更新钱包充值记录中支付订单 |
| 94 | - walletRechargeMapper.updateById(new PayWalletRechargeDO().setPayOrderId(payOrderId) | |
| 95 | - .setId(walletRecharge.getId())); | |
| 96 | - | |
| 97 | - walletRecharge.setPayOrderId(payOrderId); | |
| 98 | - return walletRecharge; | |
| 96 | + walletRechargeMapper.updateById(new PayWalletRechargeDO().setId(recharge.getId()).setPayOrderId(payOrderId)); | |
| 97 | + recharge.setPayOrderId(payOrderId); | |
| 98 | + return recharge; | |
| 99 | 99 | } |
| 100 | 100 | |
| 101 | 101 | @Override |
| ... | ... | @@ -136,9 +136,11 @@ public class PayWalletRechargeServiceImpl implements PayWalletRechargeService { |
| 136 | 136 | } |
| 137 | 137 | // 1.2 校验钱包充值是否可以发起退款 |
| 138 | 138 | PayWalletDO wallet = validateWalletRechargeCanRefund(walletRecharge); |
| 139 | - // 2 冻结退款的余额, 暂时只处理赠送的余额也全部退回 | |
| 139 | + | |
| 140 | + // 2. 冻结退款的余额,暂时只处理赠送的余额也全部退回 | |
| 140 | 141 | payWalletService.freezePrice(wallet.getId(), walletRecharge.getTotalPrice()); |
| 141 | - // 3 创建退款单 | |
| 142 | + | |
| 143 | + // 3. 创建退款单 | |
| 142 | 144 | String walletRechargeId = String.valueOf(id); |
| 143 | 145 | String refundId = walletRechargeId + "-refund"; |
| 144 | 146 | Long payRefundId = payRefundService.createPayRefund(new PayRefundCreateReqDTO() |
| ... | ... | @@ -146,7 +148,9 @@ public class PayWalletRechargeServiceImpl implements PayWalletRechargeService { |
| 146 | 148 | .setMerchantOrderId(walletRechargeId) |
| 147 | 149 | .setMerchantRefundId(refundId) |
| 148 | 150 | .setReason("想退钱").setPrice(walletRecharge.getPayPrice())); |
| 149 | - // 4 更新充值记录退款单号 | |
| 151 | + | |
| 152 | + // 4. 更新充值记录退款单号 | |
| 153 | + // TODO @jaosn:一般新建这种 update 对象,建议是,第一个 set id 属性,容易知道以它为更新 | |
| 150 | 154 | walletRechargeMapper.updateById(new PayWalletRechargeDO().setPayRefundId(payRefundId) |
| 151 | 155 | .setRefundStatus(WAITING.getStatus()).setId(walletRecharge.getId())); |
| 152 | 156 | } |
| ... | ... | @@ -229,6 +233,7 @@ public class PayWalletRechargeServiceImpl implements PayWalletRechargeService { |
| 229 | 233 | if (wallet.getBalance() < walletRecharge.getTotalPrice()) { |
| 230 | 234 | throw exception(WALLET_RECHARGE_REFUND_BALANCE_NOT_ENOUGH); |
| 231 | 235 | } |
| 236 | + // TODO @芋艿:需要考虑下,赠送的金额,会不会导致提现超过; | |
| 232 | 237 | return wallet; |
| 233 | 238 | } |
| 234 | 239 | ... | ... |
yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/service/wallet/PayWalletService.java
yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/service/wallet/PayWalletServiceImpl.java
| ... | ... | @@ -109,6 +109,7 @@ public class PayWalletServiceImpl implements PayWalletService { |
| 109 | 109 | if (walletTransaction == null) { |
| 110 | 110 | throw exception(WALLET_TRANSACTION_NOT_FOUND); |
| 111 | 111 | } |
| 112 | + // 2. 校验退款是否存在 | |
| 112 | 113 | PayWalletTransactionDO refundTransaction = walletTransactionService.getWalletTransaction( |
| 113 | 114 | String.valueOf(refundId), PAYMENT_REFUND); |
| 114 | 115 | if (refundTransaction != null) { |
| ... | ... | @@ -128,7 +129,7 @@ public class PayWalletServiceImpl implements PayWalletService { |
| 128 | 129 | } |
| 129 | 130 | |
| 130 | 131 | // 2.1 扣除余额 |
| 131 | - int updateCounts = 0 ; | |
| 132 | + int updateCounts; | |
| 132 | 133 | switch (bizType) { |
| 133 | 134 | case PAYMENT: { |
| 134 | 135 | updateCounts = walletMapper.updateWhenConsumption(payWallet.getId(), price); | ... | ... |
yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/api/social/SocialClientApi.java
0 → 100644
| 1 | +package cn.iocoder.yudao.module.system.api.social; | |
| 2 | + | |
| 3 | +import cn.iocoder.yudao.module.system.api.social.dto.SocialWxJsapiSignatureRespDTO; | |
| 4 | +import cn.iocoder.yudao.module.system.api.social.dto.SocialWxPhoneNumberInfoRespDTO; | |
| 5 | +import cn.iocoder.yudao.module.system.enums.social.SocialTypeEnum; | |
| 6 | + | |
| 7 | +/** | |
| 8 | + * 社交应用的 API 接口 | |
| 9 | + * | |
| 10 | + * @author 芋道源码 | |
| 11 | + */ | |
| 12 | +public interface SocialClientApi { | |
| 13 | + | |
| 14 | + /** | |
| 15 | + * 获得社交平台的授权 URL | |
| 16 | + * | |
| 17 | + * @param type 社交平台的类型 {@link SocialTypeEnum} | |
| 18 | + * @param userType 用户类型 | |
| 19 | + * @param redirectUri 重定向 URL | |
| 20 | + * @return 社交平台的授权 URL | |
| 21 | + */ | |
| 22 | + String getAuthorizeUrl(Integer type, Integer userType, String redirectUri); | |
| 23 | + | |
| 24 | + /** | |
| 25 | + * 创建微信公众号 JS SDK 初始化所需的签名 | |
| 26 | + * | |
| 27 | + * @param userType 用户类型 | |
| 28 | + * @param url 访问的 URL 地址 | |
| 29 | + * @return 签名 | |
| 30 | + */ | |
| 31 | + SocialWxJsapiSignatureRespDTO createWxMpJsapiSignature(Integer userType, String url); | |
| 32 | + | |
| 33 | + /** | |
| 34 | + * 获得微信小程序的手机信息 | |
| 35 | + * | |
| 36 | + * @param userType 用户类型 | |
| 37 | + * @param phoneCode 手机授权码 | |
| 38 | + * @return 手机信息 | |
| 39 | + */ | |
| 40 | + SocialWxPhoneNumberInfoRespDTO getWxMaPhoneNumberInfo(Integer userType, String phoneCode); | |
| 41 | + | |
| 42 | +} | ... | ... |
yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/api/social/SocialUserApi.java
| ... | ... | @@ -4,7 +4,6 @@ import cn.iocoder.yudao.framework.common.exception.ServiceException; |
| 4 | 4 | import cn.iocoder.yudao.module.system.api.social.dto.SocialUserBindReqDTO; |
| 5 | 5 | import cn.iocoder.yudao.module.system.api.social.dto.SocialUserRespDTO; |
| 6 | 6 | import cn.iocoder.yudao.module.system.api.social.dto.SocialUserUnbindReqDTO; |
| 7 | -import cn.iocoder.yudao.module.system.enums.social.SocialTypeEnum; | |
| 8 | 7 | |
| 9 | 8 | import javax.validation.Valid; |
| 10 | 9 | |
| ... | ... | @@ -16,15 +15,6 @@ import javax.validation.Valid; |
| 16 | 15 | public interface SocialUserApi { |
| 17 | 16 | |
| 18 | 17 | /** |
| 19 | - * 获得社交平台的授权 URL | |
| 20 | - * | |
| 21 | - * @param type 社交平台的类型 {@link SocialTypeEnum} | |
| 22 | - * @param redirectUri 重定向 URL | |
| 23 | - * @return 社交平台的授权 URL | |
| 24 | - */ | |
| 25 | - String getAuthorizeUrl(Integer type, String redirectUri); | |
| 26 | - | |
| 27 | - /** | |
| 28 | 18 | * 绑定社交用户 |
| 29 | 19 | * |
| 30 | 20 | * @param reqDTO 绑定信息 | ... | ... |
yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/api/social/dto/SocialUserBindReqDTO.java
yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/api/social/dto/SocialUserUnbindReqDTO.java
| ... | ... | @@ -33,12 +33,12 @@ public class SocialUserUnbindReqDTO { |
| 33 | 33 | */ |
| 34 | 34 | @InEnum(SocialTypeEnum.class) |
| 35 | 35 | @NotNull(message = "社交平台的类型不能为空") |
| 36 | - private Integer type; | |
| 36 | + private Integer socialType; | |
| 37 | 37 | |
| 38 | 38 | /** |
| 39 | - * 社交平台的 unionId | |
| 39 | + * 社交平台的 openid | |
| 40 | 40 | */ |
| 41 | - @NotEmpty(message = "社交平台的 unionId 不能为空") | |
| 42 | - private String unionId; | |
| 41 | + @NotEmpty(message = "社交平台的 openid 不能为空") | |
| 42 | + private String openid; | |
| 43 | 43 | |
| 44 | 44 | } | ... | ... |
yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/api/social/dto/SocialWxJsapiSignatureRespDTO.java
0 → 100644
| 1 | +package cn.iocoder.yudao.module.system.api.social.dto; | |
| 2 | + | |
| 3 | +import lombok.Data; | |
| 4 | + | |
| 5 | +/** | |
| 6 | + * 微信公众号 JSAPI 签名 Response DTO | |
| 7 | + * | |
| 8 | + * @author 芋道源码 | |
| 9 | + */ | |
| 10 | +@Data | |
| 11 | +public class SocialWxJsapiSignatureRespDTO { | |
| 12 | + | |
| 13 | + /** | |
| 14 | + * 微信公众号的 appId | |
| 15 | + */ | |
| 16 | + private String appId; | |
| 17 | + /** | |
| 18 | + * 匿名串 | |
| 19 | + */ | |
| 20 | + private String nonceStr; | |
| 21 | + /** | |
| 22 | + * 时间戳 | |
| 23 | + */ | |
| 24 | + private Long timestamp; | |
| 25 | + /** | |
| 26 | + * URL | |
| 27 | + */ | |
| 28 | + private String url; | |
| 29 | + /** | |
| 30 | + * 签名 | |
| 31 | + */ | |
| 32 | + private String signature; | |
| 33 | + | |
| 34 | +} | ... | ... |
yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/api/social/dto/SocialWxPhoneNumberInfoRespDTO.java
0 → 100644
| 1 | +package cn.iocoder.yudao.module.system.api.social.dto; | |
| 2 | + | |
| 3 | +import lombok.Data; | |
| 4 | + | |
| 5 | +/** | |
| 6 | + * 微信小程序的手机信息 Response DTO | |
| 7 | + * | |
| 8 | + * @author 芋道源码 | |
| 9 | + */ | |
| 10 | +@Data | |
| 11 | +public class SocialWxPhoneNumberInfoRespDTO { | |
| 12 | + | |
| 13 | + /** | |
| 14 | + * 用户绑定的手机号(国外手机号会有区号) | |
| 15 | + */ | |
| 16 | + private String phoneNumber; | |
| 17 | + | |
| 18 | + /** | |
| 19 | + * 没有区号的手机号 | |
| 20 | + */ | |
| 21 | + private String purePhoneNumber; | |
| 22 | + /** | |
| 23 | + * 区号 | |
| 24 | + */ | |
| 25 | + private String countryCode; | |
| 26 | + | |
| 27 | +} | ... | ... |
yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/enums/ErrorCodeConstants.java
| ... | ... | @@ -119,6 +119,8 @@ public interface ErrorCodeConstants { |
| 119 | 119 | ErrorCode SOCIAL_USER_UNBIND_NOT_SELF = new ErrorCode(1_002_018_001, "社交解绑失败,非当前用户绑定"); |
| 120 | 120 | ErrorCode SOCIAL_USER_NOT_FOUND = new ErrorCode(1_002_018_002, "社交授权失败,找不到对应的用户"); |
| 121 | 121 | |
| 122 | + ErrorCode SOCIAL_APP_WEIXIN_MINI_APP_PHONE_CODE_ERROR = new ErrorCode(1_002_018_103, "获得手机号失败"); | |
| 123 | + | |
| 122 | 124 | // ========== 系统敏感词 1-002-019-000 ========= |
| 123 | 125 | ErrorCode SENSITIVE_WORD_NOT_EXISTS = new ErrorCode(1_002_019_000, "系统敏感词在所有标签中都不存在"); |
| 124 | 126 | ErrorCode SENSITIVE_WORD_EXISTS = new ErrorCode(1_002_019_001, "系统敏感词已在标签中存在"); | ... | ... |
yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/enums/social/SocialTypeEnum.java
| ... | ... | @@ -18,33 +18,39 @@ public enum SocialTypeEnum implements IntArrayValuable { |
| 18 | 18 | |
| 19 | 19 | /** |
| 20 | 20 | * Gitee |
| 21 | - * 文档链接:https://gitee.com/api/v5/oauth_doc#/ | |
| 21 | + * | |
| 22 | + * @see <a href="https://gitee.com/api/v5/oauth_doc#/">接入文档</a> | |
| 22 | 23 | */ |
| 23 | 24 | GITEE(10, "GITEE"), |
| 24 | 25 | /** |
| 25 | 26 | * 钉钉 |
| 26 | - * 文档链接:https://developers.dingtalk.com/document/app/obtain-identity-credentials | |
| 27 | + * | |
| 28 | + * @see <a href="https://developers.dingtalk.com/document/app/obtain-identity-credentials">接入文档</a> | |
| 27 | 29 | */ |
| 28 | 30 | DINGTALK(20, "DINGTALK"), |
| 29 | 31 | |
| 30 | 32 | /** |
| 31 | 33 | * 企业微信 |
| 32 | - * 文档链接:https://xkcoding.com/2019/08/06/use-justauth-integration-wechat-enterprise.html | |
| 34 | + * | |
| 35 | + * @see <a href="https://xkcoding.com/2019/08/06/use-justauth-integration-wechat-enterprise.html">接入文档</a> | |
| 33 | 36 | */ |
| 34 | 37 | WECHAT_ENTERPRISE(30, "WECHAT_ENTERPRISE"), |
| 35 | 38 | /** |
| 36 | 39 | * 微信公众平台 - 移动端 H5 |
| 37 | - * 文档链接:https://www.cnblogs.com/juewuzhe/p/11905461.html | |
| 40 | + * | |
| 41 | + * @see <a href="https://www.cnblogs.com/juewuzhe/p/11905461.html">接入文档</a> | |
| 38 | 42 | */ |
| 39 | 43 | WECHAT_MP(31, "WECHAT_MP"), |
| 40 | 44 | /** |
| 41 | 45 | * 微信开放平台 - 网站应用 PC 端扫码授权登录 |
| 42 | - * 文档链接:https://justauth.wiki/guide/oauth/wechat_open/#_2-申请开发者资质认证 | |
| 46 | + * | |
| 47 | + * @see <a href="https://justauth.wiki/guide/oauth/wechat_open/#_2-申请开发者资质认证">接入文档</a> | |
| 43 | 48 | */ |
| 44 | 49 | WECHAT_OPEN(32, "WECHAT_OPEN"), |
| 45 | 50 | /** |
| 46 | 51 | * 微信小程序 |
| 47 | - * 文档链接:https://developers.weixin.qq.com/miniprogram/dev/framework/open-ability/login.html | |
| 52 | + * | |
| 53 | + * @see <a href="https://developers.weixin.qq.com/miniprogram/dev/framework/open-ability/login.html">接入文档</a> | |
| 48 | 54 | */ |
| 49 | 55 | WECHAT_MINI_APP(34, "WECHAT_MINI_APP"), |
| 50 | 56 | ; | ... | ... |
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/api/social/SocialClientApiImpl.java
0 → 100644
| 1 | +package cn.iocoder.yudao.module.system.api.social; | |
| 2 | + | |
| 3 | +import cn.binarywang.wx.miniapp.bean.WxMaPhoneNumberInfo; | |
| 4 | +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.convert.social.SocialClientConvert; | |
| 7 | +import cn.iocoder.yudao.module.system.service.social.SocialClientService; | |
| 8 | +import me.chanjar.weixin.common.bean.WxJsapiSignature; | |
| 9 | +import org.springframework.stereotype.Service; | |
| 10 | +import org.springframework.validation.annotation.Validated; | |
| 11 | + | |
| 12 | +import javax.annotation.Resource; | |
| 13 | + | |
| 14 | +/** | |
| 15 | + * 社交应用的 API 实现类 | |
| 16 | + * | |
| 17 | + * @author 芋道源码 | |
| 18 | + */ | |
| 19 | +@Service | |
| 20 | +@Validated | |
| 21 | +public class SocialClientApiImpl implements SocialClientApi { | |
| 22 | + | |
| 23 | + @Resource | |
| 24 | + private SocialClientService socialClientService; | |
| 25 | + | |
| 26 | + @Override | |
| 27 | + public String getAuthorizeUrl(Integer type, Integer userType, String redirectUri) { | |
| 28 | + return socialClientService.getAuthorizeUrl(type, userType, redirectUri); | |
| 29 | + } | |
| 30 | + | |
| 31 | + @Override | |
| 32 | + public SocialWxJsapiSignatureRespDTO createWxMpJsapiSignature(Integer userType, String url) { | |
| 33 | + WxJsapiSignature signature = socialClientService.createWxMpJsapiSignature(userType, url); | |
| 34 | + return SocialClientConvert.INSTANCE.convert(signature); | |
| 35 | + } | |
| 36 | + | |
| 37 | + @Override | |
| 38 | + public SocialWxPhoneNumberInfoRespDTO getWxMaPhoneNumberInfo(Integer userType, String phoneCode) { | |
| 39 | + WxMaPhoneNumberInfo info = socialClientService.getWxMaPhoneNumberInfo(userType, phoneCode); | |
| 40 | + return SocialClientConvert.INSTANCE.convert(info); | |
| 41 | + } | |
| 42 | + | |
| 43 | +} | ... | ... |
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/api/social/SocialUserApiImpl.java
| ... | ... | @@ -22,11 +22,6 @@ public class SocialUserApiImpl implements SocialUserApi { |
| 22 | 22 | private SocialUserService socialUserService; |
| 23 | 23 | |
| 24 | 24 | @Override |
| 25 | - public String getAuthorizeUrl(Integer type, String redirectUri) { | |
| 26 | - return socialUserService.getAuthorizeUrl(type, redirectUri); | |
| 27 | - } | |
| 28 | - | |
| 29 | - @Override | |
| 30 | 25 | public String bindSocialUser(SocialUserBindReqDTO reqDTO) { |
| 31 | 26 | return socialUserService.bindSocialUser(reqDTO); |
| 32 | 27 | } |
| ... | ... | @@ -34,7 +29,7 @@ public class SocialUserApiImpl implements SocialUserApi { |
| 34 | 29 | @Override |
| 35 | 30 | public void unbindSocialUser(SocialUserUnbindReqDTO reqDTO) { |
| 36 | 31 | socialUserService.unbindSocialUser(reqDTO.getUserId(), reqDTO.getUserType(), |
| 37 | - reqDTO.getType(), reqDTO.getUnionId()); | |
| 32 | + reqDTO.getSocialType(), reqDTO.getOpenid()); | |
| 38 | 33 | } |
| 39 | 34 | |
| 40 | 35 | @Override | ... | ... |
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/auth/AuthController.java
| ... | ... | @@ -3,6 +3,7 @@ package cn.iocoder.yudao.module.system.controller.admin.auth; |
| 3 | 3 | import cn.hutool.core.collection.CollUtil; |
| 4 | 4 | import cn.hutool.core.util.StrUtil; |
| 5 | 5 | import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; |
| 6 | +import cn.iocoder.yudao.framework.common.enums.UserTypeEnum; | |
| 6 | 7 | import cn.iocoder.yudao.framework.common.pojo.CommonResult; |
| 7 | 8 | import cn.iocoder.yudao.framework.operatelog.core.annotations.OperateLog; |
| 8 | 9 | import cn.iocoder.yudao.framework.security.config.SecurityProperties; |
| ... | ... | @@ -16,7 +17,7 @@ import cn.iocoder.yudao.module.system.service.auth.AdminAuthService; |
| 16 | 17 | import cn.iocoder.yudao.module.system.service.permission.MenuService; |
| 17 | 18 | import cn.iocoder.yudao.module.system.service.permission.PermissionService; |
| 18 | 19 | import cn.iocoder.yudao.module.system.service.permission.RoleService; |
| 19 | -import cn.iocoder.yudao.module.system.service.social.SocialUserService; | |
| 20 | +import cn.iocoder.yudao.module.system.service.social.SocialClientService; | |
| 20 | 21 | import cn.iocoder.yudao.module.system.service.user.AdminUserService; |
| 21 | 22 | import io.swagger.v3.oas.annotations.Operation; |
| 22 | 23 | import io.swagger.v3.oas.annotations.Parameter; |
| ... | ... | @@ -57,7 +58,7 @@ public class AuthController { |
| 57 | 58 | @Resource |
| 58 | 59 | private PermissionService permissionService; |
| 59 | 60 | @Resource |
| 60 | - private SocialUserService socialUserService; | |
| 61 | + private SocialClientService socialClientService; | |
| 61 | 62 | |
| 62 | 63 | @Resource |
| 63 | 64 | private SecurityProperties securityProperties; |
| ... | ... | @@ -147,7 +148,7 @@ public class AuthController { |
| 147 | 148 | }) |
| 148 | 149 | public CommonResult<String> socialLogin(@RequestParam("type") Integer type, |
| 149 | 150 | @RequestParam("redirectUri") String redirectUri) { |
| 150 | - return CommonResult.success(socialUserService.getAuthorizeUrl(type, redirectUri)); | |
| 151 | + return success(socialClientService.getAuthorizeUrl(type, UserTypeEnum.ADMIN.getValue(), redirectUri)); | |
| 151 | 152 | } |
| 152 | 153 | |
| 153 | 154 | @PostMapping("/social-login") | ... | ... |
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/app/package-info.java deleted
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/app/weixin/AppWxMpController.http deleted
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/app/weixin/AppWxMpController.java deleted
| 1 | -package cn.iocoder.yudao.module.system.controller.app.weixin; | |
| 2 | - | |
| 3 | -import cn.iocoder.yudao.framework.common.pojo.CommonResult; | |
| 4 | -import io.swagger.v3.oas.annotations.tags.Tag; | |
| 5 | -import io.swagger.v3.oas.annotations.Operation; | |
| 6 | -import lombok.extern.slf4j.Slf4j; | |
| 7 | -import me.chanjar.weixin.common.bean.WxJsapiSignature; | |
| 8 | -import me.chanjar.weixin.common.error.WxErrorException; | |
| 9 | -import me.chanjar.weixin.mp.api.WxMpService; | |
| 10 | -import org.springframework.validation.annotation.Validated; | |
| 11 | -import org.springframework.web.bind.annotation.PostMapping; | |
| 12 | -import org.springframework.web.bind.annotation.RequestMapping; | |
| 13 | -import org.springframework.web.bind.annotation.RequestParam; | |
| 14 | -import org.springframework.web.bind.annotation.RestController; | |
| 15 | - | |
| 16 | -import javax.annotation.Resource; | |
| 17 | - | |
| 18 | -import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; | |
| 19 | - | |
| 20 | -@Tag(name = "微信公众号") | |
| 21 | -@RestController | |
| 22 | -@RequestMapping("/system/wx-mp") | |
| 23 | -@Validated | |
| 24 | -@Slf4j | |
| 25 | -public class AppWxMpController { | |
| 26 | - | |
| 27 | - @Resource | |
| 28 | - private WxMpService mpService; | |
| 29 | - | |
| 30 | - // TODO @芋艿:需要额外考虑个问题;多租户下,如果每个小程序一个微信公众号,则会存在多个 appid; | |
| 31 | - @PostMapping("/create-jsapi-signature") | |
| 32 | - @Operation(summary = "创建微信 JS SDK 初始化所需的签名", | |
| 33 | - description = "参考 https://developers.weixin.qq.com/doc/offiaccount/OA_Web_Apps/JS-SDK.html 文档") | |
| 34 | - public CommonResult<WxJsapiSignature> createJsapiSignature(@RequestParam("url") String url) throws WxErrorException { | |
| 35 | - return success(mpService.createJsapiSignature(url)); | |
| 36 | - } | |
| 37 | - | |
| 38 | -} |
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/convert/social/SocialClientConvert.java
0 → 100644
| 1 | +package cn.iocoder.yudao.module.system.convert.social; | |
| 2 | + | |
| 3 | +import cn.binarywang.wx.miniapp.bean.WxMaPhoneNumberInfo; | |
| 4 | +import cn.iocoder.yudao.module.system.api.social.dto.SocialWxJsapiSignatureRespDTO; | |
| 5 | +import cn.iocoder.yudao.module.system.api.social.dto.SocialWxPhoneNumberInfoRespDTO; | |
| 6 | +import me.chanjar.weixin.common.bean.WxJsapiSignature; | |
| 7 | +import org.mapstruct.Mapper; | |
| 8 | +import org.mapstruct.factory.Mappers; | |
| 9 | + | |
| 10 | +@Mapper | |
| 11 | +public interface SocialClientConvert { | |
| 12 | + | |
| 13 | + SocialClientConvert INSTANCE = Mappers.getMapper(SocialClientConvert.class); | |
| 14 | + | |
| 15 | + SocialWxJsapiSignatureRespDTO convert(WxJsapiSignature bean); | |
| 16 | + | |
| 17 | + SocialWxPhoneNumberInfoRespDTO convert(WxMaPhoneNumberInfo bean); | |
| 18 | + | |
| 19 | +} | ... | ... |
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/dataobject/social/SocialClientDO.java
0 → 100644
| 1 | +package cn.iocoder.yudao.module.system.dal.dataobject.social; | |
| 2 | + | |
| 3 | +import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; | |
| 4 | +import cn.iocoder.yudao.framework.common.enums.UserTypeEnum; | |
| 5 | +import cn.iocoder.yudao.framework.tenant.core.db.TenantBaseDO; | |
| 6 | +import cn.iocoder.yudao.module.system.enums.social.SocialTypeEnum; | |
| 7 | +import com.baomidou.mybatisplus.annotation.KeySequence; | |
| 8 | +import com.baomidou.mybatisplus.annotation.TableId; | |
| 9 | +import com.baomidou.mybatisplus.annotation.TableName; | |
| 10 | +import com.xingyuv.jushauth.config.AuthConfig; | |
| 11 | +import lombok.*; | |
| 12 | + | |
| 13 | +/** | |
| 14 | + * 社交客户端 DO | |
| 15 | + * | |
| 16 | + * 对应 {@link AuthConfig} 配置,满足不同租户,有自己的客户端配置,实现社交(三方)登录 | |
| 17 | + * | |
| 18 | + * @author 芋道源码 | |
| 19 | + */ | |
| 20 | +@TableName(value = "system_social_client", autoResultMap = true) | |
| 21 | +@KeySequence("system_social_client_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。 | |
| 22 | +@Data | |
| 23 | +@EqualsAndHashCode(callSuper = true) | |
| 24 | +@Builder | |
| 25 | +@NoArgsConstructor | |
| 26 | +@AllArgsConstructor | |
| 27 | +public class SocialClientDO extends TenantBaseDO { | |
| 28 | + | |
| 29 | + /** | |
| 30 | + * 编号,自增 | |
| 31 | + */ | |
| 32 | + @TableId | |
| 33 | + private Long id; | |
| 34 | + /** | |
| 35 | + * 应用名 | |
| 36 | + */ | |
| 37 | + private String name; | |
| 38 | + /** | |
| 39 | + * 社交类型 | |
| 40 | + * | |
| 41 | + * 枚举 {@link SocialTypeEnum} | |
| 42 | + */ | |
| 43 | + private Integer socialType; | |
| 44 | + /** | |
| 45 | + * 用户类型 | |
| 46 | + * | |
| 47 | + * 目的:不同用户类型,对应不同的小程序,需要自己的配置 | |
| 48 | + * | |
| 49 | + * 枚举 {@link UserTypeEnum} | |
| 50 | + */ | |
| 51 | + private Integer userType; | |
| 52 | + /** | |
| 53 | + * 状态 | |
| 54 | + * | |
| 55 | + * 枚举 {@link CommonStatusEnum} | |
| 56 | + */ | |
| 57 | + private Integer status; | |
| 58 | + | |
| 59 | + /** | |
| 60 | + * 客户端 id | |
| 61 | + */ | |
| 62 | + private String clientId; | |
| 63 | + /** | |
| 64 | + * 客户端 Secret | |
| 65 | + */ | |
| 66 | + private String clientSecret; | |
| 67 | + | |
| 68 | +} | ... | ... |
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/mysql/social/SocialClientMapper.java
0 → 100644
| 1 | +package cn.iocoder.yudao.module.system.dal.mysql.social; | |
| 2 | + | |
| 3 | +import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; | |
| 4 | +import cn.iocoder.yudao.module.system.dal.dataobject.social.SocialClientDO; | |
| 5 | +import org.apache.ibatis.annotations.Mapper; | |
| 6 | + | |
| 7 | +@Mapper | |
| 8 | +public interface SocialClientMapper extends BaseMapperX<SocialClientDO> { | |
| 9 | + | |
| 10 | + default SocialClientDO selectBySocialTypeAndUserType(Integer socialType, Integer userType) { | |
| 11 | + return selectOne(SocialClientDO::getSocialType, socialType, | |
| 12 | + SocialClientDO::getUserType, userType); | |
| 13 | + } | |
| 14 | + | |
| 15 | +} | ... | ... |
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/social/SocialClientService.java
0 → 100644
| 1 | +package cn.iocoder.yudao.module.system.service.social; | |
| 2 | + | |
| 3 | +import cn.binarywang.wx.miniapp.bean.WxMaPhoneNumberInfo; | |
| 4 | +import cn.iocoder.yudao.module.system.enums.social.SocialTypeEnum; | |
| 5 | +import com.xingyuv.jushauth.model.AuthUser; | |
| 6 | +import me.chanjar.weixin.common.bean.WxJsapiSignature; | |
| 7 | + | |
| 8 | +/** | |
| 9 | + * 社交应用 Service 接口 | |
| 10 | + * | |
| 11 | + * @author 芋道源码 | |
| 12 | + */ | |
| 13 | +public interface SocialClientService { | |
| 14 | + | |
| 15 | + /** | |
| 16 | + * 获得社交平台的授权 URL | |
| 17 | + * | |
| 18 | + * @param socialType 社交平台的类型 {@link SocialTypeEnum} | |
| 19 | + * @param userType 用户类型 | |
| 20 | + * @param redirectUri 重定向 URL | |
| 21 | + * @return 社交平台的授权 URL | |
| 22 | + */ | |
| 23 | + String getAuthorizeUrl(Integer socialType, Integer userType, String redirectUri); | |
| 24 | + | |
| 25 | + /** | |
| 26 | + * 请求社交平台,获得授权的用户 | |
| 27 | + * | |
| 28 | + * @param socialType 社交平台的类型 | |
| 29 | + * @param userType 用户类型 | |
| 30 | + * @param code 授权码 | |
| 31 | + * @param state 授权 state | |
| 32 | + * @return 授权的用户 | |
| 33 | + */ | |
| 34 | + AuthUser getAuthUser(Integer socialType, Integer userType, String code, String state); | |
| 35 | + | |
| 36 | + // =================== 微信公众号独有 =================== | |
| 37 | + | |
| 38 | + /** | |
| 39 | + * 创建微信公众号的 JS SDK 初始化所需的签名 | |
| 40 | + * | |
| 41 | + * @param userType 用户类型 | |
| 42 | + * @param url 访问的 URL 地址 | |
| 43 | + * @return 签名 | |
| 44 | + */ | |
| 45 | + WxJsapiSignature createWxMpJsapiSignature(Integer userType, String url); | |
| 46 | + | |
| 47 | + // =================== 微信小程序独有 =================== | |
| 48 | + | |
| 49 | + /** | |
| 50 | + * 获得微信小程序的手机信息 | |
| 51 | + * | |
| 52 | + * @param userType 用户类型 | |
| 53 | + * @param phoneCode 手机授权码 | |
| 54 | + * @return 手机信息 | |
| 55 | + */ | |
| 56 | + WxMaPhoneNumberInfo getWxMaPhoneNumberInfo(Integer userType, String phoneCode); | |
| 57 | + | |
| 58 | +} | ... | ... |
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/social/SocialClientServiceImpl.java
0 → 100644
| 1 | +package cn.iocoder.yudao.module.system.service.social; | |
| 2 | + | |
| 3 | +import cn.binarywang.wx.miniapp.api.WxMaService; | |
| 4 | +import cn.binarywang.wx.miniapp.api.impl.WxMaServiceImpl; | |
| 5 | +import cn.binarywang.wx.miniapp.bean.WxMaPhoneNumberInfo; | |
| 6 | +import cn.binarywang.wx.miniapp.config.impl.WxMaRedisBetterConfigImpl; | |
| 7 | +import cn.hutool.core.bean.BeanUtil; | |
| 8 | +import cn.hutool.core.lang.Assert; | |
| 9 | +import cn.hutool.core.util.ReflectUtil; | |
| 10 | +import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; | |
| 11 | +import cn.iocoder.yudao.framework.common.util.cache.CacheUtils; | |
| 12 | +import cn.iocoder.yudao.framework.common.util.http.HttpUtils; | |
| 13 | +import cn.iocoder.yudao.framework.social.core.YudaoAuthRequestFactory; | |
| 14 | +import cn.iocoder.yudao.module.system.dal.dataobject.social.SocialClientDO; | |
| 15 | +import cn.iocoder.yudao.module.system.dal.mysql.social.SocialClientMapper; | |
| 16 | +import cn.iocoder.yudao.module.system.enums.social.SocialTypeEnum; | |
| 17 | +import com.binarywang.spring.starter.wxjava.miniapp.properties.WxMaProperties; | |
| 18 | +import com.binarywang.spring.starter.wxjava.mp.properties.WxMpProperties; | |
| 19 | +import com.google.common.cache.CacheLoader; | |
| 20 | +import com.google.common.cache.LoadingCache; | |
| 21 | +import com.xingyuv.jushauth.config.AuthConfig; | |
| 22 | +import com.xingyuv.jushauth.model.AuthCallback; | |
| 23 | +import com.xingyuv.jushauth.model.AuthResponse; | |
| 24 | +import com.xingyuv.jushauth.model.AuthUser; | |
| 25 | +import com.xingyuv.jushauth.request.AuthRequest; | |
| 26 | +import com.xingyuv.jushauth.utils.AuthStateUtils; | |
| 27 | +import lombok.SneakyThrows; | |
| 28 | +import lombok.extern.slf4j.Slf4j; | |
| 29 | +import me.chanjar.weixin.common.bean.WxJsapiSignature; | |
| 30 | +import me.chanjar.weixin.common.error.WxErrorException; | |
| 31 | +import me.chanjar.weixin.common.redis.RedisTemplateWxRedisOps; | |
| 32 | +import me.chanjar.weixin.mp.api.WxMpService; | |
| 33 | +import me.chanjar.weixin.mp.api.impl.WxMpServiceImpl; | |
| 34 | +import me.chanjar.weixin.mp.config.impl.WxMpRedisConfigImpl; | |
| 35 | +import org.springframework.data.redis.core.StringRedisTemplate; | |
| 36 | +import org.springframework.stereotype.Service; | |
| 37 | + | |
| 38 | +import javax.annotation.Resource; | |
| 39 | +import java.time.Duration; | |
| 40 | +import java.util.Objects; | |
| 41 | + | |
| 42 | +import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; | |
| 43 | +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; | |
| 46 | + | |
| 47 | +/** | |
| 48 | + * 社交应用 Service 实现类 | |
| 49 | + * | |
| 50 | + * @author 芋道源码 | |
| 51 | + */ | |
| 52 | +@Service | |
| 53 | +@Slf4j | |
| 54 | +public class SocialClientServiceImpl implements SocialClientService { | |
| 55 | + | |
| 56 | + @Resource // 由于自定义了 YudaoAuthRequestFactory 无法覆盖默认的 AuthRequestFactory,所以只能注入它 | |
| 57 | + private YudaoAuthRequestFactory yudaoAuthRequestFactory; | |
| 58 | + | |
| 59 | + @Resource | |
| 60 | + private WxMpService wxMpService; | |
| 61 | + @Resource | |
| 62 | + private WxMpProperties wxMpProperties; | |
| 63 | + @Resource | |
| 64 | + private StringRedisTemplate stringRedisTemplate; // WxMpService 需要使用到,所以在 Service 注入了它 | |
| 65 | + /** | |
| 66 | + * 缓存 WxMpService 对象 | |
| 67 | + * | |
| 68 | + * key:使用微信公众号的 appId + secret 拼接,即 {@link SocialClientDO} 的 clientId 和 clientSecret 属性。 | |
| 69 | + * 为什么 key 使用这种格式?因为 {@link SocialClientDO} 在管理后台可以变更,通过这个 key 存储它的单例。 | |
| 70 | + * | |
| 71 | + * 为什么要做 WxMpService 缓存?因为 WxMpService 构建成本比较大,所以尽量保证它是单例。 | |
| 72 | + */ | |
| 73 | + private final LoadingCache<String, WxMpService> wxMpServiceCache = CacheUtils.buildAsyncReloadingCache( | |
| 74 | + Duration.ofSeconds(10L), | |
| 75 | + new CacheLoader<String, WxMpService>() { | |
| 76 | + | |
| 77 | + @Override | |
| 78 | + public WxMpService load(String key) { | |
| 79 | + String[] keys = key.split(":"); | |
| 80 | + return buildWxMpService(keys[0], keys[1]); | |
| 81 | + } | |
| 82 | + | |
| 83 | + }); | |
| 84 | + | |
| 85 | + @Resource | |
| 86 | + private WxMaService wxMaService; | |
| 87 | + @Resource | |
| 88 | + private WxMaProperties wxMaProperties; | |
| 89 | + /** | |
| 90 | + * 缓存 WxMaService 对象 | |
| 91 | + * | |
| 92 | + * 说明同 {@link #wxMpServiceCache} 变量 | |
| 93 | + */ | |
| 94 | + private final LoadingCache<String, WxMaService> wxMaServiceCache = CacheUtils.buildAsyncReloadingCache( | |
| 95 | + Duration.ofSeconds(10L), | |
| 96 | + new CacheLoader<String, WxMaService>() { | |
| 97 | + | |
| 98 | + @Override | |
| 99 | + public WxMaService load(String key) { | |
| 100 | + String[] keys = key.split(":"); | |
| 101 | + return buildWxMaService(keys[0], keys[1]); | |
| 102 | + } | |
| 103 | + | |
| 104 | + }); | |
| 105 | + | |
| 106 | + @Resource | |
| 107 | + private SocialClientMapper socialClientMapper; | |
| 108 | + | |
| 109 | + @Override | |
| 110 | + public String getAuthorizeUrl(Integer socialType, Integer userType, String redirectUri) { | |
| 111 | + // 获得对应的 AuthRequest 实现 | |
| 112 | + AuthRequest authRequest = buildAuthRequest(socialType, userType); | |
| 113 | + // 生成跳转地址 | |
| 114 | + String authorizeUri = authRequest.authorize(AuthStateUtils.createState()); | |
| 115 | + return HttpUtils.replaceUrlQuery(authorizeUri, "redirect_uri", redirectUri); | |
| 116 | + } | |
| 117 | + | |
| 118 | + @Override | |
| 119 | + public AuthUser getAuthUser(Integer socialType, Integer userType, String code, String state) { | |
| 120 | + // 构建请求 | |
| 121 | + AuthRequest authRequest = buildAuthRequest(socialType, userType); | |
| 122 | + AuthCallback authCallback = AuthCallback.builder().code(code).state(state).build(); | |
| 123 | + // 执行请求 | |
| 124 | + AuthResponse<?> authResponse = authRequest.login(authCallback); | |
| 125 | + log.info("[getAuthUser][请求社交平台 type({}) request({}) response({})]", socialType, | |
| 126 | + toJsonString(authCallback), toJsonString(authResponse)); | |
| 127 | + if (!authResponse.ok()) { | |
| 128 | + throw exception(SOCIAL_USER_AUTH_FAILURE, authResponse.getMsg()); | |
| 129 | + } | |
| 130 | + return (AuthUser) authResponse.getData(); | |
| 131 | + } | |
| 132 | + | |
| 133 | + /** | |
| 134 | + * 构建 AuthRequest 对象,支持多租户配置 | |
| 135 | + * | |
| 136 | + * @param socialType 社交类型 | |
| 137 | + * @param userType 用户类型 | |
| 138 | + * @return AuthRequest 对象 | |
| 139 | + */ | |
| 140 | + private AuthRequest buildAuthRequest(Integer socialType, Integer userType) { | |
| 141 | + // 1. 先查找默认的配置项,从 application-*.yaml 中读取 | |
| 142 | + AuthRequest request = yudaoAuthRequestFactory.get(SocialTypeEnum.valueOfType(socialType).getSource()); | |
| 143 | + Assert.notNull(request, String.format("社交平台(%d) 不存在", socialType)); | |
| 144 | + // 2. 查询 DB 的配置项,如果存在则进行覆盖 | |
| 145 | + SocialClientDO client = socialClientMapper.selectBySocialTypeAndUserType(socialType, userType); | |
| 146 | + if (client != null && Objects.equals(client.getStatus(), CommonStatusEnum.ENABLE.getStatus())) { | |
| 147 | + // 2.1 构造新的 AuthConfig 对象 | |
| 148 | + AuthConfig authConfig = (AuthConfig) ReflectUtil.getFieldValue(request, "config"); | |
| 149 | + AuthConfig newAuthConfig = ReflectUtil.newInstance(authConfig.getClass()); | |
| 150 | + BeanUtil.copyProperties(authConfig, newAuthConfig); | |
| 151 | + // 2.2 修改对应的 clientId + clientSecret 密钥 | |
| 152 | + newAuthConfig.setClientId(client.getClientId()); | |
| 153 | + newAuthConfig.setClientSecret(client.getClientSecret()); | |
| 154 | + // 2.3 设置会 request 里,进行后续使用 | |
| 155 | + ReflectUtil.setFieldValue(request, "config", newAuthConfig); | |
| 156 | + } | |
| 157 | + return request; | |
| 158 | + } | |
| 159 | + | |
| 160 | + // =================== 微信公众号独有 =================== | |
| 161 | + | |
| 162 | + @Override | |
| 163 | + @SneakyThrows | |
| 164 | + public WxJsapiSignature createWxMpJsapiSignature(Integer userType, String url) { | |
| 165 | + WxMpService service = getWxMpService(userType); | |
| 166 | + return service.createJsapiSignature(url); | |
| 167 | + } | |
| 168 | + | |
| 169 | + /** | |
| 170 | + * 获得 clientId + clientSecret 对应的 WxMpService 对象 | |
| 171 | + * | |
| 172 | + * @param userType 用户类型 | |
| 173 | + * @return WxMpService 对象 | |
| 174 | + */ | |
| 175 | + private WxMpService getWxMpService(Integer userType) { | |
| 176 | + // 第一步,查询 DB 的配置项,获得对应的 WxMpService 对象 | |
| 177 | + SocialClientDO client = socialClientMapper.selectBySocialTypeAndUserType( | |
| 178 | + SocialTypeEnum.WECHAT_MP.getType(), userType); | |
| 179 | + if (client != null && Objects.equals(client.getStatus(), CommonStatusEnum.ENABLE.getStatus())) { | |
| 180 | + return wxMpServiceCache.getUnchecked(client.getClientId() + ":" + client.getClientSecret()); | |
| 181 | + } | |
| 182 | + // 第二步,不存在 DB 配置项,则使用 application-*.yaml 对应的 WxMpService 对象 | |
| 183 | + return wxMpService; | |
| 184 | + } | |
| 185 | + | |
| 186 | + /** | |
| 187 | + * 创建 clientId + clientSecret 对应的 WxMpService 对象 | |
| 188 | + * | |
| 189 | + * @param clientId 微信公众号 appId | |
| 190 | + * @param clientSecret 微信公众号 secret | |
| 191 | + * @return WxMpService 对象 | |
| 192 | + */ | |
| 193 | + private WxMpService buildWxMpService(String clientId, String clientSecret) { | |
| 194 | + // 第一步,创建 WxMpRedisConfigImpl 对象 | |
| 195 | + WxMpRedisConfigImpl configStorage = new WxMpRedisConfigImpl( | |
| 196 | + new RedisTemplateWxRedisOps(stringRedisTemplate), | |
| 197 | + wxMpProperties.getConfigStorage().getKeyPrefix()); | |
| 198 | + configStorage.setAppId(clientId); | |
| 199 | + configStorage.setSecret(clientSecret); | |
| 200 | + | |
| 201 | + // 第二步,创建 WxMpService 对象 | |
| 202 | + WxMpService service = new WxMpServiceImpl(); | |
| 203 | + service.setWxMpConfigStorage(configStorage); | |
| 204 | + return service; | |
| 205 | + } | |
| 206 | + | |
| 207 | + // =================== 微信小程序独有 =================== | |
| 208 | + | |
| 209 | + @Override | |
| 210 | + public WxMaPhoneNumberInfo getWxMaPhoneNumberInfo(Integer userType, String phoneCode) { | |
| 211 | + WxMaService service = getWxMaService(userType); | |
| 212 | + try { | |
| 213 | + return service.getUserService().getPhoneNoInfo(phoneCode); | |
| 214 | + } catch (WxErrorException e) { | |
| 215 | + log.error("[getPhoneNoInfo][userType({}) phoneCode({}) 获得手机号失败]", userType, phoneCode, e); | |
| 216 | + throw exception(SOCIAL_APP_WEIXIN_MINI_APP_PHONE_CODE_ERROR); | |
| 217 | + } | |
| 218 | + } | |
| 219 | + | |
| 220 | + /** | |
| 221 | + * 获得 clientId + clientSecret 对应的 WxMpService 对象 | |
| 222 | + * | |
| 223 | + * @param userType 用户类型 | |
| 224 | + * @return WxMpService 对象 | |
| 225 | + */ | |
| 226 | + private WxMaService getWxMaService(Integer userType) { | |
| 227 | + // 第一步,查询 DB 的配置项,获得对应的 WxMaService 对象 | |
| 228 | + SocialClientDO client = socialClientMapper.selectBySocialTypeAndUserType( | |
| 229 | + SocialTypeEnum.WECHAT_MINI_APP.getType(), userType); | |
| 230 | + if (client != null && Objects.equals(client.getStatus(), CommonStatusEnum.ENABLE.getStatus())) { | |
| 231 | + return wxMaServiceCache.getUnchecked(client.getClientId() + ":" + client.getClientSecret()); | |
| 232 | + } | |
| 233 | + // 第二步,不存在 DB 配置项,则使用 application-*.yaml 对应的 WxMaService 对象 | |
| 234 | + return wxMaService; | |
| 235 | + } | |
| 236 | + | |
| 237 | + /** | |
| 238 | + * 创建 clientId + clientSecret 对应的 WxMaService 对象 | |
| 239 | + * | |
| 240 | + * @param clientId 微信小程序 appId | |
| 241 | + * @param clientSecret 微信小程序 secret | |
| 242 | + * @return WxMaService 对象 | |
| 243 | + */ | |
| 244 | + private WxMaService buildWxMaService(String clientId, String clientSecret) { | |
| 245 | + // 第一步,创建 WxMaRedisBetterConfigImpl 对象 | |
| 246 | + WxMaRedisBetterConfigImpl configStorage = new WxMaRedisBetterConfigImpl( | |
| 247 | + new RedisTemplateWxRedisOps(stringRedisTemplate), | |
| 248 | + wxMaProperties.getConfigStorage().getKeyPrefix()); | |
| 249 | + configStorage.setAppid(clientId); | |
| 250 | + configStorage.setSecret(clientSecret); | |
| 251 | + | |
| 252 | + // 第二步,创建 WxMpService 对象 | |
| 253 | + WxMaService service = new WxMaServiceImpl(); | |
| 254 | + service.setWxMaConfig(configStorage); | |
| 255 | + return service; | |
| 256 | + } | |
| 257 | + | |
| 258 | +} | ... | ... |
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/social/SocialUserService.java
| ... | ... | @@ -7,7 +7,6 @@ import cn.iocoder.yudao.module.system.dal.dataobject.social.SocialUserDO; |
| 7 | 7 | import cn.iocoder.yudao.module.system.enums.social.SocialTypeEnum; |
| 8 | 8 | |
| 9 | 9 | import javax.validation.Valid; |
| 10 | -import javax.validation.constraints.NotNull; | |
| 11 | 10 | import java.util.List; |
| 12 | 11 | |
| 13 | 12 | /** |
| ... | ... | @@ -18,27 +17,6 @@ import java.util.List; |
| 18 | 17 | public interface SocialUserService { |
| 19 | 18 | |
| 20 | 19 | /** |
| 21 | - * 获得社交平台的授权 URL | |
| 22 | - * | |
| 23 | - * @param type 社交平台的类型 {@link SocialTypeEnum} | |
| 24 | - * @param redirectUri 重定向 URL | |
| 25 | - * @return 社交平台的授权 URL | |
| 26 | - */ | |
| 27 | - String getAuthorizeUrl(Integer type, String redirectUri); | |
| 28 | - | |
| 29 | - /** | |
| 30 | - * 授权获得对应的社交用户 | |
| 31 | - * 如果授权失败,则会抛出 {@link ServiceException} 异常 | |
| 32 | - * | |
| 33 | - * @param type 社交平台的类型 {@link SocialTypeEnum} | |
| 34 | - * @param code 授权码 | |
| 35 | - * @param state state | |
| 36 | - * @return 授权用户 | |
| 37 | - */ | |
| 38 | - @NotNull | |
| 39 | - SocialUserDO authSocialUser(Integer type, String code, String state); | |
| 40 | - | |
| 41 | - /** | |
| 42 | 20 | * 获得指定用户的社交用户列表 |
| 43 | 21 | * |
| 44 | 22 | * @param userId 用户编号 | ... | ... |
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/social/SocialUserServiceImpl.java
| ... | ... | @@ -2,8 +2,7 @@ package cn.iocoder.yudao.module.system.service.social; |
| 2 | 2 | |
| 3 | 3 | import cn.hutool.core.collection.CollUtil; |
| 4 | 4 | import cn.hutool.core.lang.Assert; |
| 5 | -import cn.iocoder.yudao.framework.common.util.http.HttpUtils; | |
| 6 | -import cn.iocoder.yudao.framework.social.core.YudaoAuthRequestFactory; | |
| 5 | +import cn.iocoder.yudao.framework.common.exception.ServiceException; | |
| 7 | 6 | import cn.iocoder.yudao.module.system.api.social.dto.SocialUserBindReqDTO; |
| 8 | 7 | import cn.iocoder.yudao.module.system.api.social.dto.SocialUserRespDTO; |
| 9 | 8 | import cn.iocoder.yudao.module.system.dal.dataobject.social.SocialUserBindDO; |
| ... | ... | @@ -11,24 +10,22 @@ import cn.iocoder.yudao.module.system.dal.dataobject.social.SocialUserDO; |
| 11 | 10 | import cn.iocoder.yudao.module.system.dal.mysql.social.SocialUserBindMapper; |
| 12 | 11 | import cn.iocoder.yudao.module.system.dal.mysql.social.SocialUserMapper; |
| 13 | 12 | import cn.iocoder.yudao.module.system.enums.social.SocialTypeEnum; |
| 14 | -import com.xingyuv.jushauth.model.AuthCallback; | |
| 15 | -import com.xingyuv.jushauth.model.AuthResponse; | |
| 16 | 13 | import com.xingyuv.jushauth.model.AuthUser; |
| 17 | -import com.xingyuv.jushauth.request.AuthRequest; | |
| 18 | -import com.xingyuv.jushauth.utils.AuthStateUtils; | |
| 19 | 14 | import lombok.extern.slf4j.Slf4j; |
| 20 | 15 | import org.springframework.stereotype.Service; |
| 21 | 16 | import org.springframework.transaction.annotation.Transactional; |
| 22 | 17 | import org.springframework.validation.annotation.Validated; |
| 23 | 18 | |
| 24 | 19 | import javax.annotation.Resource; |
| 20 | +import javax.validation.constraints.NotNull; | |
| 25 | 21 | import java.util.Collections; |
| 26 | 22 | import java.util.List; |
| 27 | 23 | |
| 28 | 24 | import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; |
| 29 | 25 | import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet; |
| 30 | 26 | import static cn.iocoder.yudao.framework.common.util.json.JsonUtils.toJsonString; |
| 31 | -import static cn.iocoder.yudao.module.system.enums.ErrorCodeConstants.*; | |
| 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 | 29 | |
| 33 | 30 | /** |
| 34 | 31 | * 社交用户 Service 实现类 |
| ... | ... | @@ -40,51 +37,13 @@ import static cn.iocoder.yudao.module.system.enums.ErrorCodeConstants.*; |
| 40 | 37 | @Slf4j |
| 41 | 38 | public class SocialUserServiceImpl implements SocialUserService { |
| 42 | 39 | |
| 43 | - @Resource// 由于自定义了 YudaoAuthRequestFactory 无法覆盖默认的 AuthRequestFactory,所以只能注入它 | |
| 44 | - private YudaoAuthRequestFactory yudaoAuthRequestFactory; | |
| 45 | - | |
| 46 | 40 | @Resource |
| 47 | 41 | private SocialUserBindMapper socialUserBindMapper; |
| 48 | 42 | @Resource |
| 49 | 43 | private SocialUserMapper socialUserMapper; |
| 50 | 44 | |
| 51 | - @Override | |
| 52 | - public String getAuthorizeUrl(Integer type, String redirectUri) { | |
| 53 | - // 获得对应的 AuthRequest 实现 | |
| 54 | - AuthRequest authRequest = yudaoAuthRequestFactory.get(SocialTypeEnum.valueOfType(type).getSource()); | |
| 55 | - // 生成跳转地址 | |
| 56 | - String authorizeUri = authRequest.authorize(AuthStateUtils.createState()); | |
| 57 | - return HttpUtils.replaceUrlQuery(authorizeUri, "redirect_uri", redirectUri); | |
| 58 | - } | |
| 59 | - | |
| 60 | - @Override | |
| 61 | - public SocialUserDO authSocialUser(Integer type, String code, String state) { | |
| 62 | - // 优先从 DB 中获取,因为 code 有且可以使用一次。 | |
| 63 | - // 在社交登录时,当未绑定 User 时,需要绑定登录,此时需要 code 使用两次 | |
| 64 | - SocialUserDO socialUser = socialUserMapper.selectByTypeAndCodeAnState(type, code, state); | |
| 65 | - if (socialUser != null) { | |
| 66 | - return socialUser; | |
| 67 | - } | |
| 68 | - | |
| 69 | - // 请求获取 | |
| 70 | - AuthUser authUser = getAuthUser(type, code, state); | |
| 71 | - Assert.notNull(authUser, "三方用户不能为空"); | |
| 72 | - | |
| 73 | - // 保存到 DB 中 | |
| 74 | - socialUser = socialUserMapper.selectByTypeAndOpenid(type, authUser.getUuid()); | |
| 75 | - if (socialUser == null) { | |
| 76 | - socialUser = new SocialUserDO(); | |
| 77 | - } | |
| 78 | - socialUser.setType(type).setCode(code).setState(state) // 需要保存 code + state 字段,保证后续可查询 | |
| 79 | - .setOpenid(authUser.getUuid()).setToken(authUser.getToken().getAccessToken()).setRawTokenInfo((toJsonString(authUser.getToken()))) | |
| 80 | - .setNickname(authUser.getNickname()).setAvatar(authUser.getAvatar()).setRawUserInfo(toJsonString(authUser.getRawUserInfo())); | |
| 81 | - if (socialUser.getId() == null) { | |
| 82 | - socialUserMapper.insert(socialUser); | |
| 83 | - } else { | |
| 84 | - socialUserMapper.updateById(socialUser); | |
| 85 | - } | |
| 86 | - return socialUser; | |
| 87 | - } | |
| 45 | + @Resource | |
| 46 | + private SocialClientService socialClientService; | |
| 88 | 47 | |
| 89 | 48 | @Override |
| 90 | 49 | public List<SocialUserDO> getSocialUserList(Long userId, Integer userType) { |
| ... | ... | @@ -101,7 +60,8 @@ public class SocialUserServiceImpl implements SocialUserService { |
| 101 | 60 | @Transactional |
| 102 | 61 | public String bindSocialUser(SocialUserBindReqDTO reqDTO) { |
| 103 | 62 | // 获得社交用户 |
| 104 | - SocialUserDO socialUser = authSocialUser(reqDTO.getType(), reqDTO.getCode(), reqDTO.getState()); | |
| 63 | + SocialUserDO socialUser = authSocialUser(reqDTO.getSocialType(), reqDTO.getUserType(), | |
| 64 | + reqDTO.getCode(), reqDTO.getState()); | |
| 105 | 65 | Assert.notNull(socialUser, "社交用户不能为空"); |
| 106 | 66 | |
| 107 | 67 | // 社交用户可能之前绑定过别的用户,需要进行解绑 |
| ... | ... | @@ -134,7 +94,7 @@ public class SocialUserServiceImpl implements SocialUserService { |
| 134 | 94 | @Override |
| 135 | 95 | public SocialUserRespDTO getSocialUser(Integer userType, Integer type, String code, String state) { |
| 136 | 96 | // 获得社交用户 |
| 137 | - SocialUserDO socialUser = authSocialUser(type, code, state); | |
| 97 | + SocialUserDO socialUser = authSocialUser(type, userType, code, state); | |
| 138 | 98 | Assert.notNull(socialUser, "社交用户不能为空"); |
| 139 | 99 | |
| 140 | 100 | // 如果未绑定的社交用户,则无法自动登录,进行报错 |
| ... | ... | @@ -146,24 +106,44 @@ public class SocialUserServiceImpl implements SocialUserService { |
| 146 | 106 | return new SocialUserRespDTO(socialUser.getOpenid(), socialUserBind.getUserId()); |
| 147 | 107 | } |
| 148 | 108 | |
| 109 | + // TODO 芋艿:调整下单测 | |
| 149 | 110 | /** |
| 150 | - * 请求社交平台,获得授权的用户 | |
| 111 | + * 授权获得对应的社交用户 | |
| 112 | + * 如果授权失败,则会抛出 {@link ServiceException} 异常 | |
| 151 | 113 | * |
| 152 | - * @param type 社交平台的类型 | |
| 114 | + * @param type 社交平台的类型 {@link SocialTypeEnum} | |
| 115 | + * @param userType 用户类型 | |
| 153 | 116 | * @param code 授权码 |
| 154 | - * @param state 授权 state | |
| 155 | - * @return 授权的用户 | |
| 117 | + * @param state state | |
| 118 | + * @return 授权用户 | |
| 156 | 119 | */ |
| 157 | - private AuthUser getAuthUser(Integer type, String code, String state) { | |
| 158 | - AuthRequest authRequest = yudaoAuthRequestFactory.get(SocialTypeEnum.valueOfType(type).getSource()); | |
| 159 | - AuthCallback authCallback = AuthCallback.builder().code(code).state(state).build(); | |
| 160 | - AuthResponse<?> authResponse = authRequest.login(authCallback); | |
| 161 | - log.info("[getAuthUser][请求社交平台 type({}) request({}) response({})]", type, | |
| 162 | - toJsonString(authCallback), toJsonString(authResponse)); | |
| 163 | - if (!authResponse.ok()) { | |
| 164 | - throw exception(SOCIAL_USER_AUTH_FAILURE, authResponse.getMsg()); | |
| 120 | + @NotNull | |
| 121 | + public SocialUserDO authSocialUser(Integer type, Integer userType, String code, String state) { | |
| 122 | + // 优先从 DB 中获取,因为 code 有且可以使用一次。 | |
| 123 | + // 在社交登录时,当未绑定 User 时,需要绑定登录,此时需要 code 使用两次 | |
| 124 | + SocialUserDO socialUser = socialUserMapper.selectByTypeAndCodeAnState(type, code, state); | |
| 125 | + if (socialUser != null) { | |
| 126 | + return socialUser; | |
| 165 | 127 | } |
| 166 | - return (AuthUser) authResponse.getData(); | |
| 128 | + | |
| 129 | + // 请求获取 | |
| 130 | + AuthUser authUser = socialClientService.getAuthUser(type, userType, code, state); | |
| 131 | + Assert.notNull(authUser, "三方用户不能为空"); | |
| 132 | + | |
| 133 | + // 保存到 DB 中 | |
| 134 | + socialUser = socialUserMapper.selectByTypeAndOpenid(type, authUser.getUuid()); | |
| 135 | + if (socialUser == null) { | |
| 136 | + socialUser = new SocialUserDO(); | |
| 137 | + } | |
| 138 | + socialUser.setType(type).setCode(code).setState(state) // 需要保存 code + state 字段,保证后续可查询 | |
| 139 | + .setOpenid(authUser.getUuid()).setToken(authUser.getToken().getAccessToken()).setRawTokenInfo((toJsonString(authUser.getToken()))) | |
| 140 | + .setNickname(authUser.getNickname()).setAvatar(authUser.getAvatar()).setRawUserInfo(toJsonString(authUser.getRawUserInfo())); | |
| 141 | + if (socialUser.getId() == null) { | |
| 142 | + socialUserMapper.insert(socialUser); | |
| 143 | + } else { | |
| 144 | + socialUserMapper.updateById(socialUser); | |
| 145 | + } | |
| 146 | + return socialUser; | |
| 167 | 147 | } |
| 168 | 148 | |
| 169 | 149 | } | ... | ... |