Commit 5d6bb84d2565df76f0c25a448e3ef127dd1bad6b

Authored by puhui999
2 parents 0e875597 5808f77a

Merge remote-tracking branch 'yudao/feature/mall_product' into feature/mall_product

Showing 169 changed files with 4078 additions and 689 deletions
.gitignore
... ... @@ -8,6 +8,8 @@
8 8 target/
9 9 !.mvn/wrapper/maven-wrapper.jar
10 10  
  11 +.flattened-pom.xml
  12 +
11 13 ######################################################################
12 14 # IDE
13 15  
... ...
... ... @@ -16,10 +16,10 @@
16 16 <module>yudao-module-member</module>
17 17 <module>yudao-module-system</module>
18 18 <module>yudao-module-infra</module>
  19 + <!-- <module>yudao-module-bpm</module>-->
  20 +<!-- <module>yudao-module-report</module>-->
  21 +<!-- <module>yudao-module-mp</module>-->
19 22 <module>yudao-module-pay</module>
20   - <module>yudao-module-bpm</module>
21   - <module>yudao-module-report</module>
22   - <module>yudao-module-mp</module>
23 23 <module>yudao-module-mall</module>
24 24 <!-- 示例项目 -->
25 25 <module>yudao-example</module>
... ... @@ -30,13 +30,14 @@
30 30 <url>https://github.com/YunaiV/ruoyi-vue-pro</url>
31 31  
32 32 <properties>
33   - <revision>1.8.0-snapshot</revision>
  33 + <revision>1.8.1-snapshot</revision>
34 34 <!-- Maven 相关 -->
35 35 <java.version>1.8</java.version>
36 36 <maven.compiler.source>${java.version}</maven.compiler.source>
37 37 <maven.compiler.target>${java.version}</maven.compiler.target>
38 38 <maven-surefire-plugin.version>3.0.0-M5</maven-surefire-plugin.version>
39 39 <maven-compiler-plugin.version>3.8.1</maven-compiler-plugin.version>
  40 + <flatten-maven-plugin.version>1.5.0</flatten-maven-plugin.version>
40 41 <!-- 看看咋放到 bom 里 -->
41 42 <lombok.version>1.18.28</lombok.version>
42 43 <spring.boot.version>2.7.14</spring.boot.version>
... ... @@ -92,8 +93,41 @@
92 93 </annotationProcessorPaths>
93 94 </configuration>
94 95 </plugin>
  96 + <plugin>
  97 + <groupId>org.codehaus.mojo</groupId>
  98 + <artifactId>flatten-maven-plugin</artifactId>
  99 + </plugin>
95 100 </plugins>
96 101 </pluginManagement>
  102 +
  103 + <plugins>
  104 + <!-- 统一 revision 版本 -->
  105 + <plugin>
  106 + <groupId>org.codehaus.mojo</groupId>
  107 + <artifactId>flatten-maven-plugin</artifactId>
  108 + <version>${flatten-maven-plugin.version}</version>
  109 + <configuration>
  110 + <flattenMode>resolveCiFriendliesOnly</flattenMode>
  111 + <updatePomFile>true</updatePomFile>
  112 + </configuration>
  113 + <executions>
  114 + <execution>
  115 + <goals>
  116 + <goal>flatten</goal>
  117 + </goals>
  118 + <id>flatten</id>
  119 + <phase>process-resources</phase>
  120 + </execution>
  121 + <execution>
  122 + <goals>
  123 + <goal>clean</goal>
  124 + </goals>
  125 + <id>flatten.clean</id>
  126 + <phase>clean</phase>
  127 + </execution>
  128 + </executions>
  129 + </plugin>
  130 + </plugins>
97 131 </build>
98 132  
99 133 <!-- 使用 huawei / aliyun 的 Maven 源,提升下载速度 -->
... ...
sql/mysql/brokerage.sql 0 → 100644
  1 +-- 增加配置表
  2 +create table trade_config
  3 +(
  4 + id bigint auto_increment comment '自增主键' primary key,
  5 + brokerage_enabled bit default 1 not null comment '是否启用分佣',
  6 + brokerage_enabled_condition tinyint default 0 not null comment '分佣模式:0-人人分销 1-指定分销',
  7 + brokerage_bind_mode tinyint default 0 not null comment '分销关系绑定模式: 0-没有推广人,1-新用户',
  8 + brokerage_post_urls varchar(2000) default '' null comment '分销海报图地址数组',
  9 + brokerage_first_percent int default 0 not null comment '一级返佣比例',
  10 + brokerage_second_percent int default 0 not null comment '二级返佣比例',
  11 + brokerage_withdraw_min_price int default 0 not null comment '用户提现最低金额',
  12 + brokerage_bank_names varchar(200) default '' not null comment '提现银行(字典类型=brokerage_bank_name)',
  13 + brokerage_frozen_days int default 7 not null comment '佣金冻结时间(天)',
  14 + brokerage_withdraw_type varchar(32) default '1,2,3,4' not null comment '提现方式:1-钱包;2-银行卡;3-微信;4-支付宝',
  15 + creator varchar(64) collate utf8mb4_unicode_ci default '' null comment '创建者',
  16 + create_time datetime default CURRENT_TIMESTAMP not null comment '创建时间',
  17 + updater varchar(64) collate utf8mb4_unicode_ci default '' null comment '更新者',
  18 + update_time datetime default CURRENT_TIMESTAMP not null on update CURRENT_TIMESTAMP comment '更新时间',
  19 + deleted bit default b'0' not null comment '是否删除',
  20 + tenant_id bigint default 0 not null comment '租户编号'
  21 +) comment '交易中心配置';
  22 +
  23 +-- 增加分销用户扩展表
  24 +create table trade_brokerage_user
  25 +(
  26 + id bigint auto_increment comment '用户编号' primary key,
  27 + brokerage_user_id bigint not null comment '推广员编号',
  28 + brokerage_bind_time datetime null comment '推广员绑定时间',
  29 + brokerage_enabled bit default 1 not null comment '是否成为推广员',
  30 + brokerage_time datetime null comment '成为分销员时间',
  31 + brokerage_price int default 0 not null comment '可用佣金',
  32 + frozen_brokerage_price int default 0 not null comment '冻结佣金',
  33 + creator varchar(64) collate utf8mb4_unicode_ci default '' null comment '创建者',
  34 + create_time datetime default CURRENT_TIMESTAMP not null comment '创建时间',
  35 + updater varchar(64) collate utf8mb4_unicode_ci default '' null comment '更新者',
  36 + update_time datetime default CURRENT_TIMESTAMP not null on update CURRENT_TIMESTAMP comment '更新时间',
  37 + deleted bit default b'0' not null comment '是否删除',
  38 + tenant_id bigint default 0 not null comment '租户编号'
  39 +) comment '分销用户';
  40 +
  41 +create index idx_invite_user_id on trade_brokerage_user (brokerage_user_id) comment '推广员编号';
  42 +create index idx_agent on trade_brokerage_user (brokerage_enabled) comment '是否成为推广员';
  43 +
  44 +
  45 +create table trade_brokerage_record
  46 +(
  47 + id int auto_increment comment '编号'
  48 + primary key,
  49 + user_id bigint not null comment '用户编号',
  50 + biz_id varchar(64) default '' not null comment '业务编号',
  51 + biz_type tinyint default 0 not null comment '业务类型:0-订单,1-提现',
  52 + title varchar(64) default '' not null comment '标题',
  53 + price int default 0 not null comment '金额',
  54 + total_price int default 0 not null comment '当前总佣金',
  55 + description varchar(500) default '' not null comment '说明',
  56 + status tinyint default 0 not null comment '状态:0-待结算,1-已结算,2-已取消',
  57 + frozen_days int default 0 not null comment '冻结时间(天)',
  58 + unfreeze_time datetime null comment '解冻时间',
  59 + creator varchar(64) collate utf8mb4_general_ci default '' null comment '创建者',
  60 + create_time datetime default CURRENT_TIMESTAMP not null comment '创建时间',
  61 + updater varchar(64) collate utf8mb4_general_ci default '' null comment '更新者',
  62 + update_time datetime default CURRENT_TIMESTAMP not null on update CURRENT_TIMESTAMP comment '更新时间',
  63 + deleted bit default b'0' not null comment '是否删除',
  64 + tenant_id bigint default 0 not null comment '租户编号'
  65 +)
  66 + comment '佣金记录';
  67 +
  68 +create index idx_user_id on trade_brokerage_record (user_id) comment '用户编号';
  69 +create index idx_biz on trade_brokerage_record (biz_type, biz_id) comment '业务';
  70 +create index idx_status on trade_brokerage_record (status) comment '状态';
  71 +
  72 +
  73 +create table trade_brokerage_withdraw
  74 +(
  75 + id int auto_increment comment '编号'
  76 + primary key,
  77 + user_id bigint not null comment '用户编号',
  78 + price int default 0 not null comment '提现金额',
  79 + fee_price int default 0 not null comment '提现手续费',
  80 + total_price int default 0 not null comment '当前总佣金',
  81 + type tinyint default 0 not null comment '提现类型:1-钱包;2-银行卡;3-微信;4-支付宝',
  82 + name varchar(64) null comment '真实姓名',
  83 + account_no varchar(64) null comment '账号',
  84 + bank_name varchar(100) null comment '银行名称',
  85 + bank_address varchar(200) null comment '开户地址',
  86 + account_qr_code_url varchar(512) null comment '收款码',
  87 + status tinyint(2) default 0 not null comment '状态:0-审核中,10-审核通过 20-审核不通过;预留:11 - 提现成功;21-提现失败',
  88 + audit_reason varchar(128) null comment '审核驳回原因',
  89 + audit_time datetime null comment '审核时间',
  90 + remark varchar(500) null comment '备注',
  91 + creator varchar(64) collate utf8mb4_general_ci default '' null comment '创建者',
  92 + create_time datetime default CURRENT_TIMESTAMP not null comment '创建时间',
  93 + updater varchar(64) collate utf8mb4_general_ci default '' null comment '更新者',
  94 + update_time datetime default CURRENT_TIMESTAMP not null on update CURRENT_TIMESTAMP comment '更新时间',
  95 + deleted bit default b'0' not null comment '是否删除',
  96 + tenant_id bigint default 0 not null comment '租户编号'
  97 +)
  98 + comment '佣金提现';
  99 +
  100 +create index idx_user_id on trade_brokerage_withdraw (user_id) comment '用户编号';
  101 +create index idx_audit_status on trade_brokerage_withdraw (status) comment '状态';
  102 +
  103 +-- 增加字典
  104 +insert into system_dict_type(type, name)
  105 +values ('brokerage_enabled_condition', '分佣模式');
  106 +insert into system_dict_data(dict_type, label, value, sort, remark)
  107 +values ('brokerage_enabled_condition', '人人分销', 0, 0, '所有用户都可以分销'),
  108 + ('brokerage_enabled_condition', '指定分销', 1, 1, '仅可后台手动设置推广员');
  109 +
  110 +insert into system_dict_type(type, name)
  111 +values ('brokerage_bind_mode', '分销关系绑定模式');
  112 +insert into system_dict_data(dict_type, label, value, sort, remark)
  113 +values ('brokerage_bind_mode', '没有推广人', 0, 0, '只要用户没有推广人,随时都可以绑定推广关系'),
  114 + ('brokerage_bind_mode', '新用户', 1, 1, '仅新用户注册时才能绑定推广关系');
  115 +
  116 +insert into system_dict_type(type, name)
  117 +values ('brokerage_withdraw_type', '佣金提现类型');
  118 +insert into system_dict_data(dict_type, label, value, sort)
  119 +values ('brokerage_withdraw_type', '钱包', 1, 1),
  120 + ('brokerage_withdraw_type', '银行卡', 2, 2),
  121 + ('brokerage_withdraw_type', '微信', 3, 3),
  122 + ('brokerage_withdraw_type', '支付宝', 4, 4);
  123 +
  124 +insert into system_dict_type(type, name)
  125 +values ('brokerage_record_biz_type', '佣金记录业务类型');
  126 +insert into system_dict_data(dict_type, label, value, sort)
  127 +values ('brokerage_record_biz_type', '订单返佣', 0, 0),
  128 + ('brokerage_record_biz_type', '申请提现', 1, 1);
  129 +
  130 +insert into system_dict_type(type, name)
  131 +values ('brokerage_record_status', '佣金记录状态');
  132 +insert into system_dict_data(dict_type, label, value, sort)
  133 +values ('brokerage_record_status', '待结算', 0, 0),
  134 + ('brokerage_record_status', '已结算', 1, 1),
  135 + ('brokerage_record_status', '已取消', 2, 2);
  136 +
  137 +insert into system_dict_type(type, name)
  138 +values ('brokerage_withdraw_status', '佣金提现状态');
  139 +insert into system_dict_data(dict_type, label, value, sort)
  140 +values ('brokerage_withdraw_status', '审核中', 0, 0),
  141 + ('brokerage_withdraw_status', '审核通过', 10, 10),
  142 + ('brokerage_withdraw_status', '提现成功', 11, 11),
  143 + ('brokerage_withdraw_status', '审核不通过', 20, 20),
  144 + ('brokerage_withdraw_status', '提现失败', 21, 21);
  145 +
  146 +insert into system_dict_type(type, name)
  147 +values ('brokerage_bank_name', '佣金提现银行');
  148 +insert into system_dict_data(dict_type, label, value, sort)
  149 +values ('brokerage_bank_name', '工商银行', 0, 0),
  150 + ('brokerage_bank_name', '建设银行', 1, 1),
  151 + ('brokerage_bank_name', '农业银行', 2, 2),
  152 + ('brokerage_bank_name', '中国银行', 3, 3),
  153 + ('brokerage_bank_name', '交通银行', 4, 4),
  154 + ('brokerage_bank_name', '招商银行', 5, 5);
  155 +
  156 +
  157 +-- 交易中心配置:菜单 SQL
  158 +INSERT INTO system_menu(name, permission, type, sort, parent_id, path, icon, component, status, component_name)
  159 +VALUES ('交易中心配置', '', 2, 0, 2072, 'config', 'ep:setting', 'trade/config/index', 0, 'TradeConfig');
  160 +-- 按钮父菜单ID
  161 +-- 暂时只支持 MySQL。如果你是 Oracle、PostgreSQL、SQLServer 的话,需要手动修改 @parentId 的部分的代码
  162 +SELECT @parentId := LAST_INSERT_ID();
  163 +-- 按钮 SQL
  164 +INSERT INTO system_menu(name, permission, type, sort, parent_id, path, icon, component, status)
  165 +VALUES ('交易中心配置查询', 'trade:config:query', 3, 1, @parentId, '', '', '', 0);
  166 +INSERT INTO system_menu(name, permission, type, sort, parent_id, path, icon, component, status)
  167 +VALUES ('交易中心配置保存', 'trade:config:save', 3, 2, @parentId, '', '', '', 0);
  168 +
  169 +
  170 +-- 增加菜单:分销
  171 +INSERT INTO system_menu(name, permission, type, sort, parent_id, path, icon, component, status, component_name)
  172 +VALUES ('分销', '', 1, 5, 2072, 'brokerage', 'fa-solid:project-diagram', '', 0, '');
  173 +-- 按钮父菜单ID
  174 +SELECT @brokerageMenuId := LAST_INSERT_ID();
  175 +
  176 +-- 增加菜单:分销员
  177 +-- 菜单 SQL
  178 +INSERT INTO system_menu(name, permission, type, sort, parent_id, path, icon, component, status, component_name)
  179 +VALUES ('分销用户', '', 2, 0, @brokerageMenuId, 'brokerage-user', 'fa-solid:user-tie', 'trade/brokerage/user/index', 0,
  180 + 'TradeBrokerageUser');
  181 +-- 按钮父菜单ID
  182 +-- 暂时只支持 MySQL。如果你是 Oracle、PostgreSQL、SQLServer 的话,需要手动修改 @parentId 的部分的代码
  183 +SELECT @parentId := LAST_INSERT_ID();
  184 +-- 按钮 SQL
  185 +INSERT INTO system_menu(name, permission, type, sort, parent_id, path, icon, component, status)
  186 +VALUES ('分销用户查询', 'trade:brokerage-user:query', 3, 1, @parentId, '', '', '', 0);
  187 +INSERT INTO system_menu(name, permission, type, sort, parent_id, path, icon, component, status)
  188 +VALUES ('分销用户修改推广员', 'trade:brokerage-user:update-brokerage-user', 3, 2, @parentId, '', '', '', 0);
  189 +INSERT INTO system_menu(name, permission, type, sort, parent_id, path, icon, component, status)
  190 +VALUES ('分销用户清除推广员', 'trade:brokerage-user:clear-brokerage-user', 3, 3, @parentId, '', '', '', 0);
  191 +INSERT INTO system_menu(name, permission, type, sort, parent_id, path, icon, component, status)
  192 +VALUES ('分销用户修改推广资格', 'trade:brokerage-user:update-brokerage-enable', 3, 4, @parentId, '', '', '', 0);
  193 +
  194 +
  195 +-- 增加菜单:佣金记录
  196 +INSERT INTO system_menu(name, permission, type, sort, parent_id, path, icon, component, status, component_name)
  197 +VALUES ('佣金记录', '', 2, 1, @brokerageMenuId, 'brokerage-record', 'fa:money', 'trade/brokerage/record/index', 0,
  198 + 'TradeBrokerageRecord');
  199 +-- 按钮父菜单ID
  200 +-- 暂时只支持 MySQL。如果你是 Oracle、PostgreSQL、SQLServer 的话,需要手动修改 @parentId 的部分的代码
  201 +SELECT @parentId := LAST_INSERT_ID();
  202 +-- 按钮 SQL
  203 +INSERT INTO system_menu(name, permission, type, sort, parent_id, path, icon, component, status)
  204 +VALUES ('佣金记录查询', 'trade:brokerage-record:query', 3, 1, @parentId, '', '', '', 0);
  205 +
  206 +-- 增加菜单:佣金提现
  207 +INSERT INTO system_menu(name, permission, type, sort, parent_id, path, icon, component, status, component_name)
  208 +VALUES ('佣金提现', '', 2, 2, @brokerageMenuId, 'brokerage-withdraw', 'fa:credit-card',
  209 + 'trade/brokerage/withdraw/index', 0, 'TradeBrokerageWithdraw');
  210 +-- 按钮父菜单ID
  211 +-- 暂时只支持 MySQL。如果你是 Oracle、PostgreSQL、SQLServer 的话,需要手动修改 @parentId 的部分的代码
  212 +SELECT @parentId := LAST_INSERT_ID();
  213 +-- 按钮 SQL
  214 +INSERT INTO system_menu(name, permission, type, sort, parent_id, path, icon, component, status)
  215 +VALUES ('佣金提现查询', 'trade:brokerage-withdraw:query', 3, 1, @parentId, '', '', '', 0);
  216 +INSERT INTO system_menu(name, permission, type, sort, parent_id, path, icon, component, status)
  217 +VALUES ('佣金提现审核', 'trade:brokerage-withdraw:audit', 3, 2, @parentId, '', '', '', 0);
0 218 \ No newline at end of file
... ...
sql/mysql/pay_wallet.sql
1 1 -- ----------------------------
2   --- 支付-钱包表
  2 +-- 会员钱包表
3 3 -- ----------------------------
4 4 DROP TABLE IF EXISTS `pay_wallet`;
5 5 CREATE TABLE `pay_wallet`
... ... @@ -17,28 +17,27 @@ CREATE TABLE `pay_wallet`
17 17 `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除',
18 18 `tenant_id` bigint NOT NULL DEFAULT 0 COMMENT '租户编号',
19 19 PRIMARY KEY (`id`) USING BTREE
20   -) ENGINE=InnoDB COMMENT='支付钱包表';
  20 +) ENGINE=InnoDB COMMENT='会员钱包表';
21 21  
22 22 -- ----------------------------
23   --- 支付- 钱包余额明细表
  23 +-- 会员钱包流水表
24 24 -- ----------------------------
25 25 DROP TABLE IF EXISTS `pay_wallet_transaction`;
26 26 CREATE TABLE `pay_wallet_transaction`
27 27 (
28   - `id` bigint NOT NULL AUTO_INCREMENT COMMENT '编号',
29   - `wallet_id` bigint NOT NULL COMMENT '会员钱包 id',
30   - `biz_type` tinyint NOT NULL COMMENT '关联类型',
31   - `biz_id` bigint NOT NULL COMMENT '关联业务编号',
32   - `no` varchar(64) NOT NULL COMMENT '流水号',
33   - `description` varchar(255) COMMENT '操作说明',
34   - `amount` int NOT NULL COMMENT '交易金额, 单位分',
35   - `balance` int NOT NULL COMMENT '余额, 单位分',
36   - `transaction_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '交易时间',
37   - `creator` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT '' COMMENT '创建者',
38   - `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
39   - `updater` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT '' COMMENT '更新者',
40   - `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
41   - `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除',
42   - `tenant_id` bigint NOT NULL DEFAULT 0 COMMENT '租户编号',
  28 + `id` bigint NOT NULL AUTO_INCREMENT COMMENT '编号',
  29 + `wallet_id` bigint NOT NULL COMMENT '会员钱包 id',
  30 + `biz_type` tinyint NOT NULL COMMENT '关联类型',
  31 + `biz_id` varchar(64) NOT NULL COMMENT '关联业务编号',
  32 + `no` varchar(64) NOT NULL COMMENT '流水号',
  33 + `title` varchar(128) NOT NULL COMMENT '流水标题',
  34 + `price` int NOT NULL COMMENT '交易金额, 单位分',
  35 + `balance` int NOT NULL COMMENT '余额, 单位分',
  36 + `creator` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT '' COMMENT '创建者',
  37 + `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
  38 + `updater` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT '' COMMENT '更新者',
  39 + `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
  40 + `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除',
  41 + `tenant_id` bigint NOT NULL DEFAULT 0 COMMENT '租户编号',
43 42 PRIMARY KEY (`id`) USING BTREE
44   -) ENGINE=InnoDB COMMENT='支付钱包余额明细表';
  43 +) ENGINE=InnoDB COMMENT='会员钱包流水表';
... ...
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: 20/08/2023 19:42:16
  14 + Date: 03/09/2023 19:13:55
15 15 */
16 16  
17 17 SET NAMES utf8mb4;
... ... @@ -360,7 +360,7 @@ CREATE TABLE `infra_api_error_log` (
360 360 `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除',
361 361 `tenant_id` bigint NOT NULL DEFAULT 0 COMMENT '租户编号',
362 362 PRIMARY KEY (`id`) USING BTREE
363   -) ENGINE = InnoDB AUTO_INCREMENT = 1453 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '系统异常日志';
  363 +) ENGINE = InnoDB AUTO_INCREMENT = 1497 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '系统异常日志';
364 364  
365 365 -- ----------------------------
366 366 -- Records of infra_api_error_log
... ... @@ -514,7 +514,7 @@ CREATE TABLE `infra_file` (
514 514 `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
515 515 `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除',
516 516 PRIMARY KEY (`id`) USING BTREE
517   -) ENGINE = InnoDB AUTO_INCREMENT = 975 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '文件表';
  517 +) ENGINE = InnoDB AUTO_INCREMENT = 1054 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '文件表';
518 518  
519 519 -- ----------------------------
520 520 -- Records of infra_file
... ... @@ -568,7 +568,7 @@ CREATE TABLE `infra_file_content` (
568 568 `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
569 569 `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除',
570 570 PRIMARY KEY (`id`) USING BTREE
571   -) ENGINE = InnoDB AUTO_INCREMENT = 66 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '文件表';
  571 +) ENGINE = InnoDB AUTO_INCREMENT = 145 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '文件表';
572 572  
573 573 -- ----------------------------
574 574 -- Records of infra_file_content
... ... @@ -694,6 +694,124 @@ INSERT INTO `member_address` (`id`, `user_id`, `name`, `mobile`, `area_id`, `det
694 694 COMMIT;
695 695  
696 696 -- ----------------------------
  697 +-- Table structure for member_experience_record
  698 +-- ----------------------------
  699 +DROP TABLE IF EXISTS `member_experience_record`;
  700 +CREATE TABLE `member_experience_record` (
  701 + `id` bigint NOT NULL AUTO_INCREMENT COMMENT '编号',
  702 + `user_id` bigint NOT NULL DEFAULT 0 COMMENT '用户编号',
  703 + `biz_id` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '' COMMENT '业务编号',
  704 + `biz_type` tinyint NOT NULL DEFAULT 0 COMMENT '业务类型',
  705 + `title` varchar(30) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '' COMMENT '标题',
  706 + `description` varchar(512) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '' COMMENT '描述',
  707 + `experience` int NOT NULL DEFAULT 0 COMMENT '经验',
  708 + `total_experience` int NOT NULL DEFAULT 0 COMMENT '变更后的经验',
  709 + `creator` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT '' COMMENT '创建者',
  710 + `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
  711 + `updater` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT '' COMMENT '更新者',
  712 + `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
  713 + `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除',
  714 + `tenant_id` bigint NOT NULL DEFAULT 0 COMMENT '租户编号',
  715 + PRIMARY KEY (`id`) USING BTREE,
  716 + INDEX `idx_user_id`(`user_id` ASC) USING BTREE COMMENT '会员经验记录-用户编号',
  717 + INDEX `idx_user_biz_type`(`user_id` ASC, `biz_type` ASC) USING BTREE COMMENT '会员经验记录-用户业务类型'
  718 +) ENGINE = InnoDB AUTO_INCREMENT = 7 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '会员经验记录';
  719 +
  720 +-- ----------------------------
  721 +-- Records of member_experience_record
  722 +-- ----------------------------
  723 +BEGIN;
  724 +INSERT INTO `member_experience_record` (`id`, `user_id`, `biz_id`, `biz_type`, `title`, `description`, `experience`, `total_experience`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (1, 247, '0', 0, '管理员调整', '管理员调整获得100经验', 100, 100, '1', '2023-08-22 21:52:44', '1', '2023-08-22 21:52:44', b'0', 1);
  725 +INSERT INTO `member_experience_record` (`id`, `user_id`, `biz_id`, `biz_type`, `title`, `description`, `experience`, `total_experience`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (2, 247, '0', 0, '管理员调整', '管理员调整获得100经验', -50, 100, '1', '2023-08-22 21:52:44', '1', '2023-08-22 21:52:44', b'0', 1);
  726 +INSERT INTO `member_experience_record` (`id`, `user_id`, `biz_id`, `biz_type`, `title`, `description`, `experience`, `total_experience`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (3, 247, '78', 2, '下单奖励', '下单获得 27 经验', 27, 127, NULL, '2023-08-30 18:46:52', NULL, '2023-08-30 18:46:52', b'0', 1);
  727 +INSERT INTO `member_experience_record` (`id`, `user_id`, `biz_id`, `biz_type`, `title`, `description`, `experience`, `total_experience`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (4, 247, 'null', 3, '退单扣除', '退单获得 -6 经验', -6, 121, NULL, '2023-08-31 19:56:21', NULL, '2023-08-31 19:56:21', b'0', 1);
  728 +INSERT INTO `member_experience_record` (`id`, `user_id`, `biz_id`, `biz_type`, `title`, `description`, `experience`, `total_experience`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (5, 247, '80', 2, '下单奖励', '下单获得 699906 经验', 699906, 700027, NULL, '2023-08-31 23:43:29', NULL, '2023-08-31 23:43:29', b'0', 1);
  729 +INSERT INTO `member_experience_record` (`id`, `user_id`, `biz_id`, `biz_type`, `title`, `description`, `experience`, `total_experience`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (6, 247, '81', 2, '下单奖励', '下单获得 2799606 经验', 2799606, 3499633, NULL, '2023-08-31 23:46:17', NULL, '2023-08-31 23:46:17', b'0', 1);
  730 +COMMIT;
  731 +
  732 +-- ----------------------------
  733 +-- Table structure for member_group
  734 +-- ----------------------------
  735 +DROP TABLE IF EXISTS `member_group`;
  736 +CREATE TABLE `member_group` (
  737 + `id` bigint NOT NULL AUTO_INCREMENT COMMENT '编号',
  738 + `name` varchar(30) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '' COMMENT '名称',
  739 + `status` tinyint NOT NULL DEFAULT 0 COMMENT '状态',
  740 + `remark` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '' COMMENT '备注',
  741 + `creator` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT '' COMMENT '创建者',
  742 + `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
  743 + `updater` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT '' COMMENT '更新者',
  744 + `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
  745 + `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除',
  746 + `tenant_id` bigint NOT NULL DEFAULT 0 COMMENT '租户编号',
  747 + PRIMARY KEY (`id`) USING BTREE
  748 +) ENGINE = InnoDB AUTO_INCREMENT = 2 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '用户分组';
  749 +
  750 +-- ----------------------------
  751 +-- Records of member_group
  752 +-- ----------------------------
  753 +BEGIN;
  754 +COMMIT;
  755 +
  756 +-- ----------------------------
  757 +-- Table structure for member_level
  758 +-- ----------------------------
  759 +DROP TABLE IF EXISTS `member_level`;
  760 +CREATE TABLE `member_level` (
  761 + `id` bigint NOT NULL AUTO_INCREMENT COMMENT '编号',
  762 + `name` varchar(30) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '' COMMENT '等级名称',
  763 + `level` int NOT NULL DEFAULT 0 COMMENT '等级',
  764 + `experience` int NOT NULL DEFAULT 0 COMMENT '升级经验',
  765 + `discount_percent` tinyint NOT NULL DEFAULT 100 COMMENT '享受折扣',
  766 + `icon` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '' COMMENT '等级图标',
  767 + `background_url` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '' COMMENT '等级背景图',
  768 + `status` tinyint NOT NULL DEFAULT 0 COMMENT '状态',
  769 + `creator` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT '' COMMENT '创建者',
  770 + `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
  771 + `updater` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT '' COMMENT '更新者',
  772 + `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
  773 + `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除',
  774 + `tenant_id` bigint NOT NULL DEFAULT 0 COMMENT '租户编号',
  775 + PRIMARY KEY (`id`) USING BTREE
  776 +) ENGINE = InnoDB AUTO_INCREMENT = 4 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '会员等级';
  777 +
  778 +-- ----------------------------
  779 +-- Records of member_level
  780 +-- ----------------------------
  781 +BEGIN;
  782 +COMMIT;
  783 +
  784 +-- ----------------------------
  785 +-- Table structure for member_level_record
  786 +-- ----------------------------
  787 +DROP TABLE IF EXISTS `member_level_record`;
  788 +CREATE TABLE `member_level_record` (
  789 + `id` bigint NOT NULL AUTO_INCREMENT COMMENT '编号',
  790 + `user_id` bigint NOT NULL DEFAULT 0 COMMENT '用户编号',
  791 + `level_id` bigint NOT NULL DEFAULT 0 COMMENT '等级编号',
  792 + `level` int NOT NULL DEFAULT 0 COMMENT '会员等级',
  793 + `discount_percent` tinyint NOT NULL DEFAULT 100 COMMENT '享受折扣',
  794 + `experience` int NOT NULL DEFAULT 0 COMMENT '升级经验',
  795 + `user_experience` int NOT NULL DEFAULT 0 COMMENT '会员此时的经验',
  796 + `remark` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '' COMMENT '备注',
  797 + `description` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '' COMMENT '描述',
  798 + `creator` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT '' COMMENT '创建者',
  799 + `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
  800 + `updater` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT '' COMMENT '更新者',
  801 + `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
  802 + `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除',
  803 + `tenant_id` bigint NOT NULL DEFAULT 0 COMMENT '租户编号',
  804 + PRIMARY KEY (`id`) USING BTREE,
  805 + INDEX `idx_user_id`(`user_id` ASC) USING BTREE COMMENT '会员等级记录-用户编号'
  806 +) ENGINE = InnoDB AUTO_INCREMENT = 4 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '会员等级记录';
  807 +
  808 +-- ----------------------------
  809 +-- Records of member_level_record
  810 +-- ----------------------------
  811 +BEGIN;
  812 +COMMIT;
  813 +
  814 +-- ----------------------------
697 815 -- Table structure for member_point_config
698 816 -- ----------------------------
699 817 DROP TABLE IF EXISTS `member_point_config`;
... ... @@ -741,7 +859,7 @@ CREATE TABLE `member_point_record` (
741 859 PRIMARY KEY (`id`) USING BTREE,
742 860 INDEX `index_userId`(`user_id` ASC) USING BTREE,
743 861 INDEX `index_title`(`title` ASC) USING BTREE
744   -) ENGINE = InnoDB AUTO_INCREMENT = 4 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci COMMENT = '用户积分记录';
  862 +) ENGINE = InnoDB AUTO_INCREMENT = 8 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci COMMENT = '用户积分记录';
745 863  
746 864 -- ----------------------------
747 865 -- Records of member_point_record
... ... @@ -749,7 +867,11 @@ CREATE TABLE `member_point_record` (
749 867 BEGIN;
750 868 INSERT INTO `member_point_record` (`id`, `user_id`, `biz_id`, `biz_type`, `title`, `description`, `point`, `total_point`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (1, 247, '1', 1, '12', NULL, 33, 12, '', '2023-07-02 14:50:23', '', '2023-08-20 11:03:01', b'0', 1);
751 869 INSERT INTO `member_point_record` (`id`, `user_id`, `biz_id`, `biz_type`, `title`, `description`, `point`, `total_point`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (2, 247, '12', 1, '123', NULL, 22, 130, '', '2023-07-02 14:50:23', '', '2023-08-20 11:03:00', b'0', 1);
752   -INSERT INTO `member_point_record` (`id`, `user_id`, `biz_id`, `biz_type`, `title`, `description`, `point`, `total_point`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (3, 247, '12', 1, '12', NULL, -12, 12, '', '2023-07-02 14:50:23', '', '2023-08-20 11:02:50', b'0', 1);
  870 +INSERT INTO `member_point_record` (`id`, `user_id`, `biz_id`, `biz_type`, `title`, `description`, `point`, `total_point`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (3, 247, '12', 1, '12', NULL, -12, 12, '', '2023-07-02 14:50:55', '', '2023-08-21 14:19:29', b'0', 1);
  871 +INSERT INTO `member_point_record` (`id`, `user_id`, `biz_id`, `biz_type`, `title`, `description`, `point`, `total_point`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (4, 247, '78', 10, '订单消费', '下单获得 81 积分', 81, 91, NULL, '2023-08-30 18:46:52', NULL, '2023-08-30 18:46:52', b'0', 1);
  872 +INSERT INTO `member_point_record` (`id`, `user_id`, `biz_id`, `biz_type`, `title`, `description`, `point`, `total_point`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (5, 247, 'null', 11, '订单取消', '退单获得 -18 积分', -18, 73, NULL, '2023-08-31 19:56:21', NULL, '2023-08-31 19:56:21', b'0', 1);
  873 +INSERT INTO `member_point_record` (`id`, `user_id`, `biz_id`, `biz_type`, `title`, `description`, `point`, `total_point`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (6, 247, '80', 10, '订单消费', '下单获得 2099718 积分', 2099718, 2099791, NULL, '2023-08-31 23:43:29', NULL, '2023-08-31 23:43:29', b'0', 1);
  874 +INSERT INTO `member_point_record` (`id`, `user_id`, `biz_id`, `biz_type`, `title`, `description`, `point`, `total_point`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (7, 247, '81', 10, '订单消费', '下单获得 8398818 积分', 8398818, 10498609, NULL, '2023-08-31 23:46:17', NULL, '2023-08-31 23:46:17', b'0', 1);
753 875 COMMIT;
754 876  
755 877 -- ----------------------------
... ... @@ -768,7 +890,7 @@ CREATE TABLE `member_sign_in_config` (
768 890 `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除',
769 891 `tenant_id` bigint NOT NULL DEFAULT 0 COMMENT '租户编号',
770 892 PRIMARY KEY (`id`) USING BTREE
771   -) ENGINE = InnoDB AUTO_INCREMENT = 8 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci COMMENT = '签到规则';
  893 +) ENGINE = InnoDB AUTO_INCREMENT = 13 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci COMMENT = '签到规则';
772 894  
773 895 -- ----------------------------
774 896 -- Records of member_sign_in_config
... ... @@ -781,6 +903,11 @@ INSERT INTO `member_sign_in_config` (`id`, `day`, `point`, `status`, `creator`,
781 903 INSERT INTO `member_sign_in_config` (`id`, `day`, `point`, `status`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (5, 2, 12, 0, '', '2023-08-20 01:38:56', '', '2023-08-20 01:38:56', b'0', 0);
782 904 INSERT INTO `member_sign_in_config` (`id`, `day`, `point`, `status`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (6, 1, 10, 0, '1', '2023-08-20 19:20:42', '1', '2023-08-20 19:20:56', b'0', 1);
783 905 INSERT INTO `member_sign_in_config` (`id`, `day`, `point`, `status`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (7, 7, 22, 0, '1', '2023-08-20 19:20:48', '1', '2023-08-20 19:20:48', b'0', 1);
  906 +INSERT INTO `member_sign_in_config` (`id`, `day`, `point`, `status`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (8, 2, 3, 0, '1', '2023-08-21 20:22:44', '1', '2023-08-21 20:22:44', b'0', 1);
  907 +INSERT INTO `member_sign_in_config` (`id`, `day`, `point`, `status`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (9, 3, 4, 0, '1', '2023-08-21 20:22:48', '1', '2023-08-21 20:22:48', b'0', 1);
  908 +INSERT INTO `member_sign_in_config` (`id`, `day`, `point`, `status`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (10, 4, 5, 0, '1', '2023-08-21 20:22:51', '1', '2023-08-21 20:22:51', b'0', 1);
  909 +INSERT INTO `member_sign_in_config` (`id`, `day`, `point`, `status`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (11, 5, 6, 0, '1', '2023-08-21 20:22:56', '1', '2023-08-21 20:22:56', b'0', 1);
  910 +INSERT INTO `member_sign_in_config` (`id`, `day`, `point`, `status`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (12, 6, 7, 0, '1', '2023-08-21 20:22:59', '1', '2023-08-21 20:22:59', b'0', 1);
784 911 COMMIT;
785 912  
786 913 -- ----------------------------
... ... @@ -822,7 +949,7 @@ CREATE TABLE `member_tag` (
822 949 `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除',
823 950 `tenant_id` bigint NOT NULL DEFAULT 0 COMMENT '租户编号',
824 951 PRIMARY KEY (`id`) USING BTREE
825   -) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '会员标签';
  952 +) ENGINE = InnoDB AUTO_INCREMENT = 3 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '会员标签';
826 953  
827 954 -- ----------------------------
828 955 -- Records of member_tag
... ... @@ -853,6 +980,9 @@ CREATE TABLE `member_user` (
853 980 `mark` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '会员备注',
854 981 `point` int NOT NULL DEFAULT 0 COMMENT '积分',
855 982 `tag_ids` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '用户标签编号列表,以逗号分隔',
  983 + `level_id` bigint NULL DEFAULT NULL COMMENT '等级编号',
  984 + `experience` int NOT NULL DEFAULT 0 COMMENT '经验',
  985 + `group_id` bigint NULL DEFAULT NULL COMMENT '用户分组编号',
856 986 `creator` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT '' COMMENT '创建者',
857 987 `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
858 988 `updater` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT '' COMMENT '更新者',
... ... @@ -929,7 +1059,7 @@ CREATE TABLE `system_dict_data` (
929 1059 `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
930 1060 `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除',
931 1061 PRIMARY KEY (`id`) USING BTREE
932   -) ENGINE = InnoDB AUTO_INCREMENT = 1350 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '字典数据表';
  1062 +) ENGINE = InnoDB AUTO_INCREMENT = 1359 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '字典数据表';
933 1063  
934 1064 -- ----------------------------
935 1065 -- Records of system_dict_data
... ... @@ -1058,8 +1188,8 @@ INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `st
1058 1188 INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1166, 2, '折扣', '2', 'promotion_discount_type', 0, 'primary', '', '优惠类型 - 折扣', '1', '2022-11-01 12:46:51', '1', '2022-11-01 12:50:08', b'0');
1059 1189 INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1167, 1, '固定日期', '1', 'promotion_coupon_template_validity_type', 0, 'default', '', '优惠劵模板的有限期类型 - 固定日期', '1', '2022-11-02 00:07:34', '1', '2022-11-04 00:07:49', b'0');
1060 1190 INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1168, 2, '领取之后', '2', 'promotion_coupon_template_validity_type', 0, 'default', '', '优惠劵模板的有限期类型 - 领取之后', '1', '2022-11-02 00:07:54', '1', '2022-11-04 00:07:52', b'0');
1061   -INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1169, 1, '全部商品参与', '1', 'promotion_product_scope', 0, 'default', '', '营销的商品范围 - 全部商品参与', '1', '2022-11-02 00:28:22', '1', '2022-11-02 00:28:22', b'0');
1062   -INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1170, 2, '指定商品参与', '2', 'promotion_product_scope', 0, 'default', '', '营销的商品范围 - 指定商品参与', '1', '2022-11-02 00:28:34', '1', '2022-11-02 00:28:40', b'0');
  1191 +INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1169, 1, '通用卷', '1', 'promotion_product_scope', 0, 'default', '', '营销的商品范围 - 全部商品参与', '1', '2022-11-02 00:28:22', '1', '2023-09-01 23:42:49', b'0');
  1192 +INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1170, 2, '商品卷', '2', 'promotion_product_scope', 0, 'default', '', '营销的商品范围 - 指定商品参与', '1', '2022-11-02 00:28:34', '1', '2023-09-01 23:42:54', b'0');
1063 1193 INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1171, 1, '已领取', '1', 'promotion_coupon_status', 0, 'primary', '', '优惠劵的状态 - 已领取', '1', '2022-11-04 00:15:08', '1', '2022-11-04 19:16:04', b'0');
1064 1194 INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1172, 2, '已使用', '2', 'promotion_coupon_status', 0, 'success', '', '优惠劵的状态 - 已使用', '1', '2022-11-04 00:15:21', '1', '2022-11-04 19:16:08', b'0');
1065 1195 INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1173, 3, '已过期', '3', 'promotion_coupon_status', 0, 'info', '', '优惠劵的状态 - 已过期', '1', '2022-11-04 00:15:43', '1', '2022-11-04 19:16:12', b'0');
... ... @@ -1146,6 +1276,15 @@ INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `st
1146 1276 INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1347, 2, '退款单', '2', 'pay_notify_type', 0, 'danger', '', NULL, '1', '2023-07-20 12:23:26', '1', '2023-07-20 12:23:26', b'0');
1147 1277 INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1348, 20, '模拟支付', 'mock', 'pay_channel_code', 0, 'default', '', '模拟支付', '1', '2023-07-29 11:10:51', '1', '2023-07-29 03:14:10', b'0');
1148 1278 INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1349, 12, '订单取消', '12', 'member_point_biz_type', 0, '', '', '', '1', '2023-08-20 12:00:03', '1', '2023-08-20 12:00:03', b'0');
  1279 +INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1350, 0, '管理员调整', '0', 'member_experience_biz_type', 0, '', '', NULL, '', '2023-08-22 12:41:01', '', '2023-08-22 12:41:01', b'0');
  1280 +INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1351, 1, '邀新奖励', '1', 'member_experience_biz_type', 0, '', '', NULL, '', '2023-08-22 12:41:01', '', '2023-08-22 12:41:01', b'0');
  1281 +INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1352, 2, '下单奖励', '2', 'member_experience_biz_type', 0, '', '', NULL, '', '2023-08-22 12:41:01', '', '2023-08-22 12:41:01', b'0');
  1282 +INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1353, 3, '退单扣除', '3', 'member_experience_biz_type', 0, '', '', NULL, '', '2023-08-22 12:41:01', '', '2023-08-22 12:41:01', b'0');
  1283 +INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1354, 4, '签到奖励', '4', 'member_experience_biz_type', 0, '', '', NULL, '', '2023-08-22 12:41:01', '', '2023-08-22 12:41:01', b'0');
  1284 +INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1355, 5, '抽奖奖励', '5', 'member_experience_biz_type', 0, '', '', NULL, '', '2023-08-22 12:41:01', '', '2023-08-22 12:41:01', b'0');
  1285 +INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1356, 1, '快递发货', '1', 'trade_delivery_type', 0, '', '', '', '1', '2023-08-23 00:04:55', '1', '2023-08-23 00:04:55', b'0');
  1286 +INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1357, 2, '用户自提', '2', 'trade_delivery_type', 0, '', '', '', '1', '2023-08-23 00:05:05', '1', '2023-08-23 00:05:05', b'0');
  1287 +INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1358, 3, '品类卷', '3', 'promotion_product_scope', 0, 'default', '', '', '1', '2023-09-01 23:43:07', '1', '2023-09-01 23:43:07', b'0');
1149 1288 COMMIT;
1150 1289  
1151 1290 -- ----------------------------
... ... @@ -1166,7 +1305,7 @@ CREATE TABLE `system_dict_type` (
1166 1305 `deleted_time` datetime NULL DEFAULT NULL COMMENT '删除时间',
1167 1306 PRIMARY KEY (`id`) USING BTREE,
1168 1307 UNIQUE INDEX `dict_type`(`type` ASC) USING BTREE
1169   -) ENGINE = InnoDB AUTO_INCREMENT = 174 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '字典类型表';
  1308 +) ENGINE = InnoDB AUTO_INCREMENT = 176 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '字典类型表';
1170 1309  
1171 1310 -- ----------------------------
1172 1311 -- Records of system_dict_type
... ... @@ -1229,6 +1368,8 @@ INSERT INTO `system_dict_type` (`id`, `name`, `type`, `status`, `remark`, `creat
1229 1368 INSERT INTO `system_dict_type` (`id`, `name`, `type`, `status`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `deleted_time`) VALUES (170, '快递计费方式', 'trade_delivery_express_charge_mode', 0, '用于商城交易模块配送管理', '1', '2023-05-21 22:45:03', '1', '2023-05-21 22:45:03', b'0', '1970-01-01 00:00:00');
1230 1369 INSERT INTO `system_dict_type` (`id`, `name`, `type`, `status`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `deleted_time`) VALUES (171, '积分业务类型', 'member_point_biz_type', 0, '', '1', '2023-06-10 12:15:00', '1', '2023-06-28 13:48:20', b'0', '1970-01-01 00:00:00');
1231 1370 INSERT INTO `system_dict_type` (`id`, `name`, `type`, `status`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `deleted_time`) VALUES (173, '支付通知类型', 'pay_notify_type', 0, NULL, '1', '2023-07-20 12:23:03', '1', '2023-07-20 12:23:03', b'0', '1970-01-01 00:00:00');
  1371 +INSERT INTO `system_dict_type` (`id`, `name`, `type`, `status`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `deleted_time`) VALUES (174, '会员经验业务类型', 'member_experience_biz_type', 0, NULL, '', '2023-08-22 12:41:01', '', '2023-08-22 12:41:01', b'0', NULL);
  1372 +INSERT INTO `system_dict_type` (`id`, `name`, `type`, `status`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `deleted_time`) VALUES (175, '交易配送类型', 'trade_delivery_type', 0, '', '1', '2023-08-23 00:03:14', '1', '2023-08-23 00:03:14', b'0', '1970-01-01 00:00:00');
1232 1373 COMMIT;
1233 1374  
1234 1375 -- ----------------------------
... ... @@ -1277,7 +1418,7 @@ CREATE TABLE `system_login_log` (
1277 1418 `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除',
1278 1419 `tenant_id` bigint NOT NULL DEFAULT 0 COMMENT '租户编号',
1279 1420 PRIMARY KEY (`id`) USING BTREE
1280   -) ENGINE = InnoDB AUTO_INCREMENT = 2303 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '系统访问记录';
  1421 +) ENGINE = InnoDB AUTO_INCREMENT = 2375 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '系统访问记录';
1281 1422  
1282 1423 -- ----------------------------
1283 1424 -- Records of system_login_log
... ... @@ -1407,7 +1548,7 @@ CREATE TABLE `system_menu` (
1407 1548 `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
1408 1549 `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除',
1409 1550 PRIMARY KEY (`id`) USING BTREE
1410   -) ENGINE = InnoDB AUTO_INCREMENT = 2325 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '菜单权限表';
  1551 +) ENGINE = InnoDB AUTO_INCREMENT = 2342 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '菜单权限表';
1411 1552  
1412 1553 -- ----------------------------
1413 1554 -- Records of system_menu
... ... @@ -1638,33 +1779,33 @@ INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_i
1638 1779 INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1267, '客户端删除', 'system:oauth2-client:delete', 3, 4, 1263, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2022-05-10 16:26:33', '1', '2022-05-11 00:31:33', b'0');
1639 1780 INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1281, '报表管理', '', 1, 40, 0, '/report', 'chart', NULL, NULL, 0, b'1', b'1', b'1', '1', '2022-07-10 20:22:15', '1', '2023-02-07 17:16:40', b'0');
1640 1781 INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1282, '报表设计器', '', 2, 1, 1281, 'jimu-report', 'example', 'report/jmreport/index', 'GoView', 0, b'1', b'1', b'1', '1', '2022-07-10 20:26:36', '1', '2023-04-08 10:47:59', b'0');
1641   -INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2000, '商品中心', '', 1, 60, 0, '/product', 'merchant', NULL, NULL, 0, b'1', b'1', b'1', '', '2022-07-29 15:53:53', '1', '2022-07-30 22:26:19', b'0');
1642   -INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2002, '商品分类', '', 2, 2, 2000, 'category', 'dict', 'mall/product/category/index', 'ProductCategory', 0, b'1', b'1', b'1', '', '2022-07-29 15:53:53', '1', '2023-04-08 11:34:59', b'0');
  1782 +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2000, '商品中心', '', 1, 60, 0, '/product', 'fa:product-hunt', NULL, NULL, 0, b'1', b'1', b'1', '', '2022-07-29 15:53:53', '1', '2023-08-21 10:26:51', b'0');
  1783 +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2002, '商品分类', '', 2, 2, 2000, 'category', 'ep:cellphone', 'mall/product/category/index', 'ProductCategory', 0, b'1', b'1', b'1', '', '2022-07-29 15:53:53', '1', '2023-08-21 10:27:15', b'0');
1643 1784 INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2003, '分类查询', 'product:category:query', 3, 1, 2002, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2022-07-29 15:53:53', '', '2022-07-29 15:53:53', b'0');
1644 1785 INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2004, '分类创建', 'product:category:create', 3, 2, 2002, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2022-07-29 15:53:53', '', '2022-07-29 15:53:53', b'0');
1645 1786 INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2005, '分类更新', 'product:category:update', 3, 3, 2002, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2022-07-29 15:53:53', '', '2022-07-29 15:53:53', b'0');
1646 1787 INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2006, '分类删除', 'product:category:delete', 3, 4, 2002, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2022-07-29 15:53:53', '', '2022-07-29 15:53:53', b'0');
1647   -INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2008, '商品品牌', '', 2, 3, 2000, 'brand', 'dashboard', 'mall/product/brand/index', 'ProductBrand', 0, b'1', b'1', b'1', '', '2022-07-30 13:52:44', '1', '2023-04-08 11:35:29', b'0');
  1788 +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2008, '商品品牌', '', 2, 3, 2000, 'brand', 'ep:chicken', 'mall/product/brand/index', 'ProductBrand', 0, b'1', b'1', b'1', '', '2022-07-30 13:52:44', '1', '2023-08-21 10:27:28', b'0');
1648 1789 INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2009, '品牌查询', 'product:brand:query', 3, 1, 2008, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2022-07-30 13:52:44', '', '2022-07-30 13:52:44', b'0');
1649 1790 INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2010, '品牌创建', 'product:brand:create', 3, 2, 2008, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2022-07-30 13:52:44', '', '2022-07-30 13:52:44', b'0');
1650 1791 INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2011, '品牌更新', 'product:brand:update', 3, 3, 2008, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2022-07-30 13:52:44', '', '2022-07-30 13:52:44', b'0');
1651 1792 INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2012, '品牌删除', 'product:brand:delete', 3, 4, 2008, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2022-07-30 13:52:44', '', '2022-07-30 13:52:44', b'0');
1652   -INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2014, '商品列表', '', 2, 1, 2000, 'spu', 'list', 'mall/product/spu/index', 'ProductSpu', 0, b'1', b'1', b'1', '', '2022-07-30 14:22:58', '1', '2023-04-08 11:34:47', b'0');
  1793 +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2014, '商品列表', '', 2, 1, 2000, 'spu', 'ep:apple', 'mall/product/spu/index', 'ProductSpu', 0, b'1', b'1', b'1', '', '2022-07-30 14:22:58', '1', '2023-08-21 10:27:01', b'0');
1653 1794 INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2015, '商品查询', 'product:spu:query', 3, 1, 2014, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2022-07-30 14:22:58', '', '2022-07-30 14:22:58', b'0');
1654 1795 INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2016, '商品创建', 'product:spu:create', 3, 2, 2014, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2022-07-30 14:22:58', '', '2022-07-30 14:22:58', b'0');
1655 1796 INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2017, '商品更新', 'product:spu:update', 3, 3, 2014, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2022-07-30 14:22:58', '', '2022-07-30 14:22:58', b'0');
1656 1797 INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2018, '商品删除', 'product:spu:delete', 3, 4, 2014, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2022-07-30 14:22:58', '', '2022-07-30 14:22:58', b'0');
1657   -INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2019, '商品属性', '', 2, 3, 2000, 'property', 'eye', 'mall/product/property/index', 'ProductProperty', 0, b'1', b'1', b'1', '', '2022-08-01 14:55:35', '1', '2023-04-08 11:35:15', b'0');
  1798 +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2019, '商品属性', '', 2, 4, 2000, 'property', 'ep:cold-drink', 'mall/product/property/index', 'ProductProperty', 0, b'1', b'1', b'1', '', '2022-08-01 14:55:35', '1', '2023-08-26 11:01:05', b'0');
1658 1799 INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2020, '规格查询', 'product:property:query', 3, 1, 2019, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2022-08-01 14:55:35', '', '2022-12-12 20:26:24', b'0');
1659 1800 INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2021, '规格创建', 'product:property:create', 3, 2, 2019, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2022-08-01 14:55:35', '', '2022-12-12 20:26:30', b'0');
1660 1801 INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2022, '规格更新', 'product:property:update', 3, 3, 2019, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2022-08-01 14:55:35', '', '2022-12-12 20:26:33', b'0');
1661 1802 INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2023, '规格删除', 'product:property:delete', 3, 4, 2019, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2022-08-01 14:55:35', '', '2022-12-12 20:26:37', b'0');
1662   -INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2025, 'Banner管理', '', 2, 100, 2000, 'banner', '', 'mall/market/banner/index', NULL, 0, b'1', b'1', b'1', '', '2022-08-01 14:56:14', '1', '2022-10-24 22:29:39', b'0');
  1803 +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2025, 'Banner管理', '', 2, 100, 2030, 'banner', '', 'mall/market/banner/index', NULL, 0, b'1', b'1', b'1', '', '2022-08-01 14:56:14', '1', '2023-08-21 10:27:51', b'0');
1663 1804 INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2026, 'Banner查询', 'market:banner:query', 3, 1, 2025, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2022-08-01 14:56:14', '', '2022-08-01 14:56:14', b'0');
1664 1805 INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2027, 'Banner创建', 'market:banner:create', 3, 2, 2025, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2022-08-01 14:56:14', '', '2022-08-01 14:56:14', b'0');
1665 1806 INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2028, 'Banner更新', 'market:banner:update', 3, 3, 2025, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2022-08-01 14:56:14', '', '2022-08-01 14:56:14', b'0');
1666 1807 INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2029, 'Banner删除', 'market:banner:delete', 3, 4, 2025, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2022-08-01 14:56:14', '', '2022-08-01 14:56:14', b'0');
1667   -INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2030, '营销中心', '', 1, 70, 0, '/promotion', 'rate', NULL, NULL, 0, b'1', b'1', b'1', '1', '2022-10-31 21:25:09', '1', '2022-10-31 21:25:09', b'0');
  1808 +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2030, '营销中心', '', 1, 70, 0, '/promotion', 'ep:present', NULL, NULL, 0, b'1', b'1', b'1', '1', '2022-10-31 21:25:09', '1', '2023-08-31 15:49:31', b'0');
1668 1809 INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2032, '优惠劵', '', 2, 1, 2030, 'coupon-template', 'ep:discount', 'mall/promotion/coupon/template/index', 'PromotionCouponTemplate', 0, b'1', b'1', b'1', '', '2022-10-31 22:27:14', '1', '2023-08-12 11:35:35', b'0');
1669 1810 INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2033, '优惠劵模板查询', 'promotion:coupon-template:query', 3, 1, 2032, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2022-10-31 22:27:14', '', '2022-10-31 22:27:14', b'0');
1670 1811 INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2034, '优惠劵模板创建', 'promotion:coupon-template:create', 3, 2, 2032, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2022-10-31 22:27:14', '', '2022-10-31 22:27:14', b'0');
... ... @@ -1695,11 +1836,11 @@ INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_i
1695 1836 INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2068, '秒杀时段创建', 'promotion:seckill-config:create', 3, 2, 2066, '', '', '', '', 0, b'1', b'1', b'1', '', '2022-11-15 19:46:51', '1', '2023-06-24 17:48:39', b'0');
1696 1837 INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2069, '秒杀时段更新', 'promotion:seckill-config:update', 3, 3, 2066, '', '', '', '', 0, b'1', b'1', b'1', '', '2022-11-15 19:46:51', '1', '2023-06-24 17:50:29', b'0');
1697 1838 INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2070, '秒杀时段删除', 'promotion:seckill-config:delete', 3, 4, 2066, '', '', '', '', 0, b'1', b'1', b'1', '', '2022-11-15 19:46:51', '1', '2023-06-24 17:50:32', b'0');
1698   -INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2072, '订单中心', '', 1, 65, 0, '/trade', 'order', NULL, NULL, 0, b'1', b'1', b'1', '1', '2022-11-19 18:57:19', '1', '2022-12-10 16:32:57', b'0');
1699   -INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2073, '售后退款', '', 2, 1, 2072, 'trade/after-sale', 'education', 'mall/trade/afterSale/index', 'TradeAfterSale', 0, b'1', b'1', b'1', '', '2022-11-19 20:15:32', '1', '2023-04-08 11:43:19', b'0');
  1839 +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2072, '订单中心', '', 1, 65, 0, '/trade', 'ep:eleme', NULL, NULL, 0, b'1', b'1', b'1', '1', '2022-11-19 18:57:19', '1', '2023-08-30 21:01:48', b'0');
  1840 +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2073, '售后退款', '', 2, 1, 2072, 'trade/after-sale', 'ep:refrigerator', 'mall/trade/afterSale/index', 'TradeAfterSale', 0, b'1', b'1', b'1', '', '2022-11-19 20:15:32', '1', '2023-08-30 21:02:16', b'0');
1700 1841 INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2074, '售后查询', 'trade:after-sale:query', 3, 1, 2073, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2022-11-19 20:15:33', '1', '2022-12-10 21:04:29', b'0');
1701 1842 INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2075, '秒杀活动关闭', 'promotion:sekill-activity:close', 3, 5, 2059, '', '', '', '', 0, b'1', b'1', b'1', '1', '2022-11-28 20:20:15', '1', '2023-08-12 17:53:02', b'0');
1702   -INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2076, '订单列表', '', 2, 0, 2072, 'trade/order', 'list', 'mall/trade/order/index', 'TradeOrder', 0, b'1', b'1', b'1', '1', '2022-12-10 21:05:44', '1', '2023-04-08 11:42:23', b'0');
  1843 +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2076, '订单列表', '', 2, 0, 2072, 'trade/order', 'ep:list', 'mall/trade/order/index', 'TradeOrder', 0, b'1', b'1', b'1', '1', '2022-12-10 21:05:44', '1', '2023-08-30 21:02:00', b'0');
1703 1844 INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2083, '地区管理', '', 2, 14, 1, 'area', 'row', 'system/area/index', 'SystemArea', 0, b'1', b'1', b'1', '1', '2022-12-23 17:35:05', '1', '2023-04-08 09:01:37', b'0');
1704 1845 INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2084, '公众号管理', '', 1, 100, 0, '/mp', 'wechat', NULL, NULL, 0, b'1', b'1', b'1', '1', '2023-01-01 20:11:04', '1', '2023-01-15 11:28:57', b'0');
1705 1846 INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2085, '账号管理', '', 2, 1, 2084, 'account', 'phone', 'mp/account/index', 'MpAccount', 0, b'1', b'1', b'1', '1', '2023-01-01 20:13:31', '1', '2023-02-09 23:56:39', b'0');
... ... @@ -1780,22 +1921,22 @@ INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_i
1780 1921 INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2160, 'Cloud 开发文档', '', 1, 2, 0, 'https://cloud.iocoder.cn', 'documentation', NULL, NULL, 0, b'1', b'1', b'1', '1', '2023-02-10 22:47:07', '1', '2023-02-10 22:47:07', b'0');
1781 1922 INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2161, '接入示例', '', 2, 99, 1117, 'demo-order', 'drag', 'pay/demo/index', NULL, 0, b'1', b'1', b'1', '', '2023-02-11 14:21:42', '1', '2023-02-11 22:26:35', b'0');
1782 1923 INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2162, '商品导出', 'product:spu:export', 3, 5, 2014, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2022-07-30 14:22:58', '', '2022-07-30 14:22:58', b'0');
1783   -INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2164, '配送管理', '', 1, 2, 2072, 'delivery', '', '', '', 0, b'1', b'1', b'1', '1', '2023-05-18 09:18:02', '1', '2023-05-24 23:24:13', b'0');
1784   -INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2165, '快递发货', '', 1, 0, 2164, 'express', '', '', '', 0, b'1', b'1', b'1', '1', '2023-05-18 09:22:06', '1', '2023-05-18 09:22:06', b'0');
1785   -INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2166, '门店自提', '', 1, 1, 2164, 'pick-up-store', '', '', '', 0, b'1', b'1', b'1', '1', '2023-05-18 09:23:14', '1', '2023-05-18 09:23:14', b'0');
1786   -INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2167, '快递公司', '', 2, 0, 2165, 'express', '', 'mall/trade/delivery/express/index', 'Express', 0, b'1', b'1', b'1', '1', '2023-05-18 09:27:21', '1', '2023-05-18 22:11:14', b'0');
  1924 +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2164, '配送管理', '', 1, 2, 2072, 'delivery', 'ep:shopping-cart', '', '', 0, b'1', b'1', b'1', '1', '2023-05-18 09:18:02', '1', '2023-08-30 21:02:27', b'0');
  1925 +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2165, '快递发货', '', 1, 0, 2164, 'express', 'ep:bicycle', '', '', 0, b'1', b'1', b'1', '1', '2023-05-18 09:22:06', '1', '2023-08-30 21:02:49', b'0');
  1926 +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2166, '门店自提', '', 1, 1, 2164, 'pick-up-store', 'ep:add-location', '', '', 0, b'1', b'1', b'1', '1', '2023-05-18 09:23:14', '1', '2023-08-30 21:03:21', b'0');
  1927 +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2167, '快递公司', '', 2, 0, 2165, 'express', 'ep:compass', 'mall/trade/delivery/express/index', 'Express', 0, b'1', b'1', b'1', '1', '2023-05-18 09:27:21', '1', '2023-08-30 21:02:59', b'0');
1787 1928 INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2168, '快递公司查询', 'trade:delivery:express:query', 3, 1, 2167, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2023-05-18 09:37:53', '', '2023-05-18 09:37:53', b'0');
1788 1929 INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2169, '快递公司创建', 'trade:delivery:express:create', 3, 2, 2167, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2023-05-18 09:37:53', '', '2023-05-18 09:37:53', b'0');
1789 1930 INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2170, '快递公司更新', 'trade:delivery:express:update', 3, 3, 2167, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2023-05-18 09:37:53', '', '2023-05-18 09:37:53', b'0');
1790 1931 INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2171, '快递公司删除', 'trade:delivery:express:delete', 3, 4, 2167, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2023-05-18 09:37:53', '', '2023-05-18 09:37:53', b'0');
1791 1932 INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2172, '快递公司导出', 'trade:delivery:express:export', 3, 5, 2167, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2023-05-18 09:37:53', '', '2023-05-18 09:37:53', b'0');
1792   -INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2173, '运费模版', 'trade:delivery:express-template:query', 2, 1, 2165, 'express-template', '', 'mall/trade/delivery/expressTemplate/index', 'ExpressTemplate', 0, b'1', b'1', b'1', '1', '2023-05-20 06:48:10', '1', '2023-05-20 06:48:29', b'0');
  1933 +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2173, '运费模版', 'trade:delivery:express-template:query', 2, 1, 2165, 'express-template', 'ep:coordinate', 'mall/trade/delivery/expressTemplate/index', 'ExpressTemplate', 0, b'1', b'1', b'1', '1', '2023-05-20 06:48:10', '1', '2023-08-30 21:03:13', b'0');
1793 1934 INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2174, '快递运费模板查询', 'trade:delivery:express-template:query', 3, 1, 2173, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2023-05-20 06:49:53', '', '2023-05-20 06:49:53', b'0');
1794 1935 INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2175, '快递运费模板创建', 'trade:delivery:express-template:create', 3, 2, 2173, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2023-05-20 06:49:53', '', '2023-05-20 06:49:53', b'0');
1795 1936 INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2176, '快递运费模板更新', 'trade:delivery:express-template:update', 3, 3, 2173, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2023-05-20 06:49:53', '', '2023-05-20 06:49:53', b'0');
1796 1937 INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2177, '快递运费模板删除', 'trade:delivery:express-template:delete', 3, 4, 2173, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2023-05-20 06:49:53', '', '2023-05-20 06:49:53', b'0');
1797 1938 INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2178, '快递运费模板导出', 'trade:delivery:express-template:export', 3, 5, 2173, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2023-05-20 06:49:53', '', '2023-05-20 06:49:53', b'0');
1798   -INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2179, '门店管理', '', 2, 1, 2166, 'pick-up-store', '', 'mall/trade/delivery/pickUpStore/index', 'PickUpStore', 0, b'1', b'1', b'1', '1', '2023-05-25 10:50:00', '1', '2023-05-25 10:50:00', b'0');
  1939 +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2179, '门店管理', '', 2, 1, 2166, 'pick-up-store', 'ep:basketball', 'mall/trade/delivery/pickUpStore/index', 'PickUpStore', 0, b'1', b'1', b'1', '1', '2023-05-25 10:50:00', '1', '2023-08-30 21:03:28', b'0');
1799 1940 INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2180, '自提门店查询', 'trade:delivery:pick-up-store:query', 3, 1, 2179, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2023-05-25 10:53:29', '', '2023-05-25 10:53:29', b'0');
1800 1941 INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2181, '自提门店创建', 'trade:delivery:pick-up-store:create', 3, 2, 2179, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2023-05-25 10:53:29', '', '2023-05-25 10:53:29', b'0');
1801 1942 INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2182, '自提门店更新', 'trade:delivery:pick-up-store:update', 3, 3, 2179, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2023-05-25 10:53:29', '', '2023-05-25 10:53:29', b'0');
... ... @@ -1834,7 +1975,7 @@ INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_i
1834 1975 INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2314, '砍价活动更新', 'promotion:bargain-activity:update', 3, 3, 2311, '', '', '', '', 0, b'1', b'1', b'1', '1', '2023-08-13 00:32:55', '1', '2023-08-13 00:32:55', b'0');
1835 1976 INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2315, '砍价活动删除', 'promotion:bargain-activity:delete', 3, 4, 2311, '', '', '', '', 0, b'1', b'1', b'1', '1', '2023-08-13 00:34:50', '1', '2023-08-13 00:34:50', b'0');
1836 1977 INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2316, '砍价活动关闭', 'promotion:bargain-activity:close', 3, 5, 2311, '', '', '', '', 0, b'1', b'1', b'1', '1', '2023-08-13 00:35:02', '1', '2023-08-13 00:35:02', b'0');
1837   -INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2317, '会员管理', '', 2, 0, 2262, 'user', 'ep:avatar', 'member/user/index', 'MemberUser', 0, b'1', b'1', b'1', '', '2023-08-19 04:12:15', '1', '2023-08-19 12:13:06', b'0');
  1978 +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2317, '会员管理', '', 2, 0, 2262, 'user', 'ep:avatar', 'member/user/index', 'MemberUser', 0, b'1', b'1', b'1', '', '2023-08-19 04:12:15', '1', '2023-08-24 00:50:55', b'0');
1838 1979 INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2318, '会员用户查询', 'member:user:query', 3, 1, 2317, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2023-08-19 04:12:15', '', '2023-08-19 04:12:15', b'0');
1839 1980 INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2319, '会员用户更新', 'member:user:update', 3, 3, 2317, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2023-08-19 04:12:15', '', '2023-08-19 04:12:15', b'0');
1840 1981 INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2320, '会员标签', '', 2, 1, 2262, 'tag', 'ep:collection-tag', 'member/tag/index', 'MemberTag', 0, b'1', b'1', b'1', '', '2023-08-20 01:03:08', '1', '2023-08-20 09:23:19', b'0');
... ... @@ -1842,6 +1983,23 @@ INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_i
1842 1983 INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2322, '会员标签创建', 'member:tag:create', 3, 2, 2320, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2023-08-20 01:03:08', '', '2023-08-20 01:03:08', b'0');
1843 1984 INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2323, '会员标签更新', 'member:tag:update', 3, 3, 2320, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2023-08-20 01:03:08', '', '2023-08-20 01:03:08', b'0');
1844 1985 INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2324, '会员标签删除', 'member:tag:delete', 3, 4, 2320, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2023-08-20 01:03:08', '', '2023-08-20 01:03:08', b'0');
  1986 +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2325, '会员等级', '', 2, 2, 2262, 'level', 'fa:level-up', 'member/level/index', 'MemberLevel', 0, b'1', b'1', b'1', '', '2023-08-22 12:41:01', '1', '2023-08-22 21:47:00', b'0');
  1987 +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2326, '会员等级查询', 'member:level:query', 3, 1, 2325, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2023-08-22 12:41:02', '', '2023-08-22 12:41:02', b'0');
  1988 +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2327, '会员等级创建', 'member:level:create', 3, 2, 2325, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2023-08-22 12:41:02', '', '2023-08-22 12:41:02', b'0');
  1989 +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2328, '会员等级更新', 'member:level:update', 3, 3, 2325, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2023-08-22 12:41:02', '', '2023-08-22 12:41:02', b'0');
  1990 +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2329, '会员等级删除', 'member:level:delete', 3, 4, 2325, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2023-08-22 12:41:02', '', '2023-08-22 12:41:02', b'0');
  1991 +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2330, '用户分组', '', 2, 3, 2262, 'group', 'fa:group', 'member/group/index', 'MemberGroup', 0, b'1', b'1', b'1', '', '2023-08-22 13:50:06', '1', '2023-08-22 21:57:47', b'0');
  1992 +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2331, '用户分组查询', 'member:group:query', 3, 1, 2330, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2023-08-22 13:50:06', '', '2023-08-22 13:50:06', b'0');
  1993 +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2332, '用户分组创建', 'member:group:create', 3, 2, 2330, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2023-08-22 13:50:06', '', '2023-08-22 13:50:06', b'0');
  1994 +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2333, '用户分组更新', 'member:group:update', 3, 3, 2330, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2023-08-22 13:50:06', '', '2023-08-22 13:50:06', b'0');
  1995 +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2334, '用户分组删除', 'member:group:delete', 3, 4, 2330, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2023-08-22 13:50:06', '', '2023-08-22 13:50:06', b'0');
  1996 +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2335, '用户等级修改', 'member:user:update-level', 3, 5, 2317, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2023-08-23 16:49:05', '', '2023-08-23 16:50:48', b'0');
  1997 +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2336, '商品评论', '', 2, 5, 2000, 'comment', 'ep:comment', 'mall/product/comment/index', 'ProductComment', 0, b'1', b'1', b'1', '1', '2023-08-26 11:03:00', '1', '2023-08-26 11:03:38', b'0');
  1998 +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2337, '评论查询', 'product:comment:query', 3, 1, 2336, '', '', '', '', 0, b'1', b'1', b'1', '1', '2023-08-26 11:04:01', '1', '2023-08-26 11:04:01', b'0');
  1999 +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2338, '添加自评', 'product:comment:create', 3, 2, 2336, '', '', '', '', 0, b'1', b'1', b'1', '1', '2023-08-26 11:04:23', '1', '2023-08-26 11:08:18', b'0');
  2000 +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2339, '商家回复', 'product:comment:update', 3, 3, 2336, '', '', '', '', 0, b'1', b'1', b'1', '1', '2023-08-26 11:04:37', '1', '2023-08-26 11:04:37', b'0');
  2001 +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2340, '显隐评论', 'product:comment:update', 3, 4, 2336, '', '', '', '', 0, b'1', b'1', b'1', '1', '2023-08-26 11:04:55', '1', '2023-08-26 11:04:55', b'0');
  2002 +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2341, '优惠劵发送', 'promotion:coupon:send', 3, 2, 2038, '', '', '', '', 0, b'1', b'1', b'1', '1', '2023-09-02 00:03:14', '1', '2023-09-02 00:03:14', b'0');
1845 2003 COMMIT;
1846 2004  
1847 2005 -- ----------------------------
... ... @@ -1958,7 +2116,7 @@ CREATE TABLE `system_oauth2_access_token` (
1958 2116 `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除',
1959 2117 `tenant_id` bigint NOT NULL DEFAULT 0 COMMENT '租户编号',
1960 2118 PRIMARY KEY (`id`) USING BTREE
1961   -) ENGINE = InnoDB AUTO_INCREMENT = 2453 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = 'OAuth2 访问令牌';
  2119 +) ENGINE = InnoDB AUTO_INCREMENT = 2597 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = 'OAuth2 访问令牌';
1962 2120  
1963 2121 -- ----------------------------
1964 2122 -- Records of system_oauth2_access_token
... ... @@ -2080,7 +2238,7 @@ CREATE TABLE `system_oauth2_refresh_token` (
2080 2238 `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除',
2081 2239 `tenant_id` bigint NOT NULL DEFAULT 0 COMMENT '租户编号',
2082 2240 PRIMARY KEY (`id`) USING BTREE
2083   -) ENGINE = InnoDB AUTO_INCREMENT = 850 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = 'OAuth2 刷新令牌';
  2241 +) ENGINE = InnoDB AUTO_INCREMENT = 896 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = 'OAuth2 刷新令牌';
2084 2242  
2085 2243 -- ----------------------------
2086 2244 -- Records of system_oauth2_refresh_token
... ... @@ -2120,7 +2278,7 @@ CREATE TABLE `system_operate_log` (
2120 2278 `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除',
2121 2279 `tenant_id` bigint NOT NULL DEFAULT 0 COMMENT '租户编号',
2122 2280 PRIMARY KEY (`id`) USING BTREE
2123   -) ENGINE = InnoDB AUTO_INCREMENT = 8043 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '操作日志记录';
  2281 +) ENGINE = InnoDB AUTO_INCREMENT = 8321 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '操作日志记录';
2124 2282  
2125 2283 -- ----------------------------
2126 2284 -- Records of system_operate_log
... ... @@ -3128,7 +3286,7 @@ CREATE TABLE `system_sms_code` (
3128 3286 `tenant_id` bigint NOT NULL DEFAULT 0 COMMENT '租户编号',
3129 3287 PRIMARY KEY (`id`) USING BTREE,
3130 3288 INDEX `idx_mobile`(`mobile` ASC) USING BTREE COMMENT '手机号'
3131   -) ENGINE = InnoDB AUTO_INCREMENT = 500 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '手机验证码';
  3289 +) ENGINE = InnoDB AUTO_INCREMENT = 501 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '手机验证码';
3132 3290  
3133 3291 -- ----------------------------
3134 3292 -- Records of system_sms_code
... ... @@ -3171,7 +3329,7 @@ CREATE TABLE `system_sms_log` (
3171 3329 `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
3172 3330 `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除',
3173 3331 PRIMARY KEY (`id`) USING BTREE
3174   -) ENGINE = InnoDB AUTO_INCREMENT = 364 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '短信日志';
  3332 +) ENGINE = InnoDB AUTO_INCREMENT = 365 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '短信日志';
3175 3333  
3176 3334 -- ----------------------------
3177 3335 -- Records of system_sms_log
... ... @@ -3444,7 +3602,7 @@ CREATE TABLE `system_users` (
3444 3602 -- Records of system_users
3445 3603 -- ----------------------------
3446 3604 BEGIN;
3447   -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-08-20 19:24:52', 'admin', '2021-01-05 17:03:47', NULL, '2023-08-20 19:24:52', b'0', 1);
  3605 +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-09-02 00:03:37', 'admin', '2021-01-05 17:03:47', NULL, '2023-09-02 00:03:37', b'0', 1);
3448 3606 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);
3449 3607 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);
3450 3608 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, '127.0.0.1', '2022-05-28 15:43:17', '', '2021-01-21 02:13:53', NULL, '2022-07-09 09:00:33', b'0', 1);
... ...
sql/postgresql/ruoyi-vue-pro.sql
... ... @@ -2587,7 +2587,7 @@ INSERT INTO &quot;qrtz_job_details&quot; (&quot;sched_name&quot;, &quot;job_name&quot;, &quot;job_group&quot;, &quot;descript
2587 2587 "is_nonconcurrent", "is_update_data", "requests_recovery", "job_data")
2588 2588 VALUES ('schedulerName', 'userSessionTimeoutJob', 'DEFAULT', NULL,
2589 2589 'cn.iocoder.yudao.framework.quartz.core.handler.JobHandlerInvoker', 'f', 't', 't', 'f',
2590   - E '\254\355\000\005sr\000\025org.quartz.JobDataMap\237\260\203\350\277\251\260\313\002\000\000xr\000&org.quartz.utils.StringKeyDirtyFlagMap\202\010\350\303\373\305](\002\000\001Z\000\023allowsTransientDataxr\000\035org.quartz.utils.DirtyFlagMap\023\346.\255(v\012\316\002\000\002Z\000\005dirtyL\000\003mapt\000\017Ljava/util/Map;xp\001sr\000\021java.util.HashMap\005\007\332\301\303\026`\321\003\000\002F\000\012loadFactorI\000\011thresholdxp?@\000\000\000\000\000\014w\010\000\000\000\020\000\000\000\002t\000\006JOB_IDsr\000\016java.lang.Long;\213\344\220\314\217#\337\002\000\001J\000\005valuexr\000\020java.lang.Number\206\254\225\035\013\224\340\213\002\000\000xp\000\000\000\000\000\000\000\002t\000\020JOB_HANDLER_NAMEt\000\025userSessionTimeoutJobx\000');
  2590 + '\254\355\000\005sr\000\025org.quartz.JobDataMap\237\260\203\350\277\251\260\313\002\000\000xr\000&org.quartz.utils.StringKeyDirtyFlagMap\202\010\350\303\373\305](\002\000\001Z\000\023allowsTransientDataxr\000\035org.quartz.utils.DirtyFlagMap\023\346.\255(v\012\316\002\000\002Z\000\005dirtyL\000\003mapt\000\017Ljava/util/Map;xp\001sr\000\021java.util.HashMap\005\007\332\301\303\026`\321\003\000\002F\000\012loadFactorI\000\011thresholdxp?@\000\000\000\000\000\014w\010\000\000\000\020\000\000\000\002t\000\006JOB_IDsr\000\016java.lang.Long;\213\344\220\314\217#\337\002\000\001J\000\005valuexr\000\020java.lang.Number\206\254\225\035\013\224\340\213\002\000\000xp\000\000\000\000\000\000\000\002t\000\020JOB_HANDLER_NAMEt\000\025userSessionTimeoutJobx\000');
2591 2591 COMMIT;
2592 2592  
2593 2593 -- ----------------------------
... ... @@ -2733,7 +2733,7 @@ INSERT INTO &quot;qrtz_triggers&quot; (&quot;sched_name&quot;, &quot;trigger_name&quot;, &quot;trigger_group&quot;, &quot;job
2733 2733 "start_time", "end_time", "calendar_name", "misfire_instr", "job_data")
2734 2734 VALUES ('schedulerName', 'userSessionTimeoutJob', 'DEFAULT', 'userSessionTimeoutJob', 'DEFAULT', NULL, 1651328700000,
2735 2735 1651328640000, 5, 'WAITING', 'CRON', 1651328526000, 0, NULL, 0,
2736   - E '\254\355\000\005sr\000\025org.quartz.JobDataMap\237\260\203\350\277\251\260\313\002\000\000xr\000&org.quartz.utils.StringKeyDirtyFlagMap\202\010\350\303\373\305](\002\000\001Z\000\023allowsTransientDataxr\000\035org.quartz.utils.DirtyFlagMap\023\346.\255(v\012\316\002\000\002Z\000\005dirtyL\000\003mapt\000\017Ljava/util/Map;xp\001sr\000\021java.util.HashMap\005\007\332\301\303\026`\321\003\000\002F\000\012loadFactorI\000\011thresholdxp?@\000\000\000\000\000\014w\010\000\000\000\020\000\000\000\003t\000\021JOB_HANDLER_PARAMpt\000\022JOB_RETRY_INTERVALsr\000\021java.lang.Integer\022\342\240\244\367\201\2078\002\000\001I\000\005valuexr\000\020java.lang.Number\206\254\225\035\013\224\340\213\002\000\000xp\000\000\007\320t\000\017JOB_RETRY_COUNTsq\000~\000\011\000\000\000\003x\000');
  2736 + '\254\355\000\005sr\000\025org.quartz.JobDataMap\237\260\203\350\277\251\260\313\002\000\000xr\000&org.quartz.utils.StringKeyDirtyFlagMap\202\010\350\303\373\305](\002\000\001Z\000\023allowsTransientDataxr\000\035org.quartz.utils.DirtyFlagMap\023\346.\255(v\012\316\002\000\002Z\000\005dirtyL\000\003mapt\000\017Ljava/util/Map;xp\001sr\000\021java.util.HashMap\005\007\332\301\303\026`\321\003\000\002F\000\012loadFactorI\000\011thresholdxp?@\000\000\000\000\000\014w\010\000\000\000\020\000\000\000\003t\000\021JOB_HANDLER_PARAMpt\000\022JOB_RETRY_INTERVALsr\000\021java.lang.Integer\022\342\240\244\367\201\2078\002\000\001I\000\005valuexr\000\020java.lang.Number\206\254\225\035\013\224\340\213\002\000\000xp\000\000\007\320t\000\017JOB_RETRY_COUNTsq\000~\000\011\000\000\000\003x\000');
2737 2737 COMMIT;
2738 2738  
2739 2739 -- ----------------------------
... ...
yudao-dependencies/pom.xml
... ... @@ -14,7 +14,8 @@
14 14 <url>https://github.com/YunaiV/ruoyi-vue-pro</url>
15 15  
16 16 <properties>
17   - <revision>1.8.0-snapshot</revision>
  17 + <revision>1.8.1-snapshot</revision>
  18 + <flatten-maven-plugin.version>1.5.0</flatten-maven-plugin.version>
18 19 <!-- 统一依赖管理 -->
19 20 <spring.boot.version>2.7.14</spring.boot.version>
20 21 <!-- Web 相关 -->
... ... @@ -23,10 +24,10 @@
23 24 <servlet.versoin>2.5</servlet.versoin>
24 25 <!-- DB 相关 -->
25 26 <druid.version>1.2.18</druid.version>
26   - <mybatis-plus.version>3.5.3.1</mybatis-plus.version>
27   - <mybatis-plus-generator.version>3.5.3.1</mybatis-plus-generator.version>
  27 + <mybatis-plus.version>3.5.3.2</mybatis-plus.version>
  28 + <mybatis-plus-generator.version>3.5.3.2</mybatis-plus-generator.version>
28 29 <dynamic-datasource.version>3.6.1</dynamic-datasource.version>
29   - <mybatis-plus-join-boot-starter.version>1.4.5</mybatis-plus-join-boot-starter.version>
  30 + <mybatis-plus-join.version>1.4.6</mybatis-plus-join.version>
30 31 <redisson.version>3.18.0</redisson.version>
31 32 <dm8.jdbc.version>8.1.2.141</dm8.jdbc.version>
32 33 <!-- 服务保障相关 -->
... ... @@ -219,7 +220,7 @@
219 220 <dependency>
220 221 <groupId>com.github.yulichang</groupId>
221 222 <artifactId>mybatis-plus-join-boot-starter</artifactId> <!-- MyBatis 联表查询 -->
222   - <version>${mybatis-plus-join-boot-starter.version}</version>
  223 + <version>${mybatis-plus-join.version}</version>
223 224 </dependency>
224 225  
225 226 <dependency>
... ... @@ -645,4 +646,35 @@
645 646 </dependencies>
646 647 </dependencyManagement>
647 648  
  649 + <build>
  650 + <plugins>
  651 + <!-- 统一 revision 版本 -->
  652 + <plugin>
  653 + <groupId>org.codehaus.mojo</groupId>
  654 + <artifactId>flatten-maven-plugin</artifactId>
  655 + <version>${flatten-maven-plugin.version}</version>
  656 + <configuration>
  657 + <flattenMode>resolveCiFriendliesOnly</flattenMode>
  658 + <updatePomFile>true</updatePomFile>
  659 + </configuration>
  660 + <executions>
  661 + <execution>
  662 + <goals>
  663 + <goal>flatten</goal>
  664 + </goals>
  665 + <id>flatten</id>
  666 + <phase>process-resources</phase>
  667 + </execution>
  668 + <execution>
  669 + <goals>
  670 + <goal>clean</goal>
  671 + </goals>
  672 + <id>flatten.clean</id>
  673 + <phase>clean</phase>
  674 + </execution>
  675 + </executions>
  676 + </plugin>
  677 + </plugins>
  678 + </build>
  679 +
648 680 </project>
... ...
yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/pojo/SortingField.java
1 1 package cn.iocoder.yudao.framework.common.pojo;
2 2  
  3 +import lombok.AllArgsConstructor;
  4 +import lombok.Data;
  5 +import lombok.NoArgsConstructor;
  6 +
3 7 import java.io.Serializable;
4 8  
5 9 /**
... ... @@ -7,6 +11,9 @@ import java.io.Serializable;
7 11 *
8 12 * 类名加了 ing 的原因是,避免和 ES SortField 重名。
9 13 */
  14 +@Data
  15 +@NoArgsConstructor
  16 +@AllArgsConstructor
10 17 public class SortingField implements Serializable {
11 18  
12 19 /**
... ... @@ -27,30 +34,4 @@ public class SortingField implements Serializable {
27 34 */
28 35 private String order;
29 36  
30   - // 空构造方法,解决反序列化
31   - public SortingField() {
32   - }
33   -
34   - public SortingField(String field, String order) {
35   - this.field = field;
36   - this.order = order;
37   - }
38   -
39   - public String getField() {
40   - return field;
41   - }
42   -
43   - public SortingField setField(String field) {
44   - this.field = field;
45   - return this;
46   - }
47   -
48   - public String getOrder() {
49   - return order;
50   - }
51   -
52   - public SortingField setOrder(String order) {
53   - this.order = order;
54   - return this;
55   - }
56 37 }
... ...
yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/util/date/DateUtils.java
... ... @@ -36,6 +36,9 @@ public class DateUtils {
36 36 * @return LocalDateTime
37 37 */
38 38 public static Date of(LocalDateTime date) {
  39 + if (date == null) {
  40 + return null;
  41 + }
39 42 // 将此日期时间与时区相结合以创建 ZonedDateTime
40 43 ZonedDateTime zonedDateTime = date.atZone(ZoneId.systemDefault());
41 44 // 本地时间线 LocalDateTime 到即时时间线 Instant 时间戳
... ... @@ -51,6 +54,9 @@ public class DateUtils {
51 54 * @return LocalDateTime
52 55 */
53 56 public static LocalDateTime of(Date date) {
  57 + if (date == null) {
  58 + return null;
  59 + }
54 60 // 转为时间戳
55 61 Instant instant = date.toInstant();
56 62 // UTC时间(世界协调时间,UTC + 00:00)转北京(北京,UTC + 8:00)时间
... ...
yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/validation/InEnum.java
... ... @@ -17,7 +17,7 @@ import java.lang.annotation.*;
17 17 @Retention(RetentionPolicy.RUNTIME)
18 18 @Documented
19 19 @Constraint(
20   - validatedBy = InEnumValidator.class
  20 + validatedBy = {InEnumValidator.class, InEnumCollectionValidator.class}
21 21 )
22 22 public @interface InEnum {
23 23  
... ...
yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/validation/InEnumCollectionValidator.java 0 → 100644
  1 +package cn.iocoder.yudao.framework.common.validation;
  2 +
  3 +import cn.hutool.core.collection.CollUtil;
  4 +import cn.iocoder.yudao.framework.common.core.IntArrayValuable;
  5 +
  6 +import javax.validation.ConstraintValidator;
  7 +import javax.validation.ConstraintValidatorContext;
  8 +import java.util.Arrays;
  9 +import java.util.Collection;
  10 +import java.util.Collections;
  11 +import java.util.List;
  12 +import java.util.stream.Collectors;
  13 +
  14 +public class InEnumCollectionValidator implements ConstraintValidator<InEnum, Collection<Integer>> {
  15 +
  16 + private List<Integer> values;
  17 +
  18 + @Override
  19 + public void initialize(InEnum annotation) {
  20 + IntArrayValuable[] values = annotation.value().getEnumConstants();
  21 + if (values.length == 0) {
  22 + this.values = Collections.emptyList();
  23 + } else {
  24 + this.values = Arrays.stream(values[0].array()).boxed().collect(Collectors.toList());
  25 + }
  26 + }
  27 +
  28 + @Override
  29 + public boolean isValid(Collection<Integer> list, ConstraintValidatorContext context) {
  30 + // 校验通过
  31 + if (CollUtil.containsAll(values, list)) {
  32 + return true;
  33 + }
  34 + // 校验不通过,自定义提示语句(因为,注解上的 value 是枚举类,无法获得枚举类的实际值)
  35 + context.disableDefaultConstraintViolation(); // 禁用默认的 message 的值
  36 + context.buildConstraintViolationWithTemplate(context.getDefaultConstraintMessageTemplate()
  37 + .replaceAll("\\{value}", CollUtil.join(list, ","))).addConstraintViolation(); // 重新添加错误提示语句
  38 + return false;
  39 + }
  40 +
  41 +}
  42 +
... ...
yudao-framework/yudao-spring-boot-starter-biz-data-permission/src/main/java/cn/iocoder/yudao/framework/datapermission/core/db/DataPermissionDatabaseInterceptor.java
... ... @@ -5,7 +5,6 @@ import cn.iocoder.yudao.framework.common.util.collection.SetUtils;
5 5 import cn.iocoder.yudao.framework.datapermission.core.rule.DataPermissionRule;
6 6 import cn.iocoder.yudao.framework.datapermission.core.rule.DataPermissionRuleFactory;
7 7 import cn.iocoder.yudao.framework.mybatis.core.util.MyBatisUtils;
8   -import com.alibaba.ttl.TransmittableThreadLocal;
9 8 import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
10 9 import com.baomidou.mybatisplus.core.toolkit.PluginUtils;
11 10 import com.baomidou.mybatisplus.extension.parser.JsqlParserSupport;
... ... @@ -508,6 +507,9 @@ public class DataPermissionDatabaseInterceptor extends JsqlParserSupport impleme
508 507 // 单条规则的条件
509 508 String tableName = MyBatisUtils.getTableName(table);
510 509 Expression oneExpress = rule.getExpression(tableName, table.getAlias());
  510 + if (oneExpress == null){
  511 + continue;
  512 + }
511 513 // 拼接到 allExpression 中
512 514 allExpression = allExpression == null ? oneExpress
513 515 : new AndExpression(allExpression, oneExpress);
... ...
yudao-framework/yudao-spring-boot-starter-biz-data-permission/src/main/java/cn/iocoder/yudao/framework/datapermission/core/rule/dept/DeptDataPermissionRule.java
... ... @@ -7,7 +7,6 @@ import cn.iocoder.yudao.framework.common.enums.UserTypeEnum;
7 7 import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils;
8 8 import cn.iocoder.yudao.framework.common.util.json.JsonUtils;
9 9 import cn.iocoder.yudao.framework.datapermission.core.rule.DataPermissionRule;
10   -import cn.iocoder.yudao.framework.expression.OrExpressionX;
11 10 import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
12 11 import cn.iocoder.yudao.framework.mybatis.core.util.MyBatisUtils;
13 12 import cn.iocoder.yudao.framework.security.core.LoginUser;
... ... @@ -17,10 +16,8 @@ import cn.iocoder.yudao.module.system.api.permission.dto.DeptDataPermissionRespD
17 16 import com.baomidou.mybatisplus.core.metadata.TableInfoHelper;
18 17 import lombok.AllArgsConstructor;
19 18 import lombok.extern.slf4j.Slf4j;
20   -import net.sf.jsqlparser.expression.Alias;
21   -import net.sf.jsqlparser.expression.Expression;
22   -import net.sf.jsqlparser.expression.LongValue;
23   -import net.sf.jsqlparser.expression.NullValue;
  19 +import net.sf.jsqlparser.expression.*;
  20 +import net.sf.jsqlparser.expression.operators.conditional.OrExpression;
24 21 import net.sf.jsqlparser.expression.operators.relational.EqualsTo;
25 22 import net.sf.jsqlparser.expression.operators.relational.ExpressionList;
26 23 import net.sf.jsqlparser.expression.operators.relational.InExpression;
... ... @@ -144,7 +141,7 @@ public class DeptDataPermissionRule implements DataPermissionRule {
144 141 return deptExpression;
145 142 }
146 143 // 目前,如果有指定部门 + 可查看自己,采用 OR 条件。即,WHERE (dept_id IN ? OR user_id = ?)
147   - return new OrExpressionX(deptExpression, userExpression);
  144 + return new Parenthesis(new OrExpression(deptExpression, userExpression));
148 145 }
149 146  
150 147 private Expression buildDeptExpression(String tableName, Alias tableAlias, Set<Long> deptIds) {
... ...
yudao-framework/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/impl/delegate/DelegatePayClient.java deleted
1   -package cn.iocoder.yudao.framework.pay.core.client.impl.delegate;
2   -
3   -import cn.iocoder.yudao.framework.pay.core.client.PayClientConfig;
4   -import cn.iocoder.yudao.framework.pay.core.client.dto.order.PayOrderRespDTO;
5   -import cn.iocoder.yudao.framework.pay.core.client.dto.order.PayOrderUnifiedReqDTO;
6   -import cn.iocoder.yudao.framework.pay.core.client.dto.refund.PayRefundRespDTO;
7   -import cn.iocoder.yudao.framework.pay.core.client.dto.refund.PayRefundUnifiedReqDTO;
8   -import cn.iocoder.yudao.framework.pay.core.client.impl.AbstractPayClient;
9   -
10   -import java.util.Map;
11   -
12   -// TODO @jason:其它模块,主要是无法 pay client 初始化存在问题,所以我感觉,是不是可以搞个 PayClientInitializer 接口。这样,PayClientFactory 去 get 这个支付模式对应的 PayClientInitializer,通过它来创建。具体注入的地方,可以在 PayChannel init 方法那;
13   -/**
14   - * 代理支付 Client 的抽象类。
15   - *
16   - * 用于支付 Client 由其它模块实现,例如钱包支付
17   - *
18   - * @author jason
19   - */
20   -public abstract class DelegatePayClient<Config extends PayClientConfig> extends AbstractPayClient<PayClientConfig> {
21   -
22   - private final DelegatePayClient<Config> delegate;
23   -
24   - public DelegatePayClient(Long channelId, String channelCode, PayClientConfig config) {
25   - super(channelId, channelCode, config);
26   - delegate = this;
27   - }
28   -
29   - @Override
30   - protected void doInit() {
31   - delegate.doInit();
32   - }
33   -
34   - @Override
35   - protected PayOrderRespDTO doUnifiedOrder(PayOrderUnifiedReqDTO reqDTO) {
36   - return delegate.doUnifiedOrder(reqDTO);
37   - }
38   -
39   - @Override
40   - protected PayOrderRespDTO doGetOrder(String outTradeNo) {
41   - return delegate.doGetOrder(outTradeNo);
42   - }
43   -
44   - @Override
45   - protected PayRefundRespDTO doUnifiedRefund(PayRefundUnifiedReqDTO reqDTO) {
46   - return delegate.doUnifiedRefund(reqDTO);
47   - }
48   -
49   - @Override
50   - protected PayRefundRespDTO doGetRefund(String outTradeNo, String outRefundNo) {
51   - return delegate.doGetRefund(outTradeNo, outRefundNo);
52   - }
53   -
54   - @Override
55   - protected PayRefundRespDTO doParseRefundNotify(Map<String,String> params, String body) {
56   - return delegate.doParseRefundNotify(params, body);
57   - }
58   -
59   - @Override
60   - protected PayOrderRespDTO doParseOrderNotify(Map<String,String> params, String body) {
61   - return delegate.doParseOrderNotify(params, body);
62   - }
63   -}
yudao-framework/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/impl/mock/MockPayClient.java
... ... @@ -5,6 +5,7 @@ import cn.iocoder.yudao.framework.pay.core.client.dto.order.PayOrderUnifiedReqDT
5 5 import cn.iocoder.yudao.framework.pay.core.client.dto.refund.PayRefundRespDTO;
6 6 import cn.iocoder.yudao.framework.pay.core.client.dto.refund.PayRefundUnifiedReqDTO;
7 7 import cn.iocoder.yudao.framework.pay.core.client.impl.AbstractPayClient;
  8 +import cn.iocoder.yudao.framework.pay.core.client.impl.NonePayClientConfig;
8 9 import cn.iocoder.yudao.framework.pay.core.enums.channel.PayChannelEnum;
9 10  
10 11 import java.time.LocalDateTime;
... ... @@ -17,11 +18,11 @@ import java.util.Map;
17 18 *
18 19 * @author jason
19 20 */
20   -public class MockPayClient extends AbstractPayClient<MockPayClientConfig> {
  21 +public class MockPayClient extends AbstractPayClient<NonePayClientConfig> {
21 22  
22 23 private static final String MOCK_RESP_SUCCESS_DATA = "MOCK_SUCCESS";
23 24  
24   - public MockPayClient(Long channelId, MockPayClientConfig config) {
  25 + public MockPayClient(Long channelId, NonePayClientConfig config) {
25 26 super(channelId, PayChannelEnum.MOCK.getCode(), config);
26 27 }
27 28  
... ...
yudao-framework/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/impl/mock/MockPayClientConfig.java deleted
1   -package cn.iocoder.yudao.framework.pay.core.client.impl.mock;
2   -
3   -import cn.iocoder.yudao.framework.pay.core.client.PayClientConfig;
4   -import lombok.Data;
5   -
6   -import javax.validation.Validator;
7   -
8   -/**
9   - * 模拟支付的 PayClientConfig 实现类
10   - *
11   - * @author jason
12   - */
13   -@Data
14   -public class MockPayClientConfig implements PayClientConfig {
15   -
16   - /**
17   - * 配置名称
18   - *
19   - * 如果不加任何属性,JsonUtils.parseObject2 解析会报错,所以暂时加个名称
20   - */
21   - private String name;
22   -
23   - @Override
24   - public void validate(Validator validator) {
25   - // 模拟支付配置无需校验
26   - }
27   -
28   -}
yudao-framework/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/impl/weixin/AbstractWxPayClient.java
... ... @@ -56,7 +56,7 @@ public abstract class AbstractWxPayClient extends AbstractPayClient&lt;WxPayClientC
56 56 protected void doInit(String tradeType) {
57 57 // 创建 config 配置
58 58 WxPayConfig payConfig = new WxPayConfig();
59   - BeanUtil.copyProperties(config, payConfig, "keyContent");
  59 + BeanUtil.copyProperties(config, payConfig, "keyContent", "privateKeyContent", "privateCertContent");
60 60 payConfig.setTradeType(tradeType);
61 61 // weixin-pay-java 无法设置内容,只允许读取文件,所以这里要创建临时文件来解决
62 62 if (Base64.isBase64(config.getKeyContent())) {
... ...
yudao-framework/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/enums/channel/PayChannelEnum.java
... ... @@ -4,7 +4,6 @@ import cn.hutool.core.util.ArrayUtil;
4 4 import cn.iocoder.yudao.framework.pay.core.client.impl.NonePayClientConfig;
5 5 import cn.iocoder.yudao.framework.pay.core.client.PayClientConfig;
6 6 import cn.iocoder.yudao.framework.pay.core.client.impl.alipay.AlipayPayClientConfig;
7   -import cn.iocoder.yudao.framework.pay.core.client.impl.mock.MockPayClientConfig;
8 7 import cn.iocoder.yudao.framework.pay.core.client.impl.weixin.WxPayClientConfig;
9 8 import lombok.AllArgsConstructor;
10 9 import lombok.Getter;
... ... @@ -30,7 +29,7 @@ public enum PayChannelEnum {
30 29 ALIPAY_QR("alipay_qr", "支付宝扫码支付", AlipayPayClientConfig.class),
31 30 ALIPAY_BAR("alipay_bar", "支付宝条码支付", AlipayPayClientConfig.class),
32 31  
33   - MOCK("mock", "模拟支付", MockPayClientConfig.class),
  32 + MOCK("mock", "模拟支付", NonePayClientConfig.class),
34 33  
35 34 WALLET("wallet", "钱包支付", NonePayClientConfig.class);
36 35  
... ...
yudao-framework/yudao-spring-boot-starter-mybatis/src/main/java/cn/iocoder/yudao/framework/expression/AndExpressionX.java deleted
1   -package cn.iocoder.yudao.framework.expression;
2   -
3   -import net.sf.jsqlparser.expression.Expression;
4   -import net.sf.jsqlparser.expression.operators.conditional.AndExpression;
5   -
6   -/**
7   - * AndExpression 的扩展类(会在原有表达式两端加上括号)
8   - */
9   -public class AndExpressionX extends AndExpression {
10   -
11   - public AndExpressionX() {
12   - }
13   -
14   - public AndExpressionX(Expression leftExpression, Expression rightExpression) {
15   - this.setLeftExpression(leftExpression);
16   - this.setRightExpression(rightExpression);
17   - }
18   -
19   - @Override
20   - public String toString() {
21   - return "(" + super.toString() + ")";
22   - }
23   -
24   -}
yudao-framework/yudao-spring-boot-starter-mybatis/src/main/java/cn/iocoder/yudao/framework/expression/OrExpressionX.java deleted
1   -package cn.iocoder.yudao.framework.expression;
2   -
3   -import net.sf.jsqlparser.expression.Expression;
4   -import net.sf.jsqlparser.expression.operators.conditional.OrExpression;
5   -
6   -/**
7   - * OrExpression 的扩展类(会在原有表达式两端加上括号)
8   - */
9   -public class OrExpressionX extends OrExpression {
10   -
11   - public OrExpressionX() {
12   - }
13   -
14   - public OrExpressionX(Expression leftExpression, Expression rightExpression) {
15   - this.setLeftExpression(leftExpression);
16   - this.setRightExpression(rightExpression);
17   - }
18   -
19   - @Override
20   - public String toString() {
21   - return "(" + super.toString() + ")";
22   - }
23   -
24   -}
yudao-framework/yudao-spring-boot-starter-mybatis/src/main/java/cn/iocoder/yudao/framework/mybatis/core/mapper/BaseMapperX.java
1 1 package cn.iocoder.yudao.framework.mybatis.core.mapper;
2 2  
  3 +import cn.hutool.core.collection.CollUtil;
3 4 import cn.iocoder.yudao.framework.common.pojo.PageParam;
4 5 import cn.iocoder.yudao.framework.common.pojo.PageResult;
5 6 import cn.iocoder.yudao.framework.mybatis.core.util.MyBatisUtils;
... ... @@ -10,6 +11,7 @@ import com.baomidou.mybatisplus.core.mapper.BaseMapper;
10 11 import com.baomidou.mybatisplus.core.metadata.IPage;
11 12 import com.baomidou.mybatisplus.core.toolkit.support.SFunction;
12 13 import com.baomidou.mybatisplus.extension.toolkit.Db;
  14 +import com.github.yulichang.base.MPJBaseMapper;
13 15 import org.apache.ibatis.annotations.Param;
14 16  
15 17 import java.util.Collection;
... ... @@ -17,8 +19,11 @@ import java.util.List;
17 19  
18 20 /**
19 21 * 在 MyBatis Plus 的 BaseMapper 的基础上拓展,提供更多的能力
  22 + *
  23 + * 1. {@link BaseMapper} 为 MyBatis Plus 的基础接口,提供基础的 CRUD 能力
  24 + * 2. {@link MPJBaseMapper} 为 MyBatis Plus Join 的基础接口,提供连表 Join 能力
20 25 */
21   -public interface BaseMapperX<T> extends BaseMapper<T> {
  26 +public interface BaseMapperX<T> extends MPJBaseMapper<T> {
22 27  
23 28 default PageResult<T> selectPage(PageParam pageParam, @Param("ew") Wrapper<T> queryWrapper) {
24 29 // MyBatis Plus 查询
... ... @@ -75,10 +80,16 @@ public interface BaseMapperX&lt;T&gt; extends BaseMapper&lt;T&gt; {
75 80 }
76 81  
77 82 default List<T> selectList(String field, Collection<?> values) {
  83 + if (CollUtil.isEmpty(values)) {
  84 + return CollUtil.newArrayList();
  85 + }
78 86 return selectList(new QueryWrapper<T>().in(field, values));
79 87 }
80 88  
81 89 default List<T> selectList(SFunction<T, ?> field, Collection<?> values) {
  90 + if (CollUtil.isEmpty(values)) {
  91 + return CollUtil.newArrayList();
  92 + }
82 93 return selectList(new LambdaQueryWrapper<T>().in(field, values));
83 94 }
84 95  
... ...
yudao-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/web/core/util/WebFrameworkUtils.java
1 1 package cn.iocoder.yudao.framework.web.core.util;
2 2  
3 3 import cn.hutool.core.util.NumberUtil;
4   -import cn.hutool.core.util.StrUtil;
5 4 import cn.iocoder.yudao.framework.common.enums.UserTypeEnum;
6 5 import cn.iocoder.yudao.framework.common.pojo.CommonResult;
7 6 import cn.iocoder.yudao.framework.web.config.WebProperties;
... ... @@ -89,10 +88,10 @@ public class WebFrameworkUtils {
89 88 return userType;
90 89 }
91 90 // 2. 其次,基于 URL 前缀的约定
92   - if (request.getRequestURI().startsWith(properties.getAdminApi().getPrefix())) {
  91 + if (request.getServletPath().startsWith(properties.getAdminApi().getPrefix())) {
93 92 return UserTypeEnum.ADMIN.getValue();
94 93 }
95   - if (request.getRequestURI().startsWith(properties.getAppApi().getPrefix())) {
  94 + if (request.getServletPath().startsWith(properties.getAppApi().getPrefix())) {
96 95 return UserTypeEnum.MEMBER.getValue();
97 96 }
98 97 return null;
... ...
yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/convert/task/BpmActivityConvert.java
1 1 package cn.iocoder.yudao.module.bpm.convert.task;
2 2  
  3 +import cn.iocoder.yudao.framework.common.util.date.DateUtils;
3 4 import cn.iocoder.yudao.module.bpm.controller.admin.task.vo.activity.BpmActivityRespVO;
4 5 import org.flowable.engine.history.HistoricActivityInstance;
5 6 import org.mapstruct.Mapper;
... ... @@ -14,7 +15,7 @@ import java.util.List;
14 15 *
15 16 * @author 芋道源码
16 17 */
17   -@Mapper
  18 +@Mapper(uses = DateUtils.class)
18 19 public interface BpmActivityConvert {
19 20  
20 21 BpmActivityConvert INSTANCE = Mappers.getMapper(BpmActivityConvert.class);
... ...
yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/convert/task/BpmProcessInstanceConvert.java
1 1 package cn.iocoder.yudao.module.bpm.convert.task;
2 2  
3 3 import cn.iocoder.yudao.framework.common.pojo.PageResult;
  4 +import cn.iocoder.yudao.framework.common.util.date.DateUtils;
4 5 import cn.iocoder.yudao.framework.common.util.number.NumberUtils;
5 6 import cn.iocoder.yudao.module.bpm.controller.admin.task.vo.instance.BpmProcessInstancePageItemRespVO;
6 7 import cn.iocoder.yudao.module.bpm.controller.admin.task.vo.instance.BpmProcessInstanceRespVO;
... ... @@ -28,7 +29,7 @@ import java.util.Map;
28 29 *
29 30 * @author 芋道源码
30 31 */
31   -@Mapper
  32 +@Mapper(uses = DateUtils.class)
32 33 public interface BpmProcessInstanceConvert {
33 34  
34 35 BpmProcessInstanceConvert INSTANCE = Mappers.getMapper(BpmProcessInstanceConvert.class);
... ...
yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/convert/task/BpmTaskConvert.java
... ... @@ -2,6 +2,7 @@ package cn.iocoder.yudao.module.bpm.convert.task;
2 2  
3 3 import cn.hutool.core.date.LocalDateTimeUtil;
4 4 import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils;
  5 +import cn.iocoder.yudao.framework.common.util.date.DateUtils;
5 6 import cn.iocoder.yudao.framework.common.util.number.NumberUtils;
6 7 import cn.iocoder.yudao.module.bpm.controller.admin.task.vo.task.BpmTaskDonePageItemRespVO;
7 8 import cn.iocoder.yudao.module.bpm.controller.admin.task.vo.task.BpmTaskRespVO;
... ... @@ -26,7 +27,7 @@ import java.util.Map;
26 27 *
27 28 * @author 芋道源码
28 29 */
29   -@Mapper
  30 +@Mapper(uses = DateUtils.class)
30 31 public interface BpmTaskConvert {
31 32  
32 33 BpmTaskConvert INSTANCE = Mappers.getMapper(BpmTaskConvert.class);
... ... @@ -46,8 +47,6 @@ public interface BpmTaskConvert {
46 47 }
47 48  
48 49 @Mapping(source = "suspended", target = "suspensionState", qualifiedByName = "convertSuspendedToSuspensionState")
49   - @Mapping(target = "claimTime", expression = "java(bean.getClaimTime()==null?null: LocalDateTime.ofInstant(bean.getClaimTime().toInstant(),ZoneId.systemDefault()))")
50   - @Mapping(target = "createTime", expression = "java(bean.getCreateTime()==null?null:LocalDateTime.ofInstant(bean.getCreateTime().toInstant(),ZoneId.systemDefault()))")
51 50 BpmTaskTodoPageItemRespVO convert1(Task bean);
52 51  
53 52 @Named("convertSuspendedToSuspensionState")
... ... @@ -106,8 +105,6 @@ public interface BpmTaskConvert {
106 105 }
107 106  
108 107 @Mapping(source = "taskDefinitionKey", target = "definitionKey")
109   - @Mapping(target = "createTime", expression = "java(bean.getCreateTime() == null ? null : LocalDateTime.ofInstant(bean.getCreateTime().toInstant(), ZoneId.systemDefault()))")
110   - @Mapping(target = "endTime", expression = "java(bean.getEndTime() == null ? null : LocalDateTime.ofInstant(bean.getEndTime().toInstant(), ZoneId.systemDefault()))")
111 108 BpmTaskRespVO convert3(HistoricTaskInstance bean);
112 109  
113 110 BpmTaskRespVO.User convert3(AdminUserRespDTO bean);
... ...
yudao-module-infra/yudao-module-infra-biz/src/main/resources/codegen/vue3_vben/views/data.ts.vm
... ... @@ -15,7 +15,7 @@ export const columns: BasicColumn[] = [
15 15 width: 180,
16 16 customRender: ({ text }) => {
17 17 return useRender.renderDate(text)
18   - }
  18 + },
19 19 },
20 20 #elseif("" != $column.dictType)## 数据字典
21 21 {
... ... @@ -24,13 +24,13 @@ export const columns: BasicColumn[] = [
24 24 width: 180,
25 25 customRender: ({ text }) => {
26 26 return useRender.renderDict(text, DICT_TYPE.$dictType.toUpperCase())
27   - }
  27 + },
28 28 },
29 29 #else
30 30 {
31 31 title: '${comment}',
32 32 dataIndex: '${javaField}',
33   - width: 160
  33 + width: 160,
34 34 },
35 35 #end
36 36 #end
... ... @@ -53,15 +53,15 @@ export const searchFormSchema: FormSchema[] = [
53 53 component: 'Select',
54 54 componentProps: {
55 55 #if ("" != $dictType)## 设置了 dictType 数据字典的情况
56   - options: getDictOptions(DICT_TYPE.$dictType.toUpperCase())
  56 + options: getDictOptions(DICT_TYPE.$dictType.toUpperCase()),
57 57 #else## 未设置 dictType 数据字典的情况
58   - options: []
  58 + options: [],
59 59 #end
60 60 },
61 61 #elseif($column.htmlType == "datetime")
62 62 component: 'RangePicker',
63 63 #end
64   - colProps: { span: 8 }
  64 + colProps: { span: 8 },
65 65 },
66 66 #end
67 67 #end
... ... @@ -72,7 +72,7 @@ export const createFormSchema: FormSchema[] = [
72 72 label: '编号',
73 73 field: 'id',
74 74 show: false,
75   - component: 'Input'
  75 + component: 'Input',
76 76 },
77 77 #foreach($column in $columns)
78 78 #if ($column.createOperation)
... ... @@ -88,52 +88,52 @@ export const createFormSchema: FormSchema[] = [
88 88 required: true,
89 89 #end
90 90 #if ($column.htmlType == "input")
91   - component: 'Input'
  91 + component: 'Input',
92 92 #elseif($column.htmlType == "imageUpload")## 图片上传
93 93 component: 'FileUpload',
94 94 componentProps: {
95 95 fileType: 'file',
96   - maxCount: 1
97   - }
  96 + maxCount: 1,
  97 + },
98 98 #elseif($column.htmlType == "fileUpload")## 文件上传
99 99 component: 'FileUpload',
100 100 componentProps: {
101 101 fileType: 'image',
102   - maxCount: 1
103   - }
  102 + maxCount: 1,
  103 + },
104 104 #elseif($column.htmlType == "editor")## 文本编辑器
105   - component: 'Editor'
  105 + component: 'Editor',
106 106 #elseif($column.htmlType == "select")## 下拉框
107 107 component: 'Select',
108 108 componentProps: {
109 109 #if ("" != $dictType)## 有数据字典
110   - options: getDictOptions(DICT_TYPE.$dictType.toUpperCase(), 'number')
  110 + options: getDictOptions(DICT_TYPE.$dictType.toUpperCase(), 'number'),
111 111 #else##没数据字典
112   - options:[]
  112 + options:[],
113 113 #end
114   - }
  114 + },
115 115 #elseif($column.htmlType == "checkbox")## 多选框
116 116 component: 'Checkbox',
117 117 componentProps: {
118 118 #if ("" != $dictType)## 有数据字典
119   - options: getDictOptions(DICT_TYPE.$dictType.toUpperCase(), 'number')
  119 + options: getDictOptions(DICT_TYPE.$dictType.toUpperCase(), 'number'),
120 120 #else##没数据字典
121   - options:[]
  121 + options:[],
122 122 #end
123   - }
  123 + },
124 124 #elseif($column.htmlType == "radio")## 单选框
125 125 component: 'RadioButtonGroup',
126 126 componentProps: {
127 127 #if ("" != $dictType)## 有数据字典
128   - options: getDictOptions(DICT_TYPE.$dictType.toUpperCase(), 'number')
  128 + options: getDictOptions(DICT_TYPE.$dictType.toUpperCase(), 'number'),
129 129 #else##没数据字典
130   - options:[]
  130 + options:[],
131 131 #end
132   - }
  132 + },
133 133 #elseif($column.htmlType == "datetime")## 时间框
134   - component: 'DatePicker'
  134 + component: 'DatePicker',
135 135 #elseif($column.htmlType == "textarea")## 文本域
136   - component: 'InputTextArea'
  136 + component: 'InputTextArea',
137 137 #end
138 138 },
139 139 #end
... ... @@ -146,7 +146,7 @@ export const updateFormSchema: FormSchema[] = [
146 146 label: '编号',
147 147 field: 'id',
148 148 show: false,
149   - component: 'Input'
  149 + component: 'Input',
150 150 },
151 151 #foreach($column in $columns)
152 152 #if ($column.updateOperation)
... ... @@ -162,44 +162,44 @@ export const updateFormSchema: FormSchema[] = [
162 162 required: true,
163 163 #end
164 164 #if ($column.htmlType == "input")
165   - component: 'Input'
  165 + component: 'Input',
166 166 #elseif($column.htmlType == "imageUpload")## 图片上传
167   - component: 'Upload'
  167 + component: 'Upload',
168 168 #elseif($column.htmlType == "fileUpload")## 文件上传
169   - component: 'Upload'
  169 + component: 'Upload',
170 170 #elseif($column.htmlType == "editor")## 文本编辑器
171   - component: 'Editor'
  171 + component: 'Editor',
172 172 #elseif($column.htmlType == "select")## 下拉框
173 173 component: 'Select',
174 174 componentProps: {
175 175 #if ("" != $dictType)## 有数据字典
176   - options: getDictOptions(DICT_TYPE.$dictType.toUpperCase(), 'number')
  176 + options: getDictOptions(DICT_TYPE.$dictType.toUpperCase(), 'number'),
177 177 #else##没数据字典
178   - options:[]
  178 + options:[],
179 179 #end
180   - }
  180 + },
181 181 #elseif($column.htmlType == "checkbox")## 多选框
182 182 component: 'Checkbox',
183 183 componentProps: {
184 184 #if ("" != $dictType)## 有数据字典
185   - options: getDictOptions(DICT_TYPE.$dictType.toUpperCase(), 'number')
  185 + options: getDictOptions(DICT_TYPE.$dictType.toUpperCase(), 'number'),
186 186 #else##没数据字典
187   - options:[]
  187 + options:[],
188 188 #end
189   - }
  189 + },
190 190 #elseif($column.htmlType == "radio")## 单选框
191 191 component: 'RadioButtonGroup',
192 192 componentProps: {
193 193 #if ("" != $dictType)## 有数据字典
194   - options: getDictOptions(DICT_TYPE.$dictType.toUpperCase(), 'number')
  194 + options: getDictOptions(DICT_TYPE.$dictType.toUpperCase(), 'number'),
195 195 #else##没数据字典
196   - options:[]
  196 + options:[],
197 197 #end
198   - }
  198 + },
199 199 #elseif($column.htmlType == "datetime")## 时间框
200   - component: 'DatePicker'
  200 + component: 'DatePicker',
201 201 #elseif($column.htmlType == "textarea")## 文本域
202   - component: 'InputTextArea'
  202 + component: 'InputTextArea',
203 203 #end
204 204 },
205 205 #end
... ...
yudao-module-infra/yudao-module-infra-biz/src/main/resources/codegen/vue3_vben/views/form.vue.vm
1   -<template>
2   - <BasicModal v-bind="$attrs" @register="registerModal" :title="isUpdate ? t('action.edit') : t('action.create')" @ok="handleSubmit">
3   - <BasicForm @register="registerForm" />
4   - </BasicModal>
5   -</template>
6 1 <script lang="ts" setup>
7 2 import { ref, unref } from 'vue'
  3 +import { createFormSchema, updateFormSchema } from './${classNameVar}.data'
8 4 import { useI18n } from '@/hooks/web/useI18n'
9 5 import { useMessage } from '@/hooks/web/useMessage'
10 6 import { BasicForm, useForm } from '@/components/Form'
11 7 import { BasicModal, useModalInner } from '@/components/Modal'
12   -import { createFormSchema, updateFormSchema } from './${classNameVar}.data'
13 8 import { create${simpleClassName}, get${simpleClassName}, update${simpleClassName} } from '@/api/${table.moduleName}/${classNameVar}'
14 9  
15 10 defineOptions({ name: '${table.className}Modal' })
... ... @@ -24,7 +19,7 @@ const [registerForm, { setFieldsValue, resetFields, resetSchema, validate }] = u
24 19 baseColProps: { span: 24 },
25 20 schemas: createFormSchema,
26 21 showActionButtonGroup: false,
27   - actionColOptions: { span: 23 }
  22 + actionColOptions: { span: 23 },
28 23 })
29 24  
30 25 const [registerModal, { setModalProps, closeModal }] = useModalInner(async (data) => {
... ... @@ -55,3 +50,8 @@ async function handleSubmit() {
55 50 }
56 51 }
57 52 </script>
  53 +<template>
  54 + <BasicModal v-bind="$attrs" @register="registerModal" :title="isUpdate ? t('action.edit') : t('action.create')" @ok="handleSubmit">
  55 + <BasicForm @register="registerForm" />
  56 + </BasicModal>
  57 +</template>
58 58 \ No newline at end of file
... ...
yudao-module-infra/yudao-module-infra-biz/src/main/resources/codegen/vue3_vben/views/index.vue.vm
1   -<template>
2   - <div>
3   - <BasicTable @register="registerTable">
4   - <template #toolbar>
5   - <a-button type="primary" v-auth="['${permissionPrefix}:create']" :preIcon="IconEnum.ADD" @click="handleCreate">
6   - {{ t('action.create') }}
7   - </a-button>
8   - <a-button type="warning" v-auth="['${permissionPrefix}:export']" :preIcon="IconEnum.EXPORT" @click="handleExport">
9   - {{ t('action.export') }}
10   - </a-button>
11   - </template>
12   - <template #bodyCell="{ column, record }">
13   - <template v-if="column.key === 'action'">
14   - <TableAction
15   - :actions="[
16   - { icon: IconEnum.EDIT, label: t('action.edit'), auth: '${permissionPrefix}:update', onClick: handleEdit.bind(null, record) },
17   - {
18   - icon: IconEnum.DELETE,
19   - color: 'error',
20   - label: t('action.delete'),
21   - auth: '${permissionPrefix}:delete',
22   - popConfirm: {
23   - title: t('common.delMessage'),
24   - placement: 'left',
25   - confirm: handleDelete.bind(null, record)
26   - }
27   - }
28   - ]"
29   - />
30   - </template>
31   - </template>
32   - </BasicTable>
33   - <${simpleClassName}Modal @register="registerModal" @success="reload()" />
34   - </div>
35   -</template>
36 1 <script lang="ts" setup>
  2 +import ${simpleClassName}Modal from './${simpleClassName}Modal.vue'
  3 +import { columns, searchFormSchema } from './${classNameVar}.data'
37 4 import { useI18n } from '@/hooks/web/useI18n'
38 5 import { useMessage } from '@/hooks/web/useMessage'
39 6 import { useModal } from '@/components/Modal'
40   -import ${simpleClassName}Modal from './${simpleClassName}Modal.vue'
41 7 import { IconEnum } from '@/enums/appEnum'
42 8 import { BasicTable, useTable, TableAction } from '@/components/Table'
43 9 import { delete${simpleClassName}, export${simpleClassName}, get${simpleClassName}Page } from '@/api/${table.moduleName}/${classNameVar}'
44   -import { columns, searchFormSchema } from './${classNameVar}.data'
45 10  
46 11 defineOptions({ name: '${table.className}' })
47 12  
... ... @@ -60,8 +25,8 @@ const [registerTable, { getForm, reload }] = useTable({
60 25 width: 140,
61 26 title: t('common.action'),
62 27 dataIndex: 'action',
63   - fixed: 'right'
64   - }
  28 + fixed: 'right',
  29 + },
65 30 })
66 31  
67 32 function handleCreate() {
... ... @@ -80,7 +45,7 @@ async function handleExport() {
80 45 async onOk() {
81 46 await export${simpleClassName}(getForm().getFieldsValue())
82 47 createMessage.success(t('common.exportSuccessText'))
83   - }
  48 + },
84 49 })
85 50 }
86 51  
... ... @@ -90,3 +55,38 @@ async function handleDelete(record: Recordable) {
90 55 reload()
91 56 }
92 57 </script>
  58 +<template>
  59 + <div>
  60 + <BasicTable @register="registerTable">
  61 + <template #toolbar>
  62 + <a-button type="primary" v-auth="['${permissionPrefix}:create']" :preIcon="IconEnum.ADD" @click="handleCreate">
  63 + {{ t('action.create') }}
  64 + </a-button>
  65 + <a-button type="warning" v-auth="['${permissionPrefix}:export']" :preIcon="IconEnum.EXPORT" @click="handleExport">
  66 + {{ t('action.export') }}
  67 + </a-button>
  68 + </template>
  69 + <template #bodyCell="{ column, record }">
  70 + <template v-if="column.key === 'action'">
  71 + <TableAction
  72 + :actions="[
  73 + { icon: IconEnum.EDIT, label: t('action.edit'), auth: '${permissionPrefix}:update', onClick: handleEdit.bind(null, record) },
  74 + {
  75 + icon: IconEnum.DELETE,
  76 + danger: true,
  77 + label: t('action.delete'),
  78 + auth: '${permissionPrefix}:delete',
  79 + popConfirm: {
  80 + title: t('common.delMessage'),
  81 + placement: 'left',
  82 + confirm: handleDelete.bind(null, record),
  83 + },
  84 + },
  85 + ]"
  86 + />
  87 + </template>
  88 + </template>
  89 + </BasicTable>
  90 + <${simpleClassName}Modal @register="registerModal" @success="reload()" />
  91 + </div>
  92 +</template>
93 93 \ No newline at end of file
... ...
yudao-module-mall/yudao-module-product-api/src/main/java/cn/iocoder/yudao/module/product/api/sku/dto/ProductSkuRespDTO.java
... ... @@ -60,4 +60,14 @@ public class ProductSkuRespDTO {
60 60 */
61 61 private Double volume;
62 62  
  63 + // TODO @puhui:这 2 字段,需要改下;firstBrokerageRecord、secondBrokerageRecord;和分佣保持一致;
  64 + /**
  65 + * 一级分销的佣金,单位:分
  66 + */
  67 + private Integer subCommissionFirstPrice;
  68 + /**
  69 + * 二级分销的佣金,单位:分
  70 + */
  71 + private Integer subCommissionSecondPrice;
  72 +
63 73 }
... ...
yudao-module-mall/yudao-module-promotion-api/src/main/java/cn/iocoder/yudao/module/promotion/api/coupon/dto/CouponRespDTO.java
... ... @@ -71,9 +71,9 @@ public class CouponRespDTO {
71 71 */
72 72 private Integer productScope;
73 73 /**
74   - * 商品 SPU 编号的数组
  74 + * 商品范围编号的数组
75 75 */
76   - private List<Long> productSpuIds;
  76 + private List<Long> productScopeValues;
77 77 // ========== 使用规则 END ==========
78 78  
79 79 // ========== 使用效果 BEGIN ==========
... ...
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/coupon/vo/coupon/CouponBaseVO.java
... ... @@ -67,8 +67,8 @@ public class CouponBaseVO {
67 67 @InEnum(PromotionProductScopeEnum.class)
68 68 private Integer productScope;
69 69  
70   - @Schema(description = "商品 SPU 编号的数组", example = "1,3")
71   - private List<Long> productSpuIds;
  70 + @Schema(description = "商品范围编号的数组", example = "1,3")
  71 + private List<Long> productScopeValues;
72 72 // ========== 使用规则 END ==========
73 73  
74 74 // ========== 使用效果 BEGIN ==========
... ...
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/coupon/vo/template/CouponTemplateBaseVO.java
... ... @@ -54,8 +54,8 @@ public class CouponTemplateBaseVO {
54 54 @InEnum(PromotionProductScopeEnum.class)
55 55 private Integer productScope;
56 56  
57   - @Schema(description = "商品 SPU 编号的数组", example = "1,3")
58   - private List<Long> productSpuIds;
  57 + @Schema(description = "商品范围编号的数组", example = "[1, 3]")
  58 + private List<Long> productScopeValues;
59 59  
60 60 @Schema(description = "生效日期类型", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
61 61 @NotNull(message = "生效日期类型不能为空")
... ... @@ -95,11 +95,11 @@ public class CouponTemplateBaseVO {
95 95 @Schema(description = "折扣上限", example = "100") // 单位:分,仅在 discountType 为 PERCENT 使用
96 96 private Integer discountLimitPrice;
97 97  
98   - @AssertTrue(message = "商品 SPU 编号的数组不能为空")
  98 + @AssertTrue(message = "商品范围编号的数组不能为空")
99 99 @JsonIgnore
100   - public boolean isProductSpuIdsValid() {
  100 + public boolean isProductScopeValuesValid() {
101 101 return Objects.equals(productScope, PromotionProductScopeEnum.ALL.getScope()) // 全部范围时,可以为空
102   - || CollUtil.isNotEmpty(productSpuIds);
  102 + || CollUtil.isNotEmpty(productScopeValues);
103 103 }
104 104  
105 105 @AssertTrue(message = "生效开始时间不能为空")
... ...
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/app/combination/AppCombinationRecordController.java
1 1 package cn.iocoder.yudao.module.promotion.controller.app.combination;
2 2  
3 3 import cn.iocoder.yudao.framework.common.pojo.CommonResult;
4   -import cn.iocoder.yudao.framework.common.util.date.DateUtils;
  4 +import cn.iocoder.yudao.framework.common.util.date.LocalDateTimeUtils;
5 5 import cn.iocoder.yudao.module.promotion.controller.app.combination.vo.record.AppCombinationRecordDetailRespVO;
6 6 import cn.iocoder.yudao.module.promotion.controller.app.combination.vo.record.AppCombinationRecordRespVO;
7 7 import cn.iocoder.yudao.module.promotion.controller.app.combination.vo.record.AppCombinationRecordSummaryRespVO;
... ... @@ -16,8 +16,8 @@ import org.springframework.web.bind.annotation.RestController;
16 16  
17 17 import javax.validation.constraints.Max;
18 18 import java.time.Duration;
  19 +import java.time.LocalDateTime;
19 20 import java.util.ArrayList;
20   -import java.util.Date;
21 21 import java.util.List;
22 22  
23 23 import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
... ... @@ -58,7 +58,7 @@ public class AppCombinationRecordController {
58 58 record.setId((long) i);
59 59 record.setNickname("用户" + i);
60 60 record.setAvatar("头像" + i);
61   - record.setExpireTime(new Date());
  61 + record.setExpireTime(LocalDateTime.now());
62 62 record.setUserSize(10);
63 63 record.setUserCount(i);
64 64 record.setPicUrl("https://static.iocoder.cn/mall/a79f5d2ea6bf0c3c11b2127332dfe2df.jpg");
... ... @@ -79,7 +79,7 @@ public class AppCombinationRecordController {
79 79 headRecord.setId(1L);
80 80 headRecord.setNickname("用户" + 1);
81 81 headRecord.setAvatar("头像" + 1);
82   - headRecord.setExpireTime(DateUtils.addTime(Duration.ofDays(1)));
  82 + headRecord.setExpireTime(LocalDateTimeUtils.addTime(Duration.ofDays(1)));
83 83 headRecord.setUserSize(10);
84 84 headRecord.setUserCount(3);
85 85 headRecord.setStatus(1);
... ... @@ -94,7 +94,7 @@ public class AppCombinationRecordController {
94 94 record.setId((long) i);
95 95 record.setNickname("用户" + i);
96 96 record.setAvatar("头像" + i);
97   - record.setExpireTime(new Date());
  97 + record.setExpireTime(LocalDateTime.now());
98 98 record.setUserSize(10);
99 99 record.setUserCount(i);
100 100 record.setStatus(1);
... ...
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/app/combination/vo/record/AppCombinationRecordRespVO.java
... ... @@ -3,7 +3,7 @@ package cn.iocoder.yudao.module.promotion.controller.app.combination.vo.record;
3 3 import io.swagger.v3.oas.annotations.media.Schema;
4 4 import lombok.Data;
5 5  
6   -import java.util.Date;
  6 +import java.time.LocalDateTime;
7 7  
8 8 @Schema(description = "用户 App - 拼团记录 Response VO")
9 9 @Data
... ... @@ -22,7 +22,7 @@ public class AppCombinationRecordRespVO {
22 22 private String avatar;
23 23  
24 24 @Schema(description = "过期时间", requiredMode = Schema.RequiredMode.REQUIRED)
25   - private Date expireTime;
  25 + private LocalDateTime expireTime;
26 26  
27 27 @Schema(description = "可参团人数", requiredMode = Schema.RequiredMode.REQUIRED, example = "10")
28 28 private Integer userSize;
... ...
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/app/coupon/vo/template/AppCouponTemplateRespVO.java
... ... @@ -28,8 +28,8 @@ public class AppCouponTemplateRespVO {
28 28 // @InEnum(PromotionProductScopeEnum.class)
29 29 // private Integer productScope;
30 30 //
31   -// @Schema(description = "商品 SPU 编号的数组", example = "1,3")
32   -// private List<Long> productSpuIds;
  31 +// @Schema(description = "商品范围编号的数组", example = "1,3")
  32 +// private List<Long> productScopeValues;
33 33  
34 34 @Schema(description = "生效日期类型", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
35 35 private Integer validityType;
... ...
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/convert/coupon/CouponConvert.java
... ... @@ -33,7 +33,7 @@ public interface CouponConvert {
33 33 .setTakeType(template.getTakeType())
34 34 .setUsePrice(template.getUsePrice())
35 35 .setProductScope(template.getProductScope())
36   - .setProductSpuIds(template.getProductSpuIds())
  36 + .setProductScopeValues(template.getProductScopeValues())
37 37 .setDiscountType(template.getDiscountType())
38 38 .setDiscountPercent(template.getDiscountPercent())
39 39 .setDiscountPrice(template.getDiscountPrice())
... ...
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/dal/dataobject/coupon/CouponDO.java
... ... @@ -89,12 +89,12 @@ public class CouponDO extends BaseDO {
89 89 */
90 90 private Integer productScope;
91 91 /**
92   - * 商品 SPU 编号的数组
  92 + * 商品范围编号的数组
93 93 *
94   - * 冗余 {@link CouponTemplateDO#getProductSpuIds()}
  94 + * 冗余 {@link CouponTemplateDO#getProductScopeValues()}
95 95 */
96 96 @TableField(typeHandler = LongListTypeHandler.class)
97   - private List<Long> productSpuIds;
  97 + private List<Long> productScopeValues;
98 98 // ========== 使用规则 END ==========
99 99  
100 100 // ========== 使用效果 BEGIN ==========
... ...
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/dal/dataobject/coupon/CouponTemplateDO.java
... ... @@ -85,10 +85,10 @@ public class CouponTemplateDO extends BaseDO {
85 85 */
86 86 private Integer productScope;
87 87 /**
88   - * 商品 SPU 编号的数组
  88 + * 商品范围编号的数组
89 89 */
90 90 @TableField(typeHandler = LongListTypeHandler.class)
91   - private List<Long> productSpuIds;
  91 + private List<Long> productScopeValues;
92 92 /**
93 93 * 生效日期类型
94 94 *
... ...
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/coupon/CouponServiceImpl.java
... ... @@ -93,6 +93,7 @@ public class CouponServiceImpl implements CouponService {
93 93 public void useCoupon(Long id, Long userId, Long orderId) {
94 94 // 校验优惠劵
95 95 validCoupon(id, userId);
  96 +
96 97 // 更新状态
97 98 int updateCount = couponMapper.updateByIdAndStatus(id, CouponStatusEnum.UNUSED.getStatus(),
98 99 new CouponDO().setStatus(CouponStatusEnum.USED.getStatus())
... ... @@ -115,12 +116,14 @@ public class CouponServiceImpl implements CouponService {
115 116 }
116 117  
117 118 // 退还
118   - // TODO @疯狂:最好 where status,避免可能存在的并发问题
119 119 Integer status = LocalDateTimeUtils.beforeNow(coupon.getValidEndTime())
120   - // 退还时可能已经过期了
121   - ? CouponStatusEnum.EXPIRE.getStatus()
  120 + ? CouponStatusEnum.EXPIRE.getStatus() // 退还时可能已经过期了
122 121 : CouponStatusEnum.UNUSED.getStatus();
123   - couponMapper.updateById(new CouponDO().setId(id).setStatus(status));
  122 + int updateCount = couponMapper.updateByIdAndStatus(id, CouponStatusEnum.UNUSED.getStatus(),
  123 + new CouponDO().setStatus(status));
  124 + if (updateCount == 0) {
  125 + throw exception(COUPON_STATUS_NOT_USED);
  126 + }
124 127  
125 128 // TODO 增加优惠券变动记录?
126 129 }
... ...
yudao-module-mall/yudao-module-trade-api/src/main/java/cn/iocoder/yudao/module/trade/enums/ErrorCodeConstants.java
... ... @@ -11,7 +11,7 @@ import cn.iocoder.yudao.framework.common.exception.ErrorCode;
11 11 */
12 12 public interface ErrorCodeConstants {
13 13  
14   - // ========== Order 模块 1011000000 ==========
  14 + // ========== Order 模块 1011000000 ==========
15 15 ErrorCode ORDER_CREATE_SKU_NOT_FOUND = new ErrorCode(1011000001, "商品 SKU 不存在");
16 16 ErrorCode ORDER_CREATE_SPU_NOT_SALE = new ErrorCode(1011000002, "商品 SPU 不可售卖");
17 17 ErrorCode ORDER_CREATE_SKU_STOCK_NOT_ENOUGH = new ErrorCode(1011000004, "商品 SKU 库存不足");
... ... @@ -35,7 +35,7 @@ public interface ErrorCodeConstants {
35 35 ErrorCode ORDER_DELIVERY_FAIL_DELIVERY_TYPE_NOT_EXPRESS = new ErrorCode(1011000024, "交易订单发货失败,发货类型不是快递");
36 36 ErrorCode ORDER_CANCEL_FAIL_STATUS_NOT_UNPAID = new ErrorCode(1011000025, "交易订单取消失败,订单不是【待支付】状态");
37 37  
38   - // ========== After Sale 模块 1011000100 ==========
  38 + // ========== After Sale 模块 1011000100 ==========
39 39 ErrorCode AFTER_SALE_NOT_FOUND = new ErrorCode(1011000100, "售后单不存在");
40 40 ErrorCode AFTER_SALE_CREATE_FAIL_REFUND_PRICE_ERROR = new ErrorCode(1011000101, "申请退款金额错误");
41 41 ErrorCode AFTER_SALE_CREATE_FAIL_ORDER_STATUS_CANCELED = new ErrorCode(1011000102, "订单已关闭,无法申请售后");
... ... @@ -50,7 +50,7 @@ public interface ErrorCodeConstants {
50 50 ErrorCode AFTER_SALE_CANCEL_FAIL_STATUS_NOT_APPLY_OR_AGREE_OR_BUYER_DELIVERY =
51 51 new ErrorCode(1011000111, "取消售后单失败,售后单状态不是【待审核】或【卖家同意】或【商家待收货】");
52 52  
53   - // ========== Cart 模块 1011002000 ==========
  53 + // ========== Cart 模块 1011002000 ==========
54 54 ErrorCode CARD_ITEM_NOT_FOUND = new ErrorCode(1011002000, "购物车项不存在");
55 55  
56 56 // ========== Price 相关 1011003000 ============
... ... @@ -58,7 +58,7 @@ public interface ErrorCodeConstants {
58 58 ErrorCode PRICE_CALCULATE_DELIVERY_PRICE_USER_ADDR_IS_EMPTY = new ErrorCode(1011003001, "计算快递运费异常,收件人地址编号为空");
59 59 ErrorCode PRICE_CALCULATE_DELIVERY_PRICE_TEMPLATE_NOT_FOUND = new ErrorCode(1011003002, "计算快递运费异常,找不到对应的运费模板");
60 60  
61   - // ========== 物流 Express 模块 1011004000 ==========
  61 + // ========== 物流 Express 模块 1011004000 ==========
62 62 ErrorCode EXPRESS_NOT_EXISTS = new ErrorCode(1011004000, "快递公司不存在");
63 63 ErrorCode EXPRESS_CODE_DUPLICATE = new ErrorCode(1011004001, "已经存在该编码的快递公司");
64 64 ErrorCode EXPRESS_CLIENT_NOT_PROVIDE = new ErrorCode(1011004002, "需要接入快递服务商,比如【快递100】");
... ... @@ -67,11 +67,15 @@ public interface ErrorCodeConstants {
67 67 ErrorCode EXPRESS_API_QUERY_ERROR = new ErrorCode(1011004101, "快递查询接口异常");
68 68 ErrorCode EXPRESS_API_QUERY_FAILED = new ErrorCode(1011004102, "快递查询返回失败,原因:{}");
69 69  
70   - // ========== 物流 Template 模块 1011005000 ==========
  70 + // ========== 物流 Template 模块 1011005000 ==========
71 71 ErrorCode EXPRESS_TEMPLATE_NAME_DUPLICATE = new ErrorCode(1011005000, "已经存在该运费模板名");
72 72 ErrorCode EXPRESS_TEMPLATE_NOT_EXISTS = new ErrorCode(1011005001, "运费模板不存在");
73 73  
74   - // ========== 物流 PICK_UP 模块 1011006000 ==========
  74 + // ========== 物流 PICK_UP 模块 1011006000 ==========
75 75 ErrorCode PICK_UP_STORE_NOT_EXISTS = new ErrorCode(1011006000, "自提门店不存在");
76 76  
  77 +
  78 + // ========== 分销用户 模块 1011007000 ==========
  79 + ErrorCode BROKERAGE_USER_NOT_EXISTS = new ErrorCode(1011007000, "分销用户不存在");
  80 +
77 81 }
... ...
yudao-module-mall/yudao-module-trade-api/src/main/java/cn/iocoder/yudao/module/trade/enums/brokerage/BrokerageBindModeEnum.java 0 → 100644
  1 +package cn.iocoder.yudao.module.trade.enums.brokerage;
  2 +
  3 +import cn.iocoder.yudao.framework.common.core.IntArrayValuable;
  4 +import lombok.AllArgsConstructor;
  5 +import lombok.Getter;
  6 +
  7 +import java.util.Arrays;
  8 +
  9 +/**
  10 + * 分销关系绑定模式枚举
  11 + *
  12 + * @author owen
  13 + */
  14 +@AllArgsConstructor
  15 +@Getter
  16 +public enum BrokerageBindModeEnum implements IntArrayValuable {
  17 +
  18 + // TODO @疯狂:要不从 1 开始?
  19 + /**
  20 + * 只要用户没有推广人,随时都可以绑定分销关系
  21 + */
  22 + ANYTIME(0, "没有推广人"),
  23 + /**
  24 + * 仅新用户注册时才能绑定推广关系
  25 + */
  26 + REGISTER(1, "新用户"),
  27 + // TODO @疯狂:要加个 2,每次扫码都覆盖
  28 + ;
  29 +
  30 + public static final int[] ARRAYS = Arrays.stream(values()).mapToInt(BrokerageBindModeEnum::getMode).toArray();
  31 +
  32 + /**
  33 + * 模式
  34 + */
  35 + private final Integer mode;
  36 + /**
  37 + * 名字
  38 + */
  39 + private final String name;
  40 +
  41 + @Override
  42 + public int[] array() {
  43 + return ARRAYS;
  44 + }
  45 +
  46 +}
... ...
yudao-module-mall/yudao-module-trade-api/src/main/java/cn/iocoder/yudao/module/trade/enums/brokerage/BrokerageEnabledConditionEnum.java 0 → 100644
  1 +package cn.iocoder.yudao.module.trade.enums.brokerage;
  2 +
  3 +import cn.iocoder.yudao.framework.common.core.IntArrayValuable;
  4 +import lombok.AllArgsConstructor;
  5 +import lombok.Getter;
  6 +
  7 +import java.util.Arrays;
  8 +
  9 +/**
  10 + * 分佣模式枚举
  11 + *
  12 + * @author owen
  13 + */
  14 +@AllArgsConstructor
  15 +@Getter
  16 +public enum BrokerageEnabledConditionEnum implements IntArrayValuable {
  17 +
  18 + // TODO @疯狂:这个也从 1 开始哇
  19 + /**
  20 + * 所有用户都可以分销
  21 + */
  22 + ALL(0, "人人分销"),
  23 + /**
  24 + * 仅可后台手动设置推广员
  25 + */
  26 + ADMIN(1, "指定分销"),
  27 + ;
  28 +
  29 + public static final int[] ARRAYS = Arrays.stream(values()).mapToInt(BrokerageEnabledConditionEnum::getCondition).toArray();
  30 +
  31 + /**
  32 + * 模式
  33 + */
  34 + private final Integer condition;
  35 + /**
  36 + * 名字
  37 + */
  38 + private final String name;
  39 +
  40 + @Override
  41 + public int[] array() {
  42 + return ARRAYS;
  43 + }
  44 +
  45 +}
... ...
yudao-module-mall/yudao-module-trade-api/src/main/java/cn/iocoder/yudao/module/trade/enums/brokerage/BrokerageRecordBizTypeEnum.java 0 → 100644
  1 +package cn.iocoder.yudao.module.trade.enums.brokerage;
  2 +
  3 +import cn.iocoder.yudao.framework.common.core.IntArrayValuable;
  4 +import lombok.AllArgsConstructor;
  5 +import lombok.Getter;
  6 +
  7 +import java.util.Arrays;
  8 +
  9 +/**
  10 + * 佣金记录业务类型枚举
  11 + *
  12 + * @author owen
  13 + */
  14 +@AllArgsConstructor
  15 +@Getter
  16 +public enum BrokerageRecordBizTypeEnum implements IntArrayValuable {
  17 +
  18 + // TODO @疯狂:这个也从 1 开始哇
  19 + ORDER(0, "获得推广佣金", "获得推广佣金 {}", true),
  20 + WITHDRAW(1, "提现申请", "提现申请扣除佣金 {}", false),
  21 + ;
  22 +
  23 + public static final int[] ARRAYS = Arrays.stream(values()).mapToInt(BrokerageRecordBizTypeEnum::getType).toArray();
  24 +
  25 + /**
  26 + * 类型
  27 + */
  28 + private final Integer type;
  29 + /**
  30 + * 标题
  31 + */
  32 + private final String title;
  33 + /**
  34 + * 描述
  35 + */
  36 + private final String description;
  37 + /**
  38 + * 是否为增加佣金
  39 + */
  40 + private final boolean add;
  41 +
  42 + @Override
  43 + public int[] array() {
  44 + return ARRAYS;
  45 + }
  46 +
  47 +}
... ...
yudao-module-mall/yudao-module-trade-api/src/main/java/cn/iocoder/yudao/module/trade/enums/brokerage/BrokerageRecordStatusEnum.java 0 → 100644
  1 +package cn.iocoder.yudao.module.trade.enums.brokerage;
  2 +
  3 +import cn.iocoder.yudao.framework.common.core.IntArrayValuable;
  4 +import lombok.AllArgsConstructor;
  5 +import lombok.Getter;
  6 +
  7 +import java.util.Arrays;
  8 +
  9 +/**
  10 + * 佣金记录状态枚举
  11 + *
  12 + * @author owen
  13 + */
  14 +@AllArgsConstructor
  15 +@Getter
  16 +public enum BrokerageRecordStatusEnum implements IntArrayValuable {
  17 +
  18 + WAIT_SETTLEMENT(0, "待结算"),
  19 + SETTLEMENT(1, "已结算"),
  20 + CANCEL(2, "已取消"),
  21 + ;
  22 +
  23 + public static final int[] ARRAYS = Arrays.stream(values()).mapToInt(BrokerageRecordStatusEnum::getStatus).toArray();
  24 +
  25 + /**
  26 + * 状态
  27 + */
  28 + private final Integer status;
  29 + /**
  30 + * 名字
  31 + */
  32 + private final String name;
  33 +
  34 + @Override
  35 + public int[] array() {
  36 + return ARRAYS;
  37 + }
  38 +
  39 +}
... ...
yudao-module-mall/yudao-module-trade-api/src/main/java/cn/iocoder/yudao/module/trade/enums/brokerage/BrokerageWithdrawStatusEnum.java 0 → 100644
  1 +package cn.iocoder.yudao.module.trade.enums.brokerage;
  2 +
  3 +import cn.iocoder.yudao.framework.common.core.IntArrayValuable;
  4 +import lombok.AllArgsConstructor;
  5 +import lombok.Getter;
  6 +
  7 +import java.util.Arrays;
  8 +
  9 +/**
  10 + * 佣金提现状态枚举
  11 + *
  12 + * @author owen
  13 + */
  14 +@AllArgsConstructor
  15 +@Getter
  16 +public enum BrokerageWithdrawStatusEnum implements IntArrayValuable {
  17 +
  18 + AUDITING(0, "审核中"),
  19 + AUDIT_SUCCESS(10, "审核通过"),
  20 + WITHDRAW_SUCCESS(11, "提现成功"),
  21 + AUDIT_FAIL(20, "审核不通过"),
  22 + WITHDRAW_FAIL(21, "提现失败"),
  23 + ;
  24 +
  25 + public static final int[] ARRAYS = Arrays.stream(values()).mapToInt(BrokerageWithdrawStatusEnum::getStatus).toArray();
  26 +
  27 + /**
  28 + * 状态
  29 + */
  30 + private final Integer status;
  31 + /**
  32 + * 名字
  33 + */
  34 + private final String name;
  35 +
  36 + @Override
  37 + public int[] array() {
  38 + return ARRAYS;
  39 + }
  40 +
  41 +}
... ...
yudao-module-mall/yudao-module-trade-api/src/main/java/cn/iocoder/yudao/module/trade/enums/brokerage/BrokerageWithdrawTypeEnum.java 0 → 100644
  1 +package cn.iocoder.yudao.module.trade.enums.brokerage;
  2 +
  3 +import cn.iocoder.yudao.framework.common.core.IntArrayValuable;
  4 +import lombok.AllArgsConstructor;
  5 +import lombok.Getter;
  6 +
  7 +import java.util.Arrays;
  8 +
  9 +/**
  10 + * 佣金提现类型枚举
  11 + *
  12 + * @author owen
  13 + */
  14 +@AllArgsConstructor
  15 +@Getter
  16 +public enum BrokerageWithdrawTypeEnum implements IntArrayValuable {
  17 +
  18 + WALLET(1, "钱包"),
  19 + BANK(2, "银行卡"),
  20 + WECHAT(3, "微信"),
  21 + ALIPAY(4, "支付宝"),
  22 + ;
  23 +
  24 + public static final int[] ARRAYS = Arrays.stream(values()).mapToInt(BrokerageWithdrawTypeEnum::getType).toArray();
  25 +
  26 + /**
  27 + * 类型
  28 + */
  29 + private final Integer type;
  30 + /**
  31 + * 名字
  32 + */
  33 + private final String name;
  34 +
  35 + @Override
  36 + public int[] array() {
  37 + return ARRAYS;
  38 + }
  39 +
  40 +}
... ...
yudao-module-mall/yudao-module-trade-biz/pom.xml
... ... @@ -56,6 +56,10 @@
56 56 </dependency>
57 57 <dependency>
58 58 <groupId>cn.iocoder.boot</groupId>
  59 + <artifactId>yudao-spring-boot-starter-biz-tenant</artifactId>
  60 + </dependency>
  61 + <dependency>
  62 + <groupId>cn.iocoder.boot</groupId>
59 63 <artifactId>yudao-spring-boot-starter-biz-ip</artifactId>
60 64 </dependency>
61 65  
... ...
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/brokerage/record/TradeBrokerageRecordController.java 0 → 100644
  1 +package cn.iocoder.yudao.module.trade.controller.admin.brokerage.record;
  2 +
  3 +import cn.iocoder.yudao.framework.common.pojo.CommonResult;
  4 +import cn.iocoder.yudao.framework.common.pojo.PageResult;
  5 +import cn.iocoder.yudao.module.trade.controller.admin.brokerage.record.vo.TradeBrokerageRecordPageReqVO;
  6 +import cn.iocoder.yudao.module.trade.controller.admin.brokerage.record.vo.TradeBrokerageRecordRespVO;
  7 +import cn.iocoder.yudao.module.trade.convert.brokerage.record.TradeBrokerageRecordConvert;
  8 +import cn.iocoder.yudao.module.trade.dal.dataobject.brokerage.record.TradeBrokerageRecordDO;
  9 +import cn.iocoder.yudao.module.trade.service.brokerage.record.TradeBrokerageRecordService;
  10 +import io.swagger.v3.oas.annotations.Operation;
  11 +import io.swagger.v3.oas.annotations.Parameter;
  12 +import io.swagger.v3.oas.annotations.tags.Tag;
  13 +import org.springframework.security.access.prepost.PreAuthorize;
  14 +import org.springframework.validation.annotation.Validated;
  15 +import org.springframework.web.bind.annotation.GetMapping;
  16 +import org.springframework.web.bind.annotation.RequestMapping;
  17 +import org.springframework.web.bind.annotation.RequestParam;
  18 +import org.springframework.web.bind.annotation.RestController;
  19 +
  20 +import javax.annotation.Resource;
  21 +import javax.validation.Valid;
  22 +
  23 +import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
  24 +
  25 +@Tag(name = "管理后台 - 佣金记录")
  26 +@RestController
  27 +@RequestMapping("/trade/brokerage-record")
  28 +@Validated
  29 +public class TradeBrokerageRecordController {
  30 +
  31 + @Resource
  32 + private TradeBrokerageRecordService tradeBrokerageRecordService;
  33 +
  34 + @GetMapping("/get")
  35 + @Operation(summary = "获得佣金记录")
  36 + @Parameter(name = "id", description = "编号", required = true, example = "1024")
  37 + @PreAuthorize("@ss.hasPermission('trade:brokerage-record:query')")
  38 + public CommonResult<TradeBrokerageRecordRespVO> getBrokerageRecord(@RequestParam("id") Integer id) {
  39 + TradeBrokerageRecordDO tradeBrokerageRecord = tradeBrokerageRecordService.getBrokerageRecord(id);
  40 + return success(TradeBrokerageRecordConvert.INSTANCE.convert(tradeBrokerageRecord));
  41 + }
  42 +
  43 + @GetMapping("/page")
  44 + @Operation(summary = "获得佣金记录分页")
  45 + @PreAuthorize("@ss.hasPermission('trade:brokerage-record:query')")
  46 + public CommonResult<PageResult<TradeBrokerageRecordRespVO>> getBrokerageRecordPage(@Valid TradeBrokerageRecordPageReqVO pageVO) {
  47 + PageResult<TradeBrokerageRecordDO> pageResult = tradeBrokerageRecordService.getBrokerageRecordPage(pageVO);
  48 + return success(TradeBrokerageRecordConvert.INSTANCE.convertPage(pageResult));
  49 + }
  50 +
  51 +}
... ...
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/brokerage/record/vo/TradeBrokerageRecordBaseVO.java 0 → 100644
  1 +package cn.iocoder.yudao.module.trade.controller.admin.brokerage.record.vo;
  2 +
  3 +import io.swagger.v3.oas.annotations.media.Schema;
  4 +import lombok.Data;
  5 +import org.springframework.format.annotation.DateTimeFormat;
  6 +
  7 +import javax.validation.constraints.NotEmpty;
  8 +import javax.validation.constraints.NotNull;
  9 +import java.time.LocalDateTime;
  10 +
  11 +import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND;
  12 +
  13 +/**
  14 + * 佣金记录 Base VO,提供给添加、修改、详细的子 VO 使用
  15 + * 如果子 VO 存在差异的字段,请不要添加到这里,影响 Swagger 文档生成
  16 + */
  17 +@Data
  18 +public class TradeBrokerageRecordBaseVO {
  19 +
  20 + @Schema(description = "用户编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "25973")
  21 + @NotNull(message = "用户编号不能为空")
  22 + private Long userId;
  23 +
  24 + @Schema(description = "业务编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "23353")
  25 + @NotEmpty(message = "业务编号不能为空")
  26 + private String bizId;
  27 +
  28 + @Schema(description = "业务类型", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
  29 + @NotNull(message = "业务类型不能为空")
  30 + private Integer bizType;
  31 +
  32 + @Schema(description = "标题", requiredMode = Schema.RequiredMode.REQUIRED)
  33 + @NotEmpty(message = "标题不能为空")
  34 + private String title;
  35 +
  36 + @Schema(description = "金额", requiredMode = Schema.RequiredMode.REQUIRED, example = "28731")
  37 + @NotNull(message = "金额不能为空")
  38 + private Integer price;
  39 +
  40 + @Schema(description = "当前总佣金", requiredMode = Schema.RequiredMode.REQUIRED, example = "13226")
  41 + @NotNull(message = "当前总佣金不能为空")
  42 + private Integer totalPrice;
  43 +
  44 + @Schema(description = "说明", requiredMode = Schema.RequiredMode.REQUIRED, example = "你说的对")
  45 + @NotNull(message = "说明不能为空")
  46 + private String description;
  47 +
  48 + @Schema(description = "状态", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
  49 + @NotNull(message = "状态不能为空")
  50 + private Integer status;
  51 +
  52 + @Schema(description = "冻结时间(天)", requiredMode = Schema.RequiredMode.REQUIRED)
  53 + @NotNull(message = "冻结时间(天)不能为空")
  54 + private Integer frozenDays;
  55 +
  56 + @Schema(description = "解冻时间")
  57 + @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
  58 + private LocalDateTime unfreezeTime;
  59 +
  60 +}
... ...
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/brokerage/record/vo/TradeBrokerageRecordPageReqVO.java 0 → 100644
  1 +package cn.iocoder.yudao.module.trade.controller.admin.brokerage.record.vo;
  2 +
  3 +import cn.iocoder.yudao.framework.common.pojo.PageParam;
  4 +import io.swagger.v3.oas.annotations.media.Schema;
  5 +import lombok.Data;
  6 +import lombok.EqualsAndHashCode;
  7 +import lombok.ToString;
  8 +import org.springframework.format.annotation.DateTimeFormat;
  9 +
  10 +import java.time.LocalDateTime;
  11 +
  12 +import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND;
  13 +
  14 +@Schema(description = "管理后台 - 佣金记录分页 Request VO")
  15 +@Data
  16 +@EqualsAndHashCode(callSuper = true)
  17 +@ToString(callSuper = true)
  18 +public class TradeBrokerageRecordPageReqVO extends PageParam {
  19 +
  20 + @Schema(description = "用户编号", example = "25973")
  21 + private Long userId;
  22 +
  23 + @Schema(description = "业务类型", example = "1")
  24 + private Integer bizType;
  25 +
  26 + @Schema(description = "状态", example = "1")
  27 + private Integer status;
  28 +
  29 + @Schema(description = "创建时间")
  30 + @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
  31 + private LocalDateTime[] createTime;
  32 +
  33 +}
... ...
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/brokerage/record/vo/TradeBrokerageRecordRespVO.java 0 → 100644
  1 +package cn.iocoder.yudao.module.trade.controller.admin.brokerage.record.vo;
  2 +
  3 +import io.swagger.v3.oas.annotations.media.Schema;
  4 +import lombok.Data;
  5 +import lombok.EqualsAndHashCode;
  6 +import lombok.ToString;
  7 +
  8 +import java.time.LocalDateTime;
  9 +
  10 +@Schema(description = "管理后台 - 佣金记录 Response VO")
  11 +@Data
  12 +@EqualsAndHashCode(callSuper = true)
  13 +@ToString(callSuper = true)
  14 +public class TradeBrokerageRecordRespVO extends TradeBrokerageRecordBaseVO {
  15 +
  16 + @Schema(description = "编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "28896")
  17 + private Integer id;
  18 +
  19 + @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED)
  20 + private LocalDateTime createTime;
  21 +
  22 +}
... ...
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/brokerage/user/TradeBrokerageUserController.java 0 → 100644
  1 +package cn.iocoder.yudao.module.trade.controller.admin.brokerage.user;
  2 +
  3 +import cn.iocoder.yudao.framework.common.pojo.CommonResult;
  4 +import cn.iocoder.yudao.framework.common.pojo.PageResult;
  5 +import cn.iocoder.yudao.module.trade.controller.admin.brokerage.user.vo.*;
  6 +import cn.iocoder.yudao.module.trade.convert.brokerage.user.TradeBrokerageUserConvert;
  7 +import cn.iocoder.yudao.module.trade.dal.dataobject.brokerage.user.TradeBrokerageUserDO;
  8 +import cn.iocoder.yudao.module.trade.service.brokerage.user.TradeBrokerageUserService;
  9 +import io.swagger.v3.oas.annotations.Operation;
  10 +import io.swagger.v3.oas.annotations.Parameter;
  11 +import io.swagger.v3.oas.annotations.tags.Tag;
  12 +import org.springframework.security.access.prepost.PreAuthorize;
  13 +import org.springframework.validation.annotation.Validated;
  14 +import org.springframework.web.bind.annotation.*;
  15 +
  16 +import javax.annotation.Resource;
  17 +import javax.validation.Valid;
  18 +
  19 +import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
  20 +
  21 +@Tag(name = "管理后台 - 分销用户")
  22 +@RestController
  23 +@RequestMapping("/trade/brokerage-user")
  24 +@Validated
  25 +public class TradeBrokerageUserController {
  26 +
  27 + @Resource
  28 + private TradeBrokerageUserService brokerageUserService;
  29 +
  30 + @PutMapping("/update-brokerage-user")
  31 + @Operation(summary = "修改推广员")
  32 + @PreAuthorize("@ss.hasPermission('trade:brokerage-user:update-brokerage-user')")
  33 + public CommonResult<Boolean> updateBrokerageUser(@Valid @RequestBody TradeBrokerageUserUpdateBrokerageUserReqVO updateReqVO) {
  34 + brokerageUserService.updateBrokerageUserId(updateReqVO.getId(), updateReqVO.getBrokerageUserId());
  35 + return success(true);
  36 + }
  37 +
  38 + @PutMapping("/clear-brokerage-user")
  39 + @Operation(summary = "清除推广员")
  40 + @PreAuthorize("@ss.hasPermission('trade:brokerage-user:clear-brokerage-user')")
  41 + public CommonResult<Boolean> clearBrokerageUser(@Valid @RequestBody TradeBrokerageUserClearBrokerageUserReqVO updateReqVO) {
  42 + brokerageUserService.updateBrokerageUserId(updateReqVO.getId(), null);
  43 + return success(true);
  44 + }
  45 +
  46 + @PutMapping("/update-brokerage-enable")
  47 + @Operation(summary = "修改推广资格")
  48 + @PreAuthorize("@ss.hasPermission('trade:brokerage-user:update-brokerage-enable')")
  49 + public CommonResult<Boolean> updateBrokerageEnabled(@Valid @RequestBody TradeBrokerageUserUpdateBrokerageEnabledReqVO updateReqVO) {
  50 + brokerageUserService.updateBrokerageEnabled(updateReqVO.getId(), updateReqVO.getBrokerageEnabled());
  51 + return success(true);
  52 + }
  53 +
  54 + @GetMapping("/get")
  55 + @Operation(summary = "获得分销用户")
  56 + @Parameter(name = "id", description = "编号", required = true, example = "1024")
  57 + @PreAuthorize("@ss.hasPermission('trade:brokerage-user:query')")
  58 + public CommonResult<TradeBrokerageUserRespVO> getBrokerageUser(@RequestParam("id") Long id) {
  59 + TradeBrokerageUserDO brokerageUser = brokerageUserService.getBrokerageUser(id);
  60 + return success(TradeBrokerageUserConvert.INSTANCE.convert(brokerageUser));
  61 + }
  62 +
  63 + @GetMapping("/page")
  64 + @Operation(summary = "获得分销用户分页")
  65 + @PreAuthorize("@ss.hasPermission('trade:brokerage-user:query')")
  66 + public CommonResult<PageResult<TradeBrokerageUserRespVO>> getBrokerageUserPage(@Valid TradeBrokerageUserPageReqVO pageVO) {
  67 + PageResult<TradeBrokerageUserDO> pageResult = brokerageUserService.getBrokerageUserPage(pageVO);
  68 + return success(TradeBrokerageUserConvert.INSTANCE.convertPage(pageResult));
  69 + }
  70 +
  71 +}
... ...
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/brokerage/user/vo/TradeBrokerageUserBaseVO.java 0 → 100644
  1 +package cn.iocoder.yudao.module.trade.controller.admin.brokerage.user.vo;
  2 +
  3 +import io.swagger.v3.oas.annotations.media.Schema;
  4 +import lombok.Data;
  5 +import org.springframework.format.annotation.DateTimeFormat;
  6 +
  7 +import javax.validation.constraints.NotNull;
  8 +import java.time.LocalDateTime;
  9 +
  10 +import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND;
  11 +
  12 +/**
  13 + * 分销用户 Base VO,提供给添加、修改、详细的子 VO 使用
  14 + * 如果子 VO 存在差异的字段,请不要添加到这里,影响 Swagger 文档生成
  15 + */
  16 +@Data
  17 +public class TradeBrokerageUserBaseVO {
  18 +
  19 + @Schema(description = "推广员编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "4587")
  20 + @NotNull(message = "推广员编号不能为空")
  21 + private Long brokerageUserId;
  22 +
  23 + @Schema(description = "推广员绑定时间")
  24 + @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
  25 + private LocalDateTime brokerageBindTime;
  26 +
  27 + @Schema(description = "推广资格", requiredMode = Schema.RequiredMode.REQUIRED)
  28 + @NotNull(message = "推广资格不能为空")
  29 + private Boolean brokerageEnabled;
  30 +
  31 + @Schema(description = "成为分销员时间")
  32 + @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
  33 + private LocalDateTime brokerageTime;
  34 +
  35 + @Schema(description = "可用佣金", requiredMode = Schema.RequiredMode.REQUIRED, example = "11089")
  36 + @NotNull(message = "可用佣金不能为空")
  37 + private Integer brokeragePrice;
  38 +
  39 + @Schema(description = "冻结佣金", requiredMode = Schema.RequiredMode.REQUIRED, example = "30916")
  40 + @NotNull(message = "冻结佣金不能为空")
  41 + private Integer frozenBrokeragePrice;
  42 +
  43 +}
... ...
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/brokerage/user/vo/TradeBrokerageUserClearBrokerageUserReqVO.java 0 → 100644
  1 +package cn.iocoder.yudao.module.trade.controller.admin.brokerage.user.vo;
  2 +
  3 +import io.swagger.v3.oas.annotations.media.Schema;
  4 +import lombok.Data;
  5 +import lombok.ToString;
  6 +
  7 +import javax.validation.constraints.NotNull;
  8 +
  9 +@Schema(description = "管理后台 - 分销用户 - 清除推广员 Request VO")
  10 +@Data
  11 +@ToString(callSuper = true)
  12 +public class TradeBrokerageUserClearBrokerageUserReqVO {
  13 +
  14 + @Schema(description = "用户编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "20019")
  15 + @NotNull(message = "用户编号不能为空")
  16 + private Long id;
  17 +
  18 +}
... ...
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/brokerage/user/vo/TradeBrokerageUserPageReqVO.java 0 → 100644
  1 +package cn.iocoder.yudao.module.trade.controller.admin.brokerage.user.vo;
  2 +
  3 +import cn.iocoder.yudao.framework.common.pojo.PageParam;
  4 +import io.swagger.v3.oas.annotations.media.Schema;
  5 +import lombok.Data;
  6 +import lombok.EqualsAndHashCode;
  7 +import lombok.ToString;
  8 +import org.springframework.format.annotation.DateTimeFormat;
  9 +
  10 +import java.time.LocalDateTime;
  11 +
  12 +import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND;
  13 +
  14 +@Schema(description = "管理后台 - 分销用户分页 Request VO")
  15 +@Data
  16 +@EqualsAndHashCode(callSuper = true)
  17 +@ToString(callSuper = true)
  18 +public class TradeBrokerageUserPageReqVO extends PageParam {
  19 +
  20 + @Schema(description = "推广员编号", example = "4587")
  21 + private Long brokerageUserId;
  22 +
  23 + @Schema(description = "推广资格")
  24 + private Boolean brokerageEnabled;
  25 +
  26 + @Schema(description = "创建时间")
  27 + @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
  28 + private LocalDateTime[] createTime;
  29 +
  30 +}
... ...
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/brokerage/user/vo/TradeBrokerageUserRespVO.java 0 → 100644
  1 +package cn.iocoder.yudao.module.trade.controller.admin.brokerage.user.vo;
  2 +
  3 +import io.swagger.v3.oas.annotations.media.Schema;
  4 +import lombok.Data;
  5 +import lombok.EqualsAndHashCode;
  6 +import lombok.ToString;
  7 +
  8 +import java.time.LocalDateTime;
  9 +
  10 +@Schema(description = "管理后台 - 分销用户 Response VO")
  11 +@Data
  12 +@EqualsAndHashCode(callSuper = true)
  13 +@ToString(callSuper = true)
  14 +public class TradeBrokerageUserRespVO extends TradeBrokerageUserBaseVO {
  15 +
  16 + @Schema(description = "用户编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "20019")
  17 + private Long id;
  18 +
  19 + @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED)
  20 + private LocalDateTime createTime;
  21 +
  22 +}
... ...
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/brokerage/user/vo/TradeBrokerageUserUpdateBrokerageEnabledReqVO.java 0 → 100644
  1 +package cn.iocoder.yudao.module.trade.controller.admin.brokerage.user.vo;
  2 +
  3 +import io.swagger.v3.oas.annotations.media.Schema;
  4 +import lombok.Data;
  5 +import lombok.ToString;
  6 +
  7 +import javax.validation.constraints.NotNull;
  8 +
  9 +@Schema(description = "管理后台 - 分销用户 - 修改推广员 Request VO")
  10 +@Data
  11 +@ToString(callSuper = true)
  12 +public class TradeBrokerageUserUpdateBrokerageEnabledReqVO {
  13 +
  14 + @Schema(description = "用户编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "20019")
  15 + @NotNull(message = "用户编号不能为空")
  16 + private Long id;
  17 +
  18 + // TODO @疯狂:是不是这个字段,可以改成 enabled
  19 +
  20 + @Schema(description = "推广资格", requiredMode = Schema.RequiredMode.REQUIRED)
  21 + @NotNull(message = "推广资格不能为空")
  22 + private Boolean brokerageEnabled;
  23 +
  24 +}
... ...
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/brokerage/user/vo/TradeBrokerageUserUpdateBrokerageUserReqVO.java 0 → 100644
  1 +package cn.iocoder.yudao.module.trade.controller.admin.brokerage.user.vo;
  2 +
  3 +import io.swagger.v3.oas.annotations.media.Schema;
  4 +import lombok.Data;
  5 +import lombok.ToString;
  6 +
  7 +import javax.validation.constraints.NotNull;
  8 +
  9 +@Schema(description = "管理后台 - 分销用户 - 修改推广员 Request VO")
  10 +@Data
  11 +@ToString(callSuper = true)
  12 +public class TradeBrokerageUserUpdateBrokerageUserReqVO {
  13 +
  14 + @Schema(description = "用户编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "20019")
  15 + @NotNull(message = "用户编号不能为空")
  16 + private Long id;
  17 +
  18 + @Schema(description = "推广员编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "4587")
  19 + @NotNull(message = "推广员编号不能为空")
  20 + private Long brokerageUserId;
  21 +
  22 +}
... ...
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/config/TradeConfigController.java 0 → 100644
  1 +package cn.iocoder.yudao.module.trade.controller.admin.config;
  2 +
  3 +import cn.iocoder.yudao.framework.common.pojo.CommonResult;
  4 +import cn.iocoder.yudao.module.trade.controller.admin.config.vo.TradeConfigRespVO;
  5 +import cn.iocoder.yudao.module.trade.controller.admin.config.vo.TradeConfigSaveReqVO;
  6 +import cn.iocoder.yudao.module.trade.convert.config.TradeConfigConvert;
  7 +import cn.iocoder.yudao.module.trade.dal.dataobject.config.TradeConfigDO;
  8 +import cn.iocoder.yudao.module.trade.service.config.TradeConfigService;
  9 +import io.swagger.v3.oas.annotations.Operation;
  10 +import io.swagger.v3.oas.annotations.tags.Tag;
  11 +import org.springframework.security.access.prepost.PreAuthorize;
  12 +import org.springframework.validation.annotation.Validated;
  13 +import org.springframework.web.bind.annotation.*;
  14 +
  15 +import javax.annotation.Resource;
  16 +import javax.validation.Valid;
  17 +
  18 +import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
  19 +
  20 +@Tag(name = "管理后台 - 交易中心配置")
  21 +@RestController
  22 +@RequestMapping("/trade/config")
  23 +@Validated
  24 +public class TradeConfigController {
  25 +
  26 + @Resource
  27 + private TradeConfigService tradeConfigService;
  28 +
  29 + @PutMapping("/save")
  30 + @Operation(summary = "更新交易中心配置")
  31 + @PreAuthorize("@ss.hasPermission('trade:config:save')")
  32 + public CommonResult<Boolean> updateConfig(@Valid @RequestBody TradeConfigSaveReqVO updateReqVO) {
  33 + tradeConfigService.saveTradeConfig(updateReqVO);
  34 + return success(true);
  35 + }
  36 +
  37 + @GetMapping("/get")
  38 + @Operation(summary = "获得交易中心配置")
  39 + @PreAuthorize("@ss.hasPermission('trade:config:query')")
  40 + public CommonResult<TradeConfigRespVO> getConfig() {
  41 + TradeConfigDO config = tradeConfigService.getTradeConfig();
  42 + return success(TradeConfigConvert.INSTANCE.convert(config));
  43 + }
  44 +
  45 +}
... ...
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/config/vo/TradeConfigBaseVO.java 0 → 100644
  1 +package cn.iocoder.yudao.module.trade.controller.admin.config.vo;
  2 +
  3 +import cn.iocoder.yudao.framework.common.validation.InEnum;
  4 +import cn.iocoder.yudao.module.trade.enums.brokerage.BrokerageBindModeEnum;
  5 +import cn.iocoder.yudao.module.trade.enums.brokerage.BrokerageEnabledConditionEnum;
  6 +import cn.iocoder.yudao.module.trade.enums.brokerage.BrokerageWithdrawTypeEnum;
  7 +import io.swagger.v3.oas.annotations.media.Schema;
  8 +import lombok.Data;
  9 +import org.hibernate.validator.constraints.Range;
  10 +
  11 +import javax.validation.constraints.NotEmpty;
  12 +import javax.validation.constraints.NotNull;
  13 +import javax.validation.constraints.PositiveOrZero;
  14 +import java.util.List;
  15 +
  16 +/**
  17 + * 交易中心配置 Base VO,提供给添加、修改、详细的子 VO 使用
  18 + * 如果子 VO 存在差异的字段,请不要添加到这里,影响 Swagger 文档生成
  19 + */
  20 +@Data
  21 +public class TradeConfigBaseVO {
  22 +
  23 + // ========== 分销相关 ==========
  24 +
  25 + @Schema(description = "是否启用分佣", requiredMode = Schema.RequiredMode.REQUIRED, example = "true")
  26 + @NotNull(message = "是否启用分佣不能为空")
  27 + private Boolean brokerageEnabled;
  28 +
  29 + @Schema(description = "分佣模式", requiredMode = Schema.RequiredMode.REQUIRED, example = "0")
  30 + @NotNull(message = "分佣模式不能为空")
  31 + @InEnum(value = BrokerageEnabledConditionEnum.class, message = "分佣模式必须是 {value}")
  32 + private Integer brokerageEnabledCondition;
  33 +
  34 + @Schema(description = "分销关系绑定模式", requiredMode = Schema.RequiredMode.REQUIRED, example = "0")
  35 + @NotNull(message = "分销关系绑定模式不能为空")
  36 + @InEnum(value = BrokerageBindModeEnum.class, message = "分销关系绑定模式必须是 {value}")
  37 + private Integer brokerageBindMode;
  38 +
  39 + @Schema(description = "分销海报图地址数组", requiredMode = Schema.RequiredMode.REQUIRED, example = "[https://www.iocoder.cn/yudao.jpg]")
  40 + private List<String> brokeragePostUrls;
  41 +
  42 + @Schema(description = "一级返佣比例", requiredMode = Schema.RequiredMode.REQUIRED, example = "5")
  43 + @NotNull(message = "一级返佣比例不能为空")
  44 + @Range(min = 0, max = 100, message = "一级返佣比例必须在 0 - 100 之间")
  45 + private Integer brokerageFirstPercent;
  46 +
  47 + @Schema(description = "二级返佣比例", requiredMode = Schema.RequiredMode.REQUIRED, example = "5")
  48 + @NotNull(message = "二级返佣比例不能为空")
  49 + @Range(min = 0, max = 100, message = "二级返佣比例必须在 0 - 100 之间")
  50 + private Integer brokerageSecondPercent;
  51 +
  52 + @Schema(description = "用户提现最低金额", requiredMode = Schema.RequiredMode.REQUIRED, example = "1000")
  53 + @NotNull(message = "用户提现最低金额不能为空")
  54 + @PositiveOrZero(message = "用户提现最低金额不能是负数")
  55 + private Integer brokerageWithdrawMinPrice;
  56 +
  57 + // TODO @疯狂:要不要做成字典?按道理都可以体现对哇?感觉是全局的配置哈;
  58 + @Schema(description = "提现银行", requiredMode = Schema.RequiredMode.REQUIRED, example = "[0, 1]")
  59 + @NotEmpty(message = "提现银行不能为空")
  60 + private List<Integer> brokerageBankNames;
  61 +
  62 + @Schema(description = "佣金冻结时间(天)", requiredMode = Schema.RequiredMode.REQUIRED, example = "7")
  63 + @NotNull(message = "佣金冻结时间(天)不能为空")
  64 + @PositiveOrZero(message = "佣金冻结时间不能是负数")
  65 + private Integer brokerageFrozenDays;
  66 +
  67 + @Schema(description = "提现方式", requiredMode = Schema.RequiredMode.REQUIRED, example = "[0, 1]")
  68 + @NotNull(message = "提现方式不能为空")
  69 + @InEnum(value = BrokerageWithdrawTypeEnum.class, message = "提现方式必须是 {value}")
  70 + private List<Integer> brokerageWithdrawType;
  71 +
  72 +}
... ...
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/config/vo/TradeConfigRespVO.java 0 → 100644
  1 +package cn.iocoder.yudao.module.trade.controller.admin.config.vo;
  2 +
  3 +import io.swagger.v3.oas.annotations.media.Schema;
  4 +import lombok.Data;
  5 +import lombok.EqualsAndHashCode;
  6 +import lombok.ToString;
  7 +
  8 +@Schema(description = "管理后台 - 交易中心配置 Response VO")
  9 +@Data
  10 +@EqualsAndHashCode(callSuper = true)
  11 +@ToString(callSuper = true)
  12 +public class TradeConfigRespVO extends TradeConfigBaseVO {
  13 +
  14 + @Schema(description = "自增主键", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
  15 + private Long id;
  16 +
  17 +}
... ...
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/config/vo/TradeConfigSaveReqVO.java 0 → 100644
  1 +package cn.iocoder.yudao.module.trade.controller.admin.config.vo;
  2 +
  3 +import io.swagger.v3.oas.annotations.media.Schema;
  4 +import lombok.Data;
  5 +import lombok.EqualsAndHashCode;
  6 +import lombok.ToString;
  7 +
  8 +@Schema(description = "管理后台 - 交易中心配置更新 Request VO")
  9 +@Data
  10 +@EqualsAndHashCode(callSuper = true)
  11 +@ToString(callSuper = true)
  12 +public class TradeConfigSaveReqVO extends TradeConfigBaseVO {
  13 +
  14 +}
... ...
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/brokerage/AppBrokerageRecordController.java 0 → 100644
  1 +package cn.iocoder.yudao.module.trade.controller.app.brokerage;
  2 +
  3 +import cn.iocoder.yudao.framework.common.pojo.CommonResult;
  4 +import cn.iocoder.yudao.framework.common.pojo.PageResult;
  5 +import cn.iocoder.yudao.framework.security.core.annotations.PreAuthenticated;
  6 +import cn.iocoder.yudao.module.trade.controller.app.brokerage.vo.record.AppBrokerageRecordPageReqVO;
  7 +import cn.iocoder.yudao.module.trade.controller.app.brokerage.vo.record.AppBrokerageRecordRespVO;
  8 +import io.swagger.v3.oas.annotations.Operation;
  9 +import io.swagger.v3.oas.annotations.tags.Tag;
  10 +import lombok.extern.slf4j.Slf4j;
  11 +import org.springframework.validation.annotation.Validated;
  12 +import org.springframework.web.bind.annotation.GetMapping;
  13 +import org.springframework.web.bind.annotation.RequestMapping;
  14 +import org.springframework.web.bind.annotation.RestController;
  15 +
  16 +import javax.validation.Valid;
  17 +import java.time.LocalDateTime;
  18 +
  19 +import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
  20 +import static java.util.Arrays.asList;
  21 +
  22 +@Tag(name = "用户 APP - 分销用户")
  23 +@RestController
  24 +@RequestMapping("/trade/brokerage-record")
  25 +@Validated
  26 +@Slf4j
  27 +public class AppBrokerageRecordController {
  28 +
  29 + // TODO 芋艿:临时 mock =>
  30 + @GetMapping("/page")
  31 + @Operation(summary = "获得分销记录分页")
  32 + @PreAuthenticated
  33 + public CommonResult<PageResult<AppBrokerageRecordRespVO>> getBrokerageRecordPage(@Valid AppBrokerageRecordPageReqVO pageReqVO) {
  34 + AppBrokerageRecordRespVO vo1 = new AppBrokerageRecordRespVO()
  35 + .setId(1L).setPrice(10).setTitle("收到钱").setCreateTime(LocalDateTime.now())
  36 + .setFinishTime(LocalDateTime.now());
  37 + AppBrokerageRecordRespVO vo2 = new AppBrokerageRecordRespVO()
  38 + .setId(2L).setPrice(-20).setTitle("提现钱").setCreateTime(LocalDateTime.now())
  39 + .setFinishTime(LocalDateTime.now());
  40 + return success(new PageResult<>(asList(vo1, vo2), 10L));
  41 + }
  42 +
  43 +}
... ...
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/brokerage/AppBrokerageUserController.java 0 → 100644
  1 +package cn.iocoder.yudao.module.trade.controller.app.brokerage;
  2 +
  3 +import cn.iocoder.yudao.framework.common.pojo.CommonResult;
  4 +import cn.iocoder.yudao.framework.common.pojo.PageResult;
  5 +import cn.iocoder.yudao.framework.security.core.annotations.PreAuthenticated;
  6 +import cn.iocoder.yudao.module.trade.controller.app.brokerage.vo.user.*;
  7 +import io.swagger.v3.oas.annotations.Operation;
  8 +import io.swagger.v3.oas.annotations.Parameter;
  9 +import io.swagger.v3.oas.annotations.tags.Tag;
  10 +import lombok.extern.slf4j.Slf4j;
  11 +import org.springframework.format.annotation.DateTimeFormat;
  12 +import org.springframework.validation.annotation.Validated;
  13 +import org.springframework.web.bind.annotation.GetMapping;
  14 +import org.springframework.web.bind.annotation.RequestMapping;
  15 +import org.springframework.web.bind.annotation.RequestParam;
  16 +import org.springframework.web.bind.annotation.RestController;
  17 +
  18 +import java.time.LocalDateTime;
  19 +
  20 +import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
  21 +import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND;
  22 +import static java.util.Arrays.asList;
  23 +
  24 +@Tag(name = "用户 APP - 分销用户")
  25 +@RestController
  26 +@RequestMapping("/trade/brokerage-user")
  27 +@Validated
  28 +@Slf4j
  29 +public class AppBrokerageUserController {
  30 +
  31 + // TODO 芋艿:临时 mock =>
  32 + @GetMapping("/get")
  33 + @Operation(summary = "获得个人分销信息")
  34 + @PreAuthenticated
  35 + public CommonResult<AppBrokerageUserRespVO> getBrokerageUser() {
  36 + AppBrokerageUserRespVO respVO = new AppBrokerageUserRespVO()
  37 + .setBrokeragePrice(2000)
  38 + .setFrozenBrokeragePrice(3000);
  39 + return success(respVO);
  40 + }
  41 +
  42 + // TODO 芋艿:临时 mock =>
  43 + @GetMapping("/get-summary")
  44 + @Operation(summary = "获得个人分销统计")
  45 + @PreAuthenticated
  46 + public CommonResult<AppBrokerageUserMySummaryRespVO> getBrokerageUserSummary() {
  47 + AppBrokerageUserMySummaryRespVO respVO = new AppBrokerageUserMySummaryRespVO()
  48 + .setYesterdayBrokeragePrice(1)
  49 + .setBrokeragePrice(2)
  50 + .setFrozenBrokeragePrice(3)
  51 + .setWithdrawBrokeragePrice(4)
  52 + .setFirstBrokerageUserCount(166)
  53 + .setSecondBrokerageUserCount(233);
  54 + return success(respVO);
  55 + }
  56 +
  57 + // TODO 芋艿:临时 mock =>
  58 + @GetMapping("/rank-page-by-user-count")
  59 + @Operation(summary = "获得分销用户排行分页(基于用户量)")
  60 + @PreAuthenticated
  61 + public CommonResult<PageResult<AppBrokerageUserRankByUserCountRespVO>> getBrokerageUserRankPageByUserCount(AppBrokerageUserRankPageReqVO pageReqVO) {
  62 + AppBrokerageUserRankByUserCountRespVO vo1 = new AppBrokerageUserRankByUserCountRespVO()
  63 + .setId(1L).setNickname("芋1**艿").setAvatar("http://www.iocoder.cn/images/common/wechat_mp_2017_07_31_bak.jpg")
  64 + .setBrokerageUserCount(10);
  65 + AppBrokerageUserRankByUserCountRespVO vo2 = new AppBrokerageUserRankByUserCountRespVO()
  66 + .setId(2L).setNickname("芋2**艿").setAvatar("http://www.iocoder.cn/images/common/wechat_mp_2017_07_31_bak.jpg")
  67 + .setBrokerageUserCount(6);
  68 + AppBrokerageUserRankByUserCountRespVO vo3 = new AppBrokerageUserRankByUserCountRespVO()
  69 + .setId(3L).setNickname("芋3**艿").setAvatar("http://www.iocoder.cn/images/common/wechat_mp_2017_07_31_bak.jpg")
  70 + .setBrokerageUserCount(4);
  71 + AppBrokerageUserRankByUserCountRespVO vo4 = new AppBrokerageUserRankByUserCountRespVO()
  72 + .setId(3L).setNickname("芋3**艿").setAvatar("http://www.iocoder.cn/images/common/wechat_mp_2017_07_31_bak.jpg")
  73 + .setBrokerageUserCount(4);
  74 + return success(new PageResult<>(asList(vo1, vo2, vo3, vo4), 10L));
  75 + }
  76 +
  77 + // TODO 芋艿:临时 mock =>
  78 + @GetMapping("/rank-page-by-price")
  79 + @Operation(summary = "获得分销用户排行分页(基于佣金)")
  80 + @PreAuthenticated
  81 + public CommonResult<PageResult<AppBrokerageUserRankByPriceRespVO>> getBrokerageUserChildSummaryPageByPrice(AppBrokerageUserRankPageReqVO pageReqVO) {
  82 + AppBrokerageUserRankByPriceRespVO vo1 = new AppBrokerageUserRankByPriceRespVO()
  83 + .setId(1L).setNickname("芋1**艿").setAvatar("http://www.iocoder.cn/images/common/wechat_mp_2017_07_31_bak.jpg")
  84 + .setBrokeragePrice(10);
  85 + AppBrokerageUserRankByPriceRespVO vo2 = new AppBrokerageUserRankByPriceRespVO()
  86 + .setId(2L).setNickname("芋2**艿").setAvatar("http://www.iocoder.cn/images/common/wechat_mp_2017_07_31_bak.jpg")
  87 + .setBrokeragePrice(6);
  88 + AppBrokerageUserRankByPriceRespVO vo3 = new AppBrokerageUserRankByPriceRespVO()
  89 + .setId(3L).setNickname("芋3**艿").setAvatar("http://www.iocoder.cn/images/common/wechat_mp_2017_07_31_bak.jpg")
  90 + .setBrokeragePrice(4);
  91 + AppBrokerageUserRankByPriceRespVO vo4 = new AppBrokerageUserRankByPriceRespVO()
  92 + .setId(3L).setNickname("芋3**艿").setAvatar("http://www.iocoder.cn/images/common/wechat_mp_2017_07_31_bak.jpg")
  93 + .setBrokeragePrice(4);
  94 + return success(new PageResult<>(asList(vo1, vo2, vo3, vo4), 10L));
  95 + }
  96 +
  97 + // TODO 芋艿:临时 mock =>
  98 + @GetMapping("/child-summary-page")
  99 + @Operation(summary = "获得下级分销统计分页")
  100 + @PreAuthenticated
  101 + public CommonResult<PageResult<AppBrokerageUserChildSummaryRespVO>> getBrokerageUserChildSummaryPage(
  102 + AppBrokerageUserChildSummaryPageReqVO pageReqVO) {
  103 + AppBrokerageUserChildSummaryRespVO vo1 = new AppBrokerageUserChildSummaryRespVO()
  104 + .setId(1L).setNickname("芋1**艿").setAvatar("http://www.iocoder.cn/images/common/wechat_mp_2017_07_31_bak.jpg")
  105 + .setBrokeragePrice(10).setBrokeragePrice(20).setBrokerageOrderCount(30)
  106 + .setBrokerageTime(LocalDateTime.now());
  107 + AppBrokerageUserChildSummaryRespVO vo2 = new AppBrokerageUserChildSummaryRespVO()
  108 + .setId(1L).setNickname("芋2**艿").setAvatar("http://www.iocoder.cn/images/common/wechat_mp_2017_07_31_bak.jpg")
  109 + .setBrokeragePrice(20).setBrokeragePrice(30).setBrokerageOrderCount(40)
  110 + .setBrokerageTime(LocalDateTime.now());
  111 + return success(new PageResult<>(asList(vo1, vo2), 10L));
  112 + }
  113 +
  114 + // TODO 芋艿:临时 mock =>
  115 + @GetMapping("/get-rank-by-price")
  116 + @Operation(summary = "获得分销用户排行(基于佣金)")
  117 + @Parameter(name = "times", description = "时间段", required = true)
  118 + public CommonResult<Integer> getBrokerageUserRankByPrice(
  119 + @RequestParam("times") @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) LocalDateTime[] times) {
  120 + return success(1);
  121 + }
  122 +
  123 +}
... ...
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/brokerage/AppBrokerageWithdrawController.java 0 → 100644
  1 +package cn.iocoder.yudao.module.trade.controller.app.brokerage;
  2 +
  3 +import cn.iocoder.yudao.framework.common.pojo.CommonResult;
  4 +import cn.iocoder.yudao.framework.common.pojo.PageResult;
  5 +import cn.iocoder.yudao.framework.security.core.annotations.PreAuthenticated;
  6 +import cn.iocoder.yudao.module.trade.controller.app.brokerage.vo.withdraw.AppBrokerageWithdrawCreateReqVO;
  7 +import cn.iocoder.yudao.module.trade.controller.app.brokerage.vo.withdraw.AppBrokerageWithdrawRespVO;
  8 +import io.swagger.v3.oas.annotations.Operation;
  9 +import io.swagger.v3.oas.annotations.tags.Tag;
  10 +import lombok.extern.slf4j.Slf4j;
  11 +import org.springframework.validation.annotation.Validated;
  12 +import org.springframework.web.bind.annotation.*;
  13 +
  14 +import javax.validation.Valid;
  15 +import java.time.LocalDateTime;
  16 +
  17 +import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
  18 +import static java.util.Arrays.asList;
  19 +
  20 +@Tag(name = "用户 APP - 分销提现")
  21 +@RestController
  22 +@RequestMapping("/trade/brokerage-withdraw")
  23 +@Validated
  24 +@Slf4j
  25 +public class AppBrokerageWithdrawController {
  26 +
  27 + // TODO 芋艿:临时 mock =>
  28 + @GetMapping("/page")
  29 + @Operation(summary = "获得分销提现分页")
  30 + @PreAuthenticated
  31 + public CommonResult<PageResult<AppBrokerageWithdrawRespVO>> getBrokerageWithdrawPage() {
  32 + AppBrokerageWithdrawRespVO vo1 = new AppBrokerageWithdrawRespVO()
  33 + .setId(1L).setStatus(10).setPrice(10).setStatusName("审批通过").setCreateTime(LocalDateTime.now());
  34 + AppBrokerageWithdrawRespVO vo2 = new AppBrokerageWithdrawRespVO()
  35 + .setId(2L).setStatus(0).setPrice(20).setStatusName("审批中").setCreateTime(LocalDateTime.now());
  36 + return success(new PageResult<>(asList(vo1, vo2), 10L));
  37 + }
  38 +
  39 + // TODO 芋艿:临时 mock =>
  40 + @PostMapping("/create")
  41 + @Operation(summary = "创建分销提现")
  42 + @PreAuthenticated
  43 + public CommonResult<Long> createBrokerageWithdraw(@RequestBody @Valid AppBrokerageWithdrawCreateReqVO createReqVO) {
  44 + return success(1L);
  45 + }
  46 +
  47 +}
... ...
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/brokerage/vo/record/AppBrokerageRecordPageReqVO.java 0 → 100644
  1 +package cn.iocoder.yudao.module.trade.controller.app.brokerage.vo.record;
  2 +
  3 +import cn.iocoder.yudao.framework.common.pojo.PageParam;
  4 +import io.swagger.v3.oas.annotations.media.Schema;
  5 +import lombok.Data;
  6 +
  7 +@Schema(description = "应用 App - 分销记录分页 Request VO")
  8 +@Data
  9 +public class AppBrokerageRecordPageReqVO extends PageParam {
  10 +
  11 + // TODO @疯狂:要加下枚举校验
  12 +
  13 + @Schema(description = "业务类型", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
  14 + private Integer bizType;
  15 +
  16 + @Schema(description = "状态", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
  17 + private Integer status;
  18 +
  19 +}
... ...
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/brokerage/vo/record/AppBrokerageRecordRespVO.java 0 → 100644
  1 +package cn.iocoder.yudao.module.trade.controller.app.brokerage.vo.record;
  2 +
  3 +import io.swagger.v3.oas.annotations.media.Schema;
  4 +import lombok.Data;
  5 +
  6 +import java.time.LocalDateTime;
  7 +
  8 +@Schema(description = "用户 App - 分销记录 Response VO")
  9 +@Data
  10 +public class AppBrokerageRecordRespVO {
  11 +
  12 + @Schema(description = "记录编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "10")
  13 + private Long id;
  14 +
  15 + @Schema(description = "分销标题", requiredMode = Schema.RequiredMode.REQUIRED, example = "用户下单")
  16 + private String title;
  17 +
  18 + @Schema(description = "分销金额,单位:分", requiredMode = Schema.RequiredMode.REQUIRED, example = "1000")
  19 + private Integer price;
  20 +
  21 + @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED)
  22 + private LocalDateTime createTime;
  23 +
  24 + @Schema(description = "完成时间", requiredMode = Schema.RequiredMode.REQUIRED)
  25 + private LocalDateTime finishTime;
  26 +
  27 +}
... ...
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/brokerage/vo/user/AppBrokerageUserChildSummaryPageReqVO.java 0 → 100644
  1 +package cn.iocoder.yudao.module.trade.controller.app.brokerage.vo.user;
  2 +
  3 +import cn.iocoder.yudao.framework.common.pojo.PageParam;
  4 +import cn.iocoder.yudao.framework.common.pojo.SortingField;
  5 +import io.swagger.v3.oas.annotations.media.Schema;
  6 +import lombok.Data;
  7 +
  8 +@Schema(description = "用户 App - 下级分销统计分页 Request VO")
  9 +@Data
  10 +public class AppBrokerageUserChildSummaryPageReqVO extends PageParam {
  11 +
  12 + public static final String SORT_FIELD_USER_COUNT = "userCount";
  13 + public static final String SORT_FIELD_ORDER_COUNT = "orderCount";
  14 + public static final String SORT_FIELD_PRICE = "price";
  15 +
  16 + @Schema(description = "用户昵称", example = "李") // 模糊匹配
  17 + private String nickname;
  18 +
  19 + @Schema(description = "排序字段", example = "userCount")
  20 + private SortingField sortingField;
  21 +
  22 + @Schema(description = "下级的级别", example = "1") // 1 - 直接下级;2 - 间接下级
  23 + private Integer level;
  24 +
  25 +}
... ...
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/brokerage/vo/user/AppBrokerageUserChildSummaryRespVO.java 0 → 100644
  1 +package cn.iocoder.yudao.module.trade.controller.app.brokerage.vo.user;
  2 +
  3 +import io.swagger.v3.oas.annotations.media.Schema;
  4 +import lombok.Data;
  5 +
  6 +import java.time.LocalDateTime;
  7 +
  8 +@Schema(description = "用户 App - 下级分销统计 Response VO")
  9 +@Data
  10 +public class AppBrokerageUserChildSummaryRespVO {
  11 +
  12 + @Schema(description = "用户编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "10")
  13 + private Long id;
  14 +
  15 + @Schema(description = "用户昵称", requiredMode = Schema.RequiredMode.REQUIRED, example = "小王")
  16 + private String nickname;
  17 +
  18 + @Schema(description = "用户头像", requiredMode = Schema.RequiredMode.REQUIRED, example = "https://www.iocoder.cn/xxx.jpg")
  19 + private String avatar;
  20 +
  21 + @Schema(description = "佣金金额,单位:分", requiredMode = Schema.RequiredMode.REQUIRED, example = "10")
  22 + private Integer brokeragePrice;
  23 +
  24 + @Schema(description = "分销订单数量", requiredMode = Schema.RequiredMode.REQUIRED, example = "20")
  25 + private Integer brokerageOrderCount;
  26 +
  27 + @Schema(description = "分销用户数量", requiredMode = Schema.RequiredMode.REQUIRED, example = "30")
  28 + private Integer brokerageUserCount;
  29 +
  30 + @Schema(description = "成为分销员时间", requiredMode = Schema.RequiredMode.REQUIRED)
  31 + private LocalDateTime brokerageTime;
  32 +
  33 +}
... ...
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/brokerage/vo/user/AppBrokerageUserMySummaryRespVO.java 0 → 100644
  1 +package cn.iocoder.yudao.module.trade.controller.app.brokerage.vo.user;
  2 +
  3 +import io.swagger.v3.oas.annotations.media.Schema;
  4 +import lombok.Data;
  5 +
  6 +@Schema(description = "用户 App - 个人分销统计 Response VO")
  7 +@Data
  8 +public class AppBrokerageUserMySummaryRespVO {
  9 +
  10 + @Schema(description = "昨天的佣金,单位:分", requiredMode = Schema.RequiredMode.REQUIRED, example = "10")
  11 + private Integer yesterdayBrokeragePrice;
  12 +
  13 + @Schema(description = "提现的佣金,单位:分", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
  14 + private Integer withdrawBrokeragePrice;
  15 +
  16 + @Schema(description = "可用的佣金,单位:分", requiredMode = Schema.RequiredMode.REQUIRED, example = "2408")
  17 + private Integer brokeragePrice;
  18 +
  19 + @Schema(description = "冻结的佣金,单位:分", requiredMode = Schema.RequiredMode.REQUIRED, example = "234")
  20 + private Integer frozenBrokeragePrice;
  21 +
  22 + @Schema(description = "分销用户数量(一级)", requiredMode = Schema.RequiredMode.REQUIRED, example = "10")
  23 + private Integer firstBrokerageUserCount;
  24 +
  25 + @Schema(description = "分销用户数量(二级)", requiredMode = Schema.RequiredMode.REQUIRED, example = "10")
  26 + private Integer secondBrokerageUserCount;
  27 +
  28 +}
... ...
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/brokerage/vo/user/AppBrokerageUserRankByPriceRespVO.java 0 → 100644
  1 +package cn.iocoder.yudao.module.trade.controller.app.brokerage.vo.user;
  2 +
  3 +import io.swagger.v3.oas.annotations.media.Schema;
  4 +import lombok.Data;
  5 +
  6 +@Schema(description = "用户 App - 分销排行用户(基于用户量) Response VO")
  7 +@Data
  8 +public class AppBrokerageUserRankByPriceRespVO {
  9 +
  10 + @Schema(description = "用户编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "10")
  11 + private Long id;
  12 +
  13 + @Schema(description = "用户昵称", requiredMode = Schema.RequiredMode.REQUIRED, example = "小王")
  14 + private String nickname;
  15 +
  16 + @Schema(description = "用户头像", requiredMode = Schema.RequiredMode.REQUIRED, example = "https://www.iocoder.cn/xxx.jpg")
  17 + private String avatar;
  18 +
  19 + @Schema(description = "佣金金额", requiredMode = Schema.RequiredMode.REQUIRED, example = "10")
  20 + private Integer brokeragePrice;
  21 +
  22 +}
... ...
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/brokerage/vo/user/AppBrokerageUserRankByUserCountRespVO.java 0 → 100644
  1 +package cn.iocoder.yudao.module.trade.controller.app.brokerage.vo.user;
  2 +
  3 +import io.swagger.v3.oas.annotations.media.Schema;
  4 +import lombok.Data;
  5 +
  6 +@Schema(description = "用户 App - 分销排行用户(基于用户量) Response VO")
  7 +@Data
  8 +public class AppBrokerageUserRankByUserCountRespVO {
  9 +
  10 + @Schema(description = "用户编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "10")
  11 + private Long id;
  12 +
  13 + @Schema(description = "用户昵称", requiredMode = Schema.RequiredMode.REQUIRED, example = "小王")
  14 + private String nickname;
  15 +
  16 + @Schema(description = "用户头像", requiredMode = Schema.RequiredMode.REQUIRED, example = "https://www.iocoder.cn/xxx.jpg")
  17 + private String avatar;
  18 +
  19 + @Schema(description = "邀请用户数量", requiredMode = Schema.RequiredMode.REQUIRED, example = "10")
  20 + private Integer brokerageUserCount;
  21 +
  22 +}
... ...
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/brokerage/vo/user/AppBrokerageUserRankPageReqVO.java 0 → 100644
  1 +package cn.iocoder.yudao.module.trade.controller.app.brokerage.vo.user;
  2 +
  3 +import cn.iocoder.yudao.framework.common.pojo.PageParam;
  4 +import io.swagger.v3.oas.annotations.media.Schema;
  5 +import lombok.Data;
  6 +import org.springframework.format.annotation.DateTimeFormat;
  7 +
  8 +import javax.validation.constraints.NotEmpty;
  9 +import java.time.LocalDateTime;
  10 +
  11 +import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND;
  12 +
  13 +@Schema(description = "应用 App - 分销用户排行 Request VO")
  14 +@Data
  15 +public class AppBrokerageUserRankPageReqVO extends PageParam {
  16 +
  17 + @Schema(description = "开始 + 结束时间", requiredMode = Schema.RequiredMode.REQUIRED)
  18 + @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
  19 + @NotEmpty(message = "时间不能为空")
  20 + private LocalDateTime[] times;
  21 +
  22 +}
... ...
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/brokerage/vo/user/AppBrokerageUserRespVO.java 0 → 100644
  1 +package cn.iocoder.yudao.module.trade.controller.app.brokerage.vo.user;
  2 +
  3 +import io.swagger.v3.oas.annotations.media.Schema;
  4 +import lombok.Data;
  5 +
  6 +@Schema(description = "用户 App - 分销用户信息 Response VO")
  7 +@Data
  8 +public class AppBrokerageUserRespVO {
  9 +
  10 + @Schema(description = "可用的佣金,单位:分", requiredMode = Schema.RequiredMode.REQUIRED, example = "2408")
  11 + private Integer brokeragePrice;
  12 +
  13 + @Schema(description = "冻结的佣金,单位:分", requiredMode = Schema.RequiredMode.REQUIRED, example = "234")
  14 + private Integer frozenBrokeragePrice;
  15 +
  16 +}
... ...
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/brokerage/vo/withdraw/AppBrokerageWithdrawCreateReqVO.java 0 → 100644
  1 +package cn.iocoder.yudao.module.trade.controller.app.brokerage.vo.withdraw;
  2 +
  3 +import io.swagger.v3.oas.annotations.media.Schema;
  4 +import lombok.Data;
  5 +import org.hibernate.validator.constraints.URL;
  6 +
  7 +import javax.validation.constraints.Min;
  8 +
  9 +@Schema(description = "用户 App - 分销提现创建 Request VO")
  10 +@Data
  11 +public class AppBrokerageWithdrawCreateReqVO {
  12 +
  13 + // TODO @疯狂:参数校验逻辑,需要根据 type 进行不同的校验;感觉可以通过分组?
  14 +
  15 + @Schema(description = "提现方式", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
  16 + private Integer type;
  17 +
  18 + @Schema(description = "提现账号", requiredMode = Schema.RequiredMode.REQUIRED, example = "123456789") // 银行卡号/微信账号/支付宝账号
  19 + private String accountNo;
  20 +
  21 + @Schema(description = "收款码的图片", example = "https://www.iocoder.cn/1.png")
  22 + @URL(message = "收款码的图片,必须是一个 URL")
  23 + private String accountQrCodeUrl;
  24 +
  25 + @Schema(description = "提现金额,单位:分", requiredMode = Schema.RequiredMode.REQUIRED, example = "1000")
  26 + @Min(value = 1, message = "提现金额必须大于 1")
  27 + private Integer price;
  28 +
  29 +}
... ...
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/brokerage/vo/withdraw/AppBrokerageWithdrawRespVO.java 0 → 100644
  1 +package cn.iocoder.yudao.module.trade.controller.app.brokerage.vo.withdraw;
  2 +
  3 +import io.swagger.v3.oas.annotations.media.Schema;
  4 +import lombok.Data;
  5 +
  6 +import java.time.LocalDateTime;
  7 +
  8 +@Schema(description = "用户 App - 分销提现 Response VO")
  9 +@Data
  10 +public class AppBrokerageWithdrawRespVO {
  11 +
  12 + @Schema(description = "提现编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "10")
  13 + private Long id;
  14 +
  15 + @Schema(description = "提现状态", requiredMode = Schema.RequiredMode.REQUIRED, example = "10")
  16 + private Integer status;
  17 +
  18 + @Schema(description = "提现状态名", requiredMode = Schema.RequiredMode.REQUIRED, example = "审核中")
  19 + private String statusName;
  20 +
  21 + @Schema(description = "提现金额,单位:分", requiredMode = Schema.RequiredMode.REQUIRED, example = "1000")
  22 + private Integer price;
  23 +
  24 + @Schema(description = "提现时间", requiredMode = Schema.RequiredMode.REQUIRED)
  25 + private LocalDateTime createTime;
  26 +
  27 +}
... ...
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/config/AppTradeConfigController.java 0 → 100644
  1 +package cn.iocoder.yudao.module.trade.controller.app.config;
  2 +
  3 +import cn.iocoder.yudao.framework.common.pojo.CommonResult;
  4 +import cn.iocoder.yudao.module.trade.controller.app.config.vo.AppTradeConfigRespVO;
  5 +import io.swagger.v3.oas.annotations.tags.Tag;
  6 +import lombok.RequiredArgsConstructor;
  7 +import lombok.extern.slf4j.Slf4j;
  8 +import org.springframework.validation.annotation.Validated;
  9 +import org.springframework.web.bind.annotation.GetMapping;
  10 +import org.springframework.web.bind.annotation.RequestMapping;
  11 +import org.springframework.web.bind.annotation.RestController;
  12 +
  13 +import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
  14 +import static java.util.Arrays.asList;
  15 +
  16 +@Tag(name = "用户 App - 交易配置")
  17 +@RestController
  18 +@RequestMapping("/trade/config")
  19 +@RequiredArgsConstructor
  20 +@Validated
  21 +@Slf4j
  22 +public class AppTradeConfigController {
  23 +
  24 + @GetMapping("/get")
  25 + public CommonResult<AppTradeConfigRespVO> getTradeConfig() {
  26 + AppTradeConfigRespVO respVO = new AppTradeConfigRespVO();
  27 + respVO.setBrokeragePosterUrls(asList(
  28 + "https://api.java.crmeb.net/crmebimage/product/2020/08/03/755bf516b1ca4b6db3bfeaa4dd5901cdh71kob20re.jpg",
  29 + "https://api.java.crmeb.net/crmebimage/maintain/2021/03/01/406d729b84ed4ec9a2171bfcf6fd0634ughzbz9kfi.jpg",
  30 + "https://api.java.crmeb.net/crmebimage/maintain/2021/03/01/efb1e4e7fe604fe1988b4213ce08cb11tdsyijtd2r.jpg"
  31 + ));
  32 + respVO.setBrokerageFrozenDays(10);
  33 + respVO.setBrokerageWithdrawMinPrice(100);
  34 + return success(respVO);
  35 + }
  36 +
  37 +}
... ...
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/config/vo/AppTradeConfigRespVO.java 0 → 100644
  1 +package cn.iocoder.yudao.module.trade.controller.app.config.vo;
  2 +
  3 +import io.swagger.v3.oas.annotations.media.Schema;
  4 +import lombok.Data;
  5 +
  6 +import java.util.List;
  7 +
  8 +@Schema(description = "用户 App - 交易配置 Response VO")
  9 +@Data
  10 +public class AppTradeConfigRespVO {
  11 +
  12 + @Schema(description = "分销海报地址数组", requiredMode = Schema.RequiredMode.REQUIRED)
  13 + private List<String> brokeragePosterUrls;
  14 +
  15 + @Schema(description = "佣金冻结时间(天)", requiredMode = Schema.RequiredMode.REQUIRED, example = "10")
  16 + private Integer brokerageFrozenDays;
  17 +
  18 + @Schema(description = "佣金提现最小金额,单位:分", requiredMode = Schema.RequiredMode.REQUIRED, example = "100")
  19 + private Integer brokerageWithdrawMinPrice;
  20 +
  21 +}
... ...
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/delivery/vo/config/AppDeliveryConfigRespVO.java
... ... @@ -3,7 +3,7 @@ package cn.iocoder.yudao.module.trade.controller.app.delivery.vo.config;
3 3 import io.swagger.v3.oas.annotations.media.Schema;
4 4 import lombok.Data;
5 5  
6   -// TODO 芋艿:后续要实现下,配送配置
  6 +// TODO 芋艿:后续要实现下,配送配置;后续融合到 AppTradeConfigRespVO 中
7 7 @Schema(description = "用户 App - 配送配置 Response VO")
8 8 @Data
9 9 public class AppDeliveryConfigRespVO {
... ...
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/order/vo/AppTradeOrderDetailRespVO.java
... ... @@ -21,7 +21,7 @@ public class AppTradeOrderDetailRespVO {
21 21 private String no;
22 22  
23 23 @Schema(description = "下单时间", requiredMode = Schema.RequiredMode.REQUIRED)
24   - private Date createTime;
  24 + private LocalDateTime createTime;
25 25  
26 26 @Schema(description = "用户备注", requiredMode = Schema.RequiredMode.REQUIRED, example = "你猜")
27 27 private String userRemark;
... ...
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/order/vo/AppTradeOrderPageItemRespVO.java
... ... @@ -4,7 +4,7 @@ import cn.iocoder.yudao.module.trade.controller.app.order.vo.item.AppTradeOrderI
4 4 import io.swagger.v3.oas.annotations.media.Schema;
5 5 import lombok.Data;
6 6  
7   -import java.util.Date;
  7 +import java.time.LocalDateTime;
8 8 import java.util.List;
9 9  
10 10 @Schema(description = "用户 App - 订单交易的分页项 Response VO")
... ... @@ -30,7 +30,7 @@ public class AppTradeOrderPageItemRespVO {
30 30 private Boolean commentStatus;
31 31  
32 32 @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED)
33   - private Date createTime;
  33 + private LocalDateTime createTime;
34 34  
35 35 // ========== 价格 + 支付基本信息 ==========
36 36  
... ...
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/convert/brokerage/record/TradeBrokerageRecordConvert.java 0 → 100644
  1 +package cn.iocoder.yudao.module.trade.convert.brokerage.record;
  2 +
  3 +import cn.hutool.core.util.StrUtil;
  4 +import cn.iocoder.yudao.framework.common.pojo.PageResult;
  5 +import cn.iocoder.yudao.module.trade.controller.admin.brokerage.record.vo.TradeBrokerageRecordRespVO;
  6 +import cn.iocoder.yudao.module.trade.dal.dataobject.brokerage.record.TradeBrokerageRecordDO;
  7 +import cn.iocoder.yudao.module.trade.dal.dataobject.brokerage.user.TradeBrokerageUserDO;
  8 +import cn.iocoder.yudao.module.trade.enums.brokerage.BrokerageRecordBizTypeEnum;
  9 +import cn.iocoder.yudao.module.trade.enums.brokerage.BrokerageRecordStatusEnum;
  10 +import org.mapstruct.Mapper;
  11 +import org.mapstruct.factory.Mappers;
  12 +
  13 +import java.time.LocalDateTime;
  14 +import java.util.List;
  15 +
  16 +/**
  17 + * 佣金记录 Convert
  18 + *
  19 + * @author owen
  20 + */
  21 +@Mapper
  22 +public interface TradeBrokerageRecordConvert {
  23 +
  24 + TradeBrokerageRecordConvert INSTANCE = Mappers.getMapper(TradeBrokerageRecordConvert.class);
  25 +
  26 + TradeBrokerageRecordRespVO convert(TradeBrokerageRecordDO bean);
  27 +
  28 + List<TradeBrokerageRecordRespVO> convertList(List<TradeBrokerageRecordDO> list);
  29 +
  30 + PageResult<TradeBrokerageRecordRespVO> convertPage(PageResult<TradeBrokerageRecordDO> page);
  31 +
  32 + default TradeBrokerageRecordDO convert(TradeBrokerageUserDO user, String bizId, int brokerageFrozenDays, int brokerage, LocalDateTime unfreezeTime) {
  33 + // 不冻结时,佣金直接就是结算状态
  34 + Integer status = brokerageFrozenDays > 0
  35 + ? BrokerageRecordStatusEnum.WAIT_SETTLEMENT.getStatus()
  36 + : BrokerageRecordStatusEnum.SETTLEMENT.getStatus();
  37 + return new TradeBrokerageRecordDO()
  38 + .setUserId(user.getId())
  39 + .setBizType(BrokerageRecordBizTypeEnum.ORDER.getType())
  40 + .setBizId(bizId)
  41 + .setPrice(brokerage)
  42 + .setTotalPrice(user.getBrokeragePrice())
  43 + .setTitle(BrokerageRecordBizTypeEnum.ORDER.getTitle()) // TODO @疯狂:可能 title 不是很固化,会存在类似:沐晴成功购买《XXX JVM 实战》
  44 + .setDescription(StrUtil.format(BrokerageRecordBizTypeEnum.ORDER.getDescription(), String.valueOf(brokerage / 100.0)))
  45 + .setStatus(status)
  46 + .setFrozenDays(brokerageFrozenDays)
  47 + .setUnfreezeTime(unfreezeTime);
  48 + }
  49 +
  50 +}
... ...
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/convert/brokerage/user/TradeBrokerageUserConvert.java 0 → 100644
  1 +package cn.iocoder.yudao.module.trade.convert.brokerage.user;
  2 +
  3 +import cn.iocoder.yudao.framework.common.pojo.PageResult;
  4 +import cn.iocoder.yudao.module.trade.controller.admin.brokerage.user.vo.TradeBrokerageUserRespVO;
  5 +import cn.iocoder.yudao.module.trade.dal.dataobject.brokerage.user.TradeBrokerageUserDO;
  6 +import org.mapstruct.Mapper;
  7 +import org.mapstruct.factory.Mappers;
  8 +
  9 +import java.util.List;
  10 +
  11 +/**
  12 + * 分销用户 Convert
  13 + *
  14 + * @author owen
  15 + */
  16 +@Mapper
  17 +public interface TradeBrokerageUserConvert {
  18 +
  19 + TradeBrokerageUserConvert INSTANCE = Mappers.getMapper(TradeBrokerageUserConvert.class);
  20 +
  21 + TradeBrokerageUserRespVO convert(TradeBrokerageUserDO bean);
  22 +
  23 + List<TradeBrokerageUserRespVO> convertList(List<TradeBrokerageUserDO> list);
  24 +
  25 + PageResult<TradeBrokerageUserRespVO> convertPage(PageResult<TradeBrokerageUserDO> page);
  26 +
  27 +}
... ...
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/convert/config/TradeConfigConvert.java 0 → 100644
  1 +package cn.iocoder.yudao.module.trade.convert.config;
  2 +
  3 +import cn.iocoder.yudao.module.trade.controller.admin.config.vo.TradeConfigRespVO;
  4 +import cn.iocoder.yudao.module.trade.controller.admin.config.vo.TradeConfigSaveReqVO;
  5 +import cn.iocoder.yudao.module.trade.dal.dataobject.config.TradeConfigDO;
  6 +import org.mapstruct.Mapper;
  7 +import org.mapstruct.factory.Mappers;
  8 +
  9 +/**
  10 + * 交易中心配置 Convert
  11 + *
  12 + * @author owen
  13 + */
  14 +@Mapper
  15 +public interface TradeConfigConvert {
  16 +
  17 + TradeConfigConvert INSTANCE = Mappers.getMapper(TradeConfigConvert.class);
  18 +
  19 + TradeConfigDO convert(TradeConfigSaveReqVO bean);
  20 +
  21 + TradeConfigRespVO convert(TradeConfigDO bean);
  22 +
  23 +}
... ...
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/convert/order/TradeOrderConvert.java
... ... @@ -7,11 +7,13 @@ import cn.iocoder.yudao.framework.common.util.string.StrUtils;
7 7 import cn.iocoder.yudao.framework.dict.core.util.DictFrameworkUtils;
8 8 import cn.iocoder.yudao.framework.ip.core.utils.AreaUtils;
9 9 import cn.iocoder.yudao.module.member.api.address.dto.AddressRespDTO;
  10 +import cn.iocoder.yudao.module.trade.service.brokerage.record.bo.BrokerageAddReqBO;
10 11 import cn.iocoder.yudao.module.member.api.user.dto.MemberUserRespDTO;
11 12 import cn.iocoder.yudao.module.pay.api.order.dto.PayOrderCreateReqDTO;
12 13 import cn.iocoder.yudao.module.pay.enums.DictTypeConstants;
13 14 import cn.iocoder.yudao.module.product.api.comment.dto.ProductCommentCreateReqDTO;
14 15 import cn.iocoder.yudao.module.product.api.property.dto.ProductPropertyValueDetailRespDTO;
  16 +import cn.iocoder.yudao.module.product.api.sku.dto.ProductSkuRespDTO;
15 17 import cn.iocoder.yudao.module.product.api.sku.dto.ProductSkuUpdateStockReqDTO;
16 18 import cn.iocoder.yudao.module.promotion.api.combination.dto.CombinationRecordCreateReqDTO;
17 19 import cn.iocoder.yudao.module.trade.api.order.dto.TradeOrderRespDTO;
... ... @@ -275,4 +277,10 @@ public interface TradeOrderConvert {
275 277  
276 278 TradeOrderDO convert(TradeOrderRemarkReqVO reqVO);
277 279  
  280 + default BrokerageAddReqBO convert(TradeOrderItemDO item, ProductSkuRespDTO sku) {
  281 + return new BrokerageAddReqBO().setBizId(String.valueOf(item.getId()))
  282 + .setPayPrice(item.getPayPrice()).setCount(item.getCount())
  283 + .setSkuFirstBrokeragePrice(sku.getSubCommissionFirstPrice())
  284 + .setSkuSecondBrokeragePrice(sku.getSubCommissionSecondPrice());
  285 + }
278 286 }
... ...
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/dal/dataobject/brokerage/record/TradeBrokerageRecordDO.java 0 → 100644
  1 +package cn.iocoder.yudao.module.trade.dal.dataobject.brokerage.record;
  2 +
  3 +import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
  4 +import cn.iocoder.yudao.module.trade.enums.brokerage.BrokerageRecordBizTypeEnum;
  5 +import cn.iocoder.yudao.module.trade.enums.brokerage.BrokerageRecordStatusEnum;
  6 +import com.baomidou.mybatisplus.annotation.KeySequence;
  7 +import com.baomidou.mybatisplus.annotation.TableId;
  8 +import com.baomidou.mybatisplus.annotation.TableName;
  9 +import lombok.*;
  10 +
  11 +import java.time.LocalDateTime;
  12 +
  13 +/**
  14 + * 佣金记录 DO
  15 + *
  16 + * @author owen
  17 + */
  18 +@TableName("trade_brokerage_record")
  19 +@KeySequence("trade_brokerage_record_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。
  20 +@Data
  21 +@EqualsAndHashCode(callSuper = true)
  22 +@ToString(callSuper = true)
  23 +@Builder
  24 +@NoArgsConstructor
  25 +@AllArgsConstructor
  26 +public class TradeBrokerageRecordDO extends BaseDO {
  27 +
  28 + /**
  29 + * 编号
  30 + */
  31 + @TableId
  32 + private Integer id;
  33 + /**
  34 + * 用户编号
  35 + */
  36 + private Long userId;
  37 + /**
  38 + * 业务编号
  39 + */
  40 + private String bizId;
  41 + /**
  42 + * 业务类型
  43 + * <p>
  44 + * 枚举 {@link BrokerageRecordBizTypeEnum}
  45 + */
  46 + private Integer bizType;
  47 +
  48 + /**
  49 + * 标题
  50 + */
  51 + private String title;
  52 + /**
  53 + * 说明
  54 + */
  55 + private String description;
  56 +
  57 + /**
  58 + * 金额
  59 + */
  60 + private Integer price;
  61 + /**
  62 + * 当前总佣金
  63 + */
  64 + private Integer totalPrice;
  65 +
  66 + /**
  67 + * 状态
  68 + * <p>
  69 + * 枚举 {@link BrokerageRecordStatusEnum}
  70 + */
  71 + private Integer status;
  72 +
  73 + /**
  74 + * 冻结时间(天)
  75 + */
  76 + private Integer frozenDays;
  77 + /**
  78 + * 解冻时间
  79 + */
  80 + private LocalDateTime unfreezeTime;
  81 +
  82 +}
... ...
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/dal/dataobject/brokerage/user/TradeBrokerageUserDO.java 0 → 100644
  1 +package cn.iocoder.yudao.module.trade.dal.dataobject.brokerage.user;
  2 +
  3 +import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
  4 +import com.baomidou.mybatisplus.annotation.KeySequence;
  5 +import com.baomidou.mybatisplus.annotation.TableId;
  6 +import com.baomidou.mybatisplus.annotation.TableName;
  7 +import lombok.*;
  8 +
  9 +import java.time.LocalDateTime;
  10 +
  11 +// TODO @疯狂:因为独立了表,是不是可以把字段的 brokerage 去掉了哈?
  12 +/**
  13 + * 分销用户 DO
  14 + *
  15 + * @author owen
  16 + */
  17 +@TableName("trade_brokerage_user")
  18 +@KeySequence("trade_brokerage_user_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。
  19 +@Data
  20 +@EqualsAndHashCode(callSuper = true)
  21 +@ToString(callSuper = true)
  22 +@Builder
  23 +@NoArgsConstructor
  24 +@AllArgsConstructor
  25 +public class TradeBrokerageUserDO extends BaseDO {
  26 +
  27 + /**
  28 + * 用户编号
  29 + */
  30 + @TableId
  31 + private Long id;
  32 +
  33 + // TODO @疯狂:貌似改成 bindUserId,更明确?
  34 + /**
  35 + * 推广员编号
  36 + *
  37 + * 关联 MemberUserDO 的 id 字段
  38 + */
  39 + private Long brokerageUserId;
  40 + /**
  41 + * 推广员绑定时间
  42 + */
  43 + private LocalDateTime brokerageBindTime;
  44 +
  45 + /**
  46 + * 推广资格
  47 + */
  48 + private Boolean brokerageEnabled;
  49 + /**
  50 + * 成为分销员时间
  51 + */
  52 + private LocalDateTime brokerageTime;
  53 +
  54 + /**
  55 + * 可用佣金
  56 + */
  57 + private Integer brokeragePrice;
  58 + /**
  59 + * 冻结佣金
  60 + */
  61 + private Integer frozenBrokeragePrice;
  62 +
  63 +}
... ...
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/dal/dataobject/config/TradeConfigDO.java 0 → 100644
  1 +package cn.iocoder.yudao.module.trade.dal.dataobject.config;
  2 +
  3 +import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
  4 +import cn.iocoder.yudao.framework.mybatis.core.type.IntegerListTypeHandler;
  5 +import cn.iocoder.yudao.module.trade.enums.brokerage.BrokerageBindModeEnum;
  6 +import cn.iocoder.yudao.module.trade.enums.brokerage.BrokerageEnabledConditionEnum;
  7 +import cn.iocoder.yudao.module.trade.enums.brokerage.BrokerageWithdrawTypeEnum;
  8 +import com.baomidou.mybatisplus.annotation.KeySequence;
  9 +import com.baomidou.mybatisplus.annotation.TableField;
  10 +import com.baomidou.mybatisplus.annotation.TableId;
  11 +import com.baomidou.mybatisplus.annotation.TableName;
  12 +import com.baomidou.mybatisplus.extension.handlers.JacksonTypeHandler;
  13 +import lombok.*;
  14 +
  15 +import java.util.List;
  16 +
  17 +/**
  18 + * 交易中心配置 DO
  19 + *
  20 + * @author owen
  21 + */
  22 +@TableName(value = "trade_config", autoResultMap = true)
  23 +@KeySequence("trade_config_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。
  24 +@Data
  25 +@EqualsAndHashCode(callSuper = true)
  26 +@ToString(callSuper = true)
  27 +@Builder
  28 +@NoArgsConstructor
  29 +@AllArgsConstructor
  30 +public class TradeConfigDO extends BaseDO {
  31 +
  32 + /**
  33 + * 自增主键
  34 + */
  35 + @TableId
  36 + private Long id;
  37 +
  38 + // ========== 分销相关 ==========
  39 +
  40 + /**
  41 + * 是否启用分佣
  42 + */
  43 + private Boolean brokerageEnabled;
  44 + /**
  45 + * 分佣模式
  46 + * <p>
  47 + * 枚举 {@link BrokerageEnabledConditionEnum 对应的类}
  48 + */
  49 + private Integer brokerageEnabledCondition;
  50 + /**
  51 + * 分销关系绑定模式
  52 + * <p>
  53 + * 枚举 {@link BrokerageBindModeEnum 对应的类}
  54 + */
  55 + private Integer brokerageBindMode;
  56 + /**
  57 + * 分销海报图地址数组
  58 + */
  59 + @TableField(typeHandler = JacksonTypeHandler.class)
  60 + private List<String> brokeragePostUrls;
  61 + /**
  62 + * 一级返佣比例
  63 + */
  64 + private Integer brokerageFirstPercent;
  65 + /**
  66 + * 二级返佣比例
  67 + */
  68 + private Integer brokerageSecondPercent;
  69 + /**
  70 + * 用户提现最低金额
  71 + */
  72 + private Integer brokerageWithdrawMinPrice;
  73 + /**
  74 + * 提现银行
  75 + */
  76 + @TableField(typeHandler = IntegerListTypeHandler.class)
  77 + private List<Integer> brokerageBankNames;
  78 + /**
  79 + * 佣金冻结时间(天)
  80 + */
  81 + private Integer brokerageFrozenDays;
  82 + /**
  83 + * 提现方式
  84 + * <p>
  85 + * 枚举 {@link BrokerageWithdrawTypeEnum 对应的类}
  86 + */
  87 + @TableField(typeHandler = IntegerListTypeHandler.class)
  88 + private List<Integer> brokerageWithdrawType;
  89 +
  90 +}
... ...
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/dal/mysql/brokerage/record/TradeBrokerageRecordMapper.java 0 → 100644
  1 +package cn.iocoder.yudao.module.trade.dal.mysql.brokerage.record;
  2 +
  3 +import cn.iocoder.yudao.framework.common.pojo.PageResult;
  4 +import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX;
  5 +import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX;
  6 +import cn.iocoder.yudao.module.trade.controller.admin.brokerage.record.vo.TradeBrokerageRecordPageReqVO;
  7 +import cn.iocoder.yudao.module.trade.dal.dataobject.brokerage.record.TradeBrokerageRecordDO;
  8 +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
  9 +import org.apache.ibatis.annotations.Mapper;
  10 +
  11 +import java.time.LocalDateTime;
  12 +import java.util.List;
  13 +
  14 +/**
  15 + * 佣金记录 Mapper
  16 + *
  17 + * @author owen
  18 + */
  19 +@Mapper
  20 +public interface TradeBrokerageRecordMapper extends BaseMapperX<TradeBrokerageRecordDO> {
  21 +
  22 + default PageResult<TradeBrokerageRecordDO> selectPage(TradeBrokerageRecordPageReqVO reqVO) {
  23 + return selectPage(reqVO, new LambdaQueryWrapperX<TradeBrokerageRecordDO>()
  24 + .eqIfPresent(TradeBrokerageRecordDO::getUserId, reqVO.getUserId())
  25 + .eqIfPresent(TradeBrokerageRecordDO::getBizType, reqVO.getBizType())
  26 + .eqIfPresent(TradeBrokerageRecordDO::getStatus, reqVO.getStatus())
  27 + .betweenIfPresent(TradeBrokerageRecordDO::getCreateTime, reqVO.getCreateTime())
  28 + .orderByDesc(TradeBrokerageRecordDO::getId));
  29 + }
  30 +
  31 + default List<TradeBrokerageRecordDO> selectListByStatusAndUnfreezeTimeLt(Integer status, LocalDateTime unfreezeTime) {
  32 + return selectList(new LambdaQueryWrapper<TradeBrokerageRecordDO>()
  33 + .eq(TradeBrokerageRecordDO::getStatus, status)
  34 + .lt(TradeBrokerageRecordDO::getUnfreezeTime, unfreezeTime));
  35 + }
  36 +
  37 + default int updateByIdAndStatus(Integer id, Integer status, TradeBrokerageRecordDO updateObj) {
  38 + return update(updateObj, new LambdaQueryWrapper<TradeBrokerageRecordDO>()
  39 + .eq(TradeBrokerageRecordDO::getId, id)
  40 + .eq(TradeBrokerageRecordDO::getStatus, status));
  41 + }
  42 +
  43 + // TODO @疯狂:userId???
  44 + default TradeBrokerageRecordDO selectByUserIdAndBizTypeAndBizId(Integer bizType, String bizId) {
  45 + return selectOne(TradeBrokerageRecordDO::getBizType, bizType,
  46 + TradeBrokerageRecordDO::getBizId, bizId);
  47 + }
  48 +
  49 +}
... ...
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/dal/mysql/brokerage/user/TradeBrokerageUserMapper.java 0 → 100644
  1 +package cn.iocoder.yudao.module.trade.dal.mysql.brokerage.user;
  2 +
  3 +import cn.hutool.core.lang.Assert;
  4 +import cn.iocoder.yudao.framework.common.pojo.PageResult;
  5 +import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX;
  6 +import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX;
  7 +import cn.iocoder.yudao.module.trade.controller.admin.brokerage.user.vo.TradeBrokerageUserPageReqVO;
  8 +import cn.iocoder.yudao.module.trade.dal.dataobject.brokerage.user.TradeBrokerageUserDO;
  9 +import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
  10 +import org.apache.ibatis.annotations.Mapper;
  11 +
  12 +/**
  13 + * 分销用户 Mapper
  14 + *
  15 + * @author owen
  16 + */
  17 +@Mapper
  18 +public interface TradeBrokerageUserMapper extends BaseMapperX<TradeBrokerageUserDO> {
  19 +
  20 + default PageResult<TradeBrokerageUserDO> selectPage(TradeBrokerageUserPageReqVO reqVO) {
  21 + return selectPage(reqVO, new LambdaQueryWrapperX<TradeBrokerageUserDO>()
  22 + .eqIfPresent(TradeBrokerageUserDO::getBrokerageUserId, reqVO.getBrokerageUserId())
  23 + .eqIfPresent(TradeBrokerageUserDO::getBrokerageEnabled, reqVO.getBrokerageEnabled())
  24 + .betweenIfPresent(TradeBrokerageUserDO::getCreateTime, reqVO.getCreateTime())
  25 + .orderByDesc(TradeBrokerageUserDO::getId));
  26 + }
  27 +
  28 + /**
  29 + * 更新用户可用佣金(增加)
  30 + *
  31 + * @param id 用户编号
  32 + * @param incrCount 增加佣金(正数)
  33 + */
  34 + default void updateBrokeragePriceIncr(Long id, int incrCount) {
  35 + Assert.isTrue(incrCount > 0);
  36 + LambdaUpdateWrapper<TradeBrokerageUserDO> lambdaUpdateWrapper = new LambdaUpdateWrapper<TradeBrokerageUserDO>()
  37 + .setSql(" brokerage_price = brokerage_price + " + incrCount)
  38 + .eq(TradeBrokerageUserDO::getId, id);
  39 + update(null, lambdaUpdateWrapper);
  40 + }
  41 +
  42 + /**
  43 + * 更新用户可用佣金(减少)
  44 + * 注意:理论上佣金可能已经提现,这时会扣出负数,确保平台不会造成损失
  45 + *
  46 + * @param id 用户编号
  47 + * @param incrCount 增加佣金(负数)
  48 + */
  49 + default void updateBrokeragePriceDecr(Long id, int incrCount) {
  50 + Assert.isTrue(incrCount < 0);
  51 + LambdaUpdateWrapper<TradeBrokerageUserDO> lambdaUpdateWrapper = new LambdaUpdateWrapper<TradeBrokerageUserDO>()
  52 + .setSql(" brokerage_price = brokerage_price + " + incrCount) // 负数,所以使用 + 号
  53 + .eq(TradeBrokerageUserDO::getId, id);
  54 + update(null, lambdaUpdateWrapper);
  55 + }
  56 +
  57 + /**
  58 + * 更新用户冻结佣金(增加)
  59 + *
  60 + * @param id 用户编号
  61 + * @param incrCount 增加冻结佣金(正数)
  62 + */
  63 + default void updateFrozenBrokeragePriceIncr(Long id, int incrCount) {
  64 + Assert.isTrue(incrCount > 0);
  65 + LambdaUpdateWrapper<TradeBrokerageUserDO> lambdaUpdateWrapper = new LambdaUpdateWrapper<TradeBrokerageUserDO>()
  66 + .setSql(" frozen_brokerage_price = frozen_brokerage_price + " + incrCount)
  67 + .eq(TradeBrokerageUserDO::getId, id);
  68 + update(null, lambdaUpdateWrapper);
  69 + }
  70 +
  71 + /**
  72 + * 更新用户冻结佣金(减少)
  73 + * 注意:理论上冻结佣金可能已经解冻,这时会扣出负数,确保平台不会造成损失
  74 + *
  75 + * @param id 用户编号
  76 + * @param incrCount 减少冻结佣金(负数)
  77 + */
  78 + default void updateFrozenBrokeragePriceDecr(Long id, int incrCount) {
  79 + Assert.isTrue(incrCount < 0);
  80 + LambdaUpdateWrapper<TradeBrokerageUserDO> lambdaUpdateWrapper = new LambdaUpdateWrapper<TradeBrokerageUserDO>()
  81 + .setSql(" frozen_brokerage_price = frozen_brokerage_price + " + incrCount) // 负数,所以使用 + 号
  82 + .eq(TradeBrokerageUserDO::getId, id);
  83 + update(null, lambdaUpdateWrapper);
  84 + }
  85 +
  86 + /**
  87 + * 更新用户冻结佣金(减少), 更新用户佣金(增加)
  88 + *
  89 + * @param id 用户编号
  90 + * @param incrCount 减少冻结佣金(负数)
  91 + * @return 更新条数
  92 + */
  93 + default int updateFrozenBrokeragePriceDecrAndBrokeragePriceIncr(Long id, int incrCount) {
  94 + Assert.isTrue(incrCount < 0);
  95 + LambdaUpdateWrapper<TradeBrokerageUserDO> lambdaUpdateWrapper = new LambdaUpdateWrapper<TradeBrokerageUserDO>()
  96 + .setSql(" frozen_brokerage_price = frozen_brokerage_price + " + incrCount + // 负数,所以使用 + 号
  97 + ", brokerage_price = brokerage_price + " + -incrCount) // 负数,所以使用 - 号
  98 + .eq(TradeBrokerageUserDO::getId, id)
  99 + .ge(TradeBrokerageUserDO::getFrozenBrokeragePrice, -incrCount); // cas 逻辑
  100 + return update(null, lambdaUpdateWrapper);
  101 + }
  102 +
  103 +}
... ...
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/dal/mysql/config/TradeConfigMapper.java 0 → 100644
  1 +package cn.iocoder.yudao.module.trade.dal.mysql.config;
  2 +
  3 +import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX;
  4 +import cn.iocoder.yudao.module.trade.dal.dataobject.config.TradeConfigDO;
  5 +import org.apache.ibatis.annotations.Mapper;
  6 +
  7 +/**
  8 + * 交易中心配置 Mapper
  9 + *
  10 + * @author owen
  11 + */
  12 +@Mapper
  13 +public interface TradeConfigMapper extends BaseMapperX<TradeConfigDO> {
  14 +
  15 +}
... ...
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/job/brokerage/TradeBrokerageRecordUnfreezeJob.java 0 → 100644
  1 +package cn.iocoder.yudao.module.trade.job.brokerage;
  2 +
  3 +import cn.hutool.core.util.StrUtil;
  4 +import cn.iocoder.yudao.framework.quartz.core.handler.JobHandler;
  5 +import cn.iocoder.yudao.framework.tenant.core.job.TenantJob;
  6 +import cn.iocoder.yudao.module.trade.service.brokerage.record.TradeBrokerageRecordService;
  7 +import org.springframework.stereotype.Component;
  8 +
  9 +import javax.annotation.Resource;
  10 +
  11 +/**
  12 + * 佣金解冻 Job
  13 + *
  14 + * @author owen
  15 + */
  16 +@Component
  17 +@TenantJob
  18 +public class TradeBrokerageRecordUnfreezeJob implements JobHandler {
  19 +
  20 + @Resource
  21 + private TradeBrokerageRecordService tradeBrokerageRecordService;
  22 +
  23 + @Override
  24 + public String execute(String param) {
  25 + int count = tradeBrokerageRecordService.unfreezeRecord();
  26 + return StrUtil.format("解冻佣金 {} 个", count);
  27 + }
  28 +
  29 +}
... ...
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/job/package-info.java 0 → 100644
  1 +/**
  2 + * 占位文件,无特殊用途
  3 + */
  4 +package cn.iocoder.yudao.module.trade.job;
... ...
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/brokerage/record/TradeBrokerageRecordService.java 0 → 100644
  1 +package cn.iocoder.yudao.module.trade.service.brokerage.record;
  2 +
  3 +import cn.iocoder.yudao.framework.common.pojo.PageResult;
  4 +import cn.iocoder.yudao.module.trade.dal.dataobject.brokerage.record.TradeBrokerageRecordDO;
  5 +import cn.iocoder.yudao.module.trade.service.brokerage.record.bo.BrokerageAddReqBO;
  6 +import cn.iocoder.yudao.module.trade.controller.admin.brokerage.record.vo.TradeBrokerageRecordPageReqVO;
  7 +
  8 +import java.util.List;
  9 +
  10 +/**
  11 + * 佣金记录 Service 接口
  12 + *
  13 + * @author owen
  14 + */
  15 +public interface TradeBrokerageRecordService {
  16 +
  17 + /**
  18 + * 获得佣金记录
  19 + *
  20 + * @param id 编号
  21 + * @return 佣金记录
  22 + */
  23 + TradeBrokerageRecordDO getBrokerageRecord(Integer id);
  24 +
  25 + /**
  26 + * 获得佣金记录分页
  27 + *
  28 + * @param pageReqVO 分页查询
  29 + * @return 佣金记录分页
  30 + */
  31 + PageResult<TradeBrokerageRecordDO> getBrokerageRecordPage(TradeBrokerageRecordPageReqVO pageReqVO);
  32 +
  33 + // TODO @疯狂:是不是 bizType 得加下?方便未来拓展哈;
  34 + /**
  35 + * 增加佣金
  36 + *
  37 + * @param userId 会员编号
  38 + * @param list 请求参数列表
  39 + */
  40 + void addBrokerage(Long userId, List<BrokerageAddReqBO> list);
  41 +
  42 + // TODO @疯狂:是不是 bizType 得加下?方便未来拓展哈;
  43 + /**
  44 + * 取消佣金:将佣金记录,状态修改为已失效
  45 + *
  46 + * @param userId 会员编号
  47 + * @param bizId 业务编号
  48 + */
  49 + void cancelBrokerage(Long userId, String bizId);
  50 +
  51 + /**
  52 + * 解冻佣金:将待结算的佣金记录,状态修改为已结算
  53 + *
  54 + * @return 解冻佣金的数量
  55 + */
  56 + int unfreezeRecord();
  57 +
  58 +}
... ...
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/brokerage/record/TradeBrokerageRecordServiceImpl.java 0 → 100644
  1 +package cn.iocoder.yudao.module.trade.service.brokerage.record;
  2 +
  3 +import cn.hutool.core.collection.CollUtil;
  4 +import cn.hutool.core.util.BooleanUtil;
  5 +import cn.hutool.core.util.NumberUtil;
  6 +import cn.hutool.core.util.ObjectUtil;
  7 +import cn.hutool.extra.spring.SpringUtil;
  8 +import cn.iocoder.yudao.framework.common.pojo.PageResult;
  9 +import cn.iocoder.yudao.module.trade.controller.admin.brokerage.record.vo.TradeBrokerageRecordPageReqVO;
  10 +import cn.iocoder.yudao.module.trade.convert.brokerage.record.TradeBrokerageRecordConvert;
  11 +import cn.iocoder.yudao.module.trade.dal.dataobject.brokerage.record.TradeBrokerageRecordDO;
  12 +import cn.iocoder.yudao.module.trade.dal.dataobject.brokerage.user.TradeBrokerageUserDO;
  13 +import cn.iocoder.yudao.module.trade.dal.dataobject.config.TradeConfigDO;
  14 +import cn.iocoder.yudao.module.trade.dal.mysql.brokerage.record.TradeBrokerageRecordMapper;
  15 +import cn.iocoder.yudao.module.trade.enums.brokerage.BrokerageRecordBizTypeEnum;
  16 +import cn.iocoder.yudao.module.trade.enums.brokerage.BrokerageRecordStatusEnum;
  17 +import cn.iocoder.yudao.module.trade.service.brokerage.record.bo.BrokerageAddReqBO;
  18 +import cn.iocoder.yudao.module.trade.service.brokerage.user.TradeBrokerageUserService;
  19 +import cn.iocoder.yudao.module.trade.service.config.TradeConfigService;
  20 +import lombok.extern.slf4j.Slf4j;
  21 +import org.springframework.stereotype.Service;
  22 +import org.springframework.transaction.annotation.Transactional;
  23 +import org.springframework.validation.annotation.Validated;
  24 +
  25 +import javax.annotation.Resource;
  26 +import java.math.RoundingMode;
  27 +import java.time.LocalDateTime;
  28 +import java.util.ArrayList;
  29 +import java.util.List;
  30 +import java.util.function.Function;
  31 +
  32 +/**
  33 + * 佣金记录 Service 实现类
  34 + *
  35 + * @author owen
  36 + */
  37 +@Slf4j
  38 +@Service
  39 +@Validated
  40 +public class TradeBrokerageRecordServiceImpl implements TradeBrokerageRecordService {
  41 +
  42 + @Resource
  43 + private TradeBrokerageRecordMapper tradeBrokerageRecordMapper;
  44 + @Resource
  45 + private TradeConfigService tradeConfigService;
  46 + @Resource
  47 + private TradeBrokerageUserService tradeBrokerageUserService;
  48 +
  49 + @Override
  50 + public TradeBrokerageRecordDO getBrokerageRecord(Integer id) {
  51 + return tradeBrokerageRecordMapper.selectById(id);
  52 + }
  53 +
  54 + @Override
  55 + public PageResult<TradeBrokerageRecordDO> getBrokerageRecordPage(TradeBrokerageRecordPageReqVO pageReqVO) {
  56 + return tradeBrokerageRecordMapper.selectPage(pageReqVO);
  57 + }
  58 +
  59 + // TODO @疯狂:buyerId 要不要统一改成 userId 哈;
  60 + @Override
  61 + @Transactional(rollbackFor = Exception.class)
  62 + public void addBrokerage(Long buyerId, List<BrokerageAddReqBO> list) {
  63 + TradeConfigDO memberConfig = tradeConfigService.getTradeConfig();
  64 + // 0 未启用分销功能
  65 + // TODO @疯狂:BooleanUtil.isFalse();逻辑里,尽量不做 !取反,这样要多思考一层;
  66 + if (memberConfig == null || !BooleanUtil.isTrue(memberConfig.getBrokerageEnabled())) {
  67 + log.warn("[addBrokerage][增加佣金失败:brokerageEnabled 未配置,buyerId({})", buyerId);
  68 + return;
  69 + }
  70 +
  71 + // 1.1 获得一级推广人
  72 + TradeBrokerageUserDO firstUser = tradeBrokerageUserService.getInviteBrokerageUser(buyerId);
  73 + if (firstUser == null || !BooleanUtil.isTrue(firstUser.getBrokerageEnabled())) {
  74 + return;
  75 + }
  76 +
  77 + // 1.2 计算一级分佣 // TODO 疯狂:类似 1.1 和 1.2 的空行,可以去掉;一般在代码里的空行,是为了逻辑分块;但是分块如果太多,就会导致代码里都是空行哈;
  78 + addBrokerage(firstUser, list, memberConfig.getBrokerageFrozenDays(), memberConfig.getBrokerageFirstPercent(), BrokerageAddReqBO::getSkuFirstBrokeragePrice);
  79 +
  80 + // 2.1 获得二级推广员
  81 + // TODO @疯狂:这里可以加个 firstUser.getBrokerageUserId() 为空的判断 return
  82 + TradeBrokerageUserDO secondUser = tradeBrokerageUserService.getBrokerageUser(firstUser.getBrokerageUserId());
  83 + if (secondUser == null || !BooleanUtil.isTrue(secondUser.getBrokerageEnabled())) {
  84 + return;
  85 + }
  86 +
  87 + // 2.2 计算二级分佣
  88 + addBrokerage(secondUser, list, memberConfig.getBrokerageFrozenDays(), memberConfig.getBrokerageSecondPercent(), BrokerageAddReqBO::getSkuSecondBrokeragePrice);
  89 + }
  90 +
  91 + @Override
  92 + @Transactional(rollbackFor = Exception.class)
  93 + public void cancelBrokerage(Long userId, String bizId) {
  94 + TradeBrokerageRecordDO record = tradeBrokerageRecordMapper.selectByUserIdAndBizTypeAndBizId(BrokerageRecordBizTypeEnum.ORDER.getType(), bizId);
  95 + if (record == null || ObjectUtil.notEqual(record.getUserId(), userId)) {
  96 + log.error("[cancelBrokerage][userId({})][bizId({}) 更新为已失效失败:记录不存在]", userId, bizId);
  97 + return;
  98 + }
  99 +
  100 + // 1. 更新佣金记录为已失效
  101 + TradeBrokerageRecordDO updateObj = new TradeBrokerageRecordDO().setStatus(BrokerageRecordStatusEnum.CANCEL.getStatus());
  102 + int updateRows = tradeBrokerageRecordMapper.updateByIdAndStatus(record.getId(), record.getStatus(), updateObj);
  103 + if (updateRows == 0) {
  104 + log.error("[cancelBrokerage][record({}) 更新为已失效失败]", record.getId());
  105 + return;
  106 + }
  107 +
  108 + // 2. 更新用户的佣金
  109 + if (BrokerageRecordStatusEnum.WAIT_SETTLEMENT.getStatus().equals(record.getStatus())) {
  110 + tradeBrokerageUserService.updateUserFrozenBrokeragePrice(userId, -record.getPrice());
  111 + } else if (BrokerageRecordStatusEnum.SETTLEMENT.getStatus().equals(record.getStatus())) {
  112 + tradeBrokerageUserService.updateUserBrokeragePrice(userId, -record.getPrice());
  113 + }
  114 + }
  115 +
  116 + // TODO @疯狂:是不是 calculateBrokeragePrice
  117 + /**
  118 + * 计算佣金
  119 + *
  120 + * @param payPrice 订单支付金额
  121 + * @param percent 商品 SKU 设置的佣金
  122 + * @param skuBrokeragePrice 商品的佣金
  123 + * @return 佣金
  124 + */
  125 + int calculateBrokerage(Integer payPrice, Integer percent, Integer skuBrokeragePrice) {
  126 + // 1. 优先使用商品 SKU 设置的佣金
  127 + if (skuBrokeragePrice != null && skuBrokeragePrice > 0) {
  128 + return ObjectUtil.defaultIfNull(skuBrokeragePrice, 0);
  129 + }
  130 + // 2. 根据订单支付金额计算佣金
  131 + // TODO @疯狂:要不要把 MoneyUtils 抽到 common 里,然后这里也使用这个类的方法;
  132 + if (payPrice != null && payPrice > 0 && percent != null && percent > 0) {
  133 + return NumberUtil.div(NumberUtil.mul(payPrice, percent), 100, 0, RoundingMode.DOWN).intValue();
  134 + }
  135 + return 0;
  136 + }
  137 +
  138 + /**
  139 + * 增加用户佣金
  140 + *
  141 + * @param user 用户
  142 + * @param list 佣金增加参数列表
  143 + * @param brokerageFrozenDays 冻结天数
  144 + * @param brokeragePercent 佣金比例
  145 + * @param skuBrokeragePriceFun 商品 SKU 设置的佣金
  146 + */
  147 + private void addBrokerage(TradeBrokerageUserDO user, List<BrokerageAddReqBO> list, Integer brokerageFrozenDays,
  148 + Integer brokeragePercent, Function<BrokerageAddReqBO, Integer> skuBrokeragePriceFun) {
  149 + // 1.1 处理冻结时间
  150 + // TODO @疯狂:是不是 brokerageFrozenDays != null && brokerageFrozenDays > 0 ?然后计算;更简洁一点;
  151 + brokerageFrozenDays = ObjectUtil.defaultIfNull(brokerageFrozenDays, 0);
  152 + LocalDateTime unfreezeTime = null;
  153 + if (brokerageFrozenDays > 0) {
  154 + unfreezeTime = LocalDateTime.now().plusDays(brokerageFrozenDays);
  155 + }
  156 + // 1.2 计算分佣
  157 + int totalBrokerage = 0;
  158 + List<TradeBrokerageRecordDO> records = new ArrayList<>();
  159 + for (BrokerageAddReqBO item : list) {
  160 + int brokeragePerItem = calculateBrokerage(item.getPayPrice(), brokeragePercent, skuBrokeragePriceFun.apply(item));
  161 + // TODO @疯狂:其实可以 brokeragePerItem <= 0 ,continue;这样 { 层级更少;代码更简洁;}
  162 + if (brokeragePerItem > 0) {
  163 + int brokerage = brokeragePerItem * item.getCount();
  164 + records.add(TradeBrokerageRecordConvert.INSTANCE.convert(user, item.getBizId(), brokerageFrozenDays, brokerage, unfreezeTime));
  165 + totalBrokerage += brokerage;
  166 + }
  167 + }
  168 + if (CollUtil.isEmpty(records)) {
  169 + return;
  170 + }
  171 + // 1.3 保存佣金记录
  172 + tradeBrokerageRecordMapper.insertBatch(records);
  173 +
  174 + // 2. 更新用户佣金
  175 + if (brokerageFrozenDays > 0) { // 更新用户冻结佣金
  176 + tradeBrokerageUserService.updateUserFrozenBrokeragePrice(user.getId(), totalBrokerage);
  177 + } else { // 更新用户可用佣金
  178 + tradeBrokerageUserService.updateUserBrokeragePrice(user.getId(), totalBrokerage);
  179 + }
  180 + }
  181 +
  182 + @Override
  183 + public int unfreezeRecord() {
  184 + // 1. 查询待结算的佣金记录
  185 + List<TradeBrokerageRecordDO> records = tradeBrokerageRecordMapper.selectListByStatusAndUnfreezeTimeLt(
  186 + BrokerageRecordStatusEnum.WAIT_SETTLEMENT.getStatus(), LocalDateTime.now());
  187 + if (CollUtil.isEmpty(records)) {
  188 + return 0;
  189 + }
  190 +
  191 + // 2. 遍历执行
  192 + int count = 0;
  193 + for (TradeBrokerageRecordDO record : records) {
  194 + try {
  195 + boolean success = getSelf().unfreezeRecord(record);
  196 + if (success) {
  197 + count++;
  198 + }
  199 + } catch (Exception e) {
  200 + log.error("[unfreezeRecord][record({}) 更新为已结算失败]", record.getId(), e);
  201 + }
  202 + }
  203 + return count;
  204 + }
  205 +
  206 + @Transactional(rollbackFor = Exception.class)
  207 + public boolean unfreezeRecord(TradeBrokerageRecordDO record) {
  208 + // 更新记录状态
  209 + TradeBrokerageRecordDO updateObj = new TradeBrokerageRecordDO()
  210 + .setStatus(BrokerageRecordStatusEnum.SETTLEMENT.getStatus())
  211 + .setUnfreezeTime(LocalDateTime.now());
  212 + int updateRows = tradeBrokerageRecordMapper.updateByIdAndStatus(record.getId(), record.getStatus(), updateObj);
  213 + if (updateRows == 0) {
  214 + log.error("[unfreezeRecord][record({}) 更新为已结算失败]", record.getId());
  215 + return false;
  216 + }
  217 +
  218 + // 更新用户冻结佣金
  219 + tradeBrokerageUserService.updateFrozenBrokeragePriceDecrAndBrokeragePriceIncr(record.getUserId(), -record.getPrice());
  220 + log.info("[unfreezeRecord][record({}) 更新为已结算成功]", record.getId());
  221 + return true;
  222 + }
  223 +
  224 + /**
  225 + * 获得自身的代理对象,解决 AOP 生效问题
  226 + *
  227 + * @return 自己
  228 + */
  229 + private TradeBrokerageRecordServiceImpl getSelf() {
  230 + return SpringUtil.getBean(getClass());
  231 + }
  232 +
  233 +}
... ...
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/brokerage/record/bo/BrokerageAddReqBO.java 0 → 100644
  1 +package cn.iocoder.yudao.module.trade.service.brokerage.record.bo;
  2 +
  3 +import lombok.AllArgsConstructor;
  4 +import lombok.Data;
  5 +import lombok.NoArgsConstructor;
  6 +
  7 +// TODO @疯狂:要不要 service 还是拍平;就是都放在 brokerage 包下,然后 bo 里面,稍微分分;
  8 +/**
  9 + * 佣金 增加 Request BO
  10 + *
  11 + * @author owen
  12 + */
  13 +@Data
  14 +@NoArgsConstructor
  15 +@AllArgsConstructor
  16 +public class BrokerageAddReqBO {
  17 +
  18 + // TODO @疯狂:bo 的话,也可以考虑加下 @Validated 注解,校验下参数;防御性下哈,虽然不一定用的到
  19 +
  20 + /**
  21 + * 业务ID
  22 + */
  23 + private String bizId;
  24 + // TODO @疯狂:不需要 payPrice 和 count,计算成 price 就好啦;
  25 + /**
  26 + * 商品支付价格
  27 + */
  28 + private Integer payPrice;
  29 + // TODO @疯狂:可以去掉 sku 哈,更抽象一点;
  30 + /**
  31 + * SKU 一级佣金
  32 + */
  33 + private Integer skuFirstBrokeragePrice;
  34 + /**
  35 + * SKU 二级佣金
  36 + */
  37 + private Integer skuSecondBrokeragePrice;
  38 + /**
  39 + * 购买数量
  40 + */
  41 + private Integer count;
  42 +
  43 +}
... ...
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/brokerage/user/TradeBrokerageUserService.java 0 → 100644
  1 +package cn.iocoder.yudao.module.trade.service.brokerage.user;
  2 +
  3 +import cn.iocoder.yudao.framework.common.pojo.PageResult;
  4 +import cn.iocoder.yudao.module.trade.controller.admin.brokerage.user.vo.TradeBrokerageUserPageReqVO;
  5 +import cn.iocoder.yudao.module.trade.dal.dataobject.brokerage.user.TradeBrokerageUserDO;
  6 +
  7 +import java.util.Collection;
  8 +import java.util.List;
  9 +
  10 +// TODO @疯狂:要不去掉 Trade 前缀哈;交易这块,我准备除了 tradeorder 保持下,类似 aftersale,都要取消前缀了;tradeorder 保持的原因,是避免 payorder 和它重复
  11 +/**
  12 + * 分销用户 Service 接口
  13 + *
  14 + * @author owen
  15 + */
  16 +public interface TradeBrokerageUserService {
  17 +
  18 + /**
  19 + * 获得分销用户
  20 + *
  21 + * @param id 编号
  22 + * @return 分销用户
  23 + */
  24 + TradeBrokerageUserDO getBrokerageUser(Long id);
  25 +
  26 + /**
  27 + * 获得分销用户列表
  28 + *
  29 + * @param ids 编号
  30 + * @return 分销用户列表
  31 + */
  32 + List<TradeBrokerageUserDO> getBrokerageUserList(Collection<Long> ids);
  33 +
  34 + /**
  35 + * 获得分销用户分页
  36 + *
  37 + * @param pageReqVO 分页查询
  38 + * @return 分销用户分页
  39 + */
  40 + PageResult<TradeBrokerageUserDO> getBrokerageUserPage(TradeBrokerageUserPageReqVO pageReqVO);
  41 +
  42 + /**
  43 + * 修改推广员编号
  44 + *
  45 + * @param id 用户编号
  46 + * @param brokerageUserId 推广员编号
  47 + */
  48 + void updateBrokerageUserId(Long id, Long brokerageUserId);
  49 +
  50 + /**
  51 + * 修改推广资格
  52 + *
  53 + * @param id 用户编号
  54 + * @param brokerageEnabled 推广资格
  55 + */
  56 + void updateBrokerageEnabled(Long id, Boolean brokerageEnabled);
  57 +
  58 + /**
  59 + * 获得用户的推广人
  60 + *
  61 + * @param id 用户编号
  62 + * @return 用户的推广人
  63 + */
  64 + TradeBrokerageUserDO getInviteBrokerageUser(Long id);
  65 +
  66 + /**
  67 + * 更新用户佣金
  68 + *
  69 + * @param id 用户编号
  70 + * @param brokeragePrice 用户可用佣金
  71 + */
  72 + void updateUserBrokeragePrice(Long id, int brokeragePrice);
  73 +
  74 + // TODO @疯狂:int 类型一般不用哈;尽量都用封装类型;不差这点内存哈;
  75 + /**
  76 + * 更新用户冻结佣金
  77 + *
  78 + * @param id 用户编号
  79 + * @param frozenBrokeragePrice 用户冻结佣金
  80 + */
  81 + void updateUserFrozenBrokeragePrice(Long id, int frozenBrokeragePrice);
  82 +
  83 + /**
  84 + * 更新用户冻结佣金(减少), 更新用户佣金(增加)
  85 + *
  86 + * @param id 用户编号
  87 + * @param frozenBrokeragePrice 减少冻结佣金(负数)
  88 + */
  89 + void updateFrozenBrokeragePriceDecrAndBrokeragePriceIncr(Long id, int frozenBrokeragePrice);
  90 +
  91 +}
... ...
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/brokerage/user/TradeBrokerageUserServiceImpl.java 0 → 100644
  1 +package cn.iocoder.yudao.module.trade.service.brokerage.user;
  2 +
  3 +import cn.hutool.core.lang.Assert;
  4 +import cn.iocoder.yudao.framework.common.pojo.PageResult;
  5 +import cn.iocoder.yudao.module.trade.controller.admin.brokerage.user.vo.TradeBrokerageUserPageReqVO;
  6 +import cn.iocoder.yudao.module.trade.dal.dataobject.brokerage.user.TradeBrokerageUserDO;
  7 +import cn.iocoder.yudao.module.trade.dal.mysql.brokerage.user.TradeBrokerageUserMapper;
  8 +import org.springframework.stereotype.Service;
  9 +import org.springframework.transaction.annotation.Transactional;
  10 +import org.springframework.validation.annotation.Validated;
  11 +
  12 +import javax.annotation.Resource;
  13 +import java.util.Collection;
  14 +import java.util.List;
  15 +import java.util.Optional;
  16 +
  17 +import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
  18 +import static cn.iocoder.yudao.module.member.enums.ErrorCodeConstants.MEMBER_FROZEN_BROKERAGE_PRICE_NOT_ENOUGH;
  19 +import static cn.iocoder.yudao.module.trade.enums.ErrorCodeConstants.BROKERAGE_USER_NOT_EXISTS;
  20 +
  21 +/**
  22 + * 分销用户 Service 实现类
  23 + *
  24 + * @author owen
  25 + */
  26 +@Service
  27 +@Validated
  28 +public class TradeBrokerageUserServiceImpl implements TradeBrokerageUserService {
  29 +
  30 + @Resource
  31 + private TradeBrokerageUserMapper brokerageUserMapper;
  32 +
  33 + @Override
  34 + public TradeBrokerageUserDO getBrokerageUser(Long id) {
  35 + return brokerageUserMapper.selectById(id);
  36 + }
  37 +
  38 + @Override
  39 + public List<TradeBrokerageUserDO> getBrokerageUserList(Collection<Long> ids) {
  40 + return brokerageUserMapper.selectBatchIds(ids);
  41 + }
  42 +
  43 + @Override
  44 + public PageResult<TradeBrokerageUserDO> getBrokerageUserPage(TradeBrokerageUserPageReqVO pageReqVO) {
  45 + return brokerageUserMapper.selectPage(pageReqVO);
  46 + }
  47 +
  48 + @Override
  49 + public void updateBrokerageUserId(Long id, Long brokerageUserId) {
  50 + // 校验存在
  51 + validateBrokerageUserExists(id);
  52 + // TODO @疯狂:貌似没实现完
  53 + }
  54 +
  55 + @Override
  56 + public void updateBrokerageEnabled(Long id, Boolean brokerageEnabled) {
  57 + // 校验存在
  58 + validateBrokerageUserExists(id);
  59 + // TODO @疯狂:貌似没实现完
  60 + }
  61 +
  62 + private void validateBrokerageUserExists(Long id) {
  63 + if (brokerageUserMapper.selectById(id) == null) {
  64 + throw exception(BROKERAGE_USER_NOT_EXISTS);
  65 + }
  66 + }
  67 +
  68 + // TODO @疯狂:getBindBrokerageUser 会不会好点,因为统一使用 Bind 替代了 Invite
  69 + @Override
  70 + public TradeBrokerageUserDO getInviteBrokerageUser(Long id) {
  71 + return Optional.ofNullable(id)
  72 + .map(this::getBrokerageUser)
  73 + .map(TradeBrokerageUserDO::getBrokerageUserId)
  74 + .map(this::getBrokerageUser)
  75 + .orElse(null);
  76 + }
  77 +
  78 + // TODO @疯狂:单个更新,不用事务哈;
  79 + @Override
  80 + @Transactional(rollbackFor = Exception.class)
  81 + public void updateUserBrokeragePrice(Long id, int brokeragePrice) {
  82 + if (brokeragePrice > 0) {
  83 + brokerageUserMapper.updateBrokeragePriceIncr(id, brokeragePrice);
  84 + } else if (brokeragePrice < 0) {
  85 + brokerageUserMapper.updateBrokeragePriceDecr(id, brokeragePrice);
  86 + }
  87 + }
  88 +
  89 + // TODO @疯狂:单个更新,不用事务哈;
  90 + @Override
  91 + @Transactional(rollbackFor = Exception.class)
  92 + public void updateUserFrozenBrokeragePrice(Long id, int frozenBrokeragePrice) {
  93 + if (frozenBrokeragePrice > 0) {
  94 + brokerageUserMapper.updateFrozenBrokeragePriceIncr(id, frozenBrokeragePrice);
  95 + } else if (frozenBrokeragePrice < 0) {
  96 + brokerageUserMapper.updateFrozenBrokeragePriceDecr(id, frozenBrokeragePrice);
  97 + }
  98 + }
  99 +
  100 + // TODO @疯狂:单个更新,不用事务哈;
  101 + @Override
  102 + @Transactional(rollbackFor = Exception.class)
  103 + public void updateFrozenBrokeragePriceDecrAndBrokeragePriceIncr(Long id, int frozenBrokeragePrice) {
  104 + Assert.isTrue(frozenBrokeragePrice < 0);
  105 + int updateRows = brokerageUserMapper.updateFrozenBrokeragePriceDecrAndBrokeragePriceIncr(id, frozenBrokeragePrice);
  106 + if (updateRows == 0) {
  107 + // TODO @疯狂:挪到 trade 这变的错误码哈;
  108 + throw exception(MEMBER_FROZEN_BROKERAGE_PRICE_NOT_ENOUGH);
  109 + }
  110 + }
  111 +
  112 +}
... ...
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/config/TradeConfigService.java 0 → 100644
  1 +package cn.iocoder.yudao.module.trade.service.config;
  2 +
  3 +import cn.iocoder.yudao.module.trade.controller.admin.config.vo.TradeConfigSaveReqVO;
  4 +import cn.iocoder.yudao.module.trade.dal.dataobject.config.TradeConfigDO;
  5 +
  6 +import javax.validation.Valid;
  7 +
  8 +/**
  9 + * 交易中心配置 Service 接口
  10 + *
  11 + * @author owen
  12 + */
  13 +public interface TradeConfigService {
  14 +
  15 + /**
  16 + * 更新交易中心配置
  17 + *
  18 + * @param updateReqVO 更新信息
  19 + */
  20 + void saveTradeConfig(@Valid TradeConfigSaveReqVO updateReqVO);
  21 +
  22 + /**
  23 + * 获得交易中心配置
  24 + *
  25 + * @return 交易中心配置
  26 + */
  27 + TradeConfigDO getTradeConfig();
  28 +
  29 +}
... ...
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/config/TradeConfigServiceImpl.java 0 → 100644
  1 +package cn.iocoder.yudao.module.trade.service.config;
  2 +
  3 +import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils;
  4 +import cn.iocoder.yudao.module.trade.controller.admin.config.vo.TradeConfigSaveReqVO;
  5 +import cn.iocoder.yudao.module.trade.convert.config.TradeConfigConvert;
  6 +import cn.iocoder.yudao.module.trade.dal.dataobject.config.TradeConfigDO;
  7 +import cn.iocoder.yudao.module.trade.dal.mysql.config.TradeConfigMapper;
  8 +import org.springframework.stereotype.Service;
  9 +import org.springframework.validation.annotation.Validated;
  10 +
  11 +import javax.annotation.Resource;
  12 +import java.util.List;
  13 +
  14 +/**
  15 + * 交易中心配置 Service 实现类
  16 + *
  17 + * @author owen
  18 + */
  19 +@Service
  20 +@Validated
  21 +public class TradeConfigServiceImpl implements TradeConfigService {
  22 +
  23 + @Resource
  24 + private TradeConfigMapper tradeConfigMapper;
  25 +
  26 + @Override
  27 + public void saveTradeConfig(TradeConfigSaveReqVO saveReqVO) {
  28 + // 存在,则进行更新
  29 + TradeConfigDO dbConfig = getTradeConfig();
  30 + if (dbConfig != null) {
  31 + tradeConfigMapper.updateById(TradeConfigConvert.INSTANCE.convert(saveReqVO).setId(dbConfig.getId()));
  32 + return;
  33 + }
  34 + // 不存在,则进行插入
  35 + tradeConfigMapper.insert(TradeConfigConvert.INSTANCE.convert(saveReqVO));
  36 + }
  37 +
  38 + @Override
  39 + public TradeConfigDO getTradeConfig() {
  40 + List<TradeConfigDO> list = tradeConfigMapper.selectList();
  41 + return CollectionUtils.getFirst(list);
  42 + }
  43 +
  44 +}
... ...
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/order/TradeOrderUpdateServiceImpl.java
... ... @@ -11,6 +11,8 @@ import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils;
11 11 import cn.iocoder.yudao.framework.common.util.json.JsonUtils;
12 12 import cn.iocoder.yudao.module.member.api.address.AddressApi;
13 13 import cn.iocoder.yudao.module.member.api.address.dto.AddressRespDTO;
  14 +import cn.iocoder.yudao.module.trade.service.brokerage.record.TradeBrokerageRecordService;
  15 +import cn.iocoder.yudao.module.trade.service.brokerage.record.bo.BrokerageAddReqBO;
14 16 import cn.iocoder.yudao.module.member.api.level.MemberLevelApi;
15 17 import cn.iocoder.yudao.module.member.api.point.MemberPointApi;
16 18 import cn.iocoder.yudao.module.member.api.user.MemberUserApi;
... ... @@ -126,6 +128,8 @@ public class TradeOrderUpdateServiceImpl implements TradeOrderUpdateService {
126 128 @Resource
127 129 private MemberPointApi memberPointApi;
128 130 @Resource
  131 + private TradeBrokerageRecordService tradeBrokerageRecordService;
  132 + @Resource
129 133 private ProductCommentApi productCommentApi;
130 134  
131 135 @Resource
... ... @@ -389,6 +393,8 @@ public class TradeOrderUpdateServiceImpl implements TradeOrderUpdateService {
389 393 getSelf().addUserPointAsync(order.getUserId(), order.getPayPrice(), order.getId());
390 394 // 增加用户经验
391 395 getSelf().addUserExperienceAsync(order.getUserId(), order.getPayPrice(), order.getId());
  396 + // 增加用户佣金
  397 + getSelf().addBrokerageAsync(order.getUserId(), order.getId());
392 398 }
393 399  
394 400 /**
... ... @@ -659,12 +665,12 @@ public class TradeOrderUpdateServiceImpl implements TradeOrderUpdateService {
659 665 .setRefundStatus(TradeOrderRefundStatusEnum.PART.getStatus()).setRefundPrice(orderRefundPrice));
660 666 }
661 667  
662   - // TODO 芋艿:未来如果有分佣,需要更新相关分佣订单为已失效
663   -
664 668 // 扣减用户积分
665 669 getSelf().reduceUserPointAsync(order.getUserId(), orderRefundPrice, afterSaleId);
666 670 // 扣减用户经验
667 671 getSelf().reduceUserExperienceAsync(order.getUserId(), orderRefundPrice, afterSaleId);
  672 + // 更新分佣记录为已失效
  673 + getSelf().cancelBrokerageAsync(order.getUserId(), id);
668 674 }
669 675  
670 676 @Override
... ... @@ -772,6 +778,20 @@ public class TradeOrderUpdateServiceImpl implements TradeOrderUpdateService {
772 778 memberPointApi.addPoint(userId, -refundPrice, bizType, String.valueOf(afterSaleId));
773 779 }
774 780  
  781 +
  782 + @Async
  783 + protected void addBrokerageAsync(Long userId, Long orderId) {
  784 + List<TradeOrderItemDO> orderItems = tradeOrderItemMapper.selectListByOrderId(orderId);
  785 + List<BrokerageAddReqBO> list = convertList(orderItems,
  786 + item -> TradeOrderConvert.INSTANCE.convert(item, productSkuApi.getSku(item.getSkuId())));
  787 + tradeBrokerageRecordService.addBrokerage(userId, list);
  788 + }
  789 +
  790 + @Async
  791 + protected void cancelBrokerageAsync(Long userId, Long orderItemId) {
  792 + tradeBrokerageRecordService.cancelBrokerage(userId, String.valueOf(orderItemId));
  793 + }
  794 +
775 795 /**
776 796 * 获得自身的代理对象,解决 AOP 生效问题
777 797 *
... ...
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/price/calculator/TradeCouponPriceCalculator.java
... ... @@ -102,7 +102,10 @@ public class TradeCouponPriceCalculator implements TradePriceCalculator {
102 102 Predicate<TradePriceCalculateRespBO.OrderItem> matchPredicate = TradePriceCalculateRespBO.OrderItem::getSelected;
103 103 if (PromotionProductScopeEnum.SPU.getScope().equals(coupon.getProductScope())) {
104 104 matchPredicate = matchPredicate // 额外加如下条件
105   - .and(orderItem -> coupon.getProductSpuIds().contains(orderItem.getSpuId()));
  105 + .and(orderItem -> coupon.getProductScopeValues().contains(orderItem.getSpuId()));
  106 + } else if (PromotionProductScopeEnum.CATEGORY.getScope().equals(coupon.getProductScope())) {
  107 + matchPredicate = matchPredicate // 额外加如下条件
  108 + .and(orderItem -> coupon.getProductScopeValues().contains(orderItem.getCategoryId()));
106 109 }
107 110 return filterList(result.getItems(), matchPredicate);
108 111 }
... ...
yudao-module-mall/yudao-module-trade-biz/src/test/java/cn/iocoder/yudao/module/trade/service/brokerage/record/TradeBrokerageRecordServiceImplTest.java 0 → 100644
  1 +package cn.iocoder.yudao.module.trade.service.brokerage.record;
  2 +
  3 +import cn.hutool.core.util.NumberUtil;
  4 +import cn.iocoder.yudao.framework.common.pojo.PageResult;
  5 +import cn.iocoder.yudao.framework.test.core.ut.BaseDbUnitTest;
  6 +import cn.iocoder.yudao.module.trade.controller.admin.brokerage.record.vo.TradeBrokerageRecordPageReqVO;
  7 +import cn.iocoder.yudao.module.trade.dal.dataobject.brokerage.record.TradeBrokerageRecordDO;
  8 +import cn.iocoder.yudao.module.trade.dal.mysql.brokerage.record.TradeBrokerageRecordMapper;
  9 +import cn.iocoder.yudao.module.trade.service.brokerage.user.TradeBrokerageUserService;
  10 +import cn.iocoder.yudao.module.trade.service.config.TradeConfigService;
  11 +import org.junit.jupiter.api.Disabled;
  12 +import org.junit.jupiter.api.Test;
  13 +import org.springframework.boot.test.mock.mockito.MockBean;
  14 +import org.springframework.context.annotation.Import;
  15 +
  16 +import javax.annotation.Resource;
  17 +import java.math.RoundingMode;
  18 +
  19 +import static cn.hutool.core.util.RandomUtil.randomEle;
  20 +import static cn.hutool.core.util.RandomUtil.randomInt;
  21 +import static cn.iocoder.yudao.framework.common.util.date.LocalDateTimeUtils.buildBetweenTime;
  22 +import static cn.iocoder.yudao.framework.common.util.object.ObjectUtils.cloneIgnoreId;
  23 +import static cn.iocoder.yudao.framework.test.core.util.AssertUtils.assertPojoEquals;
  24 +import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.randomInteger;
  25 +import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.randomPojo;
  26 +import static org.junit.jupiter.api.Assertions.assertEquals;
  27 +
  28 +// TODO @芋艿:单测后续看看
  29 +/**
  30 + * {@link TradeBrokerageRecordServiceImpl} 的单元测试类
  31 + *
  32 + * @author owen
  33 + */
  34 +@Import(TradeBrokerageRecordServiceImpl.class)
  35 +public class TradeBrokerageRecordServiceImplTest extends BaseDbUnitTest {
  36 +
  37 + @Resource
  38 + private TradeBrokerageRecordServiceImpl tradeBrokerageRecordService;
  39 + @Resource
  40 + private TradeBrokerageRecordMapper tradeBrokerageRecordMapper;
  41 +
  42 + @MockBean
  43 + private TradeConfigService tradeConfigService;
  44 + @MockBean
  45 + private TradeBrokerageUserService tradeBrokerageUserService;
  46 +
  47 + @Test
  48 + @Disabled // TODO 请修改 null 为需要的值,然后删除 @Disabled 注解
  49 + public void testGetBrokerageRecordPage() {
  50 + // mock 数据
  51 + TradeBrokerageRecordDO dbBrokerageRecord = randomPojo(TradeBrokerageRecordDO.class, o -> { // 等会查询到
  52 + o.setUserId(null);
  53 + o.setBizType(null);
  54 + o.setStatus(null);
  55 + o.setCreateTime(null);
  56 + });
  57 + tradeBrokerageRecordMapper.insert(dbBrokerageRecord);
  58 + // 测试 userId 不匹配
  59 + tradeBrokerageRecordMapper.insert(cloneIgnoreId(dbBrokerageRecord, o -> o.setUserId(null)));
  60 + // 测试 bizType 不匹配
  61 + tradeBrokerageRecordMapper.insert(cloneIgnoreId(dbBrokerageRecord, o -> o.setBizType(null)));
  62 + // 测试 status 不匹配
  63 + tradeBrokerageRecordMapper.insert(cloneIgnoreId(dbBrokerageRecord, o -> o.setStatus(null)));
  64 + // 测试 createTime 不匹配
  65 + tradeBrokerageRecordMapper.insert(cloneIgnoreId(dbBrokerageRecord, o -> o.setCreateTime(null)));
  66 + // 准备参数
  67 + TradeBrokerageRecordPageReqVO reqVO = new TradeBrokerageRecordPageReqVO();
  68 + reqVO.setUserId(null);
  69 + reqVO.setBizType(null);
  70 + reqVO.setStatus(null);
  71 + reqVO.setCreateTime(buildBetweenTime(2023, 2, 1, 2023, 2, 28));
  72 +
  73 + // 调用
  74 + PageResult<TradeBrokerageRecordDO> pageResult = tradeBrokerageRecordService.getBrokerageRecordPage(reqVO);
  75 + // 断言
  76 + assertEquals(1, pageResult.getTotal());
  77 + assertEquals(1, pageResult.getList().size());
  78 + assertPojoEquals(dbBrokerageRecord, pageResult.getList().get(0));
  79 + }
  80 +
  81 + @Test
  82 + public void testCalculateBrokerage_useSkuBrokeragePrice() {
  83 + // mock 数据
  84 + Integer payPrice = randomInteger();
  85 + Integer percent = randomInt(1, 101);
  86 + Integer skuBrokeragePrice = randomInt();
  87 + // 调用
  88 + int brokerage = tradeBrokerageRecordService.calculateBrokerage(payPrice, percent, skuBrokeragePrice);
  89 + // 断言
  90 + assertEquals(brokerage, skuBrokeragePrice);
  91 + }
  92 +
  93 + @Test
  94 + public void testCalculateBrokerage_usePercent() {
  95 + // mock 数据
  96 + Integer payPrice = randomInteger();
  97 + Integer percent = randomInt(1, 101);
  98 + Integer skuBrokeragePrice = randomEle(new Integer[]{0, null});
  99 + System.out.println("skuBrokeragePrice=" + skuBrokeragePrice);
  100 + // 调用
  101 + int brokerage = tradeBrokerageRecordService.calculateBrokerage(payPrice, percent, skuBrokeragePrice);
  102 + // 断言
  103 + assertEquals(brokerage, NumberUtil.div(NumberUtil.mul(payPrice, percent), 100, 0, RoundingMode.DOWN).intValue());
  104 + }
  105 +
  106 + @Test
  107 + public void testCalculateBrokerage_equalsZero() {
  108 + // mock 数据
  109 + Integer payPrice = null;
  110 + Integer percent = null;
  111 + Integer skuBrokeragePrice = null;
  112 + // 调用
  113 + int brokerage = tradeBrokerageRecordService.calculateBrokerage(payPrice, percent, skuBrokeragePrice);
  114 + // 断言
  115 + assertEquals(brokerage, 0);
  116 + }
  117 +}
... ...
yudao-module-mall/yudao-module-trade-biz/src/test/java/cn/iocoder/yudao/module/trade/service/brokerage/user/TradeBrokerageUserServiceImplTest.java 0 → 100644
  1 +package cn.iocoder.yudao.module.trade.service.brokerage.user;
  2 +
  3 +import cn.iocoder.yudao.framework.common.pojo.PageResult;
  4 +import cn.iocoder.yudao.framework.test.core.ut.BaseDbUnitTest;
  5 +import cn.iocoder.yudao.module.trade.controller.admin.brokerage.user.vo.TradeBrokerageUserPageReqVO;
  6 +import cn.iocoder.yudao.module.trade.dal.dataobject.brokerage.user.TradeBrokerageUserDO;
  7 +import cn.iocoder.yudao.module.trade.dal.mysql.brokerage.user.TradeBrokerageUserMapper;
  8 +import org.junit.jupiter.api.Disabled;
  9 +import org.junit.jupiter.api.Test;
  10 +import org.springframework.context.annotation.Import;
  11 +
  12 +import javax.annotation.Resource;
  13 +
  14 +import static cn.iocoder.yudao.framework.common.util.date.LocalDateTimeUtils.buildBetweenTime;
  15 +import static cn.iocoder.yudao.framework.common.util.object.ObjectUtils.cloneIgnoreId;
  16 +import static cn.iocoder.yudao.framework.test.core.util.AssertUtils.assertPojoEquals;
  17 +import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.randomPojo;
  18 +import static org.junit.jupiter.api.Assertions.assertEquals;
  19 +
  20 +// TODO @芋艿:单测后续看看
  21 +/**
  22 + * {@link TradeBrokerageUserServiceImpl} 的单元测试类
  23 + *
  24 + * @author owen
  25 + */
  26 +@Import(TradeBrokerageUserServiceImpl.class)
  27 +public class TradeBrokerageUserServiceImplTest extends BaseDbUnitTest {
  28 +
  29 + @Resource
  30 + private TradeBrokerageUserServiceImpl brokerageUserService;
  31 +
  32 + @Resource
  33 + private TradeBrokerageUserMapper brokerageUserMapper;
  34 +
  35 + @Test
  36 + @Disabled // TODO 请修改 null 为需要的值,然后删除 @Disabled 注解
  37 + public void testGetBrokerageUserPage() {
  38 + // mock 数据
  39 + TradeBrokerageUserDO dbBrokerageUser = randomPojo(TradeBrokerageUserDO.class, o -> { // 等会查询到
  40 + o.setBrokerageUserId(null);
  41 + o.setBrokerageEnabled(null);
  42 + o.setCreateTime(null);
  43 + });
  44 + brokerageUserMapper.insert(dbBrokerageUser);
  45 + // 测试 brokerageUserId 不匹配
  46 + brokerageUserMapper.insert(cloneIgnoreId(dbBrokerageUser, o -> o.setBrokerageUserId(null)));
  47 + // 测试 brokerageEnabled 不匹配
  48 + brokerageUserMapper.insert(cloneIgnoreId(dbBrokerageUser, o -> o.setBrokerageEnabled(null)));
  49 + // 测试 createTime 不匹配
  50 + brokerageUserMapper.insert(cloneIgnoreId(dbBrokerageUser, o -> o.setCreateTime(null)));
  51 + // 准备参数
  52 + TradeBrokerageUserPageReqVO reqVO = new TradeBrokerageUserPageReqVO();
  53 + reqVO.setBrokerageUserId(null);
  54 + reqVO.setBrokerageEnabled(null);
  55 + reqVO.setCreateTime(buildBetweenTime(2023, 2, 1, 2023, 2, 28));
  56 +
  57 + // 调用
  58 + PageResult<TradeBrokerageUserDO> pageResult = brokerageUserService.getBrokerageUserPage(reqVO);
  59 + // 断言
  60 + assertEquals(1, pageResult.getTotal());
  61 + assertEquals(1, pageResult.getList().size());
  62 + assertPojoEquals(dbBrokerageUser, pageResult.getList().get(0));
  63 + }
  64 +
  65 +}
... ...
yudao-module-mall/yudao-module-trade-biz/src/test/java/cn/iocoder/yudao/module/trade/service/price/calculator/TradeCouponPriceCalculatorTest.java
... ... @@ -65,7 +65,7 @@ public class TradeCouponPriceCalculatorTest extends BaseMockitoUnitTest {
65 65  
66 66 // mock 方法(优惠劵 Coupon 信息)
67 67 CouponRespDTO coupon = randomPojo(CouponRespDTO.class, o -> o.setId(1024L).setName("程序员节")
68   - .setProductScope(PromotionProductScopeEnum.SPU.getScope()).setProductSpuIds(asList(1L, 2L))
  68 + .setProductScope(PromotionProductScopeEnum.SPU.getScope()).setProductScopeValues(asList(1L, 2L))
69 69 .setUsePrice(350).setDiscountType(PromotionDiscountTypeEnum.PERCENT.getType())
70 70 .setDiscountPercent(50).setDiscountLimitPrice(70));
71 71 when(couponApi.validateCoupon(eq(new CouponValidReqDTO().setId(1024L).setUserId(233L)))).thenReturn(coupon);
... ...
yudao-module-mall/yudao-module-trade-biz/src/test/resources/sql/clean.sql
... ... @@ -2,3 +2,5 @@ DELETE FROM trade_order;
2 2 DELETE FROM trade_order_item;
3 3 DELETE FROM trade_after_sale;
4 4 DELETE FROM trade_after_sale_log;
  5 +DELETE FROM trade_brokerage_user;
  6 +DELETE FROM trade_brokerage_record;
... ...
yudao-module-mall/yudao-module-trade-biz/src/test/resources/sql/create_tables.sql
... ... @@ -125,3 +125,42 @@ CREATE TABLE IF NOT EXISTS &quot;trade_after_sale_log&quot; (
125 125 "deleted" bit NOT NULL DEFAULT FALSE,
126 126 PRIMARY KEY ("id")
127 127 ) COMMENT '交易售后日志';
  128 +
  129 +CREATE TABLE IF NOT EXISTS "trade_brokerage_user"
  130 +(
  131 + "id" bigint NOT NULL GENERATED BY DEFAULT AS IDENTITY,
  132 + "brokerage_user_id" bigint NOT NULL,
  133 + "brokerage_bind_time" varchar,
  134 + "brokerage_enabled" bit NOT NULL,
  135 + "brokerage_time" varchar,
  136 + "brokerage_price" int NOT NULL,
  137 + "frozen_brokerage_price" int NOT NULL,
  138 + "creator" varchar DEFAULT '',
  139 + "create_time" datetime NOT NULL DEFAULT CURRENT_TIMESTAMP,
  140 + "updater" varchar DEFAULT '',
  141 + "update_time" datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
  142 + "deleted" bit NOT NULL DEFAULT FALSE,
  143 + "tenant_id" bigint NOT NULL DEFAULT '0',
  144 + PRIMARY KEY ("id")
  145 +) COMMENT '分销用户';
  146 +CREATE TABLE IF NOT EXISTS "trade_brokerage_record"
  147 +(
  148 + "id" int NOT NULL GENERATED BY DEFAULT AS IDENTITY,
  149 + "user_id" bigint NOT NULL,
  150 + "biz_id" varchar NOT NULL,
  151 + "biz_type" varchar NOT NULL,
  152 + "title" varchar NOT NULL,
  153 + "price" int NOT NULL,
  154 + "total_price" int NOT NULL,
  155 + "description" varchar NOT NULL,
  156 + "status" varchar NOT NULL,
  157 + "frozen_days" int NOT NULL,
  158 + "unfreeze_time" varchar,
  159 + "creator" varchar DEFAULT '',
  160 + "create_time" datetime NOT NULL DEFAULT CURRENT_TIMESTAMP,
  161 + "updater" varchar DEFAULT '',
  162 + "update_time" datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
  163 + "deleted" bit NOT NULL DEFAULT FALSE,
  164 + "tenant_id" bigint not null default '0',
  165 + PRIMARY KEY ("id")
  166 +) COMMENT '佣金记录';
128 167 \ No newline at end of file
... ...
yudao-module-member/yudao-module-member-api/src/main/java/cn/iocoder/yudao/module/member/enums/ErrorCodeConstants.java
... ... @@ -9,10 +9,11 @@ import cn.iocoder.yudao.framework.common.exception.ErrorCode;
9 9 */
10 10 public interface ErrorCodeConstants {
11 11  
12   - // ========== 用户相关 1004001000============
  12 + // ========== 用户相关 1004001000============
13 13 ErrorCode USER_NOT_EXISTS = new ErrorCode(1004001000, "用户不存在");
14 14 ErrorCode USER_MOBILE_NOT_EXISTS = new ErrorCode(1004001001, "手机号未注册用户");
15 15 ErrorCode USER_MOBILE_USED = new ErrorCode(1004001002, "修改手机失败,该手机号({})已经被使用");
  16 + ErrorCode MEMBER_FROZEN_BROKERAGE_PRICE_NOT_ENOUGH = new ErrorCode(1004001003, "用户冻结佣金({})数量不足");
16 17  
17 18 // ========== AUTH 模块 1004003000 ==========
18 19 ErrorCode AUTH_LOGIN_BAD_CREDENTIALS = new ErrorCode(1004003000, "登录失败,账号密码不正确");
... ...
yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/controller/app/user/AppMemberUserController.java
... ... @@ -39,7 +39,9 @@ public class AppMemberUserController {
39 39 public CommonResult<AppMemberUserInfoRespVO> getUserInfo() {
40 40 MemberUserDO user = userService.getUser(getLoginUserId());
41 41 MemberLevelDO level = levelService.getLevel(user.getLevelId());
42   - return success(MemberUserConvert.INSTANCE.convert(user, level));
  42 + return success(MemberUserConvert.INSTANCE.convert(user, level)
  43 + .setBrokerageEnabled(true) // TODO @疯狂:这里我先写死,后面改成 db 返回;
  44 + );
43 45 }
44 46  
45 47 @PutMapping("/update")
... ...
yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/controller/app/user/vo/AppMemberUserInfoRespVO.java
... ... @@ -29,6 +29,9 @@ public class AppMemberUserInfoRespVO {
29 29 @Schema(description = "用户等级")
30 30 private Level level;
31 31  
  32 + @Schema(description = "是否成为推广员", requiredMode = Schema.RequiredMode.REQUIRED, example = "true")
  33 + private Boolean brokerageEnabled;
  34 +
32 35 @Schema(description = "用户 App - 会员等级")
33 36 @Data
34 37 public static class Level {
... ...
yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/dal/dataobject/point/MemberPointConfigDO.java
... ... @@ -6,14 +6,12 @@ import com.baomidou.mybatisplus.annotation.TableId;
6 6 import com.baomidou.mybatisplus.annotation.TableName;
7 7 import lombok.*;
8 8  
9   -import java.math.BigDecimal;
10   -
11 9 /**
12 10 * 会员积分配置 DO
13 11 *
14 12 * @author QingX
15 13 */
16   -@TableName("member_point_config")
  14 +@TableName(value = "member_point_config", autoResultMap = true)
17 15 @KeySequence("member_point_config_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。
18 16 @Data
19 17 @EqualsAndHashCode(callSuper = true)
... ...
yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/dal/dataobject/user/MemberUserDO.java
... ... @@ -136,4 +136,38 @@ public class MemberUserDO extends TenantBaseDO {
136 136 */
137 137 private Long groupId;
138 138  
  139 + // TODO @疯狂:看看要不要删除掉哈
  140 + // ========== 分销相关 ==========
  141 +
  142 + /**
  143 + * 推广员编号
  144 + */
  145 + @TableField(exist = false) // TODO 芋艿:避免报错
  146 + private Long brokerageUserId;
  147 + /**
  148 + * 推广员绑定时间
  149 + */
  150 + @TableField(exist = false) // TODO 芋艿:避免报错
  151 + private LocalDateTime brokerageBindTime;
  152 + /**
  153 + * 是否成为推广员
  154 + */
  155 + @TableField(exist = false) // TODO 芋艿:避免报错
  156 + private Boolean brokerageEnabled;
  157 + /**
  158 + * 成为分销员时间
  159 + */
  160 + @TableField(exist = false) // TODO 芋艿:避免报错
  161 + private LocalDateTime brokerageTime;
  162 + /**
  163 + * 可用佣金
  164 + */
  165 + @TableField(exist = false) // TODO 芋艿:避免报错
  166 + private Integer brokeragePrice;
  167 + /**
  168 + * 冻结佣金
  169 + */
  170 + @TableField(exist = false) // TODO 芋艿:避免报错
  171 + private Integer frozenBrokeragePrice;
  172 +
139 173 }
... ...
yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/dal/mysql/address/AddressMapper.java renamed to yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/dal/mysql/address/MemberAddressMapper.java
... ... @@ -8,7 +8,7 @@ import org.apache.ibatis.annotations.Mapper;
8 8 import java.util.List;
9 9  
10 10 @Mapper
11   -public interface AddressMapper extends BaseMapperX<MemberAddressDO> {
  11 +public interface MemberAddressMapper extends BaseMapperX<MemberAddressDO> {
12 12  
13 13 default MemberAddressDO selectByIdAndUserId(Long id, Long userId) {
14 14 return selectOne(MemberAddressDO::getId, id, MemberAddressDO::getUserId, userId);
... ...
yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/service/address/AddressServiceImpl.java
... ... @@ -5,7 +5,7 @@ import cn.iocoder.yudao.module.member.controller.app.address.vo.AppAddressCreate
5 5 import cn.iocoder.yudao.module.member.controller.app.address.vo.AppAddressUpdateReqVO;
6 6 import cn.iocoder.yudao.module.member.convert.address.AddressConvert;
7 7 import cn.iocoder.yudao.module.member.dal.dataobject.address.MemberAddressDO;
8   -import cn.iocoder.yudao.module.member.dal.mysql.address.AddressMapper;
  8 +import cn.iocoder.yudao.module.member.dal.mysql.address.MemberAddressMapper;
9 9 import org.springframework.stereotype.Service;
10 10 import org.springframework.transaction.annotation.Transactional;
11 11 import org.springframework.validation.annotation.Validated;
... ... @@ -26,21 +26,21 @@ import static cn.iocoder.yudao.module.member.enums.ErrorCodeConstants.ADDRESS_NO
26 26 public class AddressServiceImpl implements AddressService {
27 27  
28 28 @Resource
29   - private AddressMapper addressMapper;
  29 + private MemberAddressMapper memberAddressMapper;
30 30  
31 31 @Override
32 32 @Transactional(rollbackFor = Exception.class)
33 33 public Long createAddress(Long userId, AppAddressCreateReqVO createReqVO) {
34 34 // 如果添加的是默认收件地址,则将原默认地址修改为非默认
35 35 if (Boolean.TRUE.equals(createReqVO.getDefaultStatus())) {
36   - List<MemberAddressDO> addresses = addressMapper.selectListByUserIdAndDefaulted(userId, true);
37   - addresses.forEach(address -> addressMapper.updateById(new MemberAddressDO().setId(address.getId()).setDefaultStatus(false)));
  36 + List<MemberAddressDO> addresses = memberAddressMapper.selectListByUserIdAndDefaulted(userId, true);
  37 + addresses.forEach(address -> memberAddressMapper.updateById(new MemberAddressDO().setId(address.getId()).setDefaultStatus(false)));
38 38 }
39 39  
40 40 // 插入
41 41 MemberAddressDO address = AddressConvert.INSTANCE.convert(createReqVO);
42 42 address.setUserId(userId);
43   - addressMapper.insert(address);
  43 + memberAddressMapper.insert(address);
44 44 // 返回
45 45 return address.getId();
46 46 }
... ... @@ -53,14 +53,14 @@ public class AddressServiceImpl implements AddressService {
53 53  
54 54 // 如果修改的是默认收件地址,则将原默认地址修改为非默认
55 55 if (Boolean.TRUE.equals(updateReqVO.getDefaultStatus())) {
56   - List<MemberAddressDO> addresses = addressMapper.selectListByUserIdAndDefaulted(userId, true);
  56 + List<MemberAddressDO> addresses = memberAddressMapper.selectListByUserIdAndDefaulted(userId, true);
57 57 addresses.stream().filter(u -> !u.getId().equals(updateReqVO.getId())) // 排除自己
58   - .forEach(address -> addressMapper.updateById(new MemberAddressDO().setId(address.getId()).setDefaultStatus(false)));
  58 + .forEach(address -> memberAddressMapper.updateById(new MemberAddressDO().setId(address.getId()).setDefaultStatus(false)));
59 59 }
60 60  
61 61 // 更新
62 62 MemberAddressDO updateObj = AddressConvert.INSTANCE.convert(updateReqVO);
63   - addressMapper.updateById(updateObj);
  63 + memberAddressMapper.updateById(updateObj);
64 64 }
65 65  
66 66 @Override
... ... @@ -68,7 +68,7 @@ public class AddressServiceImpl implements AddressService {
68 68 // 校验存在,校验是否能够操作
69 69 validAddressExists(userId, id);
70 70 // 删除
71   - addressMapper.deleteById(id);
  71 + memberAddressMapper.deleteById(id);
72 72 }
73 73  
74 74 private void validAddressExists(Long userId, Long id) {
... ... @@ -80,17 +80,17 @@ public class AddressServiceImpl implements AddressService {
80 80  
81 81 @Override
82 82 public MemberAddressDO getAddress(Long userId, Long id) {
83   - return addressMapper.selectByIdAndUserId(id, userId);
  83 + return memberAddressMapper.selectByIdAndUserId(id, userId);
84 84 }
85 85  
86 86 @Override
87 87 public List<MemberAddressDO> getAddressList(Long userId) {
88   - return addressMapper.selectListByUserIdAndDefaulted(userId, null);
  88 + return memberAddressMapper.selectListByUserIdAndDefaulted(userId, null);
89 89 }
90 90  
91 91 @Override
92 92 public MemberAddressDO getDefaultUserAddress(Long userId) {
93   - List<MemberAddressDO> addresses = addressMapper.selectListByUserIdAndDefaulted(userId, true);
  93 + List<MemberAddressDO> addresses = memberAddressMapper.selectListByUserIdAndDefaulted(userId, true);
94 94 return CollUtil.getFirst(addresses);
95 95 }
96 96  
... ...
yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/service/group/MemberGroupServiceImpl.java
... ... @@ -31,7 +31,8 @@ import static cn.iocoder.yudao.module.member.enums.ErrorCodeConstants.GROUP_NOT_
31 31 public class MemberGroupServiceImpl implements MemberGroupService {
32 32  
33 33 @Resource
34   - private MemberGroupMapper groupMapper;
  34 + private MemberGroupMapper memberGroupMapper;
  35 +
35 36 @Resource
36 37 private MemberUserService memberUserService;
37 38  
... ... @@ -39,7 +40,7 @@ public class MemberGroupServiceImpl implements MemberGroupService {
39 40 public Long createGroup(MemberGroupCreateReqVO createReqVO) {
40 41 // 插入
41 42 MemberGroupDO group = MemberGroupConvert.INSTANCE.convert(createReqVO);
42   - groupMapper.insert(group);
  43 + memberGroupMapper.insert(group);
43 44 // 返回
44 45 return group.getId();
45 46 }
... ... @@ -50,7 +51,7 @@ public class MemberGroupServiceImpl implements MemberGroupService {
50 51 validateGroupExists(updateReqVO.getId());
51 52 // 更新
52 53 MemberGroupDO updateObj = MemberGroupConvert.INSTANCE.convert(updateReqVO);
53   - groupMapper.updateById(updateObj);
  54 + memberGroupMapper.updateById(updateObj);
54 55 }
55 56  
56 57 @Override
... ... @@ -60,11 +61,11 @@ public class MemberGroupServiceImpl implements MemberGroupService {
60 61 // 校验分组下是否有用户
61 62 validateGroupHasUser(id);
62 63 // 删除
63   - groupMapper.deleteById(id);
  64 + memberGroupMapper.deleteById(id);
64 65 }
65 66  
66 67 void validateGroupExists(Long id) {
67   - if (groupMapper.selectById(id) == null) {
  68 + if (memberGroupMapper.selectById(id) == null) {
68 69 throw exception(GROUP_NOT_EXISTS);
69 70 }
70 71 }
... ... @@ -78,7 +79,7 @@ public class MemberGroupServiceImpl implements MemberGroupService {
78 79  
79 80 @Override
80 81 public MemberGroupDO getGroup(Long id) {
81   - return groupMapper.selectById(id);
  82 + return memberGroupMapper.selectById(id);
82 83 }
83 84  
84 85 @Override
... ... @@ -86,17 +87,17 @@ public class MemberGroupServiceImpl implements MemberGroupService {
86 87 if (CollUtil.isEmpty(ids)) {
87 88 return ListUtil.empty();
88 89 }
89   - return groupMapper.selectBatchIds(ids);
  90 + return memberGroupMapper.selectBatchIds(ids);
90 91 }
91 92  
92 93 @Override
93 94 public PageResult<MemberGroupDO> getGroupPage(MemberGroupPageReqVO pageReqVO) {
94   - return groupMapper.selectPage(pageReqVO);
  95 + return memberGroupMapper.selectPage(pageReqVO);
95 96 }
96 97  
97 98 @Override
98 99 public List<MemberGroupDO> getGroupListByStatus(Integer status) {
99   - return groupMapper.selectListByStatus(status);
  100 + return memberGroupMapper.selectListByStatus(status);
100 101 }
101 102  
102 103 }
... ...
yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/service/level/MemberLevelServiceImpl.java
... ... @@ -42,7 +42,8 @@ import static cn.iocoder.yudao.module.member.enums.ErrorCodeConstants.*;
42 42 public class MemberLevelServiceImpl implements MemberLevelService {
43 43  
44 44 @Resource
45   - private MemberLevelMapper levelMapper;
  45 + private MemberLevelMapper memberLevelMapper;
  46 +
46 47 @Resource
47 48 private MemberLevelRecordService memberLevelRecordService;
48 49 @Resource
... ... @@ -57,7 +58,7 @@ public class MemberLevelServiceImpl implements MemberLevelService {
57 58  
58 59 // 插入
59 60 MemberLevelDO level = MemberLevelConvert.INSTANCE.convert(createReqVO);
60   - levelMapper.insert(level);
  61 + memberLevelMapper.insert(level);
61 62 // 返回
62 63 return level.getId();
63 64 }
... ... @@ -71,7 +72,7 @@ public class MemberLevelServiceImpl implements MemberLevelService {
71 72  
72 73 // 更新
73 74 MemberLevelDO updateObj = MemberLevelConvert.INSTANCE.convert(updateReqVO);
74   - levelMapper.updateById(updateObj);
  75 + memberLevelMapper.updateById(updateObj);
75 76 }
76 77  
77 78 @Override
... ... @@ -81,12 +82,12 @@ public class MemberLevelServiceImpl implements MemberLevelService {
81 82 // 校验分组下是否有用户
82 83 validateLevelHasUser(id);
83 84 // 删除
84   - levelMapper.deleteById(id);
  85 + memberLevelMapper.deleteById(id);
85 86 }
86 87  
87 88 @VisibleForTesting
88 89 MemberLevelDO validateLevelExists(Long id) {
89   - MemberLevelDO levelDO = levelMapper.selectById(id);
  90 + MemberLevelDO levelDO = memberLevelMapper.selectById(id);
90 91 if (levelDO == null) {
91 92 throw exception(LEVEL_NOT_EXISTS);
92 93 }
... ... @@ -141,7 +142,7 @@ public class MemberLevelServiceImpl implements MemberLevelService {
141 142  
142 143 @VisibleForTesting
143 144 void validateConfigValid(Long id, String name, Integer level, Integer experience) {
144   - List<MemberLevelDO> list = levelMapper.selectList();
  145 + List<MemberLevelDO> list = memberLevelMapper.selectList();
145 146 // 校验名称唯一
146 147 validateNameUnique(list, id, name);
147 148 // 校验等级唯一
... ... @@ -160,7 +161,7 @@ public class MemberLevelServiceImpl implements MemberLevelService {
160 161  
161 162 @Override
162 163 public MemberLevelDO getLevel(Long id) {
163   - return id != null && id > 0 ? levelMapper.selectById(id) : null;
  164 + return id != null && id > 0 ? memberLevelMapper.selectById(id) : null;
164 165 }
165 166  
166 167 @Override
... ... @@ -168,17 +169,17 @@ public class MemberLevelServiceImpl implements MemberLevelService {
168 169 if (CollUtil.isEmpty(ids)) {
169 170 return Collections.emptyList();
170 171 }
171   - return levelMapper.selectBatchIds(ids);
  172 + return memberLevelMapper.selectBatchIds(ids);
172 173 }
173 174  
174 175 @Override
175 176 public List<MemberLevelDO> getLevelList(MemberLevelListReqVO listReqVO) {
176   - return levelMapper.selectList(listReqVO);
  177 + return memberLevelMapper.selectList(listReqVO);
177 178 }
178 179  
179 180 @Override
180 181 public List<MemberLevelDO> getLevelListByStatus(Integer status) {
181   - return levelMapper.selectListByStatus(status);
  182 + return memberLevelMapper.selectListByStatus(status);
182 183 }
183 184  
184 185 @Override
... ...
yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/service/point/MemberPointConfigServiceImpl.java
... ... @@ -21,23 +21,23 @@ import java.util.List;
21 21 public class MemberPointConfigServiceImpl implements MemberPointConfigService {
22 22  
23 23 @Resource
24   - private MemberPointConfigMapper pointConfigMapper;
  24 + private MemberPointConfigMapper memberPointConfigMapper;
25 25  
26 26 @Override
27 27 public void savePointConfig(MemberPointConfigSaveReqVO saveReqVO) {
28 28 // 存在,则进行更新
29 29 MemberPointConfigDO dbConfig = getPointConfig();
30 30 if (dbConfig != null) {
31   - pointConfigMapper.updateById(MemberPointConfigConvert.INSTANCE.convert(saveReqVO).setId(dbConfig.getId()));
  31 + memberPointConfigMapper.updateById(MemberPointConfigConvert.INSTANCE.convert(saveReqVO).setId(dbConfig.getId()));
32 32 return;
33 33 }
34 34 // 不存在,则进行插入
35   - pointConfigMapper.insert(MemberPointConfigConvert.INSTANCE.convert(saveReqVO));
  35 + memberPointConfigMapper.insert(MemberPointConfigConvert.INSTANCE.convert(saveReqVO));
36 36 }
37 37  
38 38 @Override
39 39 public MemberPointConfigDO getPointConfig() {
40   - List<MemberPointConfigDO> list = pointConfigMapper.selectList();
  40 + List<MemberPointConfigDO> list = memberPointConfigMapper.selectList();
41 41 return CollectionUtils.getFirst(list);
42 42 }
43 43  
... ...
yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/service/point/MemberPointRecordServiceImpl.java
... ... @@ -35,7 +35,7 @@ import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.
35 35 public class MemberPointRecordServiceImpl implements MemberPointRecordService {
36 36  
37 37 @Resource
38   - private MemberPointRecordMapper recordMapper;
  38 + private MemberPointRecordMapper memberPointRecordMapper;
39 39 @Resource
40 40 private MemberPointConfigService memberPointConfigService;
41 41  
... ... @@ -55,12 +55,12 @@ public class MemberPointRecordServiceImpl implements MemberPointRecordService {
55 55 userIds = convertSet(users, MemberUserDO::getId);
56 56 }
57 57 // 执行查询
58   - return recordMapper.selectPage(pageReqVO, userIds);
  58 + return memberPointRecordMapper.selectPage(pageReqVO, userIds);
59 59 }
60 60  
61 61 @Override
62 62 public PageResult<MemberPointRecordDO> getPointRecordPage(Long userId, PageParam pageVO) {
63   - return recordMapper.selectPage(userId, pageVO);
  63 + return memberPointRecordMapper.selectPage(userId, pageVO);
64 64 }
65 65  
66 66 @Override
... ... @@ -86,7 +86,7 @@ public class MemberPointRecordServiceImpl implements MemberPointRecordService {
86 86 .setUserId(userId).setBizId(bizId).setBizType(bizType.getType())
87 87 .setTitle(bizType.getName()).setDescription(StrUtil.format(bizType.getDescription(), point))
88 88 .setPoint(point).setTotalPoint(totalPoint);
89   - recordMapper.insert(record);
  89 + memberPointRecordMapper.insert(record);
90 90  
91 91 // 3. 更新用户积分
92 92 memberUserService.updateUserPoint(userId, totalPoint);
... ...
yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/service/signin/MemberSignInConfigServiceImpl.java
... ... @@ -26,7 +26,7 @@ import static cn.iocoder.yudao.module.member.enums.ErrorCodeConstants.SIGN_IN_CO
26 26 public class MemberSignInConfigServiceImpl implements MemberSignInConfigService {
27 27  
28 28 @Resource
29   - private MemberSignInConfigMapper signInConfigMapper;
  29 + private MemberSignInConfigMapper memberSignInConfigMapper;
30 30  
31 31 @Override
32 32 public Long createSignInConfig(MemberSignInConfigCreateReqVO createReqVO) {
... ... @@ -35,7 +35,7 @@ public class MemberSignInConfigServiceImpl implements MemberSignInConfigService
35 35  
36 36 // 插入
37 37 MemberSignInConfigDO signInConfig = MemberSignInConfigConvert.INSTANCE.convert(createReqVO);
38   - signInConfigMapper.insert(signInConfig);
  38 + memberSignInConfigMapper.insert(signInConfig);
39 39 // 返回
40 40 return signInConfig.getId();
41 41 }
... ... @@ -49,7 +49,7 @@ public class MemberSignInConfigServiceImpl implements MemberSignInConfigService
49 49  
50 50 // 判断更新
51 51 MemberSignInConfigDO updateObj = MemberSignInConfigConvert.INSTANCE.convert(updateReqVO);
52   - signInConfigMapper.updateById(updateObj);
  52 + memberSignInConfigMapper.updateById(updateObj);
53 53 }
54 54  
55 55 @Override
... ... @@ -57,11 +57,11 @@ public class MemberSignInConfigServiceImpl implements MemberSignInConfigService
57 57 // 校验存在
58 58 validateSignInConfigExists(id);
59 59 // 删除
60   - signInConfigMapper.deleteById(id);
  60 + memberSignInConfigMapper.deleteById(id);
61 61 }
62 62  
63 63 private void validateSignInConfigExists(Long id) {
64   - if (signInConfigMapper.selectById(id) == null) {
  64 + if (memberSignInConfigMapper.selectById(id) == null) {
65 65 throw exception(SIGN_IN_CONFIG_NOT_EXISTS);
66 66 }
67 67 }
... ... @@ -73,7 +73,7 @@ public class MemberSignInConfigServiceImpl implements MemberSignInConfigService
73 73 * @param id 编号,只有更新的时候会传递
74 74 */
75 75 private void validateSignInConfigDayDuplicate(Integer day, Long id) {
76   - MemberSignInConfigDO config = signInConfigMapper.selectByDay(day);
  76 + MemberSignInConfigDO config = memberSignInConfigMapper.selectByDay(day);
77 77 // 1. 新增时,config 非空,则说明重复
78 78 if (id == null && config != null) {
79 79 throw exception(SIGN_IN_CONFIG_EXISTS);
... ... @@ -86,19 +86,19 @@ public class MemberSignInConfigServiceImpl implements MemberSignInConfigService
86 86  
87 87 @Override
88 88 public MemberSignInConfigDO getSignInConfig(Long id) {
89   - return signInConfigMapper.selectById(id);
  89 + return memberSignInConfigMapper.selectById(id);
90 90 }
91 91  
92 92 @Override
93 93 public List <MemberSignInConfigDO> getSignInConfigList() {
94   - List<MemberSignInConfigDO> list = signInConfigMapper.selectList();
  94 + List<MemberSignInConfigDO> list = memberSignInConfigMapper.selectList();
95 95 list.sort(Comparator.comparing(MemberSignInConfigDO::getDay));
96 96 return list;
97 97 }
98 98  
99 99 @Override
100 100 public List<MemberSignInConfigDO> getSignInConfigList(Integer status) {
101   - List<MemberSignInConfigDO> list = signInConfigMapper.selectListByStatus(status);
  101 + List<MemberSignInConfigDO> list = memberSignInConfigMapper.selectListByStatus(status);
102 102 list.sort(Comparator.comparing(MemberSignInConfigDO::getDay));
103 103 return list;
104 104 }
... ...
yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/service/signin/MemberSignInRecordServiceImpl.java
... ... @@ -28,7 +28,7 @@ import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.
28 28 public class MemberSignInRecordServiceImpl implements MemberSignInRecordService {
29 29  
30 30 @Resource
31   - private MemberSignInRecordMapper signInRecordMapper;
  31 + private MemberSignInRecordMapper memberSignInRecordMapper;
32 32  
33 33 @Resource
34 34 private MemberUserApi memberUserApi;
... ... @@ -46,12 +46,12 @@ public class MemberSignInRecordServiceImpl implements MemberSignInRecordService
46 46 userIds = convertSet(users, MemberUserRespDTO::getId);
47 47 }
48 48 // 分页查询
49   - return signInRecordMapper.selectPage(pageReqVO, userIds);
  49 + return memberSignInRecordMapper.selectPage(pageReqVO, userIds);
50 50 }
51 51  
52 52 @Override
53 53 public PageResult<MemberSignInRecordDO> getSignRecordPage(Long userId, PageParam pageParam) {
54   - return signInRecordMapper.selectPage(userId, pageParam);
  54 + return memberSignInRecordMapper.selectPage(userId, pageParam);
55 55 }
56 56  
57 57 }
... ...
yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/service/tag/MemberTagServiceImpl.java
... ... @@ -31,7 +31,8 @@ import static cn.iocoder.yudao.module.member.enums.ErrorCodeConstants.*;
31 31 public class MemberTagServiceImpl implements MemberTagService {
32 32  
33 33 @Resource
34   - private MemberTagMapper tagMapper;
  34 + private MemberTagMapper memberTagMapper;
  35 +
35 36 @Resource
36 37 private MemberUserService memberUserService;
37 38  
... ... @@ -41,7 +42,7 @@ public class MemberTagServiceImpl implements MemberTagService {
41 42 validateTagNameUnique(null, createReqVO.getName());
42 43 // 插入
43 44 MemberTagDO tag = MemberTagConvert.INSTANCE.convert(createReqVO);
44   - tagMapper.insert(tag);
  45 + memberTagMapper.insert(tag);
45 46 // 返回
46 47 return tag.getId();
47 48 }
... ... @@ -54,7 +55,7 @@ public class MemberTagServiceImpl implements MemberTagService {
54 55 validateTagNameUnique(updateReqVO.getId(), updateReqVO.getName());
55 56 // 更新
56 57 MemberTagDO updateObj = MemberTagConvert.INSTANCE.convert(updateReqVO);
57   - tagMapper.updateById(updateObj);
  58 + memberTagMapper.updateById(updateObj);
58 59 }
59 60  
60 61 @Override
... ... @@ -64,11 +65,11 @@ public class MemberTagServiceImpl implements MemberTagService {
64 65 // 校验标签下是否有用户
65 66 validateTagHasUser(id);
66 67 // 删除
67   - tagMapper.deleteById(id);
  68 + memberTagMapper.deleteById(id);
68 69 }
69 70  
70 71 private void validateTagExists(Long id) {
71   - if (tagMapper.selectById(id) == null) {
  72 + if (memberTagMapper.selectById(id) == null) {
72 73 throw exception(TAG_NOT_EXISTS);
73 74 }
74 75 }
... ... @@ -77,7 +78,7 @@ public class MemberTagServiceImpl implements MemberTagService {
77 78 if (StrUtil.isBlank(name)) {
78 79 return;
79 80 }
80   - MemberTagDO tag = tagMapper.selelctByName(name);
  81 + MemberTagDO tag = memberTagMapper.selelctByName(name);
81 82 if (tag == null) {
82 83 return;
83 84 }
... ... @@ -100,7 +101,7 @@ public class MemberTagServiceImpl implements MemberTagService {
100 101  
101 102 @Override
102 103 public MemberTagDO getTag(Long id) {
103   - return tagMapper.selectById(id);
  104 + return memberTagMapper.selectById(id);
104 105 }
105 106  
106 107 @Override
... ... @@ -108,17 +109,17 @@ public class MemberTagServiceImpl implements MemberTagService {
108 109 if (CollUtil.isEmpty(ids)) {
109 110 return ListUtil.empty();
110 111 }
111   - return tagMapper.selectBatchIds(ids);
  112 + return memberTagMapper.selectBatchIds(ids);
112 113 }
113 114  
114 115 @Override
115 116 public PageResult<MemberTagDO> getTagPage(MemberTagPageReqVO pageReqVO) {
116   - return tagMapper.selectPage(pageReqVO);
  117 + return memberTagMapper.selectPage(pageReqVO);
117 118 }
118 119  
119 120 @Override
120 121 public List<MemberTagDO> getTagList() {
121   - return tagMapper.selectList();
  122 + return memberTagMapper.selectList();
122 123 }
123 124  
124 125 }
... ...
yudao-module-member/yudao-module-member-biz/src/test/java/cn/iocoder/yudao/module/member/service/address/AddressServiceImplTest.java
... ... @@ -4,7 +4,7 @@ import cn.iocoder.yudao.framework.test.core.ut.BaseDbUnitTest;
4 4 import cn.iocoder.yudao.module.member.controller.app.address.vo.AppAddressCreateReqVO;
5 5 import cn.iocoder.yudao.module.member.controller.app.address.vo.AppAddressUpdateReqVO;
6 6 import cn.iocoder.yudao.module.member.dal.dataobject.address.MemberAddressDO;
7   -import cn.iocoder.yudao.module.member.dal.mysql.address.AddressMapper;
  7 +import cn.iocoder.yudao.module.member.dal.mysql.address.MemberAddressMapper;
8 8 import org.junit.jupiter.api.Test;
9 9 import org.springframework.context.annotation.Import;
10 10  
... ... @@ -30,7 +30,7 @@ public class AddressServiceImplTest extends BaseDbUnitTest {
30 30 private AddressServiceImpl addressService;
31 31  
32 32 @Resource
33   - private AddressMapper addressMapper;
  33 + private MemberAddressMapper addressMapper;
34 34  
35 35 @Test
36 36 public void testCreateAddress_success() {
... ...
yudao-module-member/yudao-module-member-biz/src/test/java/cn/iocoder/yudao/module/member/service/group/MemberGroupServiceImplTest.java
1 1 package cn.iocoder.yudao.module.member.service.group;
2 2  
3   -import cn.hutool.core.util.RandomUtil;
4 3 import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
5 4 import cn.iocoder.yudao.framework.common.pojo.PageResult;
6 5 import cn.iocoder.yudao.framework.test.core.ut.BaseDbUnitTest;
... ... @@ -8,11 +7,10 @@ import cn.iocoder.yudao.module.member.controller.admin.group.vo.MemberGroupCreat
8 7 import cn.iocoder.yudao.module.member.controller.admin.group.vo.MemberGroupPageReqVO;
9 8 import cn.iocoder.yudao.module.member.controller.admin.group.vo.MemberGroupUpdateReqVO;
10 9 import cn.iocoder.yudao.module.member.dal.dataobject.group.MemberGroupDO;
11   -import cn.iocoder.yudao.module.member.dal.dataobject.user.MemberUserDO;
12 10 import cn.iocoder.yudao.module.member.dal.mysql.group.MemberGroupMapper;
13   -import cn.iocoder.yudao.module.member.dal.mysql.user.MemberUserMapper;
14   -import cn.iocoder.yudao.module.system.enums.common.SexEnum;
  11 +import cn.iocoder.yudao.module.member.service.user.MemberUserService;
15 12 import org.junit.jupiter.api.Test;
  13 +import org.springframework.boot.test.mock.mockito.MockBean;
16 14 import org.springframework.context.annotation.Import;
17 15  
18 16 import javax.annotation.Resource;
... ... @@ -26,7 +24,10 @@ import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.*;
26 24 import static cn.iocoder.yudao.module.member.enums.ErrorCodeConstants.GROUP_HAS_USER;
27 25 import static cn.iocoder.yudao.module.member.enums.ErrorCodeConstants.GROUP_NOT_EXISTS;
28 26 import static org.junit.jupiter.api.Assertions.*;
  27 +import static org.mockito.ArgumentMatchers.eq;
  28 +import static org.mockito.Mockito.when;
29 29  
  30 +// TODO 芋艿:完全 review 完,在去 review 单测
30 31 /**
31 32 * {@link MemberGroupServiceImpl} 的单元测试类
32 33 *
... ... @@ -40,13 +41,15 @@ public class MemberGroupServiceImplTest extends BaseDbUnitTest {
40 41  
41 42 @Resource
42 43 private MemberGroupMapper groupMapper;
43   - @Resource
44   - private MemberUserMapper memberUserMapper;
  44 +
  45 + @MockBean
  46 + private MemberUserService memberUserService;
45 47  
46 48 @Test
47 49 public void testCreateGroup_success() {
48 50 // 准备参数
49   - MemberGroupCreateReqVO reqVO = randomPojo(MemberGroupCreateReqVO.class);
  51 + MemberGroupCreateReqVO reqVO = randomPojo(MemberGroupCreateReqVO.class,
  52 + o -> o.setStatus(randomCommonStatus()));
50 53  
51 54 // 调用
52 55 Long groupId = groupService.createGroup(reqVO);
... ... @@ -65,6 +68,7 @@ public class MemberGroupServiceImplTest extends BaseDbUnitTest {
65 68 // 准备参数
66 69 MemberGroupUpdateReqVO reqVO = randomPojo(MemberGroupUpdateReqVO.class, o -> {
67 70 o.setId(dbGroup.getId()); // 设置更新的 ID
  71 + o.setStatus(randomCommonStatus());
68 72 });
69 73  
70 74 // 调用
... ... @@ -115,11 +119,7 @@ public class MemberGroupServiceImplTest extends BaseDbUnitTest {
115 119 Long id = dbGroup.getId();
116 120  
117 121 // mock 会员数据
118   - MemberUserDO dbUser = randomPojo(MemberUserDO.class, o -> {
119   - o.setGroupId(id);
120   - o.setSex(RandomUtil.randomEle(SexEnum.values()).getSex());
121   - });
122   - memberUserMapper.insert(dbUser);
  122 + when(memberUserService.getUserCountByGroupId(eq(id))).thenReturn(1L);
123 123  
124 124 // 调用, 并断言异常
125 125 assertServiceException(() -> groupService.deleteGroup(id), GROUP_HAS_USER);
... ...
yudao-module-member/yudao-module-member-biz/src/test/java/cn/iocoder/yudao/module/member/service/level/MemberLevelServiceImplTest.java
1 1 package cn.iocoder.yudao.module.member.service.level;
2 2  
3 3 import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
4   -import cn.iocoder.yudao.framework.common.pojo.PageResult;
5 4 import cn.iocoder.yudao.framework.common.util.collection.ArrayUtils;
6 5 import cn.iocoder.yudao.framework.test.core.ut.BaseDbUnitTest;
7 6 import cn.iocoder.yudao.module.member.controller.admin.level.vo.level.MemberLevelCreateReqVO;
... ... @@ -9,6 +8,7 @@ import cn.iocoder.yudao.module.member.controller.admin.level.vo.level.MemberLeve
9 8 import cn.iocoder.yudao.module.member.controller.admin.level.vo.level.MemberLevelUpdateReqVO;
10 9 import cn.iocoder.yudao.module.member.dal.dataobject.level.MemberLevelDO;
11 10 import cn.iocoder.yudao.module.member.dal.mysql.level.MemberLevelMapper;
  11 +import cn.iocoder.yudao.module.member.service.user.MemberUserService;
12 12 import org.junit.jupiter.api.Test;
13 13 import org.springframework.boot.test.mock.mockito.MockBean;
14 14 import org.springframework.context.annotation.Import;
... ... @@ -38,12 +38,14 @@ public class MemberLevelServiceImplTest extends BaseDbUnitTest {
38 38 private MemberLevelServiceImpl levelService;
39 39  
40 40 @Resource
41   - private MemberLevelMapper levelMapper;
  41 + private MemberLevelMapper memberlevelMapper;
42 42  
43 43 @MockBean
44 44 private MemberLevelRecordService memberLevelRecordService;
45 45 @MockBean
46 46 private MemberExperienceRecordService memberExperienceRecordService;
  47 + @MockBean
  48 + private MemberUserService memberUserService;
47 49  
48 50 @Test
49 51 public void testCreateLevel_success() {
... ... @@ -52,6 +54,7 @@ public class MemberLevelServiceImplTest extends BaseDbUnitTest {
52 54 o.setDiscountPercent(randomInt());
53 55 o.setIcon(randomURL());
54 56 o.setBackgroundUrl(randomURL());
  57 + o.setStatus(randomCommonStatus());
55 58 });
56 59  
57 60 // 调用
... ... @@ -59,7 +62,7 @@ public class MemberLevelServiceImplTest extends BaseDbUnitTest {
59 62 // 断言
60 63 assertNotNull(levelId);
61 64 // 校验记录的属性是否正确
62   - MemberLevelDO level = levelMapper.selectById(levelId);
  65 + MemberLevelDO level = memberlevelMapper.selectById(levelId);
63 66 assertPojoEquals(reqVO, level);
64 67 }
65 68  
... ... @@ -67,7 +70,7 @@ public class MemberLevelServiceImplTest extends BaseDbUnitTest {
67 70 public void testUpdateLevel_success() {
68 71 // mock 数据
69 72 MemberLevelDO dbLevel = randomPojo(MemberLevelDO.class);
70   - levelMapper.insert(dbLevel);// @Sql: 先插入出一条存在的数据
  73 + memberlevelMapper.insert(dbLevel);// @Sql: 先插入出一条存在的数据
71 74 // 准备参数
72 75 MemberLevelUpdateReqVO reqVO = randomPojo(MemberLevelUpdateReqVO.class, o -> {
73 76 o.setId(dbLevel.getId()); // 设置更新的 ID
... ... @@ -79,12 +82,13 @@ public class MemberLevelServiceImplTest extends BaseDbUnitTest {
79 82 o.setDiscountPercent(randomInt());
80 83 o.setIcon(randomURL());
81 84 o.setBackgroundUrl(randomURL());
  85 + o.setStatus(randomCommonStatus());
82 86 });
83 87  
84 88 // 调用
85 89 levelService.updateLevel(reqVO);
86 90 // 校验是否更新正确
87   - MemberLevelDO level = levelMapper.selectById(reqVO.getId()); // 获取最新的
  91 + MemberLevelDO level = memberlevelMapper.selectById(reqVO.getId()); // 获取最新的
88 92 assertPojoEquals(reqVO, level);
89 93 }
90 94  
... ... @@ -101,14 +105,14 @@ public class MemberLevelServiceImplTest extends BaseDbUnitTest {
101 105 public void testDeleteLevel_success() {
102 106 // mock 数据
103 107 MemberLevelDO dbLevel = randomPojo(MemberLevelDO.class);
104   - levelMapper.insert(dbLevel);// @Sql: 先插入出一条存在的数据
  108 + memberlevelMapper.insert(dbLevel);// @Sql: 先插入出一条存在的数据
105 109 // 准备参数
106 110 Long id = dbLevel.getId();
107 111  
108 112 // 调用
109 113 levelService.deleteLevel(id);
110 114 // 校验数据不存在了
111   - assertNull(levelMapper.selectById(id));
  115 + assertNull(memberlevelMapper.selectById(id));
112 116 }
113 117  
114 118 @Test
... ... @@ -127,11 +131,11 @@ public class MemberLevelServiceImplTest extends BaseDbUnitTest {
127 131 o.setName("黄金会员");
128 132 o.setStatus(1);
129 133 });
130   - levelMapper.insert(dbLevel);
  134 + memberlevelMapper.insert(dbLevel);
131 135 // 测试 name 不匹配
132   - levelMapper.insert(cloneIgnoreId(dbLevel, o -> o.setName("")));
  136 + memberlevelMapper.insert(cloneIgnoreId(dbLevel, o -> o.setName("")));
133 137 // 测试 status 不匹配
134   - levelMapper.insert(cloneIgnoreId(dbLevel, o -> o.setStatus(0)));
  138 + memberlevelMapper.insert(cloneIgnoreId(dbLevel, o -> o.setStatus(0)));
135 139 // 准备参数
136 140 MemberLevelListReqVO reqVO = new MemberLevelListReqVO();
137 141 reqVO.setName("黄金会员");
... ... @@ -150,10 +154,10 @@ public class MemberLevelServiceImplTest extends BaseDbUnitTest {
150 154 String name = randomString();
151 155  
152 156 // mock 数据
153   - levelMapper.insert(randomLevelDO(o -> o.setName(name)));
  157 + memberlevelMapper.insert(randomLevelDO(o -> o.setName(name)));
154 158  
155 159 // 调用,校验异常
156   - List<MemberLevelDO> list = levelMapper.selectList();
  160 + List<MemberLevelDO> list = memberlevelMapper.selectList();
157 161 assertServiceException(() -> levelService.validateNameUnique(list, null, name), LEVEL_NAME_EXISTS, name);
158 162 }
159 163  
... ... @@ -164,10 +168,10 @@ public class MemberLevelServiceImplTest extends BaseDbUnitTest {
164 168 String name = randomString();
165 169  
166 170 // mock 数据
167   - levelMapper.insert(randomLevelDO(o -> o.setName(name)));
  171 + memberlevelMapper.insert(randomLevelDO(o -> o.setName(name)));
168 172  
169 173 // 调用,校验异常
170   - List<MemberLevelDO> list = levelMapper.selectList();
  174 + List<MemberLevelDO> list = memberlevelMapper.selectList();
171 175 assertServiceException(() -> levelService.validateNameUnique(list, id, name), LEVEL_NAME_EXISTS, name);
172 176 }
173 177  
... ... @@ -178,13 +182,13 @@ public class MemberLevelServiceImplTest extends BaseDbUnitTest {
178 182 String name = randomString();
179 183  
180 184 // mock 数据
181   - levelMapper.insert(randomLevelDO(o -> {
  185 + memberlevelMapper.insert(randomLevelDO(o -> {
182 186 o.setLevel(level);
183 187 o.setName(name);
184 188 }));
185 189  
186 190 // 调用,校验异常
187   - List<MemberLevelDO> list = levelMapper.selectList();
  191 + List<MemberLevelDO> list = memberlevelMapper.selectList();
188 192 assertServiceException(() -> levelService.validateLevelUnique(list, null, level), LEVEL_VALUE_EXISTS, level, name);
189 193 }
190 194  
... ... @@ -196,13 +200,13 @@ public class MemberLevelServiceImplTest extends BaseDbUnitTest {
196 200 String name = randomString();
197 201  
198 202 // mock 数据
199   - levelMapper.insert(randomLevelDO(o -> {
  203 + memberlevelMapper.insert(randomLevelDO(o -> {
200 204 o.setLevel(level);
201 205 o.setName(name);
202 206 }));
203 207  
204 208 // 调用,校验异常
205   - List<MemberLevelDO> list = levelMapper.selectList();
  209 + List<MemberLevelDO> list = memberlevelMapper.selectList();
206 210 assertServiceException(() -> levelService.validateLevelUnique(list, id, level), LEVEL_VALUE_EXISTS, level, name);
207 211 }
208 212  
... ... @@ -214,12 +218,12 @@ public class MemberLevelServiceImplTest extends BaseDbUnitTest {
214 218 String name = randomString();
215 219  
216 220 // mock 数据
217   - levelMapper.insert(randomLevelDO(o -> {
  221 + memberlevelMapper.insert(randomLevelDO(o -> {
218 222 o.setLevel(level);
219 223 o.setExperience(experience);
220 224 o.setName(name);
221 225 }));
222   - List<MemberLevelDO> list = levelMapper.selectList();
  226 + List<MemberLevelDO> list = memberlevelMapper.selectList();
223 227  
224 228 // 调用,校验异常
225 229 assertServiceException(() -> levelService.validateExperienceOutRange(list, null, level + 1, experience - 1), LEVEL_EXPERIENCE_MIN, name, level);
... ... @@ -236,12 +240,12 @@ public class MemberLevelServiceImplTest extends BaseDbUnitTest {
236 240 String name = randomString();
237 241  
238 242 // mock 数据
239   - levelMapper.insert(randomLevelDO(o -> {
  243 + memberlevelMapper.insert(randomLevelDO(o -> {
240 244 o.setLevel(level);
241 245 o.setExperience(experience);
242 246 o.setName(name);
243 247 }));
244   - List<MemberLevelDO> list = levelMapper.selectList();
  248 + List<MemberLevelDO> list = memberlevelMapper.selectList();
245 249  
246 250 // 调用,校验异常
247 251 assertServiceException(() -> levelService.validateExperienceOutRange(list, id, level + 1, experience - 1), LEVEL_EXPERIENCE_MIN, name, level);
... ...
yudao-module-member/yudao-module-member-biz/src/test/java/cn/iocoder/yudao/module/member/service/tag/MemberTagServiceImplTest.java
... ... @@ -7,7 +7,9 @@ import cn.iocoder.yudao.module.member.controller.admin.tag.vo.MemberTagPageReqVO
7 7 import cn.iocoder.yudao.module.member.controller.admin.tag.vo.MemberTagUpdateReqVO;
8 8 import cn.iocoder.yudao.module.member.dal.dataobject.tag.MemberTagDO;
9 9 import cn.iocoder.yudao.module.member.dal.mysql.tag.MemberTagMapper;
  10 +import cn.iocoder.yudao.module.member.service.user.MemberUserService;
10 11 import org.junit.jupiter.api.Test;
  12 +import org.springframework.boot.test.mock.mockito.MockBean;
11 13 import org.springframework.context.annotation.Import;
12 14  
13 15 import javax.annotation.Resource;
... ... @@ -22,6 +24,7 @@ import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.randomPojo;
22 24 import static cn.iocoder.yudao.module.member.enums.ErrorCodeConstants.TAG_NOT_EXISTS;
23 25 import static org.junit.jupiter.api.Assertions.*;
24 26  
  27 +// TODO 芋艿:完全 review 完,在去 review 单测
25 28 /**
26 29 * {@link MemberTagServiceImpl} 的单元测试类
27 30 *
... ... @@ -36,6 +39,9 @@ public class MemberTagServiceImplTest extends BaseDbUnitTest {
36 39 @Resource
37 40 private MemberTagMapper tagMapper;
38 41  
  42 + @MockBean
  43 + private MemberUserService memberUserService;
  44 +
39 45 @Test
40 46 public void testCreateTag_success() {
41 47 // 准备参数
... ...
yudao-module-member/yudao-module-member-biz/src/test/java/cn/iocoder/yudao/module/member/service/user/MemberUserServiceImplTest.java
... ... @@ -11,6 +11,7 @@ import cn.iocoder.yudao.module.member.dal.dataobject.user.MemberUserDO;
11 11 import cn.iocoder.yudao.module.member.dal.mysql.user.MemberUserMapper;
12 12 import cn.iocoder.yudao.module.member.service.auth.MemberAuthServiceImpl;
13 13 import cn.iocoder.yudao.module.system.api.sms.SmsCodeApi;
  14 +import org.junit.jupiter.api.Disabled;
14 15 import org.junit.jupiter.api.Test;
15 16 import org.springframework.boot.test.mock.mockito.MockBean;
16 17 import org.springframework.context.annotation.Import;
... ... @@ -92,6 +93,7 @@ public class MemberUserServiceImplTest extends BaseDbAndRedisUnitTest {
92 93 // }
93 94  
94 95 @Test
  96 + @Disabled // TODO 芋艿:后续再修复
95 97 public void updateMobile_success(){
96 98 // mock数据
97 99 String oldMobile = randomNumbers(11);
... ...
yudao-module-member/yudao-module-member-biz/src/test/resources/sql/create_tables.sql
... ... @@ -63,7 +63,7 @@ CREATE TABLE IF NOT EXISTS &quot;member_level&quot;
63 63 "name" varchar NOT NULL,
64 64 "experience" int NOT NULL,
65 65 "level" int NOT NULL,
66   - "discount" int NOT NULL,
  66 + "discount_percent" int NOT NULL,
67 67 "icon" varchar NOT NULL,
68 68 "background_url" varchar NOT NULL,
69 69 "creator" varchar DEFAULT '',
... ... @@ -72,7 +72,7 @@ CREATE TABLE IF NOT EXISTS &quot;member_level&quot;
72 72 "update_time" datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
73 73 "deleted" bit NOT NULL DEFAULT FALSE,
74 74 "tenant_id" bigint not null default '0',
75   - "status" int NOT NULL,
  75 + "status" tinyint NOT NULL DEFAULT '0',
76 76 PRIMARY KEY ("id")
77 77 ) COMMENT '会员等级';
78 78  
... ... @@ -81,7 +81,7 @@ CREATE TABLE IF NOT EXISTS &quot;member_group&quot;
81 81 "id" bigint NOT NULL GENERATED BY DEFAULT AS IDENTITY,
82 82 "name" varchar NOT NULL,
83 83 "remark" varchar NOT NULL,
84   - "status" varchar NOT NULL,
  84 + "status" tinyint NOT NULL DEFAULT '0',
85 85 "creator" varchar DEFAULT '',
86 86 "create_time" datetime NOT NULL DEFAULT CURRENT_TIMESTAMP,
87 87 "updater" varchar DEFAULT '',
... ... @@ -89,4 +89,25 @@ CREATE TABLE IF NOT EXISTS &quot;member_group&quot;
89 89 "deleted" bit NOT NULL DEFAULT FALSE,
90 90 "tenant_id" bigint not null default '0',
91 91 PRIMARY KEY ("id")
92   -) COMMENT '用户分组';
93 92 \ No newline at end of file
  93 +) COMMENT '用户分组';
  94 +CREATE TABLE IF NOT EXISTS "member_brokerage_record"
  95 +(
  96 + "id" int NOT NULL GENERATED BY DEFAULT AS IDENTITY,
  97 + "user_id" bigint NOT NULL,
  98 + "biz_id" varchar NOT NULL,
  99 + "biz_type" varchar NOT NULL,
  100 + "title" varchar NOT NULL,
  101 + "price" int NOT NULL,
  102 + "total_price" int NOT NULL,
  103 + "description" varchar NOT NULL,
  104 + "status" varchar NOT NULL,
  105 + "frozen_days" int NOT NULL,
  106 + "unfreeze_time" varchar,
  107 + "creator" varchar DEFAULT '',
  108 + "create_time" datetime NOT NULL DEFAULT CURRENT_TIMESTAMP,
  109 + "updater" varchar DEFAULT '',
  110 + "update_time" datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
  111 + "deleted" bit NOT NULL DEFAULT FALSE,
  112 + "tenant_id" bigint not null default '0',
  113 + PRIMARY KEY ("id")
  114 +) COMMENT '佣金记录';
... ...
yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/controller/admin/account/vo/MpAccountRespVO.java
... ... @@ -5,7 +5,7 @@ import lombok.Data;
5 5 import lombok.EqualsAndHashCode;
6 6 import lombok.ToString;
7 7  
8   -import java.util.Date;
  8 +import java.time.LocalDateTime;
9 9  
10 10 @Schema(description = "管理后台 - 公众号账号 Response VO")
11 11 @Data
... ... @@ -20,6 +20,6 @@ public class MpAccountRespVO extends MpAccountBaseVO {
20 20 private String qrCodeUrl;
21 21  
22 22 @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED)
23   - private Date createTime;
  23 + private LocalDateTime createTime;
24 24  
25 25 }
... ...
yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/controller/admin/material/vo/MpMaterialRespVO.java
... ... @@ -3,7 +3,7 @@ package cn.iocoder.yudao.module.mp.controller.admin.material.vo;
3 3 import io.swagger.v3.oas.annotations.media.Schema;
4 4 import lombok.Data;
5 5  
6   -import java.util.Date;
  6 +import java.time.LocalDateTime;
7 7  
8 8 @Schema(description = "管理后台 - 公众号素材 Response VO")
9 9 @Data
... ... @@ -42,6 +42,6 @@ public class MpMaterialRespVO {
42 42 private String introduction;
43 43  
44 44 @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED)
45   - private Date createTime;
  45 + private LocalDateTime createTime;
46 46  
47 47 }
... ...
yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/controller/admin/menu/vo/MpMenuRespVO.java
... ... @@ -5,7 +5,7 @@ import lombok.Data;
5 5 import lombok.EqualsAndHashCode;
6 6 import lombok.ToString;
7 7  
8   -import java.util.Date;
  8 +import java.time.LocalDateTime;
9 9  
10 10 @Schema(description = "管理后台 - 公众号菜单 Response VO")
11 11 @Data
... ... @@ -23,6 +23,6 @@ public class MpMenuRespVO extends MpMenuBaseVO {
23 23 private String appId;
24 24  
25 25 @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED)
26   - private Date createTime;
  26 + private LocalDateTime createTime;
27 27  
28 28 }
... ...
yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/controller/admin/message/vo/autoreply/MpAutoReplyRespVO.java
... ... @@ -5,7 +5,7 @@ import lombok.Data;
5 5 import lombok.EqualsAndHashCode;
6 6 import lombok.ToString;
7 7  
8   -import java.util.Date;
  8 +import java.time.LocalDateTime;
9 9  
10 10 @Schema(description = "管理后台 - 公众号自动回复 Response VO")
11 11 @Data
... ... @@ -22,6 +22,6 @@ public class MpAutoReplyRespVO extends MpAutoReplyBaseVO {
22 22 private String appId;
23 23  
24 24 @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED)
25   - private Date createTime;
  25 + private LocalDateTime createTime;
26 26  
27 27 }
... ...
yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/controller/admin/message/vo/message/MpMessageRespVO.java
... ... @@ -6,6 +6,7 @@ import io.swagger.v3.oas.annotations.media.Schema;
6 6 import lombok.Data;
7 7 import me.chanjar.weixin.common.api.WxConsts;
8 8  
  9 +import java.time.LocalDateTime;
9 10 import java.util.Date;
10 11 import java.util.List;
11 12  
... ... @@ -96,6 +97,6 @@ public class MpMessageRespVO {
96 97 private String eventKey;
97 98  
98 99 @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED)
99   - private Date createTime;
  100 + private LocalDateTime createTime;
100 101  
101 102 }
... ...
yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/controller/admin/statistics/vo/MpStatisticsInterfaceSummaryRespVO.java
... ... @@ -3,14 +3,14 @@ package cn.iocoder.yudao.module.mp.controller.admin.statistics.vo;
3 3 import io.swagger.v3.oas.annotations.media.Schema;
4 4 import lombok.Data;
5 5  
6   -import java.util.Date;
  6 +import java.time.LocalDateTime;
7 7  
8 8 @Schema(description = "管理后台 - 某一天的接口分析数据 Response VO")
9 9 @Data
10 10 public class MpStatisticsInterfaceSummaryRespVO {
11 11  
12 12 @Schema(description = "日期", requiredMode = Schema.RequiredMode.REQUIRED)
13   - private Date refDate;
  13 + private LocalDateTime refDate;
14 14  
15 15 @Schema(description = "通过服务器配置地址获得消息后,被动回复粉丝消息的次数", requiredMode = Schema.RequiredMode.REQUIRED, example = "10")
16 16 private Integer callbackCount;
... ...
yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/controller/admin/statistics/vo/MpStatisticsUpstreamMessageRespVO.java
... ... @@ -3,14 +3,14 @@ package cn.iocoder.yudao.module.mp.controller.admin.statistics.vo;
3 3 import io.swagger.v3.oas.annotations.media.Schema;
4 4 import lombok.Data;
5 5  
6   -import java.util.Date;
  6 +import java.time.LocalDateTime;
7 7  
8 8 @Schema(description = "管理后台 - 某一天的粉丝增减数据 Response VO")
9 9 @Data
10 10 public class MpStatisticsUpstreamMessageRespVO {
11 11  
12 12 @Schema(description = "日期", requiredMode = Schema.RequiredMode.REQUIRED)
13   - private Date refDate;
  13 + private LocalDateTime refDate;
14 14  
15 15 @Schema(description = "上行发送了(向公众号发送了)消息的粉丝数", requiredMode = Schema.RequiredMode.REQUIRED, example = "10")
16 16 private Integer messageUser;
... ...
yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/controller/admin/statistics/vo/MpStatisticsUserCumulateRespVO.java
... ... @@ -3,14 +3,14 @@ package cn.iocoder.yudao.module.mp.controller.admin.statistics.vo;
3 3 import io.swagger.v3.oas.annotations.media.Schema;
4 4 import lombok.Data;
5 5  
6   -import java.util.Date;
  6 +import java.time.LocalDateTime;
7 7  
8 8 @Schema(description = "管理后台 - 某一天的消息发送概况数据 Response VO")
9 9 @Data
10 10 public class MpStatisticsUserCumulateRespVO {
11 11  
12 12 @Schema(description = "日期", requiredMode = Schema.RequiredMode.REQUIRED)
13   - private Date refDate;
  13 + private LocalDateTime refDate;
14 14  
15 15 @Schema(description = "累计粉丝量", requiredMode = Schema.RequiredMode.REQUIRED, example = "10")
16 16 private Integer cumulateUser;
... ...
yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/controller/admin/statistics/vo/MpStatisticsUserSummaryRespVO.java
... ... @@ -3,14 +3,14 @@ package cn.iocoder.yudao.module.mp.controller.admin.statistics.vo;
3 3 import io.swagger.v3.oas.annotations.media.Schema;
4 4 import lombok.Data;
5 5  
6   -import java.util.Date;
  6 +import java.time.LocalDateTime;
7 7  
8 8 @Schema(description = "管理后台 - 某一天的粉丝增减数据 Response VO")
9 9 @Data
10 10 public class MpStatisticsUserSummaryRespVO {
11 11  
12 12 @Schema(description = "日期", requiredMode = Schema.RequiredMode.REQUIRED)
13   - private Date refDate;
  13 + private LocalDateTime refDate;
14 14  
15 15 @Schema(description = "粉丝来源", requiredMode = Schema.RequiredMode.REQUIRED, example = "0")
16 16 private Integer userSource;
... ...
yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/controller/admin/tag/vo/MpTagRespVO.java
... ... @@ -5,7 +5,7 @@ import lombok.Data;
5 5 import lombok.EqualsAndHashCode;
6 6 import lombok.ToString;
7 7  
8   -import java.util.Date;
  8 +import java.time.LocalDateTime;
9 9  
10 10 @Schema(description = "管理后台 - 公众号标签 Response VO")
11 11 @Data
... ... @@ -20,6 +20,6 @@ public class MpTagRespVO extends MpTagBaseVO {
20 20 private Integer count;
21 21  
22 22 @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED)
23   - private Date createTime;
  23 + private LocalDateTime createTime;
24 24  
25 25 }
... ...
yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/controller/admin/user/vo/MpUserRespVO.java
... ... @@ -48,6 +48,6 @@ public class MpUserRespVO {
48 48 private String appId;
49 49  
50 50 @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED)
51   - private Date createTime;
  51 + private LocalDateTime createTime;
52 52  
53 53 }
... ...
yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/convert/menu/MpMenuConvert.java
... ... @@ -40,6 +40,8 @@ public interface MpMenuConvert {
40 40 @Mappings({
41 41 @Mapping(source = "menuKey", target = "key"),
42 42 @Mapping(source = "children", target = "subButtons"),
  43 + @Mapping(source = "miniProgramAppId", target = "appId"),
  44 + @Mapping(source = "miniProgramPagePath", target = "pagePath"),
43 45 })
44 46 WxMenuButton convert(MpMenuSaveReqVO.Menu bean);
45 47  
... ...
yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/controller/admin/order/PayOrderController.java
... ... @@ -5,6 +5,8 @@ import cn.iocoder.yudao.framework.common.pojo.CommonResult;
5 5 import cn.iocoder.yudao.framework.common.pojo.PageResult;
6 6 import cn.iocoder.yudao.framework.excel.core.util.ExcelUtils;
7 7 import cn.iocoder.yudao.framework.operatelog.core.annotations.OperateLog;
  8 +import cn.iocoder.yudao.framework.pay.core.enums.channel.PayChannelEnum;
  9 +import cn.iocoder.yudao.framework.web.core.util.WebFrameworkUtils;
8 10 import cn.iocoder.yudao.module.pay.controller.admin.order.vo.*;
9 11 import cn.iocoder.yudao.module.pay.convert.order.PayOrderConvert;
10 12 import cn.iocoder.yudao.module.pay.dal.dataobject.app.PayAppDO;
... ... @@ -23,9 +25,7 @@ import javax.annotation.Resource;
23 25 import javax.servlet.http.HttpServletResponse;
24 26 import javax.validation.Valid;
25 27 import java.io.IOException;
26   -import java.util.ArrayList;
27   -import java.util.List;
28   -import java.util.Map;
  28 +import java.util.*;
29 29  
30 30 import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
31 31 import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertList;
... ... @@ -70,6 +70,13 @@ public class PayOrderController {
70 70 @PostMapping("/submit")
71 71 @Operation(summary = "提交支付订单")
72 72 public CommonResult<PayOrderSubmitRespVO> submitPayOrder(@RequestBody PayOrderSubmitReqVO reqVO) {
  73 + // 钱包支付需要 额外传 user_id 和 user_type
  74 + if (Objects.equals(reqVO.getChannelCode(), PayChannelEnum.WALLET.getCode())) {
  75 + Map<String, String> channelExtras = reqVO.getChannelExtras() == null ? new HashMap<>(8) : reqVO.getChannelExtras();
  76 + channelExtras.put("user_id", String.valueOf(WebFrameworkUtils.getLoginUserId()));
  77 + channelExtras.put("user_type", String.valueOf(WebFrameworkUtils.getLoginUserType()));
  78 + reqVO.setChannelExtras(channelExtras);
  79 + }
73 80 PayOrderSubmitRespVO respVO = orderService.submitOrder(reqVO, getClientIP());
74 81 return success(respVO);
75 82 }
... ...
yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/controller/app/wallet/AppPayWalletController.java
... ... @@ -37,7 +37,7 @@ public class AppPayWalletController {
37 37 @Operation(summary = "获取钱包")
38 38 @PreAuthenticated
39 39 public CommonResult<AppPayWalletRespVO> getPayWallet() {
40   - PayWalletDO wallet = payWalletService.getPayWallet(getLoginUserId(), UserTypeEnum.MEMBER.getValue());
  40 + PayWalletDO wallet = payWalletService.getOrCreatePayWallet(getLoginUserId(), UserTypeEnum.MEMBER.getValue());
41 41 return success(PayWalletConvert.INSTANCE.convert(wallet));
42 42 }
43 43  
... ...
yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/controller/app/wallet/vo/transaction/AppPayWalletTransactionRespVO.java
... ... @@ -15,9 +15,6 @@ public class AppPayWalletTransactionRespVO {
15 15 @Schema(description = "业务分类", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
16 16 private Integer bizType;
17 17  
18   - @Schema(description = "交易时间", requiredMode = Schema.RequiredMode.REQUIRED, example = "100")
19   - private LocalDateTime transactionTime;
20   -
21 18 @Schema(description = "交易金额,单位分", requiredMode = Schema.RequiredMode.REQUIRED, example = "100")
22 19 private Long price;
23 20  
... ...
yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/dal/dataobject/wallet/PayWalletTransactionDO.java
... ... @@ -7,8 +7,6 @@ import com.baomidou.mybatisplus.annotation.TableId;
7 7 import com.baomidou.mybatisplus.annotation.TableName;
8 8 import lombok.Data;
9 9  
10   -import java.time.LocalDateTime;
11   -
12 10 /**
13 11 * 会员钱包流水 DO
14 12 *
... ... @@ -24,6 +22,7 @@ public class PayWalletTransactionDO extends BaseDO {
24 22 */
25 23 @TableId
26 24 private Long id;
  25 +
27 26 /**
28 27 * 流水号
29 28 */
... ... @@ -42,34 +41,26 @@ public class PayWalletTransactionDO extends BaseDO {
42 41 * 枚举 {@link PayWalletBizTypeEnum#getType()}
43 42 */
44 43 private Integer bizType;
45   - // TODO @jason:使用 string;因为可能有业务是 string 接入哈。
  44 +
46 45 /**
47 46 * 关联业务编号
48 47 */
49   - private Long bizId;
  48 + private String bizId;
50 49  
51   - // TODO @jason:想了下,改成 title;流水标题;因为账户明细那,会看到这个;
52 50 /**
53   - * 附加说明
  51 + * 流水说明
54 52 */
55   - private String description;
  53 + private String title;
56 54  
57   - // TODO @jason:使用 price 哈。项目里,金额都是用这个为主;
58 55 /**
59 56 * 交易金额,单位分
60 57 *
61 58 * 正值表示余额增加,负值表示余额减少
62 59 */
63   - private Integer amount;
  60 + private Integer price;
  61 +
64 62 /**
65 63 * 交易后余额,单位分
66 64 */
67 65 private Integer balance;
68   -
69   - // TODO @jason:使用 createTime 就够啦
70   - /**
71   - * 交易时间
72   - */
73   - private LocalDateTime transactionTime;
74   -
75 66 }
... ...
yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/dal/mysql/wallet/PayWalletMapper.java
... ... @@ -3,6 +3,8 @@ package cn.iocoder.yudao.module.pay.dal.mysql.wallet;
3 3  
4 4 import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX;
5 5 import cn.iocoder.yudao.module.pay.dal.dataobject.wallet.PayWalletDO;
  6 +import cn.iocoder.yudao.module.pay.enums.member.PayWalletBizTypeEnum;
  7 +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
6 8 import org.apache.ibatis.annotations.Mapper;
7 9  
8 10 @Mapper
... ... @@ -12,6 +14,55 @@ public interface PayWalletMapper extends BaseMapperX&lt;PayWalletDO&gt; {
12 14 return selectOne(PayWalletDO::getUserId, userId,
13 15 PayWalletDO::getUserType, userType);
14 16 }
  17 +
  18 + /**
  19 + * 当余额减少时候更新
  20 + *
  21 + * @param bizType 业务类型
  22 + * @param balance 当前余额
  23 + * @param totalRecharge 当前累计充值
  24 + * @param totalExpense 当前累计支出
  25 + * @param price 支出的金额
  26 + * @param id 钱包 id
  27 + */
  28 + default int updateWhenDecBalance(PayWalletBizTypeEnum bizType, Integer balance, Long totalRecharge,
  29 + Long totalExpense, Integer price, Long id) {
  30 + PayWalletDO updateDO = new PayWalletDO().setBalance(balance - price);
  31 + if(bizType == PayWalletBizTypeEnum.PAYMENT){
  32 + updateDO.setTotalExpense(totalExpense + price);
  33 + }
  34 + if (bizType == PayWalletBizTypeEnum.RECHARGE_REFUND) {
  35 + updateDO.setTotalRecharge(totalRecharge - price);
  36 + }
  37 + return update(updateDO,
  38 + new LambdaQueryWrapper<PayWalletDO>().eq(PayWalletDO::getId, id)
  39 + .eq(PayWalletDO::getBalance, balance)
  40 + .ge(PayWalletDO::getBalance, price));
  41 + }
  42 +
  43 + /**
  44 + * 当余额增加时候更新
  45 + *
  46 + * @param bizType 业务类型
  47 + * @param balance 当前余额
  48 + * @param totalRecharge 当前累计充值
  49 + * @param totalExpense 当前累计支出
  50 + * @param price 金额
  51 + * @param id 钱包 id
  52 + */
  53 + default int updateWhenIncBalance(PayWalletBizTypeEnum bizType, Integer balance, Long totalRecharge,
  54 + Long totalExpense, Integer price, Long id) {
  55 + PayWalletDO updateDO = new PayWalletDO().setBalance(balance + price);
  56 + if (bizType == PayWalletBizTypeEnum.PAYMENT_REFUND) {
  57 + updateDO.setTotalExpense(totalExpense - price);
  58 + }
  59 + if (bizType == PayWalletBizTypeEnum.RECHARGE) {
  60 + updateDO.setTotalExpense(totalRecharge + price);
  61 + }
  62 + return update(updateDO,
  63 + new LambdaQueryWrapper<PayWalletDO>().eq(PayWalletDO::getId, id)
  64 + .eq(PayWalletDO::getBalance, balance));
  65 + }
15 66 }
16 67  
17 68  
... ...
yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/dal/mysql/wallet/PayWalletTransactionMapper.java
... ... @@ -18,9 +18,9 @@ public interface PayWalletTransactionMapper extends BaseMapperX&lt;PayWalletTransac
18 18 LambdaQueryWrapperX<PayWalletTransactionDO> query = new LambdaQueryWrapperX<PayWalletTransactionDO>()
19 19 .eq(PayWalletTransactionDO::getWalletId, walletId);
20 20 if (Objects.equals(pageReqVO.getType(), AppPayWalletTransactionPageReqVO.TYPE_INCOME)) {
21   - query.gt(PayWalletTransactionDO::getAmount, 0);
  21 + query.gt(PayWalletTransactionDO::getPrice, 0);
22 22 } else if (Objects.equals(pageReqVO.getType(), AppPayWalletTransactionPageReqVO.TYPE_EXPENSE)) {
23   - query.lt(PayWalletTransactionDO::getAmount, 0);
  23 + query.lt(PayWalletTransactionDO::getPrice, 0);
24 24 }
25 25 query.orderByDesc(PayWalletTransactionDO::getId);
26 26 return selectPage(pageReqVO, query);
... ... @@ -30,9 +30,8 @@ public interface PayWalletTransactionMapper extends BaseMapperX&lt;PayWalletTransac
30 30 return selectOne(PayWalletTransactionDO::getNo, no);
31 31 }
32 32  
33   - default PayWalletTransactionDO selectByWalletIdAndBiz(Long walletId, Long bizId, Integer bizType) {
34   - return selectOne(PayWalletTransactionDO::getWalletId, walletId,
35   - PayWalletTransactionDO::getBizId, bizId,
  33 + default PayWalletTransactionDO selectByBiz(String bizId, Integer bizType) {
  34 + return selectOne(PayWalletTransactionDO::getBizId, bizId,
36 35 PayWalletTransactionDO::getBizType, bizType);
37 36 }
38 37  
... ...
yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/framework/pay/wallet/WalletPayClient.java
1 1 package cn.iocoder.yudao.module.pay.framework.pay.wallet;
2 2  
  3 +import cn.hutool.core.lang.Assert;
  4 +import cn.hutool.core.map.MapUtil;
3 5 import cn.hutool.extra.spring.SpringUtil;
4 6 import cn.iocoder.yudao.framework.common.exception.ServiceException;
5 7 import cn.iocoder.yudao.framework.pay.core.client.dto.order.PayOrderRespDTO;
... ... @@ -9,13 +11,23 @@ import cn.iocoder.yudao.framework.pay.core.client.dto.refund.PayRefundUnifiedReq
9 11 import cn.iocoder.yudao.framework.pay.core.client.impl.AbstractPayClient;
10 12 import cn.iocoder.yudao.framework.pay.core.client.impl.NonePayClientConfig;
11 13 import cn.iocoder.yudao.framework.pay.core.enums.channel.PayChannelEnum;
  14 +import cn.iocoder.yudao.framework.pay.core.enums.refund.PayRefundStatusRespEnum;
  15 +import cn.iocoder.yudao.module.pay.dal.dataobject.order.PayOrderExtensionDO;
  16 +import cn.iocoder.yudao.module.pay.dal.dataobject.refund.PayRefundDO;
12 17 import cn.iocoder.yudao.module.pay.dal.dataobject.wallet.PayWalletTransactionDO;
  18 +import cn.iocoder.yudao.module.pay.enums.member.PayWalletBizTypeEnum;
  19 +import cn.iocoder.yudao.module.pay.enums.order.PayOrderStatusEnum;
  20 +import cn.iocoder.yudao.module.pay.service.order.PayOrderService;
  21 +import cn.iocoder.yudao.module.pay.service.refund.PayRefundService;
13 22 import cn.iocoder.yudao.module.pay.service.wallet.PayWalletService;
  23 +import cn.iocoder.yudao.module.pay.service.wallet.PayWalletTransactionService;
14 24 import lombok.extern.slf4j.Slf4j;
15 25  
16 26 import java.util.Map;
17 27  
18 28 import static cn.iocoder.yudao.framework.common.exception.enums.GlobalErrorCodeConstants.INTERNAL_SERVER_ERROR;
  29 +import static cn.iocoder.yudao.module.pay.enums.ErrorCodeConstants.ORDER_EXTENSION_NOT_FOUND;
  30 +import static cn.iocoder.yudao.module.pay.enums.ErrorCodeConstants.REFUND_NOT_FOUND;
19 31  
20 32 /**
21 33 * 钱包支付的 PayClient 实现类
... ... @@ -27,6 +39,12 @@ public class WalletPayClient extends AbstractPayClient&lt;NonePayClientConfig&gt; {
27 39  
28 40 private PayWalletService wallService;
29 41  
  42 + private PayWalletTransactionService walletTransactionService;
  43 +
  44 + private PayOrderService payOrderService;
  45 +
  46 + private PayRefundService payRefundService;
  47 +
30 48 public WalletPayClient(Long channelId, NonePayClientConfig config) {
31 49 super(channelId, PayChannelEnum.WALLET.getCode(), config);
32 50 }
... ... @@ -36,14 +54,22 @@ public class WalletPayClient extends AbstractPayClient&lt;NonePayClientConfig&gt; {
36 54 if (wallService == null) {
37 55 wallService = SpringUtil.getBean(PayWalletService.class);
38 56 }
  57 + if (walletTransactionService == null) {
  58 + walletTransactionService = SpringUtil.getBean(PayWalletTransactionService.class);
  59 + }
39 60 }
40 61  
41 62 @Override
42 63 protected PayOrderRespDTO doUnifiedOrder(PayOrderUnifiedReqDTO reqDTO) {
43 64 try {
44   - PayWalletTransactionDO transaction = wallService.pay(reqDTO.getOutTradeNo(), reqDTO.getPrice());
  65 + String userId = MapUtil.getStr(reqDTO.getChannelExtras(), "user_id");
  66 + String userType = MapUtil.getStr(reqDTO.getChannelExtras(), "user_type");
  67 + Assert.notEmpty(userId, "用户 id 不能为空");
  68 + Assert.notEmpty(userType, "用户类型不能为空");
  69 + PayWalletTransactionDO transaction = wallService.orderPay(Long.valueOf(userId), Integer.valueOf(userType),
  70 + reqDTO.getOutTradeNo(), reqDTO.getPrice());
45 71 return PayOrderRespDTO.successOf(transaction.getNo(), transaction.getCreator(),
46   - transaction.getTransactionTime(),
  72 + transaction.getCreateTime(),
47 73 reqDTO.getOutTradeNo(), transaction);
48 74 } catch (Throwable ex) {
49 75 log.error("[doUnifiedOrder] 失败", ex);
... ... @@ -66,15 +92,39 @@ public class WalletPayClient extends AbstractPayClient&lt;NonePayClientConfig&gt; {
66 92  
67 93 @Override
68 94 protected PayOrderRespDTO doGetOrder(String outTradeNo) {
69   - throw new UnsupportedOperationException("待实现");
  95 + if (payOrderService == null) {
  96 + payOrderService = SpringUtil.getBean(PayOrderService.class);
  97 + }
  98 + PayOrderExtensionDO orderExtension = payOrderService.getOrderExtensionByNo(outTradeNo);
  99 + // 支付交易拓展单不存在, 返回关闭状态
  100 + if (orderExtension == null) {
  101 + return PayOrderRespDTO.closedOf(String.valueOf(ORDER_EXTENSION_NOT_FOUND.getCode()),
  102 + ORDER_EXTENSION_NOT_FOUND.getMsg(), outTradeNo, "");
  103 + }
  104 + // 关闭状态
  105 + if (PayOrderStatusEnum.isClosed(orderExtension.getStatus())) {
  106 + return PayOrderRespDTO.closedOf(orderExtension.getChannelErrorCode(),
  107 + orderExtension.getChannelErrorMsg(), outTradeNo, "");
  108 + }
  109 + // 成功状态
  110 + if (PayOrderStatusEnum.isSuccess(orderExtension.getStatus())) {
  111 + PayWalletTransactionDO walletTransaction = walletTransactionService.getWalletTransaction(
  112 + String.valueOf(orderExtension.getOrderId()), PayWalletBizTypeEnum.PAYMENT);
  113 + Assert.notNull(walletTransaction, "支付单 {} 钱包流水不能为空", outTradeNo);
  114 + return PayOrderRespDTO.successOf(walletTransaction.getNo(), walletTransaction.getCreator(),
  115 + walletTransaction.getCreateTime(), outTradeNo, walletTransaction);
  116 + }
  117 + // 其它状态为无效状态
  118 + log.error("[doGetOrder] 支付单 {} 的状态不正确", outTradeNo);
  119 + throw new IllegalStateException(String.format("支付单[%s] 状态不正确", outTradeNo));
70 120 }
71 121  
72 122 @Override
73 123 protected PayRefundRespDTO doUnifiedRefund(PayRefundUnifiedReqDTO reqDTO) {
74 124 try {
75   - PayWalletTransactionDO payWalletTransaction = wallService.refund(reqDTO.getOutRefundNo(),
  125 + PayWalletTransactionDO payWalletTransaction = wallService.orderRefund(reqDTO.getOutRefundNo(),
76 126 reqDTO.getRefundPrice(), reqDTO.getReason());
77   - return PayRefundRespDTO.successOf(payWalletTransaction.getNo(), payWalletTransaction.getTransactionTime(),
  127 + return PayRefundRespDTO.successOf(payWalletTransaction.getNo(), payWalletTransaction.getCreateTime(),
78 128 reqDTO.getOutRefundNo(), payWalletTransaction);
79 129 } catch (Throwable ex) {
80 130 log.error("[doUnifiedRefund] 失败", ex);
... ... @@ -97,7 +147,31 @@ public class WalletPayClient extends AbstractPayClient&lt;NonePayClientConfig&gt; {
97 147  
98 148 @Override
99 149 protected PayRefundRespDTO doGetRefund(String outTradeNo, String outRefundNo) {
100   - throw new UnsupportedOperationException("待实现");
  150 + if (payRefundService == null) {
  151 + payRefundService = SpringUtil.getBean(PayRefundService.class);
  152 + }
  153 + PayRefundDO payRefund = payRefundService.getRefundByNo(outRefundNo);
  154 + // 支付退款单不存在, 返回退款失败状态
  155 + if (payRefund == null) {
  156 + return PayRefundRespDTO.failureOf(String.valueOf(REFUND_NOT_FOUND), REFUND_NOT_FOUND.getMsg(),
  157 + outRefundNo, "");
  158 + }
  159 + // 退款失败
  160 + if (PayRefundStatusRespEnum.isFailure(payRefund.getStatus())) {
  161 + return PayRefundRespDTO.failureOf(payRefund.getChannelErrorCode(), payRefund.getChannelErrorMsg(),
  162 + outRefundNo, "");
  163 + }
  164 + // 退款成功
  165 + if (PayRefundStatusRespEnum.isSuccess(payRefund.getStatus())) {
  166 + PayWalletTransactionDO walletTransaction = walletTransactionService.getWalletTransaction(
  167 + String.valueOf(payRefund.getId()), PayWalletBizTypeEnum.PAYMENT_REFUND);
  168 + Assert.notNull(walletTransaction, "支付退款单 {} 钱包流水不能为空", outRefundNo);
  169 + return PayRefundRespDTO.successOf(walletTransaction.getNo(), walletTransaction.getCreateTime(),
  170 + outRefundNo, walletTransaction);
  171 + }
  172 + // 其它状态为无效状态
  173 + log.error("[doGetRefund] 支付退款单 {} 的状态不正确", outRefundNo);
  174 + throw new IllegalStateException(String.format("支付退款单[%s] 状态不正确", outRefundNo));
101 175 }
102 176  
103 177 }
... ...
yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/service/order/PayOrderServiceImpl.java
... ... @@ -345,7 +345,8 @@ public class PayOrderServiceImpl implements PayOrderService {
345 345 .channelId(channel.getId()).channelCode(channel.getCode())
346 346 .successTime(notify.getSuccessTime()).extensionId(orderExtension.getId()).no(orderExtension.getNo())
347 347 .channelOrderNo(notify.getChannelOrderNo()).channelUserId(notify.getChannelUserId())
348   - .channelFeeRate(channel.getFeeRate()).channelFeePrice(MoneyUtils.calculateRatePrice(order.getPrice(), channel.getFeeRate()))
  348 + .channelFeeRate(channel.getFeeRate())
  349 + .channelFeePrice(MoneyUtils.calculateRatePrice(order.getPrice(), channel.getFeeRate()))
349 350 .build());
350 351 if (updateCounts == 0) { // 校验状态,必须是待支付
351 352 throw exception(ORDER_STATUS_IS_NOT_WAITING);
... ...
yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/service/wallet/PayWalletService.java
... ... @@ -2,6 +2,7 @@ package cn.iocoder.yudao.module.pay.service.wallet;
2 2  
3 3 import cn.iocoder.yudao.module.pay.dal.dataobject.wallet.PayWalletDO;
4 4 import cn.iocoder.yudao.module.pay.dal.dataobject.wallet.PayWalletTransactionDO;
  5 +import cn.iocoder.yudao.module.pay.enums.member.PayWalletBizTypeEnum;
5 6  
6 7 /**
7 8 * 钱包 Service 接口
... ... @@ -10,30 +11,59 @@ import cn.iocoder.yudao.module.pay.dal.dataobject.wallet.PayWalletTransactionDO;
10 11 */
11 12 public interface PayWalletService {
12 13  
13   - // TODO @jason:改成 getOrCreateWallet;因为目前解耦,用户注册时,不会创建钱包;需要这里兜底处理;
14 14 /**
15   - * 获取钱包信息
  15 + * 获取钱包信息,如果不存在创建钱包。由于用户注册时候不会创建钱包
16 16 *
17 17 * @param userId 用户编号
18 18 * @param userType 用户类型
19 19 */
20   - PayWalletDO getPayWallet(Long userId, Integer userType);
  20 + PayWalletDO getOrCreatePayWallet(Long userId, Integer userType);
21 21  
22 22 /**
23   - * 钱包支付
  23 + * 钱包订单支付
24 24 *
  25 + * @param userId 用户 id
  26 + * @param userType 用户类型
25 27 * @param outTradeNo 外部订单号
26 28 * @param price 金额
27 29 */
28   - PayWalletTransactionDO pay(String outTradeNo, Integer price);
  30 + PayWalletTransactionDO orderPay(Long userId, Integer userType, String outTradeNo, Integer price);
  31 +
  32 +
  33 + /**
  34 + * 扣减钱包余额
  35 + *
  36 + * @param userId 用户 id
  37 + * @param userType 用户类型
  38 + * @param bizId 业务关联 id
  39 + * @param bizType 业务关联分类
  40 + * @param price 扣减金额
  41 + * @return 钱包流水
  42 + */
  43 + PayWalletTransactionDO reduceWalletBalance(Long userId, Integer userType,
  44 + Long bizId, PayWalletBizTypeEnum bizType, Integer price);
  45 +
  46 +
  47 + /**
  48 + * 增加钱包余额
  49 + *
  50 + * @param userId 用户 id
  51 + * @param userType 用户类型
  52 + * @param bizId 业务关联 id
  53 + * @param bizType 业务关联分类
  54 + * @param price 增加金额
  55 + * @return 钱包流水
  56 + */
  57 + PayWalletTransactionDO addWalletBalance(Long userId, Integer userType,
  58 + Long bizId, PayWalletBizTypeEnum bizType, Integer price);
29 59  
30 60 /**
31   - * 钱包支付退款
  61 + * 钱包订单支付退款
32 62 *
33 63 * @param outRefundNo 外部退款号
34 64 * @param refundPrice 退款金额
35 65 * @param reason 退款原因
36 66 */
37   - PayWalletTransactionDO refund(String outRefundNo, Integer refundPrice, String reason);
  67 + PayWalletTransactionDO orderRefund(String outRefundNo, Integer refundPrice, String reason);
38 68  
39 69 }
... ...
yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/service/wallet/PayWalletServiceImpl.java
1 1 package cn.iocoder.yudao.module.pay.service.wallet;
2 2  
  3 +import cn.hutool.core.lang.Assert;
3 4 import cn.iocoder.yudao.module.pay.dal.dataobject.order.PayOrderExtensionDO;
4 5 import cn.iocoder.yudao.module.pay.dal.dataobject.refund.PayRefundDO;
5 6 import cn.iocoder.yudao.module.pay.dal.dataobject.wallet.PayWalletDO;
6 7 import cn.iocoder.yudao.module.pay.dal.dataobject.wallet.PayWalletTransactionDO;
7 8 import cn.iocoder.yudao.module.pay.dal.mysql.wallet.PayWalletMapper;
8 9 import cn.iocoder.yudao.module.pay.dal.redis.no.PayNoRedisDAO;
  10 +import cn.iocoder.yudao.module.pay.enums.member.PayWalletBizTypeEnum;
9 11 import cn.iocoder.yudao.module.pay.service.order.PayOrderService;
10 12 import cn.iocoder.yudao.module.pay.service.refund.PayRefundService;
11 13 import lombok.extern.slf4j.Slf4j;
... ... @@ -16,9 +18,8 @@ import org.springframework.transaction.annotation.Transactional;
16 18 import javax.annotation.Resource;
17 19 import java.time.LocalDateTime;
18 20  
  21 +import static cn.iocoder.yudao.framework.common.exception.enums.GlobalErrorCodeConstants.TOO_MANY_REQUESTS;
19 22 import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
20   -import static cn.iocoder.yudao.framework.web.core.util.WebFrameworkUtils.getLoginUserId;
21   -import static cn.iocoder.yudao.framework.web.core.util.WebFrameworkUtils.getLoginUserType;
22 23 import static cn.iocoder.yudao.module.pay.enums.ErrorCodeConstants.*;
23 24 import static cn.iocoder.yudao.module.pay.enums.member.PayWalletBizTypeEnum.PAYMENT;
24 25 import static cn.iocoder.yudao.module.pay.enums.member.PayWalletBizTypeEnum.PAYMENT_REFUND;
... ... @@ -56,81 +57,111 @@ public class PayWalletServiceImpl implements PayWalletService {
56 57 private PayRefundService payRefundService;
57 58  
58 59 @Override
59   - public PayWalletDO getPayWallet(Long userId, Integer userType) {
60   - return payWalletMapper.selectByUserIdAndType(userId, userType);
  60 + public PayWalletDO getOrCreatePayWallet(Long userId, Integer userType) {
  61 + PayWalletDO payWalletDO = payWalletMapper.selectByUserIdAndType(userId, userType);
  62 + if (payWalletDO == null) {
  63 + payWalletDO = new PayWalletDO();
  64 + payWalletDO.setUserId(userId);
  65 + payWalletDO.setUserType(userType);
  66 + payWalletDO.setBalance(0);
  67 + payWalletDO.setTotalExpense(0L);
  68 + payWalletDO.setTotalRecharge(0L);
  69 + payWalletDO.setCreateTime(LocalDateTime.now());
  70 + payWalletMapper.insert(payWalletDO);
  71 + }
  72 + return payWalletDO;
61 73 }
62 74  
63   - // TODO @jason:可以做的更抽象一点;pay(bizType, bizId, price);reduceWalletBalance;
64   - // TODO @jason:最好是,明确传入哪个 userId 或者 walletId;
  75 +
65 76 @Override
66 77 @Transactional(rollbackFor = Exception.class)
67   - public PayWalletTransactionDO pay(String outTradeNo, Integer price) {
68   - // 1.1 判断支付交易拓展单是否存
  78 + public PayWalletTransactionDO orderPay(Long userId, Integer userType, String outTradeNo, Integer price) {
  79 + // 判断支付交易拓展单是否存
69 80 PayOrderExtensionDO orderExtension = payOrderService.getOrderExtensionByNo(outTradeNo);
70 81 if (orderExtension == null) {
71 82 throw exception(ORDER_EXTENSION_NOT_FOUND);
72 83 }
  84 + return reduceWalletBalance(userId, userType, orderExtension.getOrderId(), PAYMENT, price);
  85 + }
  86 +
  87 + @Override
  88 + public PayWalletTransactionDO reduceWalletBalance(Long userId, Integer userType,
  89 + Long bizId, PayWalletBizTypeEnum bizType, Integer price) {
  90 + // 1.1 获取钱包
  91 + PayWalletDO payWallet = getOrCreatePayWallet(userId, userType);
73 92 // 1.2 判断余额是否足够
74   - PayWalletDO payWallet = validatePayWallet();
75 93 int afterBalance = payWallet.getBalance() - price;
76 94 if (afterBalance < 0) {
77 95 throw exception(WALLET_BALANCE_NOT_ENOUGH);
78 96 }
79 97  
80 98 // 2.1 扣除余额
81   - // TODO @jason:不要直接整个更新;而是 new 一个出来更新;然后要考虑并发,要 where 余额 > price,以及 - price
82   - payWallet.setBalance(afterBalance);
83   - payWallet.setTotalExpense(payWallet.getTotalExpense() + price);
84   - payWalletMapper.updateById(payWallet);
85   -
  99 + int number = payWalletMapper.updateWhenDecBalance(bizType,payWallet.getBalance(), payWallet.getTotalRecharge(),
  100 + payWallet.getTotalExpense(), price, payWallet.getId());
  101 + if (number == 0) {
  102 + throw exception(TOO_MANY_REQUESTS);
  103 + }
86 104 // 2.2 生成钱包流水
87   - String walletNo = noRedisDAO.generate(WALLET_PAY_NO_PREFIX);
  105 + String walletNo = generateWalletNo(bizType);
88 106 PayWalletTransactionDO walletTransaction = new PayWalletTransactionDO().setWalletId(payWallet.getId())
89   - .setNo(walletNo).setAmount(price * -1).setBalance(afterBalance).setTransactionTime(LocalDateTime.now())
90   - .setBizId(orderExtension.getOrderId()).setBizType(PAYMENT.getType());
  107 + .setNo(walletNo).setPrice(-price).setBalance(afterBalance)
  108 + .setBizId(String.valueOf(bizId)).setBizType(bizType.getType()).setTitle(bizType.getDescription());
91 109 payWalletTransactionService.createWalletTransaction(walletTransaction);
92 110 return walletTransaction;
93 111 }
94 112  
95   - // TODO @jason:不要在 service 里去使用用户上下文,这样和 request 就耦合了。
96   - private PayWalletDO validatePayWallet() {
97   - Long userId = getLoginUserId();
98   - Integer userType = getLoginUserType();
99   - PayWalletDO payWallet = getPayWallet(userId, userType);
100   - if (payWallet == null) {
101   - log.error("[validatePayWallet] 用户 {} 钱包不存在", userId);
102   - throw exception(WALLET_NOT_FOUND);
  113 + @Override
  114 + public PayWalletTransactionDO addWalletBalance(Long userId, Integer userType, Long bizId,
  115 + PayWalletBizTypeEnum bizType, Integer price) {
  116 + // 1.1 获取钱包
  117 + PayWalletDO payWallet = getOrCreatePayWallet(userId, userType);
  118 +
  119 + // 2.1 增加余额
  120 + int number = payWalletMapper.updateWhenIncBalance(bizType, payWallet.getBalance(), payWallet.getTotalRecharge(),
  121 + payWallet.getTotalExpense(), price, payWallet.getId());
  122 + if (number == 0) {
  123 + throw exception(TOO_MANY_REQUESTS);
  124 + }
  125 +
  126 + // 2.2 生成钱包流水
  127 + String walletNo = generateWalletNo(bizType);
  128 + PayWalletTransactionDO newWalletTransaction = new PayWalletTransactionDO().setWalletId(payWallet.getId())
  129 + .setNo(walletNo).setPrice(price).setBalance(payWallet.getBalance()+price)
  130 + .setBizId(String.valueOf(bizId)).setBizType(bizType.getType())
  131 + .setTitle(bizType.getDescription());
  132 + payWalletTransactionService.createWalletTransaction(newWalletTransaction);
  133 + return newWalletTransaction;
  134 + }
  135 +
  136 + private String generateWalletNo(PayWalletBizTypeEnum bizType) {
  137 + String no = "";
  138 + switch(bizType){
  139 + case PAYMENT :
  140 + no = noRedisDAO.generate(WALLET_PAY_NO_PREFIX);
  141 + break;
  142 + case PAYMENT_REFUND :
  143 + no = noRedisDAO.generate(WALLET_REFUND_NO_PREFIX);
  144 + break;
  145 + default :
  146 + // TODO 待增加
103 147 }
104   - return payWallet;
  148 + return no;
105 149 }
106 150  
107   - // TODO @jason:可以做的更抽象一点;pay(bizType, bizId, price);addWalletBalance;这样,如果后续充值,应该也是能复用这个方法的;
108 151 @Override
109 152 @Transactional(rollbackFor = Exception.class)
110   - public PayWalletTransactionDO refund(String outRefundNo, Integer refundPrice, String reason) {
  153 + public PayWalletTransactionDO orderRefund(String outRefundNo, Integer refundPrice, String reason) {
111 154 // 1.1 判断退款单是否存在
112 155 PayRefundDO payRefund = payRefundService.getRefundByNo(outRefundNo);
113 156 if (payRefund == null) {
114 157 throw exception(REFUND_NOT_FOUND);
115 158 }
116 159 // 1.2 校验是否可以退款
117   - PayWalletDO payWallet = validatePayWallet();
118   - validateWalletCanRefund(payRefund.getId(), payRefund.getChannelOrderNo(), payWallet.getId(), refundPrice);
119   -
120   - // TODO @jason:不要直接整个更新;而是 new 一个出来更新;然后要考虑并发,要 where 余额 + 金额
121   - Integer afterBalance = payWallet.getBalance() + refundPrice;
122   - payWallet.setBalance(afterBalance);
123   - payWallet.setTotalExpense(payWallet.getTotalExpense() + refundPrice * -1L);
124   - payWalletMapper.updateById(payWallet);
  160 + Long walletId = validateWalletCanRefund(payRefund.getId(), payRefund.getChannelOrderNo(), refundPrice);
125 161  
126   - // 2.2 生成钱包流水
127   - String walletNo = noRedisDAO.generate(WALLET_REFUND_NO_PREFIX);
128   - PayWalletTransactionDO newWalletTransaction = new PayWalletTransactionDO().setWalletId(payWallet.getId())
129   - .setNo(walletNo).setAmount(refundPrice).setBalance(afterBalance).setTransactionTime(LocalDateTime.now())
130   - .setBizId(payRefund.getId()).setBizType(PAYMENT_REFUND.getType())
131   - .setDescription(reason);
132   - payWalletTransactionService.createWalletTransaction(newWalletTransaction);
133   - return newWalletTransaction;
  162 + PayWalletDO payWallet = payWalletMapper.selectById(walletId);
  163 + Assert.notNull(payWallet, "钱包 {} 不存在", walletId);
  164 + return addWalletBalance(payWallet.getUserId(), payWallet.getUserType(),payRefund.getId(), PAYMENT_REFUND, refundPrice);
134 165 }
135 166  
136 167 /**
... ... @@ -138,24 +169,23 @@ public class PayWalletServiceImpl implements PayWalletService {
138 169 *
139 170 * @param refundId 支付退款单 id
140 171 * @param walletPayNo 钱包支付 no
141   - * @param walletId 钱包 id
142 172 */
143   - // TODO @jason:不要使用基本类型;
144   - private void validateWalletCanRefund(long refundId, String walletPayNo, long walletId, int refundPrice) {
  173 + private Long validateWalletCanRefund(Long refundId, String walletPayNo, Integer refundPrice) {
145 174 // 查询钱包支付交易
146 175 PayWalletTransactionDO payWalletTransaction = payWalletTransactionService.getWalletTransactionByNo(walletPayNo);
147 176 if (payWalletTransaction == null) {
148 177 throw exception(WALLET_TRANSACTION_NOT_FOUND);
149 178 }
150 179 // 原来的支付金额
151   - int amount = payWalletTransaction.getAmount() * -1; // TODO @jason:直接 - payWalletTransaction.getAmount() 即可;
  180 + int amount = - payWalletTransaction.getPrice();
152 181 if (refundPrice != amount) {
153 182 throw exception(WALLET_REFUND_AMOUNT_ERROR);
154 183 }
155   - PayWalletTransactionDO refundTransaction = payWalletTransactionService.getWalletTransaction(walletId, refundId, PAYMENT_REFUND);
  184 + PayWalletTransactionDO refundTransaction = payWalletTransactionService.getWalletTransaction(
  185 + String.valueOf(refundId), PAYMENT_REFUND);
156 186 if (refundTransaction != null) {
157 187 throw exception(WALLET_REFUND_EXIST);
158 188 }
  189 + return payWalletTransaction.getWalletId();
159 190 }
160   -
161 191 }
... ...
yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/service/wallet/PayWalletTransactionService.java
... ... @@ -40,11 +40,9 @@ public interface PayWalletTransactionService {
40 40 /**
41 41 * 获取钱包流水
42 42 *
43   - * @param walletId 钱包编号
44 43 * @param bizId 业务编号
45 44 * @param type 业务类型
46 45 * @return 钱包流水
47 46 */
48   - PayWalletTransactionDO getWalletTransaction(Long walletId, Long bizId, PayWalletBizTypeEnum type);
49   -
  47 + PayWalletTransactionDO getWalletTransaction(String bizId, PayWalletBizTypeEnum type);
50 48 }
... ...
yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/service/wallet/PayWalletTransactionServiceImpl.java
... ... @@ -11,9 +11,6 @@ import org.springframework.stereotype.Service;
11 11  
12 12 import javax.annotation.Resource;
13 13  
14   -import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
15   -import static cn.iocoder.yudao.module.pay.enums.ErrorCodeConstants.WALLET_NOT_FOUND;
16   -
17 14 /**
18 15 * 钱包流水 Service 实现类
19 16 *
... ... @@ -25,18 +22,13 @@ public class PayWalletTransactionServiceImpl implements PayWalletTransactionServ
25 22  
26 23 @Resource
27 24 private PayWalletService payWalletService;
28   -
29 25 @Resource
30 26 private PayWalletTransactionMapper payWalletTransactionMapper;
31 27  
32 28 @Override
33 29 public PageResult<PayWalletTransactionDO> getWalletTransactionPage(Long userId, Integer userType,
34 30 AppPayWalletTransactionPageReqVO pageVO) {
35   - PayWalletDO wallet = payWalletService.getPayWallet(userId, userType);
36   - if (wallet == null) {
37   - log.error("[getWalletTransactionPage][用户({}/{}) 钱包不存在", userId, userType);
38   - throw exception(WALLET_NOT_FOUND);
39   - }
  31 + PayWalletDO wallet = payWalletService.getOrCreatePayWallet(userId, userType);
40 32 return payWalletTransactionMapper.selectPage(wallet.getId(), pageVO);
41 33 }
42 34  
... ... @@ -52,8 +44,7 @@ public class PayWalletTransactionServiceImpl implements PayWalletTransactionServ
52 44 }
53 45  
54 46 @Override
55   - public PayWalletTransactionDO getWalletTransaction(Long walletId, Long bizId, PayWalletBizTypeEnum type) {
56   - return payWalletTransactionMapper.selectByWalletIdAndBiz(walletId, bizId, type.getType());
  47 + public PayWalletTransactionDO getWalletTransaction(String bizId, PayWalletBizTypeEnum type) {
  48 + return payWalletTransactionMapper.selectByBiz(bizId, type.getType());
57 49 }
58   -
59 50 }
... ...
yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/util/MoneyUtils.java
1 1 package cn.iocoder.yudao.module.pay.util;
2 2  
  3 +import cn.hutool.core.util.NumberUtil;
  4 +
3 5 import java.math.BigDecimal;
4 6 import java.math.RoundingMode;
5 7  
... ... @@ -18,10 +20,20 @@ public class MoneyUtils {
18 20 * @return 百分比金额
19 21 */
20 22 public static Integer calculateRatePrice(Integer price, Double rate) {
21   - return new BigDecimal(price)
22   - .multiply(BigDecimal.valueOf(rate)) // 乘以
23   - .setScale(0, RoundingMode.HALF_UP) // 四舍五入
24   - .intValue();
  23 + return calculateRatePrice(price, rate, 0, RoundingMode.HALF_UP).intValue();
25 24 }
26 25  
  26 + /**
  27 + * 计算百分比金额
  28 + *
  29 + * @param price 金额
  30 + * @param rate 百分比,例如说 56.77% 则传入 56.77
  31 + * @param scale 保留小数位数
  32 + * @param roundingMode 舍入模式
  33 + */
  34 + public static BigDecimal calculateRatePrice(Number price, Number rate, int scale, RoundingMode roundingMode) {
  35 + return NumberUtil.toBigDecimal(price).multiply(NumberUtil.toBigDecimal(rate)) // 乘以
  36 + .divide(BigDecimal.valueOf(100), scale, roundingMode); // 除以 100
  37 + }
  38 +
27 39 }
... ...
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/notify/vo/message/NotifyMessageRespVO.java
1 1 package cn.iocoder.yudao.module.system.controller.admin.notify.vo.message;
2 2  
3 3 import io.swagger.v3.oas.annotations.media.Schema;
4   -import lombok.*;
5   -import java.util.*;
  4 +import lombok.Data;
  5 +import lombok.EqualsAndHashCode;
  6 +import lombok.ToString;
  7 +
  8 +import java.time.LocalDateTime;
6 9  
7 10 @Schema(description = "管理后台 - 站内信 Response VO")
8 11 @Data
... ... @@ -14,6 +17,6 @@ public class NotifyMessageRespVO extends NotifyMessageBaseVO {
14 17 private Long id;
15 18  
16 19 @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED)
17   - private Date createTime;
  20 + private LocalDateTime createTime;
18 21  
19 22 }
... ...
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/notify/vo/template/NotifyTemplateRespVO.java
... ... @@ -2,6 +2,8 @@ package cn.iocoder.yudao.module.system.controller.admin.notify.vo.template;
2 2  
3 3 import io.swagger.v3.oas.annotations.media.Schema;
4 4 import lombok.*;
  5 +
  6 +import java.time.LocalDateTime;
5 7 import java.util.*;
6 8  
7 9 @Schema(description = "管理后台 - 站内信模版 Response VO")
... ... @@ -17,6 +19,6 @@ public class NotifyTemplateRespVO extends NotifyTemplateBaseVO {
17 19 private List<String> params;
18 20  
19 21 @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED)
20   - private Date createTime;
  22 + private LocalDateTime createTime;
21 23  
22 24 }
... ...
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/convert/notify/NotifyMessageConvert.java
... ... @@ -24,5 +24,4 @@ public interface NotifyMessageConvert {
24 24  
25 25 PageResult<NotifyMessageRespVO> convertPage(PageResult<NotifyMessageDO> page);
26 26  
27   -
28 27 }
... ...
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/convert/notify/NotifyTemplateConvert.java
... ... @@ -4,6 +4,7 @@ import java.util.*;
4 4  
5 5 import cn.iocoder.yudao.framework.common.pojo.PageResult;
6 6  
  7 +import cn.iocoder.yudao.framework.common.util.date.DateUtils;
7 8 import cn.iocoder.yudao.module.system.controller.admin.notify.vo.template.NotifyTemplateCreateReqVO;
8 9 import cn.iocoder.yudao.module.system.controller.admin.notify.vo.template.NotifyTemplateRespVO;
9 10 import cn.iocoder.yudao.module.system.controller.admin.notify.vo.template.NotifyTemplateUpdateReqVO;
... ... @@ -16,7 +17,7 @@ import cn.iocoder.yudao.module.system.dal.dataobject.notify.NotifyTemplateDO;
16 17 *
17 18 * @author xrcoder
18 19 */
19   -@Mapper
  20 +@Mapper(uses = DateUtils.class)
20 21 public interface NotifyTemplateConvert {
21 22  
22 23 NotifyTemplateConvert INSTANCE = Mappers.getMapper(NotifyTemplateConvert.class);
... ...
yudao-module-system/yudao-module-system-biz/src/test/java/cn/iocoder/yudao/module/system/service/tenant/TenantServiceImplTest.java
... ... @@ -197,7 +197,7 @@ public class TenantServiceImplTest extends BaseDbUnitTest {
197 197 role100.setTenantId(dbTenant.getId());
198 198 RoleDO role101 = randomPojo(RoleDO.class, o -> o.setId(101L));
199 199 role101.setTenantId(dbTenant.getId());
200   - when(roleService.getRoleListByStatus(isNull())).thenReturn(asList(role100, role101));
  200 + when(roleService.getRoleList()).thenReturn(asList(role100, role101));
201 201 // mock 每个角色的权限
202 202 when(permissionService.getRoleMenuListByRoleId(eq(101L))).thenReturn(asSet(201L, 202L));
203 203  
... ...
yudao-server/pom.xml
... ... @@ -41,13 +41,13 @@
41 41 <artifactId>yudao-spring-boot-starter-biz-error-code</artifactId>
42 42 </dependency>
43 43  
44   - <!-- 数据报表 -->
  44 + <!-- 数据报表。默认注释,保证编译速度 -->
45 45 <!-- <dependency>-->
46 46 <!-- <groupId>cn.iocoder.boot</groupId>-->
47 47 <!-- <artifactId>yudao-module-report-biz</artifactId>-->
48 48 <!-- <version>${revision}</version>-->
49 49 <!-- </dependency>-->
50   - <!-- 工作流 -->
  50 + <!-- 工作流。默认注释,保证编译速度 -->
51 51 <!-- <dependency>-->
52 52 <!-- <groupId>cn.iocoder.boot</groupId>-->
53 53 <!-- <artifactId>yudao-module-bpm-biz</artifactId>-->
... ... @@ -111,10 +111,7 @@
111 111 <plugin>
112 112 <groupId>org.springframework.boot</groupId>
113 113 <artifactId>spring-boot-maven-plugin</artifactId>
114   - <version>2.7.14</version> <!-- 如果 spring.boot.version 版本修改,则这里也要跟着修改 -->
115   - <configuration>
116   - <fork>true</fork>
117   - </configuration>
  114 + <version>${spring.boot.version}</version>
118 115 <executions>
119 116 <execution>
120 117 <goals>
... ...
yudao-ui-admin/src/components/Crontab/day.vue
... ... @@ -103,25 +103,25 @@ export default {
103 103 },
104 104 // 周期两个值变化时
105 105 cycleChange() {
106   - if (this.radioValue === '3') {
  106 + if (this.radioValue === 3) {
107 107 this.$emit('update', 'day', this.cycleTotal);
108 108 }
109 109 },
110 110 // 平均两个值变化时
111 111 averageChange() {
112   - if (this.radioValue === '4') {
  112 + if (this.radioValue === 4) {
113 113 this.$emit('update', 'day', this.averageTotal);
114 114 }
115 115 },
116 116 // 最近工作日值变化时
117 117 workdayChange() {
118   - if (this.radioValue === '5') {
  118 + if (this.radioValue === 5) {
119 119 this.$emit('update', 'day', this.workdayCheck + 'W');
120 120 }
121 121 },
122 122 // checkbox值变化时
123 123 checkboxChange() {
124   - if (this.radioValue === '7') {
  124 + if (this.radioValue === 7) {
125 125 this.$emit('update', 'day', this.checkboxString);
126 126 }
127 127 }
... ...
yudao-ui-admin/src/components/Crontab/hour.vue
... ... @@ -68,19 +68,19 @@ export default {
68 68 },
69 69 // 周期两个值变化时
70 70 cycleChange() {
71   - if (this.radioValue === '2') {
  71 + if (this.radioValue === 2) {
72 72 this.$emit('update', 'hour', this.cycleTotal);
73 73 }
74 74 },
75 75 // 平均两个值变化时
76 76 averageChange() {
77   - if (this.radioValue === '3') {
  77 + if (this.radioValue === 3) {
78 78 this.$emit('update', 'hour', this.averageTotal);
79 79 }
80 80 },
81 81 // checkbox值变化时
82 82 checkboxChange() {
83   - if (this.radioValue === '4') {
  83 + if (this.radioValue === 4) {
84 84 this.$emit('update', 'hour', this.checkboxString);
85 85 }
86 86 }
... ...
yudao-ui-admin/src/components/Crontab/min.vue
... ... @@ -69,19 +69,19 @@ export default {
69 69 },
70 70 // 周期两个值变化时
71 71 cycleChange() {
72   - if (this.radioValue === '2') {
  72 + if (this.radioValue === 2) {
73 73 this.$emit('update', 'min', this.cycleTotal, 'min');
74 74 }
75 75 },
76 76 // 平均两个值变化时
77 77 averageChange() {
78   - if (this.radioValue === '3') {
  78 + if (this.radioValue === 3) {
79 79 this.$emit('update', 'min', this.averageTotal, 'min');
80 80 }
81 81 },
82 82 // checkbox值变化时
83 83 checkboxChange() {
84   - if (this.radioValue === '4') {
  84 + if (this.radioValue === 4) {
85 85 this.$emit('update', 'min', this.checkboxString, 'min');
86 86 }
87 87 },
... ...
yudao-ui-admin/src/components/Crontab/month.vue
... ... @@ -68,19 +68,19 @@ export default {
68 68 },
69 69 // 周期两个值变化时
70 70 cycleChange() {
71   - if (this.radioValue === '2') {
  71 + if (this.radioValue === 2) {
72 72 this.$emit('update', 'month', this.cycleTotal);
73 73 }
74 74 },
75 75 // 平均两个值变化时
76 76 averageChange() {
77   - if (this.radioValue === '3') {
  77 + if (this.radioValue === 3) {
78 78 this.$emit('update', 'month', this.averageTotal);
79 79 }
80 80 },
81 81 // checkbox值变化时
82 82 checkboxChange() {
83   - if (this.radioValue === '4') {
  83 + if (this.radioValue === 4) {
84 84 this.$emit('update', 'month', this.checkboxString);
85 85 }
86 86 }
... ...
yudao-ui-admin/src/components/Crontab/second.vue
... ... @@ -68,19 +68,19 @@ export default {
68 68 },
69 69 // 周期两个值变化时
70 70 cycleChange() {
71   - if (this.radioValue === '2') {
  71 + if (this.radioValue === 2) {
72 72 this.$emit('update', 'second', this.cycleTotal);
73 73 }
74 74 },
75 75 // 平均两个值变化时
76 76 averageChange() {
77   - if (this.radioValue === '3') {
  77 + if (this.radioValue === 3) {
78 78 this.$emit('update', 'second', this.averageTotal);
79 79 }
80 80 },
81 81 // checkbox值变化时
82 82 checkboxChange() {
83   - if (this.radioValue === '4') {
  83 + if (this.radioValue === 4) {
84 84 this.$emit('update', 'second', this.checkboxString);
85 85 }
86 86 }
... ...
yudao-ui-admin/src/components/Crontab/week.vue
... ... @@ -144,25 +144,25 @@ export default {
144 144  
145 145 // 周期两个值变化时
146 146 cycleChange() {
147   - if (this.radioValue === '3') {
  147 + if (this.radioValue === 3) {
148 148 this.$emit('update', 'week', this.cycleTotal);
149 149 }
150 150 },
151 151 // 平均两个值变化时
152 152 averageChange() {
153   - if (this.radioValue === '4') {
  153 + if (this.radioValue === 4) {
154 154 this.$emit('update', 'week', this.averageTotal);
155 155 }
156 156 },
157 157 // 最近工作日值变化时
158 158 weekdayChange() {
159   - if (this.radioValue === '5') {
  159 + if (this.radioValue === 5) {
160 160 this.$emit('update', 'week', this.weekday + 'L');
161 161 }
162 162 },
163 163 // checkbox值变化时
164 164 checkboxChange() {
165   - if (this.radioValue === '6') {
  165 + if (this.radioValue === 6) {
166 166 this.$emit('update', 'week', this.checkboxString);
167 167 }
168 168 },
... ...
yudao-ui-admin/src/components/Crontab/year.vue
... ... @@ -79,19 +79,19 @@ export default {
79 79 },
80 80 // 周期两个值变化时
81 81 cycleChange() {
82   - if (this.radioValue === '3') {
  82 + if (this.radioValue === 3) {
83 83 this.$emit('update', 'year', this.cycleTotal);
84 84 }
85 85 },
86 86 // 平均两个值变化时
87 87 averageChange() {
88   - if (this.radioValue === '4') {
  88 + if (this.radioValue === 4) {
89 89 this.$emit('update', 'year', this.averageTotal);
90 90 }
91 91 },
92 92 // checkbox值变化时
93 93 checkboxChange() {
94   - if (this.radioValue === '5') {
  94 + if (this.radioValue === 5) {
95 95 this.$emit('update', 'year', this.checkboxString);
96 96 }
97 97 }
... ...
yudao-ui-admin/src/utils/constants.js
... ... @@ -163,6 +163,10 @@ export const PayChannelEnum = {
163 163 MOCK : {
164 164 "code": "mock",
165 165 "name": "模拟支付"
  166 + },
  167 + WALLET : {
  168 + "code": "wallet",
  169 + "name": "钱包支付"
166 170 }
167 171 }
168 172  
... ...
yudao-ui-admin/src/views/pay/app/components/mockChannelForm.vue renamed to yudao-ui-admin/src/views/pay/app/components/noneConfigChannelForm.vue
... ... @@ -5,7 +5,8 @@
5 5 <el-form-item label-width="180px" label="渠道状态" prop="status">
6 6 <el-radio-group v-model="formData.status" size="medium">
7 7 <el-radio v-for="dict in this.getDictDatas(DICT_TYPE.COMMON_STATUS)" :key="parseInt(dict.value)"
8   - :label="parseInt(dict.value)">
  8 + :label="parseInt(dict.value)"
  9 + >
9 10 {{ dict.label }}
10 11 </el-radio>
11 12 </el-radio-group>
... ... @@ -22,16 +23,16 @@
22 23 </div>
23 24 </template>
24 25 <script>
25   -import { createChannel, getChannel, updateChannel } from "@/api/pay/channel";
26   -import { CommonStatusEnum } from "@/utils/constants";
  26 +import { createChannel, getChannel, updateChannel } from '@/api/pay/channel'
  27 +import { CommonStatusEnum } from '@/utils/constants'
27 28  
28 29 export default {
29   - name: "mockChannelForm",
  30 + name: 'noneConfigChannelForm',
30 31 data() {
31 32 return {
32 33 dialogVisible: false,
33 34 formLoading: false,
34   - title:'',
  35 + title: '',
35 36 formData: {
36 37 appId: '',
37 38 code: '',
... ... @@ -39,54 +40,54 @@ export default {
39 40 feeRate: 0,
40 41 remark: '',
41 42 config: {
42   - name: 'mock-conf'
  43 + name: 'none-config'
43 44 }
44 45 },
45 46 rules: {
46   - status: [{ required: true, message: '渠道状态不能为空', trigger: 'blur' }]
  47 + status: [{ required: true, message: '渠道状态不能为空', trigger: 'blur' }]
47 48 }
48 49 }
49 50 },
50 51 methods: {
51 52 open(appId, code) {
52   - this.dialogVisible = true;
53   - this.formLoading = true;
54   - this.reset(appId, code);
  53 + this.dialogVisible = true
  54 + this.formLoading = true
  55 + this.reset(appId, code)
55 56 getChannel(appId, code).then(response => {
56 57 if (response.data && response.data.id) {
57   - this.formData = response.data;
58   - this.formData.config = JSON.parse(response.data.config);
  58 + this.formData = response.data
  59 + this.formData.config = JSON.parse(response.data.config)
59 60 }
60 61 this.title = !this.formData.id ? '创建支付渠道' : '编辑支付渠道'
61 62 }).finally(() => {
62   - this.formLoading = false;
63   - });
  63 + this.formLoading = false
  64 + })
64 65 },
65 66 close() {
66   - this.dialogVisible = false;
67   - this.reset(undefined, undefined);
  67 + this.dialogVisible = false
  68 + this.reset(undefined, undefined)
68 69 },
69 70 submitForm() {
70 71 this.$refs['form'].validate(valid => {
71 72 if (!valid) {
72 73 return
73 74 }
74   - const data = { ...this.formData };
75   - data.config = JSON.stringify(this.formData.config);
  75 + const data = { ...this.formData }
  76 + data.config = JSON.stringify(this.formData.config)
76 77 if (!data.id) {
77 78 createChannel(data).then(response => {
78   - this.$modal.msgSuccess("新增成功");
  79 + this.$modal.msgSuccess('新增成功')
79 80 this.$emit('success')
80   - this.close();
81   - });
  81 + this.close()
  82 + })
82 83 } else {
83 84 updateChannel(data).then(response => {
84   - this.$modal.msgSuccess("修改成功");
  85 + this.$modal.msgSuccess('修改成功')
85 86 this.$emit('success')
86   - this.close();
  87 + this.close()
87 88 })
88 89 }
89   - });
  90 + })
90 91 },
91 92 /** 重置表单 */
92 93 reset(appId, code) {
... ... @@ -97,11 +98,11 @@ export default {
97 98 remark: '',
98 99 feeRate: 0,
99 100 config: {
100   - name: 'mock-conf'
  101 + name: 'none-config'
101 102 }
102 103 }
103 104 this.resetForm('form')
104   - },
  105 + }
105 106 }
106 107 }
107 108 </script>
... ...
yudao-ui-admin/src/views/pay/app/index.vue
... ... @@ -170,6 +170,19 @@
170 170 </template>
171 171 </el-table-column>
172 172 </el-table-column>
  173 + <el-table-column label="钱包支付配置" align="center">
  174 + <el-table-column :label="payChannelEnum.WALLET.name" align="center">
  175 + <template v-slot="scope">
  176 + <el-button type="success" icon="el-icon-check" circle
  177 + v-if="isChannelExists(scope.row.channelCodes, payChannelEnum.WALLET.code)"
  178 + @click="handleChannel(scope.row, payChannelEnum.WALLET.code)">
  179 + </el-button>
  180 + <el-button v-else type="danger" icon="el-icon-close" circle
  181 + @click="handleChannel(scope.row, payChannelEnum.WALLET.code)">
  182 + </el-button>
  183 + </template>
  184 + </el-table-column>
  185 + </el-table-column>
173 186 <el-table-column label="操作" align="center" class-name="small-padding fixed-width">
174 187 <template v-slot="scope">
175 188 <el-button size="mini" type="text" icon="el-icon-edit" @click="handleUpdate(scope.row)"
... ... @@ -219,7 +232,7 @@
219 232 <!-- 对话框(支付应用的配置) -->
220 233 <weixin-channel-form ref="weixinChannelFormRef" @success="getList" />
221 234 <alipay-channel-form ref="alipayChannelFormRef" @success="getList" />
222   - <mock-channel-form ref="mockChannelFormRef" @success="getList" />
  235 + <none-config-channel-form ref="noneConfigChannelFormRef" @success="getList" />
223 236 </div>
224 237 </template>
225 238  
... ... @@ -228,14 +241,14 @@ import { createApp, updateApp, changeAppStatus, deleteApp, getApp, getAppPage }
228 241 import { PayChannelEnum, CommonStatusEnum } from "@/utils/constants";
229 242 import weixinChannelForm from "@/views/pay/app/components/weixinChannelForm";
230 243 import alipayChannelForm from "@/views/pay/app/components/alipayChannelForm";
231   -import mockChannelForm from '@/views/pay/app/components/mockChannelForm';
  244 +import noneConfigChannelForm from '@/views/pay/app/components/noneConfigChannelForm';
232 245  
233 246 export default {
234 247 name: "PayApp",
235 248 components: {
236 249 weixinChannelForm,
237 250 alipayChannelForm,
238   - mockChannelForm
  251 + noneConfigChannelForm
239 252 },
240 253 data() {
241 254 return {
... ... @@ -391,7 +404,11 @@ export default {
391 404 return
392 405 }
393 406 if (code === 'mock') {
394   - this.$refs['mockChannelFormRef'].open(row.id, code);
  407 + this.$refs['noneConfigChannelFormRef'].open(row.id, code);
  408 + return
  409 + }
  410 + if (code === 'wallet') {
  411 + this.$refs['noneConfigChannelFormRef'].open(row.id, code);
395 412 return
396 413 }
397 414 },
... ...
yudao-ui-admin/src/views/pay/cashier/index.vue
... ... @@ -136,6 +136,10 @@ export default {
136 136 name: '模拟支付',
137 137 icon: require("@/assets/images/pay/icon/mock.svg"),
138 138 code: "mock"
  139 + }, {
  140 + name: '钱包支付',
  141 + icon: require("@/assets/images/pay/icon/mock.svg"),
  142 + code: "wallet"
139 143 }],
140 144 submitLoading: false, // 提交支付的 loading
141 145 interval: undefined, // 定时任务,轮询是否完成支付
... ...