Commit 929ff4286afe6f42e1c6fa4785a34e3e9c9adb3c

Authored by owen
2 parents 171161e6 96b1662e

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

Showing 661 changed files with 3579 additions and 48251 deletions

Too many changes.

To preserve performance only 100 of 661 files are displayed.

README.md
@@ -15,6 +15,8 @@ @@ -15,6 +15,8 @@
15 * 启动文档:<https://doc.iocoder.cn/quick-start/> 15 * 启动文档:<https://doc.iocoder.cn/quick-start/>
16 * 视频教程:<https://doc.iocoder.cn/video/> 16 * 视频教程:<https://doc.iocoder.cn/video/>
17 17
  18 +已支持 Spring Boot 3.X + JDK 17 版本,可见 [master-boot3](https://gitee.com/zhijiantianya/ruoyi-vue-pro/blob/master/README.md) 分支。
  19 +
18 ## 🐯 平台简介 20 ## 🐯 平台简介
19 21
20 **芋道**,以开发者为中心,打造中国第一流的快速开发平台,全部开源,个人与企业可 100% 免费使用。 22 **芋道**,以开发者为中心,打造中国第一流的快速开发平台,全部开源,个人与企业可 100% 免费使用。
@@ -62,18 +64,18 @@ @@ -62,18 +64,18 @@
62 | [yudao-ui-admin](https://gitee.com/zhijiantianya/ruoyi-vue-pro/tree/master/yudao-ui-admin) | [![Gitee star](https://gitee.com/zhijiantianya/ruoyi-vue-pro/badge/star.svg?theme=white)](https://gitee.com/zhijiantianya/ruoyi-vue-pro/tree/master/yudao-ui-admin) [![GitHub stars](https://img.shields.io/github/stars/YunaiV/ruoyi-vue-pro.svg?style=social&label=Stars)](https://github.com/YunaiV/ruoyi-vue-pro/tree/master/yudao-ui-admin) | 基于 Vue2 + element-ui 实现的管理后台 | 64 | [yudao-ui-admin](https://gitee.com/zhijiantianya/ruoyi-vue-pro/tree/master/yudao-ui-admin) | [![Gitee star](https://gitee.com/zhijiantianya/ruoyi-vue-pro/badge/star.svg?theme=white)](https://gitee.com/zhijiantianya/ruoyi-vue-pro/tree/master/yudao-ui-admin) [![GitHub stars](https://img.shields.io/github/stars/YunaiV/ruoyi-vue-pro.svg?style=social&label=Stars)](https://github.com/YunaiV/ruoyi-vue-pro/tree/master/yudao-ui-admin) | 基于 Vue2 + element-ui 实现的管理后台 |
63 | [yudao-ui-admin-uniapp](https://gitee.com/zhijiantianya/ruoyi-vue-pro/tree/master/yudao-ui-admin-uniapp) | [![Gitee star](https://gitee.com/zhijiantianya/ruoyi-vue-pro/badge/star.svg?theme=white)](https://gitee.com/zhijiantianya/ruoyi-vue-pro/tree/master/yudao-ui-admin-uniapp) [![GitHub stars](https://img.shields.io/github/stars/YunaiV/ruoyi-vue-pro.svg?style=social&label=Stars)](https://github.com/YunaiV/ruoyi-vue-pro/tree/master/yudao-ui-admin-uniapp) | 基于 uni-app + uni-ui 实现的管理后台的小程序 | 65 | [yudao-ui-admin-uniapp](https://gitee.com/zhijiantianya/ruoyi-vue-pro/tree/master/yudao-ui-admin-uniapp) | [![Gitee star](https://gitee.com/zhijiantianya/ruoyi-vue-pro/badge/star.svg?theme=white)](https://gitee.com/zhijiantianya/ruoyi-vue-pro/tree/master/yudao-ui-admin-uniapp) [![GitHub stars](https://img.shields.io/github/stars/YunaiV/ruoyi-vue-pro.svg?style=social&label=Stars)](https://github.com/YunaiV/ruoyi-vue-pro/tree/master/yudao-ui-admin-uniapp) | 基于 uni-app + uni-ui 实现的管理后台的小程序 |
64 | [yudao-ui-go-view](https://gitee.com/yudaocode/yudao-ui-go-view) | [![Gitee star](https://gitee.com/yudaocode/yudao-ui-go-view/badge/star.svg?theme=white)](https://gitee.com/yudaocode/yudao-ui-go-view) [![GitHub stars](https://img.shields.io/github/stars/yudaocode/yudao-ui-go-view.svg?style=social&label=Stars)](https://github.com/yudaocode/yudao-ui-go-view) | 基于 Vue3 + naive-ui 实现的大屏报表 | 66 | [yudao-ui-go-view](https://gitee.com/yudaocode/yudao-ui-go-view) | [![Gitee star](https://gitee.com/yudaocode/yudao-ui-go-view/badge/star.svg?theme=white)](https://gitee.com/yudaocode/yudao-ui-go-view) [![GitHub stars](https://img.shields.io/github/stars/yudaocode/yudao-ui-go-view.svg?style=social&label=Stars)](https://github.com/yudaocode/yudao-ui-go-view) | 基于 Vue3 + naive-ui 实现的大屏报表 |
65 -| [yudao-ui-app](https://gitee.com/zhijiantianya/ruoyi-vue-pro/tree/master/yudao-ui-app) | [![Gitee star](https://gitee.com/zhijiantianya/ruoyi-vue-pro/badge/star.svg?theme=white)](https://gitee.com/zhijiantianya/ruoyi-vue-pro/tree/master/yudao-ui-app) [![GitHub stars](https://img.shields.io/github/stars/YunaiV/ruoyi-vue-pro.svg?style=social&label=Stars)](https://github.com/YunaiV/ruoyi-vue-pro/tree/master/yudao-ui-app) | 基于 uni-app + uview 实现的用户 App | 67 +| [yudao-mall-uniapp](https://gitee.com/yudaocode/yudao-mall-uniapp) | [![Gitee star](https://gitee.com/yudaocode/yudao-mall-uniapp/badge/star.svg?theme=white)](https://gitee.com/yudaocode/yudao-mall-uniapp) [![GitHub stars](https://img.shields.io/github/stars/yudaocode/yudao-mall-uniapp.svg?style=social&label=Stars)](https://github.com/yudaocode/yudao-mall-uniapp) | 基于 uni-app 实现的商城小程序 |
66 68
67 ## 🐰 分支说明 69 ## 🐰 分支说明
68 70
69 | | JDK 8 完整版 | JDK 8 精简版 | JDK 17 完整版 | 71 | | JDK 8 完整版 | JDK 8 精简版 | JDK 17 完整版 |
70 |-------|-----------------------------------------------------------|--------------------------------------------------------------------|-----------------------------------------------------------------------------| 72 |-------|-----------------------------------------------------------|--------------------------------------------------------------------|-----------------------------------------------------------------------------|
71 -| 分支 | [`master`](https://gitee.com/zhijiantianya/ruoyi-vue-pro) | [`mini`](https://gitee.com/zhijiantianya/ruoyi-vue-pro/tree/mini/) | [`boot-dev`](https://gitee.com/zhijiantianya/ruoyi-vue-pro/tree/boot3-dev/) | 73 +| 分支 | [`master`](https://gitee.com/zhijiantianya/ruoyi-vue-pro) | [`mini`](https://gitee.com/zhijiantianya/ruoyi-vue-pro/tree/mini/) | [`master-boot3`](https://gitee.com/zhijiantianya/ruoyi-vue-pro/tree/master-boot3/) |
72 | 说明 | 包括所有功能 | 只保留核心功能 | 适配 Spring Boot 3.X | 74 | 说明 | 包括所有功能 | 只保留核心功能 | 适配 Spring Boot 3.X |
73 | 系统功能 | √ | √ | √ | 75 | 系统功能 | √ | √ | √ |
74 | 基础设施 | √ | √ | √ | 76 | 基础设施 | √ | √ | √ |
75 | 会员中心 | √ | √ | √ | 77 | 会员中心 | √ | √ | √ |
76 -| 工作流程 | √ | x | 适配中 | 78 +| 工作流程 | √ | x | √ |
77 | 数据报表 | √ | x | 适配中 | 79 | 数据报表 | √ | x | 适配中 |
78 | 商城系统 | √ | x | √ | 80 | 商城系统 | √ | x | √ |
79 | 微信公众号 | √ | x | √ | 81 | 微信公众号 | √ | x | √ |
@@ -218,6 +220,10 @@ @@ -218,6 +220,10 @@
218 220
219 ![功能图](/.image/common/mall-preview.png) 221 ![功能图](/.image/common/mall-preview.png)
220 222
  223 +_前端基于 crmeb uniapp 经过授权重构,优化代码实现,接入芋道快速开发平台_
  224 +
  225 +演示地址:<https://doc.iocoder.cn/mall-preview/>
  226 +
221 ### 会员中心 227 ### 会员中心
222 228
223 | | 功能 | 描述 | 229 | | 功能 | 描述 |
@@ -248,29 +254,29 @@ @@ -248,29 +254,29 @@
248 254
249 ### 框架 255 ### 框架
250 256
251 -| 框架 | 说明 | 版本 | 学习指南 |  
252 -|---------------------------------------------------------------------------------------------|------------------|-------------|----------------------------------------------------------------|  
253 -| [Spring Boot](https://spring.io/projects/spring-boot) | 应用开发框架 | 2.7.14 | [文档](https://github.com/YunaiV/SpringBoot-Labs) |  
254 -| [MySQL](https://www.mysql.com/cn/) | 数据库服务器 | 5.7 / 8.0+ | |  
255 -| [Druid](https://github.com/alibaba/druid) | JDBC 连接池、监控组件 | 1.2.18 | [文档](http://www.iocoder.cn/Spring-Boot/datasource-pool/?yudao) |  
256 -| [MyBatis Plus](https://mp.baomidou.com/) | MyBatis 增强工具包 | 3.5.3.1 | [文档](http://www.iocoder.cn/Spring-Boot/MyBatis/?yudao) |  
257 -| [Dynamic Datasource](https://dynamic-datasource.com/) | 动态数据源 | 3.6.1 | [文档](http://www.iocoder.cn/Spring-Boot/datasource-pool/?yudao) |  
258 -| [Redis](https://redis.io/) | key-value 数据库 | 5.0 / 6.0 | |  
259 -| [Redisson](https://github.com/redisson/redisson) | Redis 客户端 | 3.18.0 | [文档](http://www.iocoder.cn/Spring-Boot/Redis/?yudao) |  
260 -| [Spring MVC](https://github.com/spring-projects/spring-framework/tree/master/spring-webmvc) | MVC 框架 | 5.3.24 | [文档](http://www.iocoder.cn/SpringMVC/MVC/?yudao) |  
261 -| [Spring Security](https://github.com/spring-projects/spring-security) | Spring 安全框架 | 5.7.6 | [文档](http://www.iocoder.cn/Spring-Boot/Spring-Security/?yudao) |  
262 -| [Hibernate Validator](https://github.com/hibernate/hibernate-validator) | 参数校验组件 | 6.2.5 | [文档](http://www.iocoder.cn/Spring-Boot/Validation/?yudao) |  
263 -| [Flowable](https://github.com/flowable/flowable-engine) | 工作流引擎 | 6.8.0 | [文档](https://doc.iocoder.cn/bpm/) |  
264 -| [Quartz](https://github.com/quartz-scheduler) | 任务调度组件 | 2.3.2 | [文档](http://www.iocoder.cn/Spring-Boot/Job/?yudao) |  
265 -| [Springdoc](https://springdoc.org/) | Swagger 文档 | 1.6.15 | [文档](http://www.iocoder.cn/Spring-Boot/Swagger/?yudao) |  
266 -| [Resilience4j](https://github.com/resilience4j/resilience4j) | 服务保障组件 | 1.7.1 | [文档](http://www.iocoder.cn/Spring-Boot/Resilience4j/?yudao) |  
267 -| [SkyWalking](https://skywalking.apache.org/) | 分布式应用追踪系统 | 8.12.0 | [文档](http://www.iocoder.cn/Spring-Boot/SkyWalking/?yudao) |  
268 -| [Spring Boot Admin](https://github.com/codecentric/spring-boot-admin) | Spring Boot 监控平台 | 2.7.10 | [文档](http://www.iocoder.cn/Spring-Boot/Admin/?yudao) |  
269 -| [Jackson](https://github.com/FasterXML/jackson) | JSON 工具库 | 2.13.3 | |  
270 -| [MapStruct](https://mapstruct.org/) | Java Bean 转换 | 1.5.5.Final | [文档](http://www.iocoder.cn/Spring-Boot/MapStruct/?yudao) |  
271 -| [Lombok](https://projectlombok.org/) | 消除冗长的 Java 代码 | 1.18.28 | [文档](http://www.iocoder.cn/Spring-Boot/Lombok/?yudao) |  
272 -| [JUnit](https://junit.org/junit5/) | Java 单元测试框架 | 5.8.2 | - |  
273 -| [Mockito](https://github.com/mockito/mockito) | Java Mock 框架 | 4.8.0 | - | 257 +| 框架 | 说明 | 版本 | 学习指南 |
  258 +|---------------------------------------------------------------------------------------------|------------------|----------------|----------------------------------------------------------------|
  259 +| [Spring Boot](https://spring.io/projects/spring-boot) | 应用开发框架 | 2.7.16 | [文档](https://github.com/YunaiV/SpringBoot-Labs) |
  260 +| [MySQL](https://www.mysql.com/cn/) | 数据库服务器 | 5.7 / 8.0+ | |
  261 +| [Druid](https://github.com/alibaba/druid) | JDBC 连接池、监控组件 | 1.2.19 | [文档](http://www.iocoder.cn/Spring-Boot/datasource-pool/?yudao) |
  262 +| [MyBatis Plus](https://mp.baomidou.com/) | MyBatis 增强工具包 | 3.5.3.2 | [文档](http://www.iocoder.cn/Spring-Boot/MyBatis/?yudao) |
  263 +| [Dynamic Datasource](https://dynamic-datasource.com/) | 动态数据源 | 3.6.1 | [文档](http://www.iocoder.cn/Spring-Boot/datasource-pool/?yudao) |
  264 +| [Redis](https://redis.io/) | key-value 数据库 | 5.0 / 6.0 /7.0 | |
  265 +| [Redisson](https://github.com/redisson/redisson) | Redis 客户端 | 3.18.0 | [文档](http://www.iocoder.cn/Spring-Boot/Redis/?yudao) |
  266 +| [Spring MVC](https://github.com/spring-projects/spring-framework/tree/master/spring-webmvc) | MVC 框架 | 5.3.24 | [文档](http://www.iocoder.cn/SpringMVC/MVC/?yudao) |
  267 +| [Spring Security](https://github.com/spring-projects/spring-security) | Spring 安全框架 | 5.7.11 | [文档](http://www.iocoder.cn/Spring-Boot/Spring-Security/?yudao) |
  268 +| [Hibernate Validator](https://github.com/hibernate/hibernate-validator) | 参数校验组件 | 6.2.5 | [文档](http://www.iocoder.cn/Spring-Boot/Validation/?yudao) |
  269 +| [Flowable](https://github.com/flowable/flowable-engine) | 工作流引擎 | 6.8.0 | [文档](https://doc.iocoder.cn/bpm/) |
  270 +| [Quartz](https://github.com/quartz-scheduler) | 任务调度组件 | 2.3.2 | [文档](http://www.iocoder.cn/Spring-Boot/Job/?yudao) |
  271 +| [Springdoc](https://springdoc.org/) | Swagger 文档 | 1.6.15 | [文档](http://www.iocoder.cn/Spring-Boot/Swagger/?yudao) |
  272 +| [Resilience4j](https://github.com/resilience4j/resilience4j) | 服务保障组件 | 1.7.1 | [文档](http://www.iocoder.cn/Spring-Boot/Resilience4j/?yudao) |
  273 +| [SkyWalking](https://skywalking.apache.org/) | 分布式应用追踪系统 | 8.12.0 | [文档](http://www.iocoder.cn/Spring-Boot/SkyWalking/?yudao) |
  274 +| [Spring Boot Admin](https://github.com/codecentric/spring-boot-admin) | Spring Boot 监控平台 | 2.7.10 | [文档](http://www.iocoder.cn/Spring-Boot/Admin/?yudao) |
  275 +| [Jackson](https://github.com/FasterXML/jackson) | JSON 工具库 | 2.13.3 | |
  276 +| [MapStruct](https://mapstruct.org/) | Java Bean 转换 | 1.5.5.Final | [文档](http://www.iocoder.cn/Spring-Boot/MapStruct/?yudao) |
  277 +| [Lombok](https://projectlombok.org/) | 消除冗长的 Java 代码 | 1.18.30 | [文档](http://www.iocoder.cn/Spring-Boot/Lombok/?yudao) |
  278 +| [JUnit](https://junit.org/junit5/) | Java 单元测试框架 | 5.8.2 | - |
  279 +| [Mockito](https://github.com/mockito/mockito) | Java Mock 框架 | 4.8.0 | - |
274 280
275 ## 🐷 演示图 281 ## 🐷 演示图
276 282
@@ -30,7 +30,7 @@ @@ -30,7 +30,7 @@
30 <url>https://github.com/YunaiV/ruoyi-vue-pro</url> 30 <url>https://github.com/YunaiV/ruoyi-vue-pro</url>
31 31
32 <properties> 32 <properties>
33 - <revision>1.8.1-snapshot</revision> 33 + <revision>1.8.2-snapshot</revision>
34 <!-- Maven 相关 --> 34 <!-- Maven 相关 -->
35 <java.version>1.8</java.version> 35 <java.version>1.8</java.version>
36 <maven.compiler.source>${java.version}</maven.compiler.source> 36 <maven.compiler.source>${java.version}</maven.compiler.source>
@@ -39,8 +39,8 @@ @@ -39,8 +39,8 @@
39 <maven-compiler-plugin.version>3.8.1</maven-compiler-plugin.version> 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 <flatten-maven-plugin.version>1.5.0</flatten-maven-plugin.version>
41 <!-- 看看咋放到 bom 里 --> 41 <!-- 看看咋放到 bom 里 -->
42 - <lombok.version>1.18.28</lombok.version>  
43 - <spring.boot.version>2.7.14</spring.boot.version> 42 + <lombok.version>1.18.30</lombok.version>
  43 + <spring.boot.version>2.7.16</spring.boot.version>
44 <mapstruct.version>1.5.5.Final</mapstruct.version> 44 <mapstruct.version>1.5.5.Final</mapstruct.version>
45 <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> 45 <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
46 </properties> 46 </properties>
sql/mysql/brokerage.sql deleted
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 1 NOT NULL COMMENT '分佣模式:1-人人分销 2-指定分销',  
7 - brokerage_bind_mode TINYINT DEFAULT 1 NOT NULL COMMENT '分销关系绑定模式: 1-没有推广人,2-新用户, 3-扫码覆盖',  
8 - brokerage_poster_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_withdraw_fee_percent INT DEFAULT 0 NOT NULL COMMENT '提现手续费百分比',  
13 - brokerage_bank_names VARCHAR(200) DEFAULT '' NOT NULL COMMENT '提现银行(字典类型=brokerage_bank_name)',  
14 - brokerage_frozen_days INT DEFAULT 7 NOT NULL COMMENT '佣金冻结时间(天)',  
15 - brokerage_withdraw_types VARCHAR(32) DEFAULT '1,2,3,4' NOT NULL COMMENT '提现方式:1-钱包;2-银行卡;3-微信;4-支付宝',  
16 - creator VARCHAR(64) DEFAULT '' NULL COMMENT '创建者',  
17 - create_time DATETIME DEFAULT CURRENT_TIMESTAMP NOT NULL COMMENT '创建时间',  
18 - updater VARCHAR(64) DEFAULT '' NULL COMMENT '更新者',  
19 - update_time DATETIME DEFAULT CURRENT_TIMESTAMP NOT NULL ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',  
20 - deleted BIT DEFAULT b'0' NOT NULL COMMENT '是否删除',  
21 - tenant_id BIGINT DEFAULT 0 NOT NULL COMMENT '租户编号'  
22 -) COMMENT '交易中心配置';  
23 -  
24 -# alter table trade_config  
25 -# add brokerage_withdraw_fee_percent int default 0 not null comment '提现手续费百分比' after brokerage_withdraw_min_price;  
26 -  
27 -# alter table trade_brokerage_user  
28 -# add level int not null default 1 comment '等级' after frozen_price;  
29 -# alter table trade_brokerage_user  
30 -# add path varchar(2000) null comment '路径' after level;  
31 -  
32 -  
33 --- 增加分销用户扩展表  
34 -create table trade_brokerage_user  
35 -(  
36 - id bigint auto_increment comment '用户编号' primary key,  
37 - bind_user_id bigint null comment '推广员编号',  
38 - bind_user_time datetime null comment '推广员绑定时间',  
39 - brokerage_enabled bit default 1 not null comment '是否成为推广员',  
40 - brokerage_time datetime null comment '成为分销员时间',  
41 - price int default 0 not null comment '可用佣金',  
42 - frozen_price int default 0 not null comment '冻结佣金',  
43 - creator varchar(64) default '' null comment '创建者',  
44 - create_time datetime default CURRENT_TIMESTAMP not null comment '创建时间',  
45 - updater varchar(64) default '' null comment '更新者',  
46 - update_time datetime default CURRENT_TIMESTAMP not null on update CURRENT_TIMESTAMP comment '更新时间',  
47 - deleted bit default b'0' not null comment '是否删除',  
48 - tenant_id bigint default 0 not null comment '租户编号'  
49 -)  
50 - comment '分销用户';  
51 -  
52 -create index idx_invite_user_id on trade_brokerage_user (bind_user_id) comment '推广员编号';  
53 -create index idx_agent on trade_brokerage_user (brokerage_enabled) comment '是否成为推广员';  
54 -  
55 -  
56 -create table trade_brokerage_record  
57 -(  
58 - id int auto_increment comment '编号'  
59 - primary key,  
60 - user_id bigint not null comment '用户编号',  
61 - biz_id varchar(64) default '' not null comment '业务编号',  
62 - biz_type tinyint default 0 not null comment '业务类型:1-订单,2-提现',  
63 - title varchar(64) default '' not null comment '标题',  
64 - price int default 0 not null comment '金额',  
65 - total_price int default 0 not null comment '当前总佣金',  
66 - description varchar(500) default '' not null comment '说明',  
67 - status tinyint default 0 not null comment '状态:0-待结算,1-已结算,2-已取消',  
68 - frozen_days int default 0 not null comment '冻结时间(天)',  
69 - unfreeze_time datetime null comment '解冻时间',  
70 - source_user_level int not null comment '来源用户等级',  
71 - source_user_id bigint not null comment '来源用户编号',  
72 - creator varchar(64) default '' null comment '创建者',  
73 - create_time datetime default CURRENT_TIMESTAMP not null comment '创建时间',  
74 - updater varchar(64) default '' null comment '更新者',  
75 - update_time datetime default CURRENT_TIMESTAMP not null on update CURRENT_TIMESTAMP comment '更新时间',  
76 - deleted bit default b'0' not null comment '是否删除',  
77 - tenant_id bigint default 0 not null comment '租户编号'  
78 -)  
79 - comment '佣金记录';  
80 -  
81 -create index idx_user_id on trade_brokerage_record (user_id) comment '用户编号';  
82 -create index idx_biz on trade_brokerage_record (biz_type, biz_id) comment '业务';  
83 -create index idx_status on trade_brokerage_record (status) comment '状态';  
84 -  
85 -  
86 -create table trade_brokerage_withdraw  
87 -(  
88 - id bigint auto_increment comment '编号'  
89 - primary key,  
90 - user_id bigint not null comment '用户编号',  
91 - price int default 0 not null comment '提现金额',  
92 - fee_price int default 0 not null comment '提现手续费',  
93 - total_price int default 0 not null comment '当前总佣金',  
94 - type tinyint default 0 not null comment '提现类型:1-钱包;2-银行卡;3-微信;4-支付宝',  
95 - name varchar(64) null comment '真实姓名',  
96 - account_no varchar(64) null comment '账号',  
97 - bank_name varchar(100) null comment '银行名称',  
98 - bank_address varchar(200) null comment '开户地址',  
99 - account_qr_code_url varchar(512) null comment '收款码',  
100 - status tinyint(2) default 0 not null comment '状态:0-审核中,10-审核通过 20-审核不通过;预留:11 - 提现成功;21-提现失败',  
101 - audit_reason varchar(128) null comment '审核驳回原因',  
102 - audit_time datetime null comment '审核时间',  
103 - remark varchar(500) null comment '备注',  
104 - creator varchar(64) default '' null comment '创建者',  
105 - create_time datetime default CURRENT_TIMESTAMP not null comment '创建时间',  
106 - updater varchar(64) default '' null comment '更新者',  
107 - update_time datetime default CURRENT_TIMESTAMP not null on update CURRENT_TIMESTAMP comment '更新时间',  
108 - deleted bit default b'0' not null comment '是否删除',  
109 - tenant_id bigint default 0 not null comment '租户编号'  
110 -)  
111 - comment '佣金提现';  
112 -  
113 -create index idx_user_id on trade_brokerage_withdraw (user_id) comment '用户编号';  
114 -create index idx_audit_status on trade_brokerage_withdraw (status) comment '状态';  
115 -  
116 --- 增加字典  
117 -insert into system_dict_type(type, name)  
118 -values ('brokerage_enabled_condition', '分佣模式');  
119 -insert into system_dict_data(dict_type, label, value, sort, remark)  
120 -values ('brokerage_enabled_condition', '人人分销', 1, 1, '所有用户都可以分销'),  
121 - ('brokerage_enabled_condition', '指定分销', 2, 2, '仅可后台手动设置推广员');  
122 -  
123 -insert into system_dict_type(type, name)  
124 -values ('brokerage_bind_mode', '分销关系绑定模式');  
125 -insert into system_dict_data(dict_type, label, value, sort, remark)  
126 -values ('brokerage_bind_mode', '没有推广人', 1, 1, '只要用户没有推广人,随时都可以绑定推广关系'),  
127 - ('brokerage_bind_mode', '新用户', 2, 2, '仅新用户注册时才能绑定推广关系'),  
128 - ('brokerage_bind_mode', '扫码覆盖', 3, 3, '如果用户已经有推广人,推广人会被变更');  
129 -  
130 -insert into system_dict_type(type, name)  
131 -values ('brokerage_withdraw_type', '佣金提现类型');  
132 -insert into system_dict_data(dict_type, label, value, sort)  
133 -values ('brokerage_withdraw_type', '钱包', 1, 1),  
134 - ('brokerage_withdraw_type', '银行卡', 2, 2),  
135 - ('brokerage_withdraw_type', '微信', 3, 3),  
136 - ('brokerage_withdraw_type', '支付宝', 4, 4);  
137 -  
138 -insert into system_dict_type(type, name)  
139 -values ('brokerage_record_biz_type', '佣金记录业务类型');  
140 -insert into system_dict_data(dict_type, label, value, sort)  
141 -values ('brokerage_record_biz_type', '订单返佣', 1, 1),  
142 - ('brokerage_record_biz_type', '申请提现', 2, 2),  
143 - ('brokerage_record_biz_type', '申请提现驳回', 3, 3);  
144 -  
145 -insert into system_dict_type(type, name)  
146 -values ('brokerage_record_status', '佣金记录状态');  
147 -insert into system_dict_data(dict_type, label, value, sort)  
148 -values ('brokerage_record_status', '待结算', 0, 0),  
149 - ('brokerage_record_status', '已结算', 1, 1),  
150 - ('brokerage_record_status', '已取消', 2, 2);  
151 -  
152 -insert into system_dict_type(type, name)  
153 -values ('brokerage_withdraw_status', '佣金提现状态');  
154 -insert into system_dict_data(dict_type, label, value, sort, color_type)  
155 -values ('brokerage_withdraw_status', '审核中', 0, 0, ''),  
156 - ('brokerage_withdraw_status', '审核通过', 10, 10, 'success'),  
157 - ('brokerage_withdraw_status', '提现成功', 11, 11, 'success'),  
158 - ('brokerage_withdraw_status', '审核不通过', 20, 20, 'danger'),  
159 - ('brokerage_withdraw_status', '提现失败', 21, 21, 'danger');  
160 -  
161 -insert into system_dict_type(type, name)  
162 -values ('brokerage_bank_name', '佣金提现银行');  
163 -insert into system_dict_data(dict_type, label, value, sort)  
164 -values ('brokerage_bank_name', '工商银行', 0, 0),  
165 - ('brokerage_bank_name', '建设银行', 1, 1),  
166 - ('brokerage_bank_name', '农业银行', 2, 2),  
167 - ('brokerage_bank_name', '中国银行', 3, 3),  
168 - ('brokerage_bank_name', '交通银行', 4, 4),  
169 - ('brokerage_bank_name', '招商银行', 5, 5);  
170 -  
171 -  
172 --- 交易中心配置:菜单 SQL  
173 -INSERT INTO system_menu(name, permission, type, sort, parent_id, path, icon, component, status, component_name)  
174 -VALUES ('交易中心配置', '', 2, 0, 2072, 'config', 'ep:setting', 'trade/config/index', 0, 'TradeConfig');  
175 --- 按钮父菜单ID  
176 --- 暂时只支持 MySQL。如果你是 Oracle、PostgreSQL、SQLServer 的话,需要手动修改 @parentId 的部分的代码  
177 -SELECT @parentId := LAST_INSERT_ID();  
178 --- 按钮 SQL  
179 -INSERT INTO system_menu(name, permission, type, sort, parent_id, path, icon, component, status)  
180 -VALUES ('交易中心配置查询', 'trade:config:query', 3, 1, @parentId, '', '', '', 0);  
181 -INSERT INTO system_menu(name, permission, type, sort, parent_id, path, icon, component, status)  
182 -VALUES ('交易中心配置保存', 'trade:config:save', 3, 2, @parentId, '', '', '', 0);  
183 -  
184 -  
185 --- 增加菜单:分销  
186 -INSERT INTO system_menu(name, permission, type, sort, parent_id, path, icon, component, status, component_name)  
187 -VALUES ('分销', '', 1, 5, 2072, 'brokerage', 'fa-solid:project-diagram', '', 0, '');  
188 --- 按钮父菜单ID  
189 -SELECT @brokerageMenuId := LAST_INSERT_ID();  
190 -  
191 --- 增加菜单:分销员  
192 --- 菜单 SQL  
193 -INSERT INTO system_menu(name, permission, type, sort, parent_id, path, icon, component, status, component_name)  
194 -VALUES ('分销用户', '', 2, 0, @brokerageMenuId, 'brokerage-user', 'fa-solid:user-tie', 'trade/brokerage/user/index', 0,  
195 - 'TradeBrokerageUser');  
196 --- 按钮父菜单ID  
197 --- 暂时只支持 MySQL。如果你是 Oracle、PostgreSQL、SQLServer 的话,需要手动修改 @parentId 的部分的代码  
198 -SELECT @parentId := LAST_INSERT_ID();  
199 --- 按钮 SQL  
200 -INSERT INTO system_menu(name, permission, type, sort, parent_id, path, icon, component, status)  
201 -VALUES ('分销用户查询', 'trade:brokerage-user:query', 3, 1, @parentId, '', '', '', 0);  
202 -INSERT INTO system_menu(name, permission, type, sort, parent_id, path, icon, component, status)  
203 -VALUES ('分销用户推广人查询', 'trade:brokerage-user:user-query', 3, 2, @parentId, '', '', '', 0);  
204 -INSERT INTO system_menu(name, permission, type, sort, parent_id, path, icon, component, status)  
205 -VALUES ('分销用户推广订单查询', 'trade:brokerage-user:order-query', 3, 3, @parentId, '', '', '', 0);  
206 -INSERT INTO system_menu(name, permission, type, sort, parent_id, path, icon, component, status)  
207 -VALUES ('分销用户修改推广资格', 'trade:brokerage-user:update-brokerage-enable', 3, 4, @parentId, '', '', '', 0);  
208 -INSERT INTO system_menu(name, permission, type, sort, parent_id, path, icon, component, status)  
209 -VALUES ('分销用户修改推广员', 'trade:brokerage-user:update-bind-user', 3, 5, @parentId, '', '', '', 0);  
210 -INSERT INTO system_menu(name, permission, type, sort, parent_id, path, icon, component, status)  
211 -VALUES ('分销用户清除推广员', 'trade:brokerage-user:clear-bind-user', 3, 6, @parentId, '', '', '', 0);  
212 -  
213 --- 增加菜单:佣金记录  
214 -INSERT INTO system_menu(name, permission, type, sort, parent_id, path, icon, component, status, component_name)  
215 -VALUES ('佣金记录', '', 2, 1, @brokerageMenuId, 'brokerage-record', 'fa:money', 'trade/brokerage/record/index', 0,  
216 - 'TradeBrokerageRecord');  
217 --- 按钮父菜单ID  
218 --- 暂时只支持 MySQL。如果你是 Oracle、PostgreSQL、SQLServer 的话,需要手动修改 @parentId 的部分的代码  
219 -SELECT @parentId := LAST_INSERT_ID();  
220 --- 按钮 SQL  
221 -INSERT INTO system_menu(name, permission, type, sort, parent_id, path, icon, component, status)  
222 -VALUES ('佣金记录查询', 'trade:brokerage-record:query', 3, 1, @parentId, '', '', '', 0);  
223 -  
224 --- 增加菜单:佣金提现  
225 -INSERT INTO system_menu(name, permission, type, sort, parent_id, path, icon, component, status, component_name)  
226 -VALUES ('佣金提现', '', 2, 2, @brokerageMenuId, 'brokerage-withdraw', 'fa:credit-card',  
227 - 'trade/brokerage/withdraw/index', 0, 'TradeBrokerageWithdraw');  
228 --- 按钮父菜单ID  
229 --- 暂时只支持 MySQL。如果你是 Oracle、PostgreSQL、SQLServer 的话,需要手动修改 @parentId 的部分的代码  
230 -SELECT @parentId := LAST_INSERT_ID();  
231 --- 按钮 SQL  
232 -INSERT INTO system_menu(name, permission, type, sort, parent_id, path, icon, component, status)  
233 -VALUES ('佣金提现查询', 'trade:brokerage-withdraw:query', 3, 1, @parentId, '', '', '', 0);  
234 -INSERT INTO system_menu(name, permission, type, sort, parent_id, path, icon, component, status)  
235 -VALUES ('佣金提现审核', 'trade:brokerage-withdraw:audit', 3, 2, @parentId, '', '', '', 0);  
236 -  
237 --- 站内信模板  
238 -INSERT INTO `ruoyi-vue-pro`.system_notify_template (name, code, nickname, content, type, params, status)  
239 -VALUES  
240 - ('佣金提现(审核通过)', 'brokerage_withdraw_audit_approve', 'system', '您在{createTime}提现¥{price}元的申请已通过审核', 2, '["createTime","price"]', 0),  
241 - ('佣金提现(审核不通过)', 'brokerage_withdraw_audit_reject', 'system', '您在{createTime}提现¥{price}元的申请未通过审核,原因:{reason}', 2, '["createTime","price","reason"]', 0);  
sql/mysql/optional/mall_trade_log.sql deleted
1 -ALTER TABLE `ruoyi-vue-pro`.`trade_after_sale_log`  
2 - ADD COLUMN `before_status` int NOT NULL COMMENT '售前状态' AFTER `id`,  
3 - ADD COLUMN `after_status` int NOT NULL COMMENT '售后状态' AFTER `before_status`;  
sql/mysql/pay_wallet.sql
@@ -73,3 +73,81 @@ CREATE TABLE `pay_wallet_recharge` @@ -73,3 +73,81 @@ CREATE TABLE `pay_wallet_recharge`
73 PRIMARY KEY (`id`) USING BTREE 73 PRIMARY KEY (`id`) USING BTREE
74 ) ENGINE=InnoDB COMMENT='会员钱包充值'; 74 ) ENGINE=InnoDB COMMENT='会员钱包充值';
75 75
  76 +-- ----------------------------
  77 +-- 转账单表
  78 +-- ----------------------------
  79 +DROP TABLE IF EXISTS `pay_transfer`;
  80 +CREATE TABLE `pay_transfer`
  81 +(
  82 + `id` bigint NOT NULL AUTO_INCREMENT COMMENT '编号',
  83 + `type` int NOT NULL COMMENT '类型',
  84 + `app_id` bigint NOT NULL COMMENT '应用编号',
  85 + `merchant_order_id` varchar(64) NOT NULL COMMENT '商户订单编号',
  86 + `price` int NOT NULL COMMENT '转账金额,单位:分',
  87 + `title` varchar(512) NOT NULL COMMENT '转账标题',
  88 + `payee_info` varchar(512) NOT NULL COMMENT '收款人信息,不同类型和渠道不同',
  89 + `status` tinyint NOT NULL COMMENT '转账状态',
  90 + `success_time` datetime NULL COMMENT '转账成功时间',
  91 + `extension_id` bigint NULL COMMENT '转账渠道编号',
  92 + `no` varchar(64) NULL COMMENT '转账单号',
  93 + `channel_id` bigint NULL COMMENT '转账渠道编号',
  94 + `channel_code` varchar(32) NULL COMMENT '转账渠道编码',
  95 + `creator` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT '' COMMENT '创建者',
  96 + `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
  97 + `updater` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT '' COMMENT '更新者',
  98 + `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
  99 + `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除',
  100 + `tenant_id` bigint NOT NULL DEFAULT 0 COMMENT '租户编号',
  101 + PRIMARY KEY (`id`) USING BTREE
  102 +) ENGINE=InnoDB COMMENT='转账单表';
  103 +
  104 +-- ----------------------------
  105 +-- 转账扩展单
  106 +-- ----------------------------
  107 +DROP TABLE IF EXISTS `pay_transfer_extension`;
  108 +CREATE TABLE `pay_transfer_extension`
  109 +(
  110 + `id` bigint NOT NULL AUTO_INCREMENT COMMENT '编号',
  111 + `no` varchar(64) NOT NULL COMMENT '转账单号',
  112 + `transfer_id` bigint NOT NULL COMMENT '转账单编号',
  113 + `channel_id` bigint NOT NULL COMMENT '转账渠道编号',
  114 + `channel_code` varchar(32) NOT NULL COMMENT '转账渠道编码',
  115 + `channel_extras` varchar(512) NULL DEFAULT NULL COMMENT '支付渠道的额外参数',
  116 + `status` tinyint NOT NULL COMMENT '转账状态',
  117 + `channel_notify_data` varchar(4096) NULL DEFAULT NULL COMMENT '支付渠道异步通知的内容',
  118 + `creator` varchar(64) NULL DEFAULT '' COMMENT '创建者',
  119 + `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
  120 + `updater` varchar(64) NULL DEFAULT '' COMMENT '更新者',
  121 + `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
  122 + `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除',
  123 + `tenant_id` bigint NOT NULL DEFAULT 0 COMMENT '租户编号',
  124 + PRIMARY KEY (`id`) USING BTREE
  125 +) ENGINE=InnoDB COMMENT='转账拓展单表';
  126 +
  127 +-- ----------------------------
  128 +-- Table structure for pay_demo_transfer
  129 +-- ----------------------------
  130 +DROP TABLE IF EXISTS `pay_demo_transfer`;
  131 +CREATE TABLE `pay_demo_transfer` (
  132 + `id` bigint NOT NULL AUTO_INCREMENT COMMENT '订单编号',
  133 + `user_id` bigint UNSIGNED NOT NULL COMMENT '用户编号',
  134 + `price` int NOT NULL COMMENT '转账金额,单位:分',
  135 + `type` int NOT NULL COMMENT '转账类型',
  136 + `payee_info` varchar(512) NOT NULL COMMENT '收款人信息,不同类型和渠道不同',
  137 + `transfer_status` tinyint NOT NULL DEFAULT 0 COMMENT '转账状态',
  138 + `pay_transfer_id` bigint NULL DEFAULT NULL COMMENT '转账订单编号',
  139 + `pay_channel_code` varchar(16) NULL DEFAULT NULL COMMENT '转账支付成功渠道',
  140 + `transfer_time` datetime NULL DEFAULT NULL COMMENT '转账支付时间',
  141 + `creator` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NULL DEFAULT '' COMMENT '创建者',
  142 + `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
  143 + `updater` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NULL DEFAULT '' COMMENT '更新者',
  144 + `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
  145 + `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除',
  146 + `tenant_id` bigint NOT NULL DEFAULT 0 COMMENT '租户编号',
  147 + PRIMARY KEY (`id`) USING BTREE
  148 +) ENGINE = InnoDB COMMENT = '示例业务转账订单\n';
  149 +
  150 +
  151 +ALTER TABLE `pay_channel`
  152 + MODIFY COLUMN `config` text CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '支付渠道配置' AFTER `app_id`;
  153 +
sql/mysql/point.sql deleted
1 -ALTER TABLE trade_order ADD COLUMN use_point int NOT NULL DEFAULT 0 COMMENT '使用的积分' AFTER point_price;  
2 -ALTER TABLE trade_order ADD COLUMN refund_point int NOT NULL DEFAULT 0 COMMENT '退还的使用积分' AFTER use_point;  
3 -ALTER TABLE trade_order ADD COLUMN give_point int NOT NULL DEFAULT 0 COMMENT '赠送的积分' AFTER refund_point;  
4 -  
5 -ALTER TABLE trade_order_item ADD COLUMN use_point int NOT NULL DEFAULT 0 COMMENT '使用的积分' AFTER point_price;  
6 -ALTER TABLE trade_order_item ADD COLUMN give_point int NOT NULL DEFAULT 0 COMMENT '赠送的积分' AFTER use_point;  
sql/mysql/ruoyi-vue-pro.sql
@@ -11,7 +11,7 @@ @@ -11,7 +11,7 @@
11 Target Server Version : 80034 11 Target Server Version : 80034
12 File Encoding : 65001 12 File Encoding : 65001
13 13
14 - Date: 03/09/2023 19:13:55 14 + Date: 24/09/2023 23:23:06
15 */ 15 */
16 16
17 SET NAMES utf8mb4; 17 SET NAMES utf8mb4;
@@ -72,6 +72,7 @@ CREATE TABLE `QRTZ_CRON_TRIGGERS` ( @@ -72,6 +72,7 @@ CREATE TABLE `QRTZ_CRON_TRIGGERS` (
72 -- Records of QRTZ_CRON_TRIGGERS 72 -- Records of QRTZ_CRON_TRIGGERS
73 -- ---------------------------- 73 -- ----------------------------
74 BEGIN; 74 BEGIN;
  75 +INSERT INTO `QRTZ_CRON_TRIGGERS` (`SCHED_NAME`, `TRIGGER_NAME`, `TRIGGER_GROUP`, `CRON_EXPRESSION`, `TIME_ZONE_ID`) VALUES ('schedulerName', 'demoJob', 'DEFAULT', '0 0 0 * * ?', 'Asia/Shanghai');
75 INSERT INTO `QRTZ_CRON_TRIGGERS` (`SCHED_NAME`, `TRIGGER_NAME`, `TRIGGER_GROUP`, `CRON_EXPRESSION`, `TIME_ZONE_ID`) VALUES ('schedulerName', 'payNotifyJob', 'DEFAULT', '* * * * * ?', 'Asia/Shanghai'); 76 INSERT INTO `QRTZ_CRON_TRIGGERS` (`SCHED_NAME`, `TRIGGER_NAME`, `TRIGGER_GROUP`, `CRON_EXPRESSION`, `TIME_ZONE_ID`) VALUES ('schedulerName', 'payNotifyJob', 'DEFAULT', '* * * * * ?', 'Asia/Shanghai');
76 INSERT INTO `QRTZ_CRON_TRIGGERS` (`SCHED_NAME`, `TRIGGER_NAME`, `TRIGGER_GROUP`, `CRON_EXPRESSION`, `TIME_ZONE_ID`) VALUES ('schedulerName', 'payOrderExpireJob', 'DEFAULT', '0 0/1 * * * ?', 'Asia/Shanghai'); 77 INSERT INTO `QRTZ_CRON_TRIGGERS` (`SCHED_NAME`, `TRIGGER_NAME`, `TRIGGER_GROUP`, `CRON_EXPRESSION`, `TIME_ZONE_ID`) VALUES ('schedulerName', 'payOrderExpireJob', 'DEFAULT', '0 0/1 * * * ?', 'Asia/Shanghai');
77 INSERT INTO `QRTZ_CRON_TRIGGERS` (`SCHED_NAME`, `TRIGGER_NAME`, `TRIGGER_GROUP`, `CRON_EXPRESSION`, `TIME_ZONE_ID`) VALUES ('schedulerName', 'payOrderSyncJob', 'DEFAULT', '0 0/1 * * * ?', 'Asia/Shanghai'); 78 INSERT INTO `QRTZ_CRON_TRIGGERS` (`SCHED_NAME`, `TRIGGER_NAME`, `TRIGGER_GROUP`, `CRON_EXPRESSION`, `TIME_ZONE_ID`) VALUES ('schedulerName', 'payOrderSyncJob', 'DEFAULT', '0 0/1 * * * ?', 'Asia/Shanghai');
@@ -135,6 +136,7 @@ CREATE TABLE `QRTZ_JOB_DETAILS` ( @@ -135,6 +136,7 @@ CREATE TABLE `QRTZ_JOB_DETAILS` (
135 -- Records of QRTZ_JOB_DETAILS 136 -- Records of QRTZ_JOB_DETAILS
136 -- ---------------------------- 137 -- ----------------------------
137 BEGIN; 138 BEGIN;
  139 +INSERT INTO `QRTZ_JOB_DETAILS` (`SCHED_NAME`, `JOB_NAME`, `JOB_GROUP`, `DESCRIPTION`, `JOB_CLASS_NAME`, `IS_DURABLE`, `IS_NONCONCURRENT`, `IS_UPDATE_DATA`, `REQUESTS_RECOVERY`, `JOB_DATA`) VALUES ('schedulerName', 'demoJob', 'DEFAULT', NULL, 'cn.iocoder.yudao.framework.quartz.core.handler.JobHandlerInvoker', '0', '1', '1', '0', 0xACED0005737200156F72672E71756172747A2E4A6F62446174614D61709FB083E8BFA9B0CB020000787200266F72672E71756172747A2E7574696C732E537472696E674B65794469727479466C61674D61708208E8C3FBC55D280200015A0013616C6C6F77735472616E7369656E74446174617872001D6F72672E71756172747A2E7574696C732E4469727479466C61674D617013E62EAD28760ACE0200025A000564697274794C00036D617074000F4C6A6176612F7574696C2F4D61703B787001737200116A6176612E7574696C2E486173684D61700507DAC1C31660D103000246000A6C6F6164466163746F724900097468726573686F6C6478703F4000000000000C770800000010000000027400064A4F425F49447372000E6A6176612E6C616E672E4C6F6E673B8BE490CC8F23DF0200014A000576616C7565787200106A6176612E6C616E672E4E756D62657286AC951D0B94E08B020000787000000000000000147400104A4F425F48414E444C45525F4E414D4574000764656D6F4A6F627800);
138 INSERT INTO `QRTZ_JOB_DETAILS` (`SCHED_NAME`, `JOB_NAME`, `JOB_GROUP`, `DESCRIPTION`, `JOB_CLASS_NAME`, `IS_DURABLE`, `IS_NONCONCURRENT`, `IS_UPDATE_DATA`, `REQUESTS_RECOVERY`, `JOB_DATA`) VALUES ('schedulerName', 'payNotifyJob', 'DEFAULT', NULL, 'cn.iocoder.yudao.framework.quartz.core.handler.JobHandlerInvoker', '0', '1', '1', '0', 0xACED0005737200156F72672E71756172747A2E4A6F62446174614D61709FB083E8BFA9B0CB020000787200266F72672E71756172747A2E7574696C732E537472696E674B65794469727479466C61674D61708208E8C3FBC55D280200015A0013616C6C6F77735472616E7369656E74446174617872001D6F72672E71756172747A2E7574696C732E4469727479466C61674D617013E62EAD28760ACE0200025A000564697274794C00036D617074000F4C6A6176612F7574696C2F4D61703B787001737200116A6176612E7574696C2E486173684D61700507DAC1C31660D103000246000A6C6F6164466163746F724900097468726573686F6C6478703F4000000000000C770800000010000000027400064A4F425F49447372000E6A6176612E6C616E672E4C6F6E673B8BE490CC8F23DF0200014A000576616C7565787200106A6176612E6C616E672E4E756D62657286AC951D0B94E08B020000787000000000000000057400104A4F425F48414E444C45525F4E414D4574000C7061794E6F746966794A6F627800); 140 INSERT INTO `QRTZ_JOB_DETAILS` (`SCHED_NAME`, `JOB_NAME`, `JOB_GROUP`, `DESCRIPTION`, `JOB_CLASS_NAME`, `IS_DURABLE`, `IS_NONCONCURRENT`, `IS_UPDATE_DATA`, `REQUESTS_RECOVERY`, `JOB_DATA`) VALUES ('schedulerName', 'payNotifyJob', 'DEFAULT', NULL, 'cn.iocoder.yudao.framework.quartz.core.handler.JobHandlerInvoker', '0', '1', '1', '0', 0xACED0005737200156F72672E71756172747A2E4A6F62446174614D61709FB083E8BFA9B0CB020000787200266F72672E71756172747A2E7574696C732E537472696E674B65794469727479466C61674D61708208E8C3FBC55D280200015A0013616C6C6F77735472616E7369656E74446174617872001D6F72672E71756172747A2E7574696C732E4469727479466C61674D617013E62EAD28760ACE0200025A000564697274794C00036D617074000F4C6A6176612F7574696C2F4D61703B787001737200116A6176612E7574696C2E486173684D61700507DAC1C31660D103000246000A6C6F6164466163746F724900097468726573686F6C6478703F4000000000000C770800000010000000027400064A4F425F49447372000E6A6176612E6C616E672E4C6F6E673B8BE490CC8F23DF0200014A000576616C7565787200106A6176612E6C616E672E4E756D62657286AC951D0B94E08B020000787000000000000000057400104A4F425F48414E444C45525F4E414D4574000C7061794E6F746966794A6F627800);
139 INSERT INTO `QRTZ_JOB_DETAILS` (`SCHED_NAME`, `JOB_NAME`, `JOB_GROUP`, `DESCRIPTION`, `JOB_CLASS_NAME`, `IS_DURABLE`, `IS_NONCONCURRENT`, `IS_UPDATE_DATA`, `REQUESTS_RECOVERY`, `JOB_DATA`) VALUES ('schedulerName', 'payOrderExpireJob', 'DEFAULT', NULL, 'cn.iocoder.yudao.framework.quartz.core.handler.JobHandlerInvoker', '0', '1', '1', '0', 0xACED0005737200156F72672E71756172747A2E4A6F62446174614D61709FB083E8BFA9B0CB020000787200266F72672E71756172747A2E7574696C732E537472696E674B65794469727479466C61674D61708208E8C3FBC55D280200015A0013616C6C6F77735472616E7369656E74446174617872001D6F72672E71756172747A2E7574696C732E4469727479466C61674D617013E62EAD28760ACE0200025A000564697274794C00036D617074000F4C6A6176612F7574696C2F4D61703B787001737200116A6176612E7574696C2E486173684D61700507DAC1C31660D103000246000A6C6F6164466163746F724900097468726573686F6C6478703F4000000000000C770800000010000000027400064A4F425F49447372000E6A6176612E6C616E672E4C6F6E673B8BE490CC8F23DF0200014A000576616C7565787200106A6176612E6C616E672E4E756D62657286AC951D0B94E08B020000787000000000000000127400104A4F425F48414E444C45525F4E414D457400117061794F726465724578706972654A6F627800); 141 INSERT INTO `QRTZ_JOB_DETAILS` (`SCHED_NAME`, `JOB_NAME`, `JOB_GROUP`, `DESCRIPTION`, `JOB_CLASS_NAME`, `IS_DURABLE`, `IS_NONCONCURRENT`, `IS_UPDATE_DATA`, `REQUESTS_RECOVERY`, `JOB_DATA`) VALUES ('schedulerName', 'payOrderExpireJob', 'DEFAULT', NULL, 'cn.iocoder.yudao.framework.quartz.core.handler.JobHandlerInvoker', '0', '1', '1', '0', 0xACED0005737200156F72672E71756172747A2E4A6F62446174614D61709FB083E8BFA9B0CB020000787200266F72672E71756172747A2E7574696C732E537472696E674B65794469727479466C61674D61708208E8C3FBC55D280200015A0013616C6C6F77735472616E7369656E74446174617872001D6F72672E71756172747A2E7574696C732E4469727479466C61674D617013E62EAD28760ACE0200025A000564697274794C00036D617074000F4C6A6176612F7574696C2F4D61703B787001737200116A6176612E7574696C2E486173684D61700507DAC1C31660D103000246000A6C6F6164466163746F724900097468726573686F6C6478703F4000000000000C770800000010000000027400064A4F425F49447372000E6A6176612E6C616E672E4C6F6E673B8BE490CC8F23DF0200014A000576616C7565787200106A6176612E6C616E672E4E756D62657286AC951D0B94E08B020000787000000000000000127400104A4F425F48414E444C45525F4E414D457400117061794F726465724578706972654A6F627800);
140 INSERT INTO `QRTZ_JOB_DETAILS` (`SCHED_NAME`, `JOB_NAME`, `JOB_GROUP`, `DESCRIPTION`, `JOB_CLASS_NAME`, `IS_DURABLE`, `IS_NONCONCURRENT`, `IS_UPDATE_DATA`, `REQUESTS_RECOVERY`, `JOB_DATA`) VALUES ('schedulerName', 'payOrderSyncJob', 'DEFAULT', NULL, 'cn.iocoder.yudao.framework.quartz.core.handler.JobHandlerInvoker', '0', '1', '1', '0', 0xACED0005737200156F72672E71756172747A2E4A6F62446174614D61709FB083E8BFA9B0CB020000787200266F72672E71756172747A2E7574696C732E537472696E674B65794469727479466C61674D61708208E8C3FBC55D280200015A0013616C6C6F77735472616E7369656E74446174617872001D6F72672E71756172747A2E7574696C732E4469727479466C61674D617013E62EAD28760ACE0200025A000564697274794C00036D617074000F4C6A6176612F7574696C2F4D61703B787001737200116A6176612E7574696C2E486173684D61700507DAC1C31660D103000246000A6C6F6164466163746F724900097468726573686F6C6478703F4000000000000C770800000010000000027400064A4F425F49447372000E6A6176612E6C616E672E4C6F6E673B8BE490CC8F23DF0200014A000576616C7565787200106A6176612E6C616E672E4E756D62657286AC951D0B94E08B020000787000000000000000117400104A4F425F48414E444C45525F4E414D4574000F7061794F7264657253796E634A6F627800); 142 INSERT INTO `QRTZ_JOB_DETAILS` (`SCHED_NAME`, `JOB_NAME`, `JOB_GROUP`, `DESCRIPTION`, `JOB_CLASS_NAME`, `IS_DURABLE`, `IS_NONCONCURRENT`, `IS_UPDATE_DATA`, `REQUESTS_RECOVERY`, `JOB_DATA`) VALUES ('schedulerName', 'payOrderSyncJob', 'DEFAULT', NULL, 'cn.iocoder.yudao.framework.quartz.core.handler.JobHandlerInvoker', '0', '1', '1', '0', 0xACED0005737200156F72672E71756172747A2E4A6F62446174614D61709FB083E8BFA9B0CB020000787200266F72672E71756172747A2E7574696C732E537472696E674B65794469727479466C61674D61708208E8C3FBC55D280200015A0013616C6C6F77735472616E7369656E74446174617872001D6F72672E71756172747A2E7574696C732E4469727479466C61674D617013E62EAD28760ACE0200025A000564697274794C00036D617074000F4C6A6176612F7574696C2F4D61703B787001737200116A6176612E7574696C2E486173684D61700507DAC1C31660D103000246000A6C6F6164466163746F724900097468726573686F6C6478703F4000000000000C770800000010000000027400064A4F425F49447372000E6A6176612E6C616E672E4C6F6E673B8BE490CC8F23DF0200014A000576616C7565787200106A6176612E6C616E672E4E756D62657286AC951D0B94E08B020000787000000000000000117400104A4F425F48414E444C45525F4E414D4574000F7061794F7264657253796E634A6F627800);
@@ -191,7 +193,7 @@ CREATE TABLE `QRTZ_SCHEDULER_STATE` ( @@ -191,7 +193,7 @@ CREATE TABLE `QRTZ_SCHEDULER_STATE` (
191 -- Records of QRTZ_SCHEDULER_STATE 193 -- Records of QRTZ_SCHEDULER_STATE
192 -- ---------------------------- 194 -- ----------------------------
193 BEGIN; 195 BEGIN;
194 -INSERT INTO `QRTZ_SCHEDULER_STATE` (`SCHED_NAME`, `INSTANCE_NAME`, `LAST_CHECKIN_TIME`, `CHECKIN_INTERVAL`) VALUES ('schedulerName', 'Yunai1690117495401', 1690119854263, 15000); 196 +INSERT INTO `QRTZ_SCHEDULER_STATE` (`SCHED_NAME`, `INSTANCE_NAME`, `LAST_CHECKIN_TIME`, `CHECKIN_INTERVAL`) VALUES ('schedulerName', 'Yunai.local1694844151505', 1694844218609, 15000);
195 COMMIT; 197 COMMIT;
196 198
197 -- ---------------------------- 199 -- ----------------------------
@@ -285,6 +287,7 @@ CREATE TABLE `QRTZ_TRIGGERS` ( @@ -285,6 +287,7 @@ CREATE TABLE `QRTZ_TRIGGERS` (
285 -- Records of QRTZ_TRIGGERS 287 -- Records of QRTZ_TRIGGERS
286 -- ---------------------------- 288 -- ----------------------------
287 BEGIN; 289 BEGIN;
  290 +INSERT INTO `QRTZ_TRIGGERS` (`SCHED_NAME`, `TRIGGER_NAME`, `TRIGGER_GROUP`, `JOB_NAME`, `JOB_GROUP`, `DESCRIPTION`, `NEXT_FIRE_TIME`, `PREV_FIRE_TIME`, `PRIORITY`, `TRIGGER_STATE`, `TRIGGER_TYPE`, `START_TIME`, `END_TIME`, `CALENDAR_NAME`, `MISFIRE_INSTR`, `JOB_DATA`) VALUES ('schedulerName', 'demoJob', 'DEFAULT', 'demoJob', 'DEFAULT', NULL, 1694880000000, -1, 5, 'WAITING', 'CRON', 1694844083000, 0, NULL, 0, 0xACED0005737200156F72672E71756172747A2E4A6F62446174614D61709FB083E8BFA9B0CB020000787200266F72672E71756172747A2E7574696C732E537472696E674B65794469727479466C61674D61708208E8C3FBC55D280200015A0013616C6C6F77735472616E7369656E74446174617872001D6F72672E71756172747A2E7574696C732E4469727479466C61674D617013E62EAD28760ACE0200025A000564697274794C00036D617074000F4C6A6176612F7574696C2F4D61703B787001737200116A6176612E7574696C2E486173684D61700507DAC1C31660D103000246000A6C6F6164466163746F724900097468726573686F6C6478703F4000000000000C770800000010000000037400114A4F425F48414E444C45525F504152414D7400007400124A4F425F52455452595F494E54455256414C737200116A6176612E6C616E672E496E746567657212E2A0A4F781873802000149000576616C7565787200106A6176612E6C616E672E4E756D62657286AC951D0B94E08B02000078700000000A74000F4A4F425F52455452595F434F554E547371007E000A000000017800);
288 INSERT INTO `QRTZ_TRIGGERS` (`SCHED_NAME`, `TRIGGER_NAME`, `TRIGGER_GROUP`, `JOB_NAME`, `JOB_GROUP`, `DESCRIPTION`, `NEXT_FIRE_TIME`, `PREV_FIRE_TIME`, `PRIORITY`, `TRIGGER_STATE`, `TRIGGER_TYPE`, `START_TIME`, `END_TIME`, `CALENDAR_NAME`, `MISFIRE_INSTR`, `JOB_DATA`) VALUES ('schedulerName', 'payNotifyJob', 'DEFAULT', 'payNotifyJob', 'DEFAULT', NULL, 1688907102000, 1688907101000, 5, 'PAUSED', 'CRON', 1635294882000, 0, NULL, 0, 0xACED0005737200156F72672E71756172747A2E4A6F62446174614D61709FB083E8BFA9B0CB020000787200266F72672E71756172747A2E7574696C732E537472696E674B65794469727479466C61674D61708208E8C3FBC55D280200015A0013616C6C6F77735472616E7369656E74446174617872001D6F72672E71756172747A2E7574696C732E4469727479466C61674D617013E62EAD28760ACE0200025A000564697274794C00036D617074000F4C6A6176612F7574696C2F4D61703B787001737200116A6176612E7574696C2E486173684D61700507DAC1C31660D103000246000A6C6F6164466163746F724900097468726573686F6C6478703F4000000000000C770800000010000000037400114A4F425F48414E444C45525F504152414D707400124A4F425F52455452595F494E54455256414C737200116A6176612E6C616E672E496E746567657212E2A0A4F781873802000149000576616C7565787200106A6176612E6C616E672E4E756D62657286AC951D0B94E08B02000078700000000074000F4A4F425F52455452595F434F554E5471007E000B7800); 291 INSERT INTO `QRTZ_TRIGGERS` (`SCHED_NAME`, `TRIGGER_NAME`, `TRIGGER_GROUP`, `JOB_NAME`, `JOB_GROUP`, `DESCRIPTION`, `NEXT_FIRE_TIME`, `PREV_FIRE_TIME`, `PRIORITY`, `TRIGGER_STATE`, `TRIGGER_TYPE`, `START_TIME`, `END_TIME`, `CALENDAR_NAME`, `MISFIRE_INSTR`, `JOB_DATA`) VALUES ('schedulerName', 'payNotifyJob', 'DEFAULT', 'payNotifyJob', 'DEFAULT', NULL, 1688907102000, 1688907101000, 5, 'PAUSED', 'CRON', 1635294882000, 0, NULL, 0, 0xACED0005737200156F72672E71756172747A2E4A6F62446174614D61709FB083E8BFA9B0CB020000787200266F72672E71756172747A2E7574696C732E537472696E674B65794469727479466C61674D61708208E8C3FBC55D280200015A0013616C6C6F77735472616E7369656E74446174617872001D6F72672E71756172747A2E7574696C732E4469727479466C61674D617013E62EAD28760ACE0200025A000564697274794C00036D617074000F4C6A6176612F7574696C2F4D61703B787001737200116A6176612E7574696C2E486173684D61700507DAC1C31660D103000246000A6C6F6164466163746F724900097468726573686F6C6478703F4000000000000C770800000010000000037400114A4F425F48414E444C45525F504152414D707400124A4F425F52455452595F494E54455256414C737200116A6176612E6C616E672E496E746567657212E2A0A4F781873802000149000576616C7565787200106A6176612E6C616E672E4E756D62657286AC951D0B94E08B02000078700000000074000F4A4F425F52455452595F434F554E5471007E000B7800);
289 INSERT INTO `QRTZ_TRIGGERS` (`SCHED_NAME`, `TRIGGER_NAME`, `TRIGGER_GROUP`, `JOB_NAME`, `JOB_GROUP`, `DESCRIPTION`, `NEXT_FIRE_TIME`, `PREV_FIRE_TIME`, `PRIORITY`, `TRIGGER_STATE`, `TRIGGER_TYPE`, `START_TIME`, `END_TIME`, `CALENDAR_NAME`, `MISFIRE_INSTR`, `JOB_DATA`) VALUES ('schedulerName', 'payOrderExpireJob', 'DEFAULT', 'payOrderExpireJob', 'DEFAULT', NULL, 1690011600000, -1, 5, 'PAUSED', 'CRON', 1690011553000, 0, NULL, 0, 0xACED0005737200156F72672E71756172747A2E4A6F62446174614D61709FB083E8BFA9B0CB020000787200266F72672E71756172747A2E7574696C732E537472696E674B65794469727479466C61674D61708208E8C3FBC55D280200015A0013616C6C6F77735472616E7369656E74446174617872001D6F72672E71756172747A2E7574696C732E4469727479466C61674D617013E62EAD28760ACE0200025A000564697274794C00036D617074000F4C6A6176612F7574696C2F4D61703B787001737200116A6176612E7574696C2E486173684D61700507DAC1C31660D103000246000A6C6F6164466163746F724900097468726573686F6C6478703F4000000000000C770800000010000000037400114A4F425F48414E444C45525F504152414D707400124A4F425F52455452595F494E54455256414C737200116A6176612E6C616E672E496E746567657212E2A0A4F781873802000149000576616C7565787200106A6176612E6C616E672E4E756D62657286AC951D0B94E08B02000078700000000074000F4A4F425F52455452595F434F554E5471007E000B7800); 292 INSERT INTO `QRTZ_TRIGGERS` (`SCHED_NAME`, `TRIGGER_NAME`, `TRIGGER_GROUP`, `JOB_NAME`, `JOB_GROUP`, `DESCRIPTION`, `NEXT_FIRE_TIME`, `PREV_FIRE_TIME`, `PRIORITY`, `TRIGGER_STATE`, `TRIGGER_TYPE`, `START_TIME`, `END_TIME`, `CALENDAR_NAME`, `MISFIRE_INSTR`, `JOB_DATA`) VALUES ('schedulerName', 'payOrderExpireJob', 'DEFAULT', 'payOrderExpireJob', 'DEFAULT', NULL, 1690011600000, -1, 5, 'PAUSED', 'CRON', 1690011553000, 0, NULL, 0, 0xACED0005737200156F72672E71756172747A2E4A6F62446174614D61709FB083E8BFA9B0CB020000787200266F72672E71756172747A2E7574696C732E537472696E674B65794469727479466C61674D61708208E8C3FBC55D280200015A0013616C6C6F77735472616E7369656E74446174617872001D6F72672E71756172747A2E7574696C732E4469727479466C61674D617013E62EAD28760ACE0200025A000564697274794C00036D617074000F4C6A6176612F7574696C2F4D61703B787001737200116A6176612E7574696C2E486173684D61700507DAC1C31660D103000246000A6C6F6164466163746F724900097468726573686F6C6478703F4000000000000C770800000010000000037400114A4F425F48414E444C45525F504152414D707400124A4F425F52455452595F494E54455256414C737200116A6176612E6C616E672E496E746567657212E2A0A4F781873802000149000576616C7565787200106A6176612E6C616E672E4E756D62657286AC951D0B94E08B02000078700000000074000F4A4F425F52455452595F434F554E5471007E000B7800);
290 INSERT INTO `QRTZ_TRIGGERS` (`SCHED_NAME`, `TRIGGER_NAME`, `TRIGGER_GROUP`, `JOB_NAME`, `JOB_GROUP`, `DESCRIPTION`, `NEXT_FIRE_TIME`, `PREV_FIRE_TIME`, `PRIORITY`, `TRIGGER_STATE`, `TRIGGER_TYPE`, `START_TIME`, `END_TIME`, `CALENDAR_NAME`, `MISFIRE_INSTR`, `JOB_DATA`) VALUES ('schedulerName', 'payOrderSyncJob', 'DEFAULT', 'payOrderSyncJob', 'DEFAULT', NULL, 1690011600000, 1690011540000, 5, 'PAUSED', 'CRON', 1690007785000, 0, NULL, 0, 0xACED0005737200156F72672E71756172747A2E4A6F62446174614D61709FB083E8BFA9B0CB020000787200266F72672E71756172747A2E7574696C732E537472696E674B65794469727479466C61674D61708208E8C3FBC55D280200015A0013616C6C6F77735472616E7369656E74446174617872001D6F72672E71756172747A2E7574696C732E4469727479466C61674D617013E62EAD28760ACE0200025A000564697274794C00036D617074000F4C6A6176612F7574696C2F4D61703B787001737200116A6176612E7574696C2E486173684D61700507DAC1C31660D103000246000A6C6F6164466163746F724900097468726573686F6C6478703F4000000000000C770800000010000000037400114A4F425F48414E444C45525F504152414D707400124A4F425F52455452595F494E54455256414C737200116A6176612E6C616E672E496E746567657212E2A0A4F781873802000149000576616C7565787200106A6176612E6C616E672E4E756D62657286AC951D0B94E08B02000078700000000074000F4A4F425F52455452595F434F554E5471007E000B7800); 293 INSERT INTO `QRTZ_TRIGGERS` (`SCHED_NAME`, `TRIGGER_NAME`, `TRIGGER_GROUP`, `JOB_NAME`, `JOB_GROUP`, `DESCRIPTION`, `NEXT_FIRE_TIME`, `PREV_FIRE_TIME`, `PRIORITY`, `TRIGGER_STATE`, `TRIGGER_TYPE`, `START_TIME`, `END_TIME`, `CALENDAR_NAME`, `MISFIRE_INSTR`, `JOB_DATA`) VALUES ('schedulerName', 'payOrderSyncJob', 'DEFAULT', 'payOrderSyncJob', 'DEFAULT', NULL, 1690011600000, 1690011540000, 5, 'PAUSED', 'CRON', 1690007785000, 0, NULL, 0, 0xACED0005737200156F72672E71756172747A2E4A6F62446174614D61709FB083E8BFA9B0CB020000787200266F72672E71756172747A2E7574696C732E537472696E674B65794469727479466C61674D61708208E8C3FBC55D280200015A0013616C6C6F77735472616E7369656E74446174617872001D6F72672E71756172747A2E7574696C732E4469727479466C61674D617013E62EAD28760ACE0200025A000564697274794C00036D617074000F4C6A6176612F7574696C2F4D61703B787001737200116A6176612E7574696C2E486173684D61700507DAC1C31660D103000246000A6C6F6164466163746F724900097468726573686F6C6478703F4000000000000C770800000010000000037400114A4F425F48414E444C45525F504152414D707400124A4F425F52455452595F494E54455256414C737200116A6176612E6C616E672E496E746567657212E2A0A4F781873802000149000576616C7565787200106A6176612E6C616E672E4E756D62657286AC951D0B94E08B02000078700000000074000F4A4F425F52455452595F434F554E5471007E000B7800);
@@ -360,7 +363,7 @@ CREATE TABLE `infra_api_error_log` ( @@ -360,7 +363,7 @@ CREATE TABLE `infra_api_error_log` (
360 `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除', 363 `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除',
361 `tenant_id` bigint NOT NULL DEFAULT 0 COMMENT '租户编号', 364 `tenant_id` bigint NOT NULL DEFAULT 0 COMMENT '租户编号',
362 PRIMARY KEY (`id`) USING BTREE 365 PRIMARY KEY (`id`) USING BTREE
363 -) ENGINE = InnoDB AUTO_INCREMENT = 1497 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '系统异常日志'; 366 +) ENGINE = InnoDB AUTO_INCREMENT = 1544 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '系统异常日志';
364 367
365 -- ---------------------------- 368 -- ----------------------------
366 -- Records of infra_api_error_log 369 -- Records of infra_api_error_log
@@ -398,7 +401,7 @@ CREATE TABLE `infra_codegen_column` ( @@ -398,7 +401,7 @@ CREATE TABLE `infra_codegen_column` (
398 `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间', 401 `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
399 `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除', 402 `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除',
400 PRIMARY KEY (`id`) USING BTREE 403 PRIMARY KEY (`id`) USING BTREE
401 -) ENGINE = InnoDB AUTO_INCREMENT = 1756 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '代码生成表字段定义'; 404 +) ENGINE = InnoDB AUTO_INCREMENT = 1755 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '代码生成表字段定义';
402 405
403 -- ---------------------------- 406 -- ----------------------------
404 -- Records of infra_codegen_column 407 -- Records of infra_codegen_column
@@ -514,7 +517,7 @@ CREATE TABLE `infra_file` ( @@ -514,7 +517,7 @@ CREATE TABLE `infra_file` (
514 `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间', 517 `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
515 `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除', 518 `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除',
516 PRIMARY KEY (`id`) USING BTREE 519 PRIMARY KEY (`id`) USING BTREE
517 -) ENGINE = InnoDB AUTO_INCREMENT = 1054 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '文件表'; 520 +) ENGINE = InnoDB AUTO_INCREMENT = 1055 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '文件表';
518 521
519 -- ---------------------------- 522 -- ----------------------------
520 -- Records of infra_file 523 -- Records of infra_file
@@ -545,12 +548,7 @@ CREATE TABLE `infra_file_config` ( @@ -545,12 +548,7 @@ CREATE TABLE `infra_file_config` (
545 -- Records of infra_file_config 548 -- Records of infra_file_config
546 -- ---------------------------- 549 -- ----------------------------
547 BEGIN; 550 BEGIN;
548 -INSERT INTO `infra_file_config` (`id`, `name`, `storage`, `remark`, `master`, `config`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (4, '数据库', 1, '我是数据库', b'1', '{\"@class\":\"cn.iocoder.yudao.framework.file.core.client.db.DBFileClientConfig\",\"domain\":\"http://127.0.0.1:48080\"}', '1', '2022-03-15 23:56:24', '1', '2023-04-08 09:44:47', b'0');  
549 -INSERT INTO `infra_file_config` (`id`, `name`, `storage`, `remark`, `master`, `config`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (5, '本地磁盘', 10, '测试下本地存储', b'0', '{\"@class\":\"cn.iocoder.yudao.framework.file.core.client.local.LocalFileClientConfig\",\"basePath\":\"/Users/yunai/file_test\",\"domain\":\"http://127.0.0.1:48080\"}', '1', '2022-03-15 23:57:00', '1', '2023-04-08 09:44:47', b'0');  
550 -INSERT INTO `infra_file_config` (`id`, `name`, `storage`, `remark`, `master`, `config`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (11, 'S3 - 七牛云', 20, NULL, b'0', '{\"@class\":\"cn.iocoder.yudao.framework.file.core.client.s3.S3FileClientConfig\",\"endpoint\":\"s3-cn-south-1.qiniucs.com\",\"domain\":\"http://test.yudao.iocoder.cn\",\"bucket\":\"ruoyi-vue-pro\",\"accessKey\":\"b7yvuhBSAGjmtPhMFcn9iMOxUOY_I06cA_p0ZUx8\",\"accessSecret\":\"kXM1l5ia1RvSX3QaOEcwI3RLz3Y2rmNszWonKZtP\"}', '1', '2022-03-19 18:00:03', '1', '2023-04-08 09:44:47', b'0');  
551 -INSERT INTO `infra_file_config` (`id`, `name`, `storage`, `remark`, `master`, `config`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (15, 'S3 - 七牛云', 20, '', b'0', '{\"@class\":\"cn.iocoder.yudao.framework.file.core.client.s3.S3FileClientConfig\",\"endpoint\":\"s3-cn-south-1.qiniucs.com\",\"domain\":\"http://test.yudao.iocoder.cn\",\"bucket\":\"ruoyi-vue-pro\",\"accessKey\":\"b7yvuhBSAGjmtPhMFcn9iMOxUOY_I06cA_p0ZUx8\",\"accessSecret\":\"kXM1l5ia1RvSX3QaOEcwI3RLz3Y2rmNszWonKZtP\"}', '1', '2022-06-10 20:50:41', '1', '2023-04-08 09:44:47', b'0');  
552 -INSERT INTO `infra_file_config` (`id`, `name`, `storage`, `remark`, `master`, `config`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (16, 'S3 - 七牛云', 20, '', b'0', '{\"@class\":\"cn.iocoder.yudao.framework.file.core.client.s3.S3FileClientConfig\",\"endpoint\":\"s3-cn-south-1.qiniucs.com\",\"domain\":\"http://test.yudao.iocoder.cn\",\"bucket\":\"ruoyi-vue-pro\",\"accessKey\":\"b7yvuhBSAGjmtPhMFcn9iMOxUOY_I06cA_p0ZUx8\",\"accessSecret\":\"kXM1l5ia1RvSX3QaOEcwI3RLz3Y2rmNszWonKZtP\"}', '1', '2022-06-11 20:32:08', '1', '2023-04-08 09:44:47', b'0');  
553 -INSERT INTO `infra_file_config` (`id`, `name`, `storage`, `remark`, `master`, `config`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (17, 'S3 - 七牛云', 20, '', b'0', '{\"@class\":\"cn.iocoder.yudao.framework.file.core.client.s3.S3FileClientConfig\",\"endpoint\":\"s3-cn-south-1.qiniucs.com\",\"domain\":\"http://test.yudao.iocoder.cn\",\"bucket\":\"ruoyi-vue-pro\",\"accessKey\":\"b7yvuhBSAGjmtPhMFcn9iMOxUOY_I06cA_p0ZUx8\",\"accessSecret\":\"kXM1l5ia1RvSX3QaOEcwI3RLz3Y2rmNszWonKZtP\"}', '1', '2022-06-11 20:32:47', '1', '2023-04-08 09:44:47', b'0'); 551 +INSERT INTO `infra_file_config` (`id`, `name`, `storage`, `remark`, `master`, `config`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (4, '数据库', 1, '我是数据库', b'1', '{\"@class\":\"cn.iocoder.yudao.framework.file.core.client.db.DBFileClientConfig\",\"domain\":\"http://127.0.0.1:48080\"}', '1', '2022-03-15 23:56:24', '1', '2023-09-15 12:05:12', b'0');
554 COMMIT; 552 COMMIT;
555 553
556 -- ---------------------------- 554 -- ----------------------------
@@ -568,7 +566,7 @@ CREATE TABLE `infra_file_content` ( @@ -568,7 +566,7 @@ CREATE TABLE `infra_file_content` (
568 `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间', 566 `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
569 `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除', 567 `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除',
570 PRIMARY KEY (`id`) USING BTREE 568 PRIMARY KEY (`id`) USING BTREE
571 -) ENGINE = InnoDB AUTO_INCREMENT = 145 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '文件表'; 569 +) ENGINE = InnoDB AUTO_INCREMENT = 149 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '文件表';
572 570
573 -- ---------------------------- 571 -- ----------------------------
574 -- Records of infra_file_content 572 -- Records of infra_file_content
@@ -596,17 +594,17 @@ CREATE TABLE `infra_job` ( @@ -596,17 +594,17 @@ CREATE TABLE `infra_job` (
596 `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间', 594 `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
597 `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除', 595 `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除',
598 PRIMARY KEY (`id`) USING BTREE 596 PRIMARY KEY (`id`) USING BTREE
599 -) ENGINE = InnoDB AUTO_INCREMENT = 20 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '定时任务表'; 597 +) ENGINE = InnoDB AUTO_INCREMENT = 21 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '定时任务表';
600 598
601 -- ---------------------------- 599 -- ----------------------------
602 -- Records of infra_job 600 -- Records of infra_job
603 -- ---------------------------- 601 -- ----------------------------
604 BEGIN; 602 BEGIN;
605 INSERT INTO `infra_job` (`id`, `name`, `status`, `handler_name`, `handler_param`, `cron_expression`, `retry_count`, `retry_interval`, `monitor_timeout`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (5, '支付通知 Job', 2, 'payNotifyJob', NULL, '* * * * * ?', 0, 0, 0, '1', '2021-10-27 08:34:42', '1', '2023-07-09 20:51:41', b'0'); 603 INSERT INTO `infra_job` (`id`, `name`, `status`, `handler_name`, `handler_param`, `cron_expression`, `retry_count`, `retry_interval`, `monitor_timeout`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (5, '支付通知 Job', 2, 'payNotifyJob', NULL, '* * * * * ?', 0, 0, 0, '1', '2021-10-27 08:34:42', '1', '2023-07-09 20:51:41', b'0');
606 -INSERT INTO `infra_job` (`id`, `name`, `status`, `handler_name`, `handler_param`, `cron_expression`, `retry_count`, `retry_interval`, `monitor_timeout`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (16, 'Job 示例', 1, 'demoJob', NULL, '* * * L * ?', 1, 1, 0, '1', '2022-09-24 22:31:41', '1', '2022-09-24 22:31:42', b'0');  
607 INSERT INTO `infra_job` (`id`, `name`, `status`, `handler_name`, `handler_param`, `cron_expression`, `retry_count`, `retry_interval`, `monitor_timeout`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (17, '支付订单同步 Job', 2, 'payOrderSyncJob', NULL, '0 0/1 * * * ?', 0, 0, 0, '1', '2023-07-22 14:36:26', '1', '2023-07-22 15:39:08', b'0'); 604 INSERT INTO `infra_job` (`id`, `name`, `status`, `handler_name`, `handler_param`, `cron_expression`, `retry_count`, `retry_interval`, `monitor_timeout`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (17, '支付订单同步 Job', 2, 'payOrderSyncJob', NULL, '0 0/1 * * * ?', 0, 0, 0, '1', '2023-07-22 14:36:26', '1', '2023-07-22 15:39:08', b'0');
608 INSERT INTO `infra_job` (`id`, `name`, `status`, `handler_name`, `handler_param`, `cron_expression`, `retry_count`, `retry_interval`, `monitor_timeout`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (18, '支付订单过期 Job', 2, 'payOrderExpireJob', NULL, '0 0/1 * * * ?', 0, 0, 0, '1', '2023-07-22 15:36:23', '1', '2023-07-22 15:39:54', b'0'); 605 INSERT INTO `infra_job` (`id`, `name`, `status`, `handler_name`, `handler_param`, `cron_expression`, `retry_count`, `retry_interval`, `monitor_timeout`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (18, '支付订单过期 Job', 2, 'payOrderExpireJob', NULL, '0 0/1 * * * ?', 0, 0, 0, '1', '2023-07-22 15:36:23', '1', '2023-07-22 15:39:54', b'0');
609 INSERT INTO `infra_job` (`id`, `name`, `status`, `handler_name`, `handler_param`, `cron_expression`, `retry_count`, `retry_interval`, `monitor_timeout`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (19, '退款订单的同步 Job', 2, 'payRefundSyncJob', NULL, '0 0/1 * * * ?', 0, 0, 0, '1', '2023-07-23 21:03:44', '1', '2023-07-23 21:09:00', b'0'); 606 INSERT INTO `infra_job` (`id`, `name`, `status`, `handler_name`, `handler_param`, `cron_expression`, `retry_count`, `retry_interval`, `monitor_timeout`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (19, '退款订单的同步 Job', 2, 'payRefundSyncJob', NULL, '0 0/1 * * * ?', 0, 0, 0, '1', '2023-07-23 21:03:44', '1', '2023-07-23 21:09:00', b'0');
  607 +INSERT INTO `infra_job` (`id`, `name`, `status`, `handler_name`, `handler_param`, `cron_expression`, `retry_count`, `retry_interval`, `monitor_timeout`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (20, 'Job 示例', 1, 'demoJob', '', '0 0 0 * * ?', 1, 10, 0, '1', '2023-09-16 14:01:23', '1', '2023-09-16 14:01:23', b'0');
610 COMMIT; 608 COMMIT;
611 609
612 -- ---------------------------- 610 -- ----------------------------
@@ -630,7 +628,7 @@ CREATE TABLE `infra_job_log` ( @@ -630,7 +628,7 @@ CREATE TABLE `infra_job_log` (
630 `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间', 628 `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
631 `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除', 629 `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除',
632 PRIMARY KEY (`id`) USING BTREE 630 PRIMARY KEY (`id`) USING BTREE
633 -) ENGINE = InnoDB AUTO_INCREMENT = 161 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '定时任务日志表'; 631 +) ENGINE = InnoDB AUTO_INCREMENT = 163 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '定时任务日志表';
634 632
635 -- ---------------------------- 633 -- ----------------------------
636 -- Records of infra_job_log 634 -- Records of infra_job_log
@@ -803,7 +801,7 @@ CREATE TABLE `member_level_record` ( @@ -803,7 +801,7 @@ CREATE TABLE `member_level_record` (
803 `tenant_id` bigint NOT NULL DEFAULT 0 COMMENT '租户编号', 801 `tenant_id` bigint NOT NULL DEFAULT 0 COMMENT '租户编号',
804 PRIMARY KEY (`id`) USING BTREE, 802 PRIMARY KEY (`id`) USING BTREE,
805 INDEX `idx_user_id`(`user_id` ASC) USING BTREE COMMENT '会员等级记录-用户编号' 803 INDEX `idx_user_id`(`user_id` ASC) USING BTREE COMMENT '会员等级记录-用户编号'
806 -) ENGINE = InnoDB AUTO_INCREMENT = 4 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '会员等级记录'; 804 +) ENGINE = InnoDB AUTO_INCREMENT = 3 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '会员等级记录';
807 805
808 -- ---------------------------- 806 -- ----------------------------
809 -- Records of member_level_record 807 -- Records of member_level_record
@@ -828,7 +826,7 @@ CREATE TABLE `member_point_config` ( @@ -828,7 +826,7 @@ CREATE TABLE `member_point_config` (
828 `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除', 826 `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除',
829 `tenant_id` bigint NOT NULL DEFAULT 0 COMMENT '租户编号', 827 `tenant_id` bigint NOT NULL DEFAULT 0 COMMENT '租户编号',
830 PRIMARY KEY (`id`) USING BTREE 828 PRIMARY KEY (`id`) USING BTREE
831 -) ENGINE = InnoDB AUTO_INCREMENT = 6 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci COMMENT = '会员积分配置表'; 829 +) ENGINE = InnoDB AUTO_INCREMENT = 6 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '会员积分配置表';
832 830
833 -- ---------------------------- 831 -- ----------------------------
834 -- Records of member_point_config 832 -- Records of member_point_config
@@ -844,10 +842,10 @@ DROP TABLE IF EXISTS `member_point_record`; @@ -844,10 +842,10 @@ DROP TABLE IF EXISTS `member_point_record`;
844 CREATE TABLE `member_point_record` ( 842 CREATE TABLE `member_point_record` (
845 `id` bigint NOT NULL AUTO_INCREMENT COMMENT '自增主键', 843 `id` bigint NOT NULL AUTO_INCREMENT COMMENT '自增主键',
846 `user_id` bigint NOT NULL COMMENT '用户编号', 844 `user_id` bigint NOT NULL COMMENT '用户编号',
847 - `biz_id` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '业务编码', 845 + `biz_id` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '业务编码',
848 `biz_type` tinyint NOT NULL COMMENT '业务类型', 846 `biz_type` tinyint NOT NULL COMMENT '业务类型',
849 - `title` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '积分标题',  
850 - `description` varchar(5000) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '积分描述', 847 + `title` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '积分标题',
  848 + `description` varchar(5000) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '积分描述',
851 `point` int NOT NULL COMMENT '积分', 849 `point` int NOT NULL COMMENT '积分',
852 `total_point` int NOT NULL COMMENT '变动后的积分', 850 `total_point` int NOT NULL COMMENT '变动后的积分',
853 `creator` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT '' COMMENT '创建者', 851 `creator` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT '' COMMENT '创建者',
@@ -859,7 +857,7 @@ CREATE TABLE `member_point_record` ( @@ -859,7 +857,7 @@ CREATE TABLE `member_point_record` (
859 PRIMARY KEY (`id`) USING BTREE, 857 PRIMARY KEY (`id`) USING BTREE,
860 INDEX `index_userId`(`user_id` ASC) USING BTREE, 858 INDEX `index_userId`(`user_id` ASC) USING BTREE,
861 INDEX `index_title`(`title` ASC) USING BTREE 859 INDEX `index_title`(`title` ASC) USING BTREE
862 -) ENGINE = InnoDB AUTO_INCREMENT = 8 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci COMMENT = '用户积分记录'; 860 +) ENGINE = InnoDB AUTO_INCREMENT = 17 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '用户积分记录';
863 861
864 -- ---------------------------- 862 -- ----------------------------
865 -- Records of member_point_record 863 -- Records of member_point_record
@@ -872,6 +870,15 @@ INSERT INTO `member_point_record` (`id`, `user_id`, `biz_id`, `biz_type`, `title @@ -872,6 +870,15 @@ INSERT INTO `member_point_record` (`id`, `user_id`, `biz_id`, `biz_type`, `title
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); 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 (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); 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 (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); 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 (7, 247, '81', 10, '订单消费', '下单获得 8398818 积分', 8398818, 10498609, NULL, '2023-08-31 23:46:17', NULL, '2023-08-31 23:46:17', 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 (8, 247, '85', 12, '订单使用', '下单使用 -30 积分', -30, 10498579, '247', '2023-09-20 17:11:36', '247', '2023-09-20 17:11:36', 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 (9, 247, '86', 12, '订单使用', '下单使用 -30 积分', -30, 10498549, '247', '2023-09-20 19:32:59', '247', '2023-09-20 19:32:59', b'0', 1);
  875 +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 (10, 247, '87', 12, '订单使用', '下单使用 -30 积分', -30, 10498519, '247', '2023-09-20 23:11:21', '247', '2023-09-20 23:11:21', b'0', 1);
  876 +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 (11, 247, '88', 12, '订单使用', '下单使用 -30 积分', -30, 10498489, '247', '2023-09-20 23:20:21', '247', '2023-09-20 23:20:21', b'0', 1);
  877 +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 (12, 247, '89', 12, '订单使用', '下单使用 -30 积分', -30, 10498459, '247', '2023-09-23 23:51:40', '247', '2023-09-23 23:51:40', b'0', 1);
  878 +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 (13, 247, '90', 12, '订单使用', '下单使用 -30 积分', -30, 10498429, '247', '2023-09-23 23:52:34', '247', '2023-09-23 23:52:34', b'0', 1);
  879 +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 (14, 247, '91', 12, '订单使用', '下单使用 -30 积分', -30, 10498399, '247', '2023-09-23 23:54:18', '247', '2023-09-23 23:54:18', b'0', 1);
  880 +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 (15, 247, '92', 12, '订单使用', '下单使用 -30 积分', -30, 10498369, '247', '2023-09-23 23:55:33', '247', '2023-09-23 23:55:33', b'0', 1);
  881 +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 (16, 247, '93', 12, '订单使用', '下单使用 -30 积分', -30, 10498339, '247', '2023-09-23 23:56:53', '247', '2023-09-23 23:56:53', b'0', 1);
875 COMMIT; 882 COMMIT;
876 883
877 -- ---------------------------- 884 -- ----------------------------
@@ -890,7 +897,7 @@ CREATE TABLE `member_sign_in_config` ( @@ -890,7 +897,7 @@ CREATE TABLE `member_sign_in_config` (
890 `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除', 897 `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除',
891 `tenant_id` bigint NOT NULL DEFAULT 0 COMMENT '租户编号', 898 `tenant_id` bigint NOT NULL DEFAULT 0 COMMENT '租户编号',
892 PRIMARY KEY (`id`) USING BTREE 899 PRIMARY KEY (`id`) USING BTREE
893 -) ENGINE = InnoDB AUTO_INCREMENT = 13 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci COMMENT = '签到规则'; 900 +) ENGINE = InnoDB AUTO_INCREMENT = 12 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '签到规则';
894 901
895 -- ---------------------------- 902 -- ----------------------------
896 -- Records of member_sign_in_config 903 -- Records of member_sign_in_config
@@ -919,20 +926,23 @@ CREATE TABLE `member_sign_in_record` ( @@ -919,20 +926,23 @@ CREATE TABLE `member_sign_in_record` (
919 `user_id` int NULL DEFAULT NULL COMMENT '签到用户', 926 `user_id` int NULL DEFAULT NULL COMMENT '签到用户',
920 `day` int NULL DEFAULT NULL COMMENT '第几天签到', 927 `day` int NULL DEFAULT NULL COMMENT '第几天签到',
921 `point` int NULL DEFAULT NULL COMMENT '签到的分数', 928 `point` int NULL DEFAULT NULL COMMENT '签到的分数',
922 - `create_time` datetime NULL DEFAULT NULL COMMENT '签到时间',  
923 - `update_time` datetime NULL DEFAULT NULL ON UPDATE CURRENT_TIMESTAMP COMMENT '变更时间',  
924 - `tenant_id` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '租户id',  
925 - `deleted` int NULL DEFAULT 0 COMMENT '是否删除',  
926 - `creator` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '创建人',  
927 - `updater` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '更新人', 929 + `creator` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT '' COMMENT '创建者',
  930 + `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
  931 + `updater` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT '' COMMENT '更新者',
  932 + `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
  933 + `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除',
  934 + `tenant_id` bigint NOT NULL DEFAULT 0 COMMENT '租户编号',
928 PRIMARY KEY (`id`) USING BTREE 935 PRIMARY KEY (`id`) USING BTREE
929 -) ENGINE = InnoDB AUTO_INCREMENT = 5 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci COMMENT = '签到记录'; 936 +) ENGINE = InnoDB AUTO_INCREMENT = 5 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '签到记录';
930 937
931 -- ---------------------------- 938 -- ----------------------------
932 -- Records of member_sign_in_record 939 -- Records of member_sign_in_record
933 -- ---------------------------- 940 -- ----------------------------
934 BEGIN; 941 BEGIN;
935 -INSERT INTO `member_sign_in_record` (`id`, `user_id`, `day`, `point`, `create_time`, `update_time`, `tenant_id`, `deleted`, `creator`, `updater`) VALUES (4, 247, 12, 1212, '2023-06-10 20:01:27', '2023-08-20 11:29:50', '1', 0, '1', '1'); 942 +INSERT INTO `member_sign_in_record` (`id`, `user_id`, `day`, `point`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (1, 247, 1, 123, '', '2023-09-24 01:23:47', '', '2023-09-24 01:23:47', b'0', 0);
  943 +INSERT INTO `member_sign_in_record` (`id`, `user_id`, `day`, `point`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (2, 247, 12, 12, '', '2023-09-24 01:23:47', '', '2023-09-24 01:23:47', b'0', 0);
  944 +INSERT INTO `member_sign_in_record` (`id`, `user_id`, `day`, `point`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (3, 247, 12, 1212, '', '2023-09-24 01:23:47', '', '2023-09-24 01:23:47', b'0', 0);
  945 +INSERT INTO `member_sign_in_record` (`id`, `user_id`, `day`, `point`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (4, 247, 12, 1212, '', '2023-09-24 01:23:47', '', '2023-09-24 01:23:47', b'0', 0);
936 COMMIT; 946 COMMIT;
937 947
938 -- ---------------------------- 948 -- ----------------------------
@@ -972,7 +982,7 @@ CREATE TABLE `member_user` ( @@ -972,7 +982,7 @@ CREATE TABLE `member_user` (
972 `login_ip` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT '' COMMENT '最后登录IP', 982 `login_ip` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT '' COMMENT '最后登录IP',
973 `login_date` datetime NULL DEFAULT NULL COMMENT '最后登录时间', 983 `login_date` datetime NULL DEFAULT NULL COMMENT '最后登录时间',
974 `nickname` varchar(30) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT '' COMMENT '用户昵称', 984 `nickname` varchar(30) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT '' COMMENT '用户昵称',
975 - `avatar` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT '' COMMENT '头像', 985 + `avatar` varchar(512) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT '' COMMENT '头像',
976 `name` varchar(30) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT '' COMMENT '真实名字', 986 `name` varchar(30) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT '' COMMENT '真实名字',
977 `sex` tinyint NULL DEFAULT 0 COMMENT '用户性别', 987 `sex` tinyint NULL DEFAULT 0 COMMENT '用户性别',
978 `area_id` bigint NULL DEFAULT NULL COMMENT '所在地', 988 `area_id` bigint NULL DEFAULT NULL COMMENT '所在地',
@@ -989,9 +999,8 @@ CREATE TABLE `member_user` ( @@ -989,9 +999,8 @@ CREATE TABLE `member_user` (
989 `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间', 999 `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
990 `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除', 1000 `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除',
991 `tenant_id` bigint NOT NULL DEFAULT 0 COMMENT '租户编号', 1001 `tenant_id` bigint NOT NULL DEFAULT 0 COMMENT '租户编号',
992 - PRIMARY KEY (`id`) USING BTREE,  
993 - UNIQUE INDEX `uk_mobile`(`mobile` ASC) USING BTREE COMMENT '手机号'  
994 -) ENGINE = InnoDB AUTO_INCREMENT = 248 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci COMMENT = '会员用户'; 1002 + PRIMARY KEY (`id`) USING BTREE
  1003 +) ENGINE = InnoDB AUTO_INCREMENT = 249 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci COMMENT = '会员用户';
995 1004
996 -- ---------------------------- 1005 -- ----------------------------
997 -- Records of member_user 1006 -- Records of member_user
@@ -1305,7 +1314,7 @@ CREATE TABLE `system_dict_type` ( @@ -1305,7 +1314,7 @@ CREATE TABLE `system_dict_type` (
1305 `deleted_time` datetime NULL DEFAULT NULL COMMENT '删除时间', 1314 `deleted_time` datetime NULL DEFAULT NULL COMMENT '删除时间',
1306 PRIMARY KEY (`id`) USING BTREE, 1315 PRIMARY KEY (`id`) USING BTREE,
1307 UNIQUE INDEX `dict_type`(`type` ASC) USING BTREE 1316 UNIQUE INDEX `dict_type`(`type` ASC) USING BTREE
1308 -) ENGINE = InnoDB AUTO_INCREMENT = 176 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '字典类型表'; 1317 +) ENGINE = InnoDB AUTO_INCREMENT = 175 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '字典类型表';
1309 1318
1310 -- ---------------------------- 1319 -- ----------------------------
1311 -- Records of system_dict_type 1320 -- Records of system_dict_type
@@ -1389,7 +1398,7 @@ CREATE TABLE `system_error_code` ( @@ -1389,7 +1398,7 @@ CREATE TABLE `system_error_code` (
1389 `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间', 1398 `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
1390 `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除', 1399 `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除',
1391 PRIMARY KEY (`id`) USING BTREE 1400 PRIMARY KEY (`id`) USING BTREE
1392 -) ENGINE = InnoDB AUTO_INCREMENT = 5933 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '错误码表'; 1401 +) ENGINE = InnoDB AUTO_INCREMENT = 5932 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '错误码表';
1393 1402
1394 -- ---------------------------- 1403 -- ----------------------------
1395 -- Records of system_error_code 1404 -- Records of system_error_code
@@ -1418,7 +1427,7 @@ CREATE TABLE `system_login_log` ( @@ -1418,7 +1427,7 @@ CREATE TABLE `system_login_log` (
1418 `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除', 1427 `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除',
1419 `tenant_id` bigint NOT NULL DEFAULT 0 COMMENT '租户编号', 1428 `tenant_id` bigint NOT NULL DEFAULT 0 COMMENT '租户编号',
1420 PRIMARY KEY (`id`) USING BTREE 1429 PRIMARY KEY (`id`) USING BTREE
1421 -) ENGINE = InnoDB AUTO_INCREMENT = 2375 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '系统访问记录'; 1430 +) ENGINE = InnoDB AUTO_INCREMENT = 2482 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '系统访问记录';
1422 1431
1423 -- ---------------------------- 1432 -- ----------------------------
1424 -- Records of system_login_log 1433 -- Records of system_login_log
@@ -1483,7 +1492,7 @@ CREATE TABLE `system_mail_log` ( @@ -1483,7 +1492,7 @@ CREATE TABLE `system_mail_log` (
1483 `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间', 1492 `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
1484 `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除', 1493 `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除',
1485 PRIMARY KEY (`id`) USING BTREE 1494 PRIMARY KEY (`id`) USING BTREE
1486 -) ENGINE = InnoDB AUTO_INCREMENT = 354 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '邮件日志表'; 1495 +) ENGINE = InnoDB AUTO_INCREMENT = 355 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '邮件日志表';
1487 1496
1488 -- ---------------------------- 1497 -- ----------------------------
1489 -- Records of system_mail_log 1498 -- Records of system_mail_log
@@ -2116,7 +2125,7 @@ CREATE TABLE `system_oauth2_access_token` ( @@ -2116,7 +2125,7 @@ CREATE TABLE `system_oauth2_access_token` (
2116 `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除', 2125 `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除',
2117 `tenant_id` bigint NOT NULL DEFAULT 0 COMMENT '租户编号', 2126 `tenant_id` bigint NOT NULL DEFAULT 0 COMMENT '租户编号',
2118 PRIMARY KEY (`id`) USING BTREE 2127 PRIMARY KEY (`id`) USING BTREE
2119 -) ENGINE = InnoDB AUTO_INCREMENT = 2597 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = 'OAuth2 访问令牌'; 2128 +) ENGINE = InnoDB AUTO_INCREMENT = 2721 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = 'OAuth2 访问令牌';
2120 2129
2121 -- ---------------------------- 2130 -- ----------------------------
2122 -- Records of system_oauth2_access_token 2131 -- Records of system_oauth2_access_token
@@ -2238,7 +2247,7 @@ CREATE TABLE `system_oauth2_refresh_token` ( @@ -2238,7 +2247,7 @@ CREATE TABLE `system_oauth2_refresh_token` (
2238 `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除', 2247 `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除',
2239 `tenant_id` bigint NOT NULL DEFAULT 0 COMMENT '租户编号', 2248 `tenant_id` bigint NOT NULL DEFAULT 0 COMMENT '租户编号',
2240 PRIMARY KEY (`id`) USING BTREE 2249 PRIMARY KEY (`id`) USING BTREE
2241 -) ENGINE = InnoDB AUTO_INCREMENT = 896 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = 'OAuth2 刷新令牌'; 2250 +) ENGINE = InnoDB AUTO_INCREMENT = 991 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = 'OAuth2 刷新令牌';
2242 2251
2243 -- ---------------------------- 2252 -- ----------------------------
2244 -- Records of system_oauth2_refresh_token 2253 -- Records of system_oauth2_refresh_token
@@ -2278,7 +2287,7 @@ CREATE TABLE `system_operate_log` ( @@ -2278,7 +2287,7 @@ CREATE TABLE `system_operate_log` (
2278 `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除', 2287 `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除',
2279 `tenant_id` bigint NOT NULL DEFAULT 0 COMMENT '租户编号', 2288 `tenant_id` bigint NOT NULL DEFAULT 0 COMMENT '租户编号',
2280 PRIMARY KEY (`id`) USING BTREE 2289 PRIMARY KEY (`id`) USING BTREE
2281 -) ENGINE = InnoDB AUTO_INCREMENT = 8321 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '操作日志记录'; 2290 +) ENGINE = InnoDB AUTO_INCREMENT = 8338 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '操作日志记录';
2282 2291
2283 -- ---------------------------- 2292 -- ----------------------------
2284 -- Records of system_operate_log 2293 -- Records of system_operate_log
@@ -3286,7 +3295,7 @@ CREATE TABLE `system_sms_code` ( @@ -3286,7 +3295,7 @@ CREATE TABLE `system_sms_code` (
3286 `tenant_id` bigint NOT NULL DEFAULT 0 COMMENT '租户编号', 3295 `tenant_id` bigint NOT NULL DEFAULT 0 COMMENT '租户编号',
3287 PRIMARY KEY (`id`) USING BTREE, 3296 PRIMARY KEY (`id`) USING BTREE,
3288 INDEX `idx_mobile`(`mobile` ASC) USING BTREE COMMENT '手机号' 3297 INDEX `idx_mobile`(`mobile` ASC) USING BTREE COMMENT '手机号'
3289 -) ENGINE = InnoDB AUTO_INCREMENT = 501 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '手机验证码'; 3298 +) ENGINE = InnoDB AUTO_INCREMENT = 513 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '手机验证码';
3290 3299
3291 -- ---------------------------- 3300 -- ----------------------------
3292 -- Records of system_sms_code 3301 -- Records of system_sms_code
@@ -3329,7 +3338,7 @@ CREATE TABLE `system_sms_log` ( @@ -3329,7 +3338,7 @@ CREATE TABLE `system_sms_log` (
3329 `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间', 3338 `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
3330 `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除', 3339 `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除',
3331 PRIMARY KEY (`id`) USING BTREE 3340 PRIMARY KEY (`id`) USING BTREE
3332 -) ENGINE = InnoDB AUTO_INCREMENT = 365 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '短信日志'; 3341 +) ENGINE = InnoDB AUTO_INCREMENT = 381 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '短信日志';
3333 3342
3334 -- ---------------------------- 3343 -- ----------------------------
3335 -- Records of system_sms_log 3344 -- Records of system_sms_log
@@ -3401,7 +3410,7 @@ CREATE TABLE `system_social_user` ( @@ -3401,7 +3410,7 @@ CREATE TABLE `system_social_user` (
3401 `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除', 3410 `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除',
3402 `tenant_id` bigint NOT NULL DEFAULT 0 COMMENT '租户编号', 3411 `tenant_id` bigint NOT NULL DEFAULT 0 COMMENT '租户编号',
3403 PRIMARY KEY (`id`) USING BTREE 3412 PRIMARY KEY (`id`) USING BTREE
3404 -) ENGINE = InnoDB AUTO_INCREMENT = 20 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '社交用户表'; 3413 +) ENGINE = InnoDB AUTO_INCREMENT = 21 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '社交用户表';
3405 3414
3406 -- ---------------------------- 3415 -- ----------------------------
3407 -- Records of system_social_user 3416 -- Records of system_social_user
@@ -3426,7 +3435,7 @@ CREATE TABLE `system_social_user_bind` ( @@ -3426,7 +3435,7 @@ CREATE TABLE `system_social_user_bind` (
3426 `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除', 3435 `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除',
3427 `tenant_id` bigint NOT NULL DEFAULT 0 COMMENT '租户编号', 3436 `tenant_id` bigint NOT NULL DEFAULT 0 COMMENT '租户编号',
3428 PRIMARY KEY (`id`) USING BTREE 3437 PRIMARY KEY (`id`) USING BTREE
3429 -) ENGINE = InnoDB AUTO_INCREMENT = 39 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '社交绑定表'; 3438 +) ENGINE = InnoDB AUTO_INCREMENT = 76 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '社交绑定表';
3430 3439
3431 -- ---------------------------- 3440 -- ----------------------------
3432 -- Records of system_social_user_bind 3441 -- Records of system_social_user_bind
@@ -3462,8 +3471,8 @@ CREATE TABLE `system_tenant` ( @@ -3462,8 +3471,8 @@ CREATE TABLE `system_tenant` (
3462 -- ---------------------------- 3471 -- ----------------------------
3463 BEGIN; 3472 BEGIN;
3464 INSERT INTO `system_tenant` (`id`, `name`, `contact_user_id`, `contact_name`, `contact_mobile`, `status`, `domain`, `package_id`, `expire_time`, `account_count`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1, '芋道源码', NULL, '芋艿', '17321315478', 0, 'https://www.iocoder.cn', 0, '2099-02-19 17:14:16', 9999, '1', '2021-01-05 17:03:47', '1', '2022-02-23 12:15:11', b'0'); 3473 INSERT INTO `system_tenant` (`id`, `name`, `contact_user_id`, `contact_name`, `contact_mobile`, `status`, `domain`, `package_id`, `expire_time`, `account_count`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1, '芋道源码', NULL, '芋艿', '17321315478', 0, 'https://www.iocoder.cn', 0, '2099-02-19 17:14:16', 9999, '1', '2021-01-05 17:03:47', '1', '2022-02-23 12:15:11', b'0');
3465 -INSERT INTO `system_tenant` (`id`, `name`, `contact_user_id`, `contact_name`, `contact_mobile`, `status`, `domain`, `package_id`, `expire_time`, `account_count`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (121, '小租户', 110, '小王2', '15601691300', 0, 'http://www.iocoder.cn', 111, '2024-03-11 00:00:00', 20, '1', '2022-02-22 00:56:14', '1', '2023-07-25 23:05:38', b'0');  
3466 -INSERT INTO `system_tenant` (`id`, `name`, `contact_user_id`, `contact_name`, `contact_mobile`, `status`, `domain`, `package_id`, `expire_time`, `account_count`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (122, '测试租户', 113, '芋道', '15601691300', 0, 'https://www.iocoder.cn', 111, '2022-04-30 00:00:00', 50, '1', '2022-03-07 21:37:58', '1', '2023-07-25 23:53:16', b'0'); 3474 +INSERT INTO `system_tenant` (`id`, `name`, `contact_user_id`, `contact_name`, `contact_mobile`, `status`, `domain`, `package_id`, `expire_time`, `account_count`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (121, '小租户', 110, '小王2', '15601691300', 0, 'http://www.iocoder.cn', 111, '2024-03-11 00:00:00', 20, '1', '2022-02-22 00:56:14', '1', '2023-09-16 16:59:42', b'0');
  3475 +INSERT INTO `system_tenant` (`id`, `name`, `contact_user_id`, `contact_name`, `contact_mobile`, `status`, `domain`, `package_id`, `expire_time`, `account_count`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (122, '测试租户', 113, '芋道', '15601691300', 0, 'https://www.iocoder.cn', 111, '2022-04-30 00:00:00', 50, '1', '2022-03-07 21:37:58', '1', '2023-09-16 16:59:27', b'0');
3467 COMMIT; 3476 COMMIT;
3468 3477
3469 -- ---------------------------- 3478 -- ----------------------------
@@ -3602,10 +3611,10 @@ CREATE TABLE `system_users` ( @@ -3602,10 +3611,10 @@ CREATE TABLE `system_users` (
3602 -- Records of system_users 3611 -- Records of system_users
3603 -- ---------------------------- 3612 -- ----------------------------
3604 BEGIN; 3613 BEGIN;
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); 3614 +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-24 12:03:56', 'admin', '2021-01-05 17:03:47', NULL, '2023-09-24 12:03:56', b'0', 1);
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); 3615 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);
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); 3616 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);
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); 3617 +INSERT INTO `system_users` (`id`, `username`, `password`, `nickname`, `remark`, `dept_id`, `post_ids`, `email`, `mobile`, `sex`, `avatar`, `status`, `login_ip`, `login_date`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (104, 'test', '$2a$10$GP8zvqHB//TekuzYZSBYAuBQJiNq1.fxQVDYJ.uBCOnWCtDVKE4H6', '测试号', NULL, 107, '[1,2]', '111@qq.com', '15601691200', 1, '', 0, '0:0:0:0:0:0:0:1', '2023-09-24 18:21:19', '', '2021-01-21 02:13:53', NULL, '2023-09-24 18:21:19', b'0', 1);
3609 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 (107, 'admin107', '$2a$10$dYOOBKMO93v/.ReCqzyFg.o67Tqk.bbc2bhrpyBGkIw9aypCtr2pm', '芋艿', NULL, NULL, NULL, '', '15601691300', 0, '', 0, '', NULL, '1', '2022-02-20 22:59:33', '1', '2022-02-27 08:26:51', b'0', 118); 3618 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 (107, 'admin107', '$2a$10$dYOOBKMO93v/.ReCqzyFg.o67Tqk.bbc2bhrpyBGkIw9aypCtr2pm', '芋艿', NULL, NULL, NULL, '', '15601691300', 0, '', 0, '', NULL, '1', '2022-02-20 22:59:33', '1', '2022-02-27 08:26:51', b'0', 118);
3610 INSERT INTO `system_users` (`id`, `username`, `password`, `nickname`, `remark`, `dept_id`, `post_ids`, `email`, `mobile`, `sex`, `avatar`, `status`, `login_ip`, `login_date`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (108, 'admin108', '$2a$10$y6mfvKoNYL1GXWak8nYwVOH.kCWqjactkzdoIDgiKl93WN3Ejg.Lu', '芋艿', NULL, NULL, NULL, '', '15601691300', 0, '', 0, '', NULL, '1', '2022-02-20 23:00:50', '1', '2022-02-27 08:26:53', b'0', 119); 3619 INSERT INTO `system_users` (`id`, `username`, `password`, `nickname`, `remark`, `dept_id`, `post_ids`, `email`, `mobile`, `sex`, `avatar`, `status`, `login_ip`, `login_date`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (108, 'admin108', '$2a$10$y6mfvKoNYL1GXWak8nYwVOH.kCWqjactkzdoIDgiKl93WN3Ejg.Lu', '芋艿', NULL, NULL, NULL, '', '15601691300', 0, '', 0, '', NULL, '1', '2022-02-20 23:00:50', '1', '2022-02-27 08:26:53', b'0', 119);
3611 INSERT INTO `system_users` (`id`, `username`, `password`, `nickname`, `remark`, `dept_id`, `post_ids`, `email`, `mobile`, `sex`, `avatar`, `status`, `login_ip`, `login_date`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (109, 'admin109', '$2a$10$JAqvH0tEc0I7dfDVBI7zyuB4E3j.uH6daIjV53.vUS6PknFkDJkuK', '芋艿', NULL, NULL, NULL, '', '15601691300', 0, '', 0, '', NULL, '1', '2022-02-20 23:11:50', '1', '2022-02-27 08:26:56', b'0', 120); 3620 INSERT INTO `system_users` (`id`, `username`, `password`, `nickname`, `remark`, `dept_id`, `post_ids`, `email`, `mobile`, `sex`, `avatar`, `status`, `login_ip`, `login_date`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (109, 'admin109', '$2a$10$JAqvH0tEc0I7dfDVBI7zyuB4E3j.uH6daIjV53.vUS6PknFkDJkuK', '芋艿', NULL, NULL, NULL, '', '15601691300', 0, '', 0, '', NULL, '1', '2022-02-20 23:11:50', '1', '2022-02-27 08:26:56', b'0', 120);
sql/sqlserver/ruoyi-vue-pro.sql
@@ -5815,8 +5815,7 @@ GO @@ -5815,8 +5815,7 @@ GO
5815 5815
5816 CREATE TABLE [dbo].[system_dict_type] 5816 CREATE TABLE [dbo].[system_dict_type]
5817 ( 5817 (
5818 - [  
5819 - id] 5818 + [id]
5820 bigint 5819 bigint
5821 IDENTITY 5820 IDENTITY
5822 ( 5821 (
yudao-dependencies/pom.xml
@@ -14,16 +14,16 @@ @@ -14,16 +14,16 @@
14 <url>https://github.com/YunaiV/ruoyi-vue-pro</url> 14 <url>https://github.com/YunaiV/ruoyi-vue-pro</url>
15 15
16 <properties> 16 <properties>
17 - <revision>1.8.1-snapshot</revision> 17 + <revision>1.8.2-snapshot</revision>
18 <flatten-maven-plugin.version>1.5.0</flatten-maven-plugin.version> 18 <flatten-maven-plugin.version>1.5.0</flatten-maven-plugin.version>
19 <!-- 统一依赖管理 --> 19 <!-- 统一依赖管理 -->
20 - <spring.boot.version>2.7.14</spring.boot.version> 20 + <spring.boot.version>2.7.16</spring.boot.version>
21 <!-- Web 相关 --> 21 <!-- Web 相关 -->
22 - <springdoc.version>1.6.15</springdoc.version>  
23 - <knife4j.version>4.1.0</knife4j.version> 22 + <springdoc.version>1.7.0</springdoc.version>
  23 + <knife4j.version>4.3.0</knife4j.version>
24 <servlet.versoin>2.5</servlet.versoin> 24 <servlet.versoin>2.5</servlet.versoin>
25 <!-- DB 相关 --> 25 <!-- DB 相关 -->
26 - <druid.version>1.2.18</druid.version> 26 + <druid.version>1.2.19</druid.version>
27 <mybatis-plus.version>3.5.3.2</mybatis-plus.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 <mybatis-plus-generator.version>3.5.3.2</mybatis-plus-generator.version>
29 <dynamic-datasource.version>3.6.1</dynamic-datasource.version> 29 <dynamic-datasource.version>3.6.1</dynamic-datasource.version>
@@ -44,33 +44,32 @@ @@ -44,33 +44,32 @@
44 <!-- Bpm 工作流相关 --> 44 <!-- Bpm 工作流相关 -->
45 <flowable.version>6.8.0</flowable.version> 45 <flowable.version>6.8.0</flowable.version>
46 <!-- 工具类相关 --> 46 <!-- 工具类相关 -->
47 - <captcha-plus.version>1.0.6</captcha-plus.version>  
48 - <jsoup.version>1.15.4</jsoup.version>  
49 - <lombok.version>1.18.28</lombok.version> 47 + <captcha-plus.version>1.0.8</captcha-plus.version>
  48 + <jsoup.version>1.16.1</jsoup.version>
  49 + <lombok.version>1.18.30</lombok.version>
50 <mapstruct.version>1.5.5.Final</mapstruct.version> 50 <mapstruct.version>1.5.5.Final</mapstruct.version>
51 - <hutool.version>5.8.20</hutool.version> 51 + <hutool.version>5.8.22</hutool.version>
52 <easyexcel.verion>3.3.2</easyexcel.verion> 52 <easyexcel.verion>3.3.2</easyexcel.verion>
53 <velocity.version>2.3</velocity.version> 53 <velocity.version>2.3</velocity.version>
54 <screw.version>1.0.5</screw.version> 54 <screw.version>1.0.5</screw.version>
55 <fastjson.version>1.2.83</fastjson.version> 55 <fastjson.version>1.2.83</fastjson.version>
56 - <guava.version>32.0.1-jre</guava.version> 56 + <guava.version>32.1.2-jre</guava.version>
57 <guice.version>5.1.0</guice.version> 57 <guice.version>5.1.0</guice.version>
58 <transmittable-thread-local.version>2.14.2</transmittable-thread-local.version> 58 <transmittable-thread-local.version>2.14.2</transmittable-thread-local.version>
59 <commons-net.version>3.9.0</commons-net.version> 59 <commons-net.version>3.9.0</commons-net.version>
60 <jsch.version>0.1.55</jsch.version> 60 <jsch.version>0.1.55</jsch.version>
61 <tika-core.version>2.7.0</tika-core.version> 61 <tika-core.version>2.7.0</tika-core.version>
62 - <netty-all.version>4.1.90.Final</netty-all.version>  
63 <ip2region.version>2.7.0</ip2region.version> 62 <ip2region.version>2.7.0</ip2region.version>
64 <!-- 三方云服务相关 --> 63 <!-- 三方云服务相关 -->
65 - <okio.version>3.0.0</okio.version>  
66 - <okhttp3.version>4.10.0</okhttp3.version> 64 + <okio.version>3.5.0</okio.version>
  65 + <okhttp3.version>4.11.0</okhttp3.version>
67 <commons-io.version>2.11.0</commons-io.version> 66 <commons-io.version>2.11.0</commons-io.version>
68 - <minio.version>8.5.4</minio.version>  
69 - <aliyun-java-sdk-core.version>4.6.3</aliyun-java-sdk-core.version> 67 + <minio.version>8.5.6</minio.version>
  68 + <aliyun-java-sdk-core.version>4.6.4</aliyun-java-sdk-core.version>
70 <aliyun-java-sdk-dysmsapi.version>2.2.1</aliyun-java-sdk-dysmsapi.version> 69 <aliyun-java-sdk-dysmsapi.version>2.2.1</aliyun-java-sdk-dysmsapi.version>
71 - <tencentcloud-sdk-java.version>3.1.758</tencentcloud-sdk-java.version>  
72 - <justauth.version>1.0.3</justauth.version>  
73 - <jimureport.version>1.5.8</jimureport.version> 70 + <tencentcloud-sdk-java.version>3.1.853</tencentcloud-sdk-java.version>
  71 + <justauth.version>1.0.5</justauth.version>
  72 + <jimureport.version>1.6.1</jimureport.version>
74 <xercesImpl.version>2.12.2</xercesImpl.version> 73 <xercesImpl.version>2.12.2</xercesImpl.version>
75 <weixin-java.version>4.5.0</weixin-java.version> 74 <weixin-java.version>4.5.0</weixin-java.version>
76 </properties> 75 </properties>
@@ -233,6 +232,12 @@ @@ -233,6 +232,12 @@
233 <groupId>org.redisson</groupId> 232 <groupId>org.redisson</groupId>
234 <artifactId>redisson-spring-boot-starter</artifactId> 233 <artifactId>redisson-spring-boot-starter</artifactId>
235 <version>${redisson.version}</version> 234 <version>${redisson.version}</version>
  235 + <exclusions>
  236 + <exclusion>
  237 + <groupId>org.springframework.boot</groupId>
  238 + <artifactId>spring-boot-starter-actuator</artifactId>
  239 + </exclusion>
  240 + </exclusions>
236 </dependency> 241 </dependency>
237 242
238 <dependency> 243 <dependency>
@@ -337,6 +342,12 @@ @@ -337,6 +342,12 @@
337 <groupId>de.codecentric</groupId> 342 <groupId>de.codecentric</groupId>
338 <artifactId>spring-boot-admin-starter-server</artifactId> <!-- 实现 Spring Boot Admin Server 服务端 --> 343 <artifactId>spring-boot-admin-starter-server</artifactId> <!-- 实现 Spring Boot Admin Server 服务端 -->
339 <version>${spring-boot-admin.version}</version> 344 <version>${spring-boot-admin.version}</version>
  345 + <exclusions>
  346 + <exclusion>
  347 + <groupId>de.codecentric</groupId>
  348 + <artifactId>spring-boot-admin-server-cloud</artifactId>
  349 + </exclusion>
  350 + </exclusions>
340 </dependency> 351 </dependency>
341 <dependency> 352 <dependency>
342 <groupId>de.codecentric</groupId> 353 <groupId>de.codecentric</groupId>
@@ -520,12 +531,6 @@ @@ -520,12 +531,6 @@
520 </dependency> 531 </dependency>
521 532
522 <dependency> 533 <dependency>
523 - <groupId>io.netty</groupId>  
524 - <artifactId>netty-all</artifactId>  
525 - <version>${netty-all.version}</version>  
526 - </dependency>  
527 -  
528 - <dependency>  
529 <groupId>com.xingyuv</groupId> 534 <groupId>com.xingyuv</groupId>
530 <artifactId>spring-boot-starter-captcha-plus</artifactId> 535 <artifactId>spring-boot-starter-captcha-plus</artifactId>
531 <version>${captcha-plus.version}</version> 536 <version>${captcha-plus.version}</version>
yudao-example/yudao-sso-demo-by-code/pom.xml
@@ -21,7 +21,7 @@ @@ -21,7 +21,7 @@
21 <maven.compiler.target>8</maven.compiler.target> 21 <maven.compiler.target>8</maven.compiler.target>
22 <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> 22 <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
23 <!-- 统一依赖管理 --> 23 <!-- 统一依赖管理 -->
24 - <spring.boot.version>2.7.14</spring.boot.version> 24 + <spring.boot.version>2.7.16</spring.boot.version>
25 </properties> 25 </properties>
26 26
27 <dependencyManagement> 27 <dependencyManagement>
@@ -52,7 +52,7 @@ @@ -52,7 +52,7 @@
52 <dependency> 52 <dependency>
53 <groupId>cn.hutool</groupId> 53 <groupId>cn.hutool</groupId>
54 <artifactId>hutool-all</artifactId> 54 <artifactId>hutool-all</artifactId>
55 - <version>5.8.20</version> 55 + <version>5.8.22</version>
56 </dependency> 56 </dependency>
57 57
58 <dependency> 58 <dependency>
yudao-example/yudao-sso-demo-by-password/pom.xml
@@ -21,7 +21,7 @@ @@ -21,7 +21,7 @@
21 <maven.compiler.target>8</maven.compiler.target> 21 <maven.compiler.target>8</maven.compiler.target>
22 <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> 22 <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
23 <!-- 统一依赖管理 --> 23 <!-- 统一依赖管理 -->
24 - <spring.boot.version>2.7.14</spring.boot.version> 24 + <spring.boot.version>2.7.16</spring.boot.version>
25 </properties> 25 </properties>
26 26
27 <dependencyManagement> 27 <dependencyManagement>
@@ -52,7 +52,7 @@ @@ -52,7 +52,7 @@
52 <dependency> 52 <dependency>
53 <groupId>cn.hutool</groupId> 53 <groupId>cn.hutool</groupId>
54 <artifactId>hutool-all</artifactId> 54 <artifactId>hutool-all</artifactId>
55 - <version>5.8.20</version> 55 + <version>5.8.22</version>
56 </dependency> 56 </dependency>
57 57
58 <dependency> 58 <dependency>
yudao-framework/yudao-common/pom.xml
@@ -137,6 +137,7 @@ @@ -137,6 +137,7 @@
137 <dependency> 137 <dependency>
138 <groupId>org.springframework.boot</groupId> 138 <groupId>org.springframework.boot</groupId>
139 <artifactId>spring-boot-starter-test</artifactId> 139 <artifactId>spring-boot-starter-test</artifactId>
  140 + <scope>test</scope>
140 </dependency> 141 </dependency>
141 </dependencies> 142 </dependencies>
142 143
yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/util/json/JsonUtils.java
@@ -10,7 +10,6 @@ import com.fasterxml.jackson.databind.ObjectMapper; @@ -10,7 +10,6 @@ import com.fasterxml.jackson.databind.ObjectMapper;
10 import com.fasterxml.jackson.databind.SerializationFeature; 10 import com.fasterxml.jackson.databind.SerializationFeature;
11 import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule; 11 import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
12 import lombok.SneakyThrows; 12 import lombok.SneakyThrows;
13 -import lombok.experimental.UtilityClass;  
14 import lombok.extern.slf4j.Slf4j; 13 import lombok.extern.slf4j.Slf4j;
15 14
16 import java.io.IOException; 15 import java.io.IOException;
@@ -23,7 +22,6 @@ import java.util.List; @@ -23,7 +22,6 @@ import java.util.List;
23 * 22 *
24 * @author 芋道源码 23 * @author 芋道源码
25 */ 24 */
26 -@UtilityClass  
27 @Slf4j 25 @Slf4j
28 public class JsonUtils { 26 public class JsonUtils {
29 27
yudao-framework/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/dto/transfer/PayTransferRespDTO.java
@@ -64,12 +64,12 @@ public class PayTransferRespDTO { @@ -64,12 +64,12 @@ public class PayTransferRespDTO {
64 } 64 }
65 65
66 /** 66 /**
67 - * 创建【FAILURE】状态的转账返回 67 + * 创建【CLOSED】状态的转账返回
68 */ 68 */
69 - public static PayTransferRespDTO failureOf(String channelErrorCode, String channelErrorMsg,  
70 - String outTransferNo, Object rawData) { 69 + public static PayTransferRespDTO closedOf(String channelErrorCode, String channelErrorMsg,
  70 + String outTransferNo, Object rawData) {
71 PayTransferRespDTO respDTO = new PayTransferRespDTO(); 71 PayTransferRespDTO respDTO = new PayTransferRespDTO();
72 - respDTO.status = PayTransferStatusRespEnum.FAILURE.getStatus(); 72 + respDTO.status = PayTransferStatusRespEnum.CLOSED.getStatus();
73 respDTO.channelErrorCode = channelErrorCode; 73 respDTO.channelErrorCode = channelErrorCode;
74 respDTO.channelErrorMsg = channelErrorMsg; 74 respDTO.channelErrorMsg = channelErrorMsg;
75 // 相对通用的字段 75 // 相对通用的字段
yudao-framework/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/dto/transfer/PayTransferUnifiedReqDTO.java
@@ -58,7 +58,6 @@ public class PayTransferUnifiedReqDTO { @@ -58,7 +58,6 @@ public class PayTransferUnifiedReqDTO {
58 58
59 /** 59 /**
60 * 支付渠道的额外参数 60 * 支付渠道的额外参数
61 - *  
62 */ 61 */
63 private Map<String, String> channelExtras; 62 private Map<String, String> channelExtras;
64 63
yudao-framework/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/impl/AbstractPayClient.java
@@ -50,7 +50,7 @@ public abstract class AbstractPayClient&lt;Config extends PayClientConfig&gt; implemen @@ -50,7 +50,7 @@ public abstract class AbstractPayClient&lt;Config extends PayClientConfig&gt; implemen
50 */ 50 */
51 public final void init() { 51 public final void init() {
52 doInit(); 52 doInit();
53 - log.info("[init][客户端({}) 初始化完成]", getId()); 53 + log.debug("[init][客户端({}) 初始化完成]", getId());
54 } 54 }
55 55
56 /** 56 /**
yudao-framework/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/impl/alipay/AlipayTransferClient.java
@@ -51,7 +51,7 @@ public class AlipayTransferClient extends AbstractAlipayPayClient { @@ -51,7 +51,7 @@ public class AlipayTransferClient extends AbstractAlipayPayClient {
51 model.setProductCode("TRANS_ACCOUNT_NO_PWD"); // 销售产品码。单笔无密转账固定为 TRANS_ACCOUNT_NO_PWD 51 model.setProductCode("TRANS_ACCOUNT_NO_PWD"); // 销售产品码。单笔无密转账固定为 TRANS_ACCOUNT_NO_PWD
52 model.setBizScene("DIRECT_TRANSFER"); // 业务场景 单笔无密转账固定为 DIRECT_TRANSFER。 52 model.setBizScene("DIRECT_TRANSFER"); // 业务场景 单笔无密转账固定为 DIRECT_TRANSFER。
53 model.setBusinessParams(JsonUtils.toJsonString(reqDTO.getChannelExtras())); 53 model.setBusinessParams(JsonUtils.toJsonString(reqDTO.getChannelExtras()));
54 - PayTransferTypeEnum transferType = PayTransferTypeEnum.valueOf(reqDTO.getType()); 54 + PayTransferTypeEnum transferType = PayTransferTypeEnum.ofType(reqDTO.getType());
55 switch(transferType){ 55 switch(transferType){
56 case WX_BALANCE : 56 case WX_BALANCE :
57 case WALLET_BALANCE : { 57 case WALLET_BALANCE : {
@@ -84,7 +84,7 @@ public class AlipayTransferClient extends AbstractAlipayPayClient { @@ -84,7 +84,7 @@ public class AlipayTransferClient extends AbstractAlipayPayClient {
84 if (ObjectUtils.equalsAny(response.getSubCode(), "SYSTEM_ERROR", "ACQ.SYSTEM_ERROR")) { 84 if (ObjectUtils.equalsAny(response.getSubCode(), "SYSTEM_ERROR", "ACQ.SYSTEM_ERROR")) {
85 return PayTransferRespDTO.waitingOf(null, reqDTO.getOutTransferNo(), response); 85 return PayTransferRespDTO.waitingOf(null, reqDTO.getOutTransferNo(), response);
86 } 86 }
87 - return PayTransferRespDTO.failureOf(response.getSubCode(), response.getSubMsg(), 87 + return PayTransferRespDTO.closedOf(response.getSubCode(), response.getSubMsg(),
88 reqDTO.getOutTransferNo(), response); 88 reqDTO.getOutTransferNo(), response);
89 } 89 }
90 return PayTransferRespDTO.successOf(response.getOrderId(), parseTime(response.getTransDate()), 90 return PayTransferRespDTO.successOf(response.getOrderId(), parseTime(response.getTransDate()),
yudao-framework/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/enums/transfer/PayTransferStatusRespEnum.java
@@ -3,6 +3,8 @@ package cn.iocoder.yudao.framework.pay.core.enums.transfer; @@ -3,6 +3,8 @@ package cn.iocoder.yudao.framework.pay.core.enums.transfer;
3 import lombok.AllArgsConstructor; 3 import lombok.AllArgsConstructor;
4 import lombok.Getter; 4 import lombok.Getter;
5 5
  6 +import java.util.Objects;
  7 +
6 /** 8 /**
7 * 渠道的转账状态枚举 9 * 渠道的转账状态枚举
8 * 10 *
@@ -12,10 +14,28 @@ import lombok.Getter; @@ -12,10 +14,28 @@ import lombok.Getter;
12 @AllArgsConstructor 14 @AllArgsConstructor
13 public enum PayTransferStatusRespEnum { 15 public enum PayTransferStatusRespEnum {
14 16
15 - WAITING(0, "等待转账"),  
16 - SUCCESS(10, "转账成功"),  
17 - FAILURE(20, "转账失败"); 17 + WAITING(0, "转账中"),
  18 +
  19 + /**
  20 + * TODO 转账到银行卡. 会有T+0 T+1 到账的请情况。 还未实现
  21 + */
  22 + IN_PROGRESS(10, "转账进行中"),
  23 +
  24 +
  25 + SUCCESS(20, "转账成功"),
  26 + /**
  27 + * 转账关闭 (失败,或者其它情况)
  28 + */
  29 + CLOSED(30, "转账关闭");
18 30
19 private final Integer status; 31 private final Integer status;
20 private final String name; 32 private final String name;
  33 +
  34 + public static boolean isSuccess(Integer status) {
  35 + return Objects.equals(status, SUCCESS.getStatus());
  36 + }
  37 +
  38 + public static boolean isClosed(Integer status) {
  39 + return Objects.equals(status, CLOSED.getStatus());
  40 + }
21 } 41 }
yudao-framework/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/enums/transfer/PayTransferTypeEnum.java
@@ -20,6 +20,9 @@ public enum PayTransferTypeEnum implements IntArrayValuable { @@ -20,6 +20,9 @@ public enum PayTransferTypeEnum implements IntArrayValuable {
20 BANK_CARD(3, "银行卡"), 20 BANK_CARD(3, "银行卡"),
21 WALLET_BALANCE(4, "钱包余额"); 21 WALLET_BALANCE(4, "钱包余额");
22 22
  23 + public static final String ALIPAY_LOGON_ID = "ALIPAY_LOGON_ID";
  24 + public static final String ALIPAY_ACCOUNT_NAME = "ALIPAY_ACCOUNT_NAME";
  25 +
23 private final Integer type; 26 private final Integer type;
24 private final String name; 27 private final String name;
25 28
@@ -30,7 +33,7 @@ public enum PayTransferTypeEnum implements IntArrayValuable { @@ -30,7 +33,7 @@ public enum PayTransferTypeEnum implements IntArrayValuable {
30 return ARRAYS; 33 return ARRAYS;
31 } 34 }
32 35
33 - public static PayTransferTypeEnum valueOf(Integer type) { 36 + public static PayTransferTypeEnum ofType(Integer type) {
34 return ArrayUtil.firstMatch(item -> item.getType().equals(type), values()); 37 return ArrayUtil.firstMatch(item -> item.getType().equals(type), values());
35 } 38 }
36 } 39 }
yudao-framework/yudao-spring-boot-starter-biz-sms/src/main/java/cn/iocoder/yudao/framework/sms/core/client/impl/AbstractSmsClient.java
@@ -40,7 +40,7 @@ public abstract class AbstractSmsClient implements SmsClient { @@ -40,7 +40,7 @@ public abstract class AbstractSmsClient implements SmsClient {
40 */ 40 */
41 public final void init() { 41 public final void init() {
42 doInit(); 42 doInit();
43 - log.info("[init][配置({}) 初始化完成]", properties); 43 + log.debug("[init][配置({}) 初始化完成]", properties);
44 } 44 }
45 45
46 /** 46 /**
yudao-framework/yudao-spring-boot-starter-biz-social/src/main/java/cn/iocoder/yudao/framework/social/config/YudaoSocialAutoConfiguration.java
1 -package cn.iocoder.yudao.framework.social.config;  
2 -  
3 -import cn.iocoder.yudao.framework.social.core.YudaoAuthRequestFactory;  
4 -import com.xingyuv.http.HttpUtil;  
5 -import com.xingyuv.http.support.hutool.HutoolImpl;  
6 -import com.xingyuv.jushauth.cache.AuthStateCache;  
7 -import com.xingyuv.justauth.autoconfigure.JustAuthProperties;  
8 -import lombok.extern.slf4j.Slf4j;  
9 -import org.springframework.boot.autoconfigure.AutoConfiguration;  
10 -import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;  
11 -import org.springframework.boot.context.properties.EnableConfigurationProperties;  
12 -import org.springframework.context.annotation.Bean;  
13 -import org.springframework.context.annotation.Primary;  
14 -  
15 -/**  
16 - * 社交自动装配类  
17 - *  
18 - * @author timfruit  
19 - * @date 2021-10-30  
20 - */  
21 -@Slf4j  
22 -@AutoConfiguration  
23 -@EnableConfigurationProperties(JustAuthProperties.class)  
24 -public class YudaoSocialAutoConfiguration {  
25 -  
26 - @Bean  
27 - @Primary  
28 - @ConditionalOnProperty(prefix = "justauth", value = "enabled", havingValue = "true", matchIfMissing = true)  
29 - public YudaoAuthRequestFactory yudaoAuthRequestFactory(JustAuthProperties properties, AuthStateCache authStateCache) {  
30 - // 需要修改 HttpUtil 使用的实现,避免类报错  
31 - HttpUtil.setHttp(new HutoolImpl());  
32 - // 创建 YudaoAuthRequestFactory  
33 - return new YudaoAuthRequestFactory(properties, authStateCache);  
34 - }  
35 -  
36 -} 1 +package cn.iocoder.yudao.framework.social.config;
  2 +
  3 +import cn.iocoder.yudao.framework.social.core.YudaoAuthRequestFactory;
  4 +import com.xingyuv.http.HttpUtil;
  5 +import com.xingyuv.http.support.hutool.HutoolImpl;
  6 +import com.xingyuv.jushauth.cache.AuthStateCache;
  7 +import com.xingyuv.justauth.autoconfigure.JustAuthProperties;
  8 +import lombok.extern.slf4j.Slf4j;
  9 +import org.springframework.boot.autoconfigure.AutoConfiguration;
  10 +import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
  11 +import org.springframework.boot.context.properties.EnableConfigurationProperties;
  12 +import org.springframework.context.annotation.Bean;
  13 +import org.springframework.context.annotation.Primary;
  14 +
  15 +/**
  16 + * 社交自动装配类
  17 + *
  18 + * @author timfruit
  19 + * @date 2021-10-30
  20 + */
  21 +@Slf4j
  22 +@AutoConfiguration
  23 +@EnableConfigurationProperties(JustAuthProperties.class)
  24 +public class YudaoSocialAutoConfiguration {
  25 +
  26 + @Bean
  27 + @Primary
  28 + @ConditionalOnProperty(prefix = "justauth", value = "enabled", havingValue = "true", matchIfMissing = true)
  29 + public YudaoAuthRequestFactory yudaoAuthRequestFactory(JustAuthProperties properties, AuthStateCache authStateCache) {
  30 + // 需要修改 HttpUtil 使用的实现,避免类报错
  31 + HttpUtil.setHttp(new HutoolImpl());
  32 + // 创建 YudaoAuthRequestFactory
  33 + return new YudaoAuthRequestFactory(properties, authStateCache);
  34 + }
  35 +
  36 +}
yudao-framework/yudao-spring-boot-starter-biz-tenant/src/main/java/cn/iocoder/yudao/framework/tenant/config/YudaoTenantAutoConfiguration.java
1 package cn.iocoder.yudao.framework.tenant.config; 1 package cn.iocoder.yudao.framework.tenant.config;
2 2
3 -import cn.hutool.core.annotation.AnnotationUtil;  
4 import cn.iocoder.yudao.framework.common.enums.WebFilterOrderEnum; 3 import cn.iocoder.yudao.framework.common.enums.WebFilterOrderEnum;
5 import cn.iocoder.yudao.framework.mybatis.core.util.MyBatisUtils; 4 import cn.iocoder.yudao.framework.mybatis.core.util.MyBatisUtils;
6 -import cn.iocoder.yudao.framework.quartz.core.handler.JobHandler;  
7 import cn.iocoder.yudao.framework.redis.config.YudaoCacheProperties; 5 import cn.iocoder.yudao.framework.redis.config.YudaoCacheProperties;
8 import cn.iocoder.yudao.framework.tenant.core.aop.TenantIgnoreAspect; 6 import cn.iocoder.yudao.framework.tenant.core.aop.TenantIgnoreAspect;
9 import cn.iocoder.yudao.framework.tenant.core.db.TenantDatabaseInterceptor; 7 import cn.iocoder.yudao.framework.tenant.core.db.TenantDatabaseInterceptor;
10 -import cn.iocoder.yudao.framework.tenant.core.job.TenantJob;  
11 -import cn.iocoder.yudao.framework.tenant.core.job.TenantJobHandlerDecorator; 8 +import cn.iocoder.yudao.framework.tenant.core.job.TenantJobAspect;
12 import cn.iocoder.yudao.framework.tenant.core.mq.TenantRedisMessageInterceptor; 9 import cn.iocoder.yudao.framework.tenant.core.mq.TenantRedisMessageInterceptor;
13 import cn.iocoder.yudao.framework.tenant.core.redis.TenantRedisCacheManager; 10 import cn.iocoder.yudao.framework.tenant.core.redis.TenantRedisCacheManager;
14 import cn.iocoder.yudao.framework.tenant.core.security.TenantSecurityWebFilter; 11 import cn.iocoder.yudao.framework.tenant.core.security.TenantSecurityWebFilter;
@@ -20,8 +17,6 @@ import cn.iocoder.yudao.framework.web.core.handler.GlobalExceptionHandler; @@ -20,8 +17,6 @@ import cn.iocoder.yudao.framework.web.core.handler.GlobalExceptionHandler;
20 import cn.iocoder.yudao.module.system.api.tenant.TenantApi; 17 import cn.iocoder.yudao.module.system.api.tenant.TenantApi;
21 import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor; 18 import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor;
22 import com.baomidou.mybatisplus.extension.plugins.inner.TenantLineInnerInterceptor; 19 import com.baomidou.mybatisplus.extension.plugins.inner.TenantLineInnerInterceptor;
23 -import org.springframework.beans.BeansException;  
24 -import org.springframework.beans.factory.config.BeanPostProcessor;  
25 import org.springframework.boot.autoconfigure.AutoConfiguration; 20 import org.springframework.boot.autoconfigure.AutoConfiguration;
26 import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; 21 import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
27 import org.springframework.boot.context.properties.EnableConfigurationProperties; 22 import org.springframework.boot.context.properties.EnableConfigurationProperties;
@@ -100,25 +95,8 @@ public class YudaoTenantAutoConfiguration { @@ -100,25 +95,8 @@ public class YudaoTenantAutoConfiguration {
100 // ========== Job ========== 95 // ========== Job ==========
101 96
102 @Bean 97 @Bean
103 - @SuppressWarnings("SpringJavaInjectionPointsAutowiringInspection")  
104 - public BeanPostProcessor jobHandlerBeanPostProcessor(TenantFrameworkService tenantFrameworkService) {  
105 - return new BeanPostProcessor() {  
106 -  
107 - @Override  
108 - public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {  
109 - if (!(bean instanceof JobHandler)) {  
110 - return bean;  
111 - }  
112 - // 有 TenantJob 注解的情况下,才会进行处理  
113 - if (!AnnotationUtil.hasAnnotation(bean.getClass(), TenantJob.class)) {  
114 - return bean;  
115 - }  
116 -  
117 - // 使用 TenantJobHandlerDecorator 装饰  
118 - return new TenantJobHandlerDecorator(tenantFrameworkService, (JobHandler) bean);  
119 - }  
120 -  
121 - }; 98 + public TenantJobAspect tenantJobAspect(TenantFrameworkService tenantFrameworkService) {
  99 + return new TenantJobAspect(tenantFrameworkService);
122 } 100 }
123 101
124 // ========== Redis ========== 102 // ========== Redis ==========
yudao-framework/yudao-spring-boot-starter-biz-tenant/src/main/java/cn/iocoder/yudao/framework/tenant/core/job/TenantJob.java
@@ -8,7 +8,7 @@ import java.lang.annotation.Target; @@ -8,7 +8,7 @@ import java.lang.annotation.Target;
8 /** 8 /**
9 * 多租户 Job 注解 9 * 多租户 Job 注解
10 */ 10 */
11 -@Target({ElementType.TYPE}) 11 +@Target({ElementType.METHOD})
12 @Retention(RetentionPolicy.RUNTIME) 12 @Retention(RetentionPolicy.RUNTIME)
13 public @interface TenantJob { 13 public @interface TenantJob {
14 } 14 }
yudao-framework/yudao-spring-boot-starter-biz-tenant/src/main/java/cn/iocoder/yudao/framework/tenant/core/job/TenantJobHandlerDecorator.java renamed to yudao-framework/yudao-spring-boot-starter-biz-tenant/src/main/java/cn/iocoder/yudao/framework/tenant/core/job/TenantJobAspect.java
1 package cn.iocoder.yudao.framework.tenant.core.job; 1 package cn.iocoder.yudao.framework.tenant.core.job;
2 2
3 import cn.hutool.core.collection.CollUtil; 3 import cn.hutool.core.collection.CollUtil;
  4 +import cn.hutool.core.exceptions.ExceptionUtil;
4 import cn.iocoder.yudao.framework.common.util.json.JsonUtils; 5 import cn.iocoder.yudao.framework.common.util.json.JsonUtils;
5 -import cn.iocoder.yudao.framework.quartz.core.handler.JobHandler;  
6 -import cn.iocoder.yudao.framework.tenant.core.context.TenantContextHolder;  
7 import cn.iocoder.yudao.framework.tenant.core.service.TenantFrameworkService; 6 import cn.iocoder.yudao.framework.tenant.core.service.TenantFrameworkService;
8 -import lombok.AllArgsConstructor; 7 +import cn.iocoder.yudao.framework.tenant.core.util.TenantUtils;
  8 +import lombok.RequiredArgsConstructor;
  9 +import lombok.extern.slf4j.Slf4j;
  10 +import org.aspectj.lang.ProceedingJoinPoint;
  11 +import org.aspectj.lang.annotation.Around;
  12 +import org.aspectj.lang.annotation.Aspect;
9 13
10 import java.util.List; 14 import java.util.List;
11 import java.util.Map; 15 import java.util.Map;
12 import java.util.concurrent.ConcurrentHashMap; 16 import java.util.concurrent.ConcurrentHashMap;
13 17
14 /** 18 /**
15 - * 多租户 JobHandler 装饰器 19 + * 多租户 JobHandler AOP
16 * 任务执行时,会按照租户逐个执行 Job 的逻辑 20 * 任务执行时,会按照租户逐个执行 Job 的逻辑
17 * 21 *
18 * 注意,需要保证 JobHandler 的幂等性。因为 Job 因为某个租户执行失败重试时,之前执行成功的租户也会再次执行。 22 * 注意,需要保证 JobHandler 的幂等性。因为 Job 因为某个租户执行失败重试时,之前执行成功的租户也会再次执行。
19 * 23 *
20 * @author 芋道源码 24 * @author 芋道源码
21 */ 25 */
22 -@AllArgsConstructor  
23 -public class TenantJobHandlerDecorator implements JobHandler { 26 +@Aspect
  27 +@RequiredArgsConstructor
  28 +@Slf4j
  29 +public class TenantJobAspect {
24 30
25 private final TenantFrameworkService tenantFrameworkService; 31 private final TenantFrameworkService tenantFrameworkService;
26 - /**  
27 - * 被装饰的 Job  
28 - */  
29 - private final JobHandler jobHandler;  
30 32
31 - @Override  
32 - public final String execute(String param) throws Exception { 33 + @Around("@annotation(tenantJob)")
  34 + public String around(ProceedingJoinPoint joinPoint, TenantJob tenantJob) {
33 // 获得租户列表 35 // 获得租户列表
34 List<Long> tenantIds = tenantFrameworkService.getTenantIds(); 36 List<Long> tenantIds = tenantFrameworkService.getTenantIds();
35 if (CollUtil.isEmpty(tenantIds)) { 37 if (CollUtil.isEmpty(tenantIds)) {
@@ -38,19 +40,15 @@ public class TenantJobHandlerDecorator implements JobHandler { @@ -38,19 +40,15 @@ public class TenantJobHandlerDecorator implements JobHandler {
38 40
39 // 逐个租户,执行 Job 41 // 逐个租户,执行 Job
40 Map<Long, String> results = new ConcurrentHashMap<>(); 42 Map<Long, String> results = new ConcurrentHashMap<>();
41 - tenantIds.parallelStream().forEach(tenantId -> { // TODO 芋艿:先通过 parallel 实现并行;1)多个租户,是一条执行日志;2)异常的情况  
42 - try {  
43 - // 设置租户  
44 - TenantContextHolder.setTenantId(tenantId);  
45 - // 执行 Job  
46 - String result = jobHandler.execute(param);  
47 - // 添加结果  
48 - results.put(tenantId, result);  
49 - } catch (Exception e) {  
50 - throw new RuntimeException(e);  
51 - } finally {  
52 - TenantContextHolder.clear();  
53 - } 43 + tenantIds.parallelStream().forEach(tenantId -> {
  44 + // TODO 芋艿:先通过 parallel 实现并行;1)多个租户,是一条执行日志;2)异常的情况
  45 + TenantUtils.execute(tenantId, () -> {
  46 + try {
  47 + joinPoint.proceed();
  48 + } catch (Throwable e) {
  49 + results.put(tenantId, ExceptionUtil.getRootCauseMessage(e));
  50 + }
  51 + });
54 }); 52 });
55 return JsonUtils.toJsonString(results); 53 return JsonUtils.toJsonString(results);
56 } 54 }
yudao-framework/yudao-spring-boot-starter-biz-tenant/src/main/java/cn/iocoder/yudao/framework/tenant/core/redis/TenantRedisCacheManager.java
1 package cn.iocoder.yudao.framework.tenant.core.redis; 1 package cn.iocoder.yudao.framework.tenant.core.redis;
2 2
  3 +import cn.iocoder.yudao.framework.redis.core.TimeoutRedisCacheManager;
3 import cn.iocoder.yudao.framework.tenant.core.context.TenantContextHolder; 4 import cn.iocoder.yudao.framework.tenant.core.context.TenantContextHolder;
4 import lombok.extern.slf4j.Slf4j; 5 import lombok.extern.slf4j.Slf4j;
5 import org.springframework.cache.Cache; 6 import org.springframework.cache.Cache;
@@ -15,7 +16,7 @@ import org.springframework.data.redis.cache.RedisCacheWriter; @@ -15,7 +16,7 @@ import org.springframework.data.redis.cache.RedisCacheWriter;
15 * @author airhead 16 * @author airhead
16 */ 17 */
17 @Slf4j 18 @Slf4j
18 -public class TenantRedisCacheManager extends RedisCacheManager { 19 +public class TenantRedisCacheManager extends TimeoutRedisCacheManager {
19 20
20 public TenantRedisCacheManager(RedisCacheWriter cacheWriter, 21 public TenantRedisCacheManager(RedisCacheWriter cacheWriter,
21 RedisCacheConfiguration defaultCacheConfiguration) { 22 RedisCacheConfiguration defaultCacheConfiguration) {
yudao-framework/yudao-spring-boot-starter-biz-tenant/src/test/java/cn/iocoder/yudao/framework/tenant/core/job/TenantJobTest.java deleted
1 -package cn.iocoder.yudao.framework.tenant.core.job;  
2 -  
3 -import cn.iocoder.yudao.framework.tenant.core.service.TenantFrameworkService;  
4 -import cn.iocoder.yudao.framework.test.core.ut.BaseMockitoUnitTest;  
5 -import com.google.common.collect.Lists;  
6 -import org.junit.jupiter.api.Test;  
7 -import org.mockito.Mock;  
8 -import org.mockito.Mockito;  
9 -  
10 -import java.util.List;  
11 -  
12 -import static org.junit.jupiter.api.Assertions.assertEquals;  
13 -  
14 -/**  
15 - * 验证 job 租户逻辑  
16 - * {@link TenantJobHandlerDecorator}  
17 - *  
18 - * @author gaibu  
19 - */  
20 -public class TenantJobTest extends BaseMockitoUnitTest {  
21 -  
22 - @Mock  
23 - TenantFrameworkService tenantFrameworkService;  
24 -  
25 - @Test  
26 - public void test() throws Exception {  
27 - // 准备测试租户 id  
28 - List<Long> tenantIds = Lists.newArrayList(1L, 2L, 3L);  
29 - // mock 数据  
30 - Mockito.doReturn(tenantIds).when(tenantFrameworkService).getTenantIds();  
31 - // 准备测试任务  
32 - TestJob testJob = new TestJob();  
33 - // 创建任务装饰器  
34 - TenantJobHandlerDecorator tenantJobHandlerDecorator = new TenantJobHandlerDecorator(tenantFrameworkService, testJob);  
35 -  
36 - // 执行任务  
37 - tenantJobHandlerDecorator.execute(null);  
38 -  
39 - // 断言返回值  
40 - assertEquals(testJob.getTenantIds(), tenantIds);  
41 - }  
42 -}  
yudao-framework/yudao-spring-boot-starter-biz-tenant/src/test/java/cn/iocoder/yudao/framework/tenant/core/job/TestJob.java
@@ -9,12 +9,12 @@ import java.util.List; @@ -9,12 +9,12 @@ import java.util.List;
9 import java.util.concurrent.CopyOnWriteArrayList; 9 import java.util.concurrent.CopyOnWriteArrayList;
10 10
11 @Component 11 @Component
12 -@TenantJob // 标记多租户  
13 public class TestJob implements JobHandler { 12 public class TestJob implements JobHandler {
14 13
15 private final List<Long> tenantIds = new CopyOnWriteArrayList<>(); 14 private final List<Long> tenantIds = new CopyOnWriteArrayList<>();
16 15
17 @Override 16 @Override
  17 + @TenantJob // 标记多租户
18 public String execute(String param) throws Exception { 18 public String execute(String param) throws Exception {
19 tenantIds.add(TenantContextHolder.getTenantId()); 19 tenantIds.add(TenantContextHolder.getTenantId());
20 return "success"; 20 return "success";
@@ -24,4 +24,5 @@ public class TestJob implements JobHandler { @@ -24,4 +24,5 @@ public class TestJob implements JobHandler {
24 CollUtil.sort(tenantIds, Long::compareTo); 24 CollUtil.sort(tenantIds, Long::compareTo);
25 return tenantIds; 25 return tenantIds;
26 } 26 }
  27 +
27 } 28 }
yudao-framework/yudao-spring-boot-starter-file/src/main/java/cn/iocoder/yudao/framework/file/core/client/AbstractFileClient.java
@@ -30,7 +30,7 @@ public abstract class AbstractFileClient&lt;Config extends FileClientConfig&gt; implem @@ -30,7 +30,7 @@ public abstract class AbstractFileClient&lt;Config extends FileClientConfig&gt; implem
30 */ 30 */
31 public final void init() { 31 public final void init() {
32 doInit(); 32 doInit();
33 - log.info("[init][配置({}) 初始化完成]", config); 33 + log.debug("[init][配置({}) 初始化完成]", config);
34 } 34 }
35 35
36 /** 36 /**
yudao-framework/yudao-spring-boot-starter-flowable/src/main/java/cn/iocoder/yudao/framework/flowable/core/util/BpmnModelUtils.java 0 → 100644
  1 +package cn.iocoder.yudao.framework.flowable.core.util;
  2 +
  3 +import cn.hutool.core.collection.CollUtil;
  4 +import org.flowable.bpmn.converter.BpmnXMLConverter;
  5 +import org.flowable.bpmn.model.Process;
  6 +import org.flowable.bpmn.model.*;
  7 +
  8 +import java.util.*;
  9 +
  10 +/**
  11 + * 流程模型转操作工具类
  12 + */
  13 +public class BpmnModelUtils {
  14 +
  15 + /**
  16 + * 根据节点,获取入口连线
  17 + *
  18 + * @param source 起始节点
  19 + * @return 入口连线列表
  20 + */
  21 + public static List<SequenceFlow> getElementIncomingFlows(FlowElement source) {
  22 + if (source instanceof FlowNode) {
  23 + return ((FlowNode) source).getIncomingFlows();
  24 + }
  25 + return new ArrayList<>();
  26 + }
  27 +
  28 + /**
  29 + * 根据节点,获取出口连线
  30 + *
  31 + * @param source 起始节点
  32 + * @return 出口连线列表
  33 + */
  34 + public static List<SequenceFlow> getElementOutgoingFlows(FlowElement source) {
  35 + if (source instanceof FlowNode) {
  36 + return ((FlowNode) source).getOutgoingFlows();
  37 + }
  38 + return new ArrayList<>();
  39 + }
  40 +
  41 + /**
  42 + * 获取流程元素信息
  43 + *
  44 + * @param model bpmnModel 对象
  45 + * @param flowElementId 元素 ID
  46 + * @return 元素信息
  47 + */
  48 + public static FlowElement getFlowElementById(BpmnModel model, String flowElementId) {
  49 + Process process = model.getMainProcess();
  50 + return process.getFlowElement(flowElementId);
  51 + }
  52 +
  53 + /**
  54 + * 获得 BPMN 流程中,指定的元素们
  55 + *
  56 + * @param model
  57 + * @param clazz 指定元素。例如说,{@link UserTask}、{@link Gateway} 等等
  58 + * @return 元素们
  59 + */
  60 + public static <T extends FlowElement> List<T> getBpmnModelElements(BpmnModel model, Class<T> clazz) {
  61 + List<T> result = new ArrayList<>();
  62 + model.getProcesses().forEach(process -> {
  63 + process.getFlowElements().forEach(flowElement -> {
  64 + if (flowElement.getClass().isAssignableFrom(clazz)) {
  65 + result.add((T) flowElement);
  66 + }
  67 + });
  68 + });
  69 + return result;
  70 + }
  71 +
  72 + /**
  73 + * 比较 两个bpmnModel 是否相同
  74 + * @param oldModel 老的bpmn model
  75 + * @param newModel 新的bpmn model
  76 + */
  77 + public static boolean equals(BpmnModel oldModel, BpmnModel newModel) {
  78 + // 由于 BpmnModel 未提供 equals 方法,所以只能转成字节数组,进行比较
  79 + return Arrays.equals(getBpmnBytes(oldModel), getBpmnBytes(newModel));
  80 + }
  81 +
  82 + /**
  83 + * 把 bpmnModel 转换成 byte[]
  84 + * @param model bpmnModel
  85 + */
  86 + public static byte[] getBpmnBytes(BpmnModel model) {
  87 + if (model == null) {
  88 + return new byte[0];
  89 + }
  90 + BpmnXMLConverter converter = new BpmnXMLConverter();
  91 + return converter.convertToXML(model);
  92 + }
  93 +
  94 + // ========== 遍历相关的方法 ==========
  95 +
  96 + /**
  97 + * 找到 source 节点之前的所有用户任务节点
  98 + *
  99 + * @param source 起始节点
  100 + * @param hasSequenceFlow 已经经过的连线的 ID,用于判断线路是否重复
  101 + * @param userTaskList 已找到的用户任务节点
  102 + * @return 用户任务节点 数组
  103 + */
  104 + public static List<UserTask> getPreviousUserTaskList(FlowElement source, Set<String> hasSequenceFlow, List<UserTask> userTaskList) {
  105 + userTaskList = userTaskList == null ? new ArrayList<>() : userTaskList;
  106 + hasSequenceFlow = hasSequenceFlow == null ? new HashSet<>() : hasSequenceFlow;
  107 + // 如果该节点为开始节点,且存在上级子节点,则顺着上级子节点继续迭代
  108 + if (source instanceof StartEvent && source.getSubProcess() != null) {
  109 + userTaskList = getPreviousUserTaskList(source.getSubProcess(), hasSequenceFlow, userTaskList);
  110 + }
  111 +
  112 + // 根据类型,获取入口连线
  113 + List<SequenceFlow> sequenceFlows = getElementIncomingFlows(source);
  114 + if (sequenceFlows == null) {
  115 + return userTaskList;
  116 + }
  117 + // 循环找到目标元素
  118 + for (SequenceFlow sequenceFlow : sequenceFlows) {
  119 + // 如果发现连线重复,说明循环了,跳过这个循环
  120 + if (hasSequenceFlow.contains(sequenceFlow.getId())) {
  121 + continue;
  122 + }
  123 + // 添加已经走过的连线
  124 + hasSequenceFlow.add(sequenceFlow.getId());
  125 + // 类型为用户节点,则新增父级节点
  126 + if (sequenceFlow.getSourceFlowElement() instanceof UserTask) {
  127 + userTaskList.add((UserTask) sequenceFlow.getSourceFlowElement());
  128 + }
  129 + // 类型为子流程,则添加子流程开始节点出口处相连的节点
  130 + if (sequenceFlow.getSourceFlowElement() instanceof SubProcess) {
  131 + // 获取子流程用户任务节点
  132 + List<UserTask> childUserTaskList = findChildProcessUserTaskList((StartEvent) ((SubProcess) sequenceFlow.getSourceFlowElement()).getFlowElements().toArray()[0], null, null);
  133 + // 如果找到节点,则说明该线路找到节点,不继续向下找,反之继续
  134 + if (CollUtil.isNotEmpty(childUserTaskList)) {
  135 + userTaskList.addAll(childUserTaskList);
  136 + }
  137 + }
  138 + // 继续迭代
  139 + userTaskList = getPreviousUserTaskList(sequenceFlow.getSourceFlowElement(), hasSequenceFlow, userTaskList);
  140 + }
  141 + return userTaskList;
  142 + }
  143 +
  144 + /**
  145 + * 迭代获取子流程用户任务节点
  146 + *
  147 + * @param source 起始节点
  148 + * @param hasSequenceFlow 已经经过的连线的 ID,用于判断线路是否重复
  149 + * @param userTaskList 需要撤回的用户任务列表
  150 + * @return 用户任务节点
  151 + */
  152 + public static List<UserTask> findChildProcessUserTaskList(FlowElement source, Set<String> hasSequenceFlow, List<UserTask> userTaskList) {
  153 + hasSequenceFlow = hasSequenceFlow == null ? new HashSet<>() : hasSequenceFlow;
  154 + userTaskList = userTaskList == null ? new ArrayList<>() : userTaskList;
  155 +
  156 + // 根据类型,获取出口连线
  157 + List<SequenceFlow> sequenceFlows = getElementOutgoingFlows(source);
  158 + if (sequenceFlows == null) {
  159 + return userTaskList;
  160 + }
  161 + // 循环找到目标元素
  162 + for (SequenceFlow sequenceFlow : sequenceFlows) {
  163 + // 如果发现连线重复,说明循环了,跳过这个循环
  164 + if (hasSequenceFlow.contains(sequenceFlow.getId())) {
  165 + continue;
  166 + }
  167 + // 添加已经走过的连线
  168 + hasSequenceFlow.add(sequenceFlow.getId());
  169 + // 如果为用户任务类型,且任务节点的 Key 正在运行的任务中存在,添加
  170 + if (sequenceFlow.getTargetFlowElement() instanceof UserTask) {
  171 + userTaskList.add((UserTask) sequenceFlow.getTargetFlowElement());
  172 + continue;
  173 + }
  174 + // 如果节点为子流程节点情况,则从节点中的第一个节点开始获取
  175 + if (sequenceFlow.getTargetFlowElement() instanceof SubProcess) {
  176 + List<UserTask> childUserTaskList = findChildProcessUserTaskList((FlowElement) (((SubProcess) sequenceFlow.getTargetFlowElement()).getFlowElements().toArray()[0]), hasSequenceFlow, null);
  177 + // 如果找到节点,则说明该线路找到节点,不继续向下找,反之继续
  178 + if (CollUtil.isNotEmpty(childUserTaskList)) {
  179 + userTaskList.addAll(childUserTaskList);
  180 + continue;
  181 + }
  182 + }
  183 + // 继续迭代
  184 + userTaskList = findChildProcessUserTaskList(sequenceFlow.getTargetFlowElement(), hasSequenceFlow, userTaskList);
  185 + }
  186 + return userTaskList;
  187 + }
  188 +
  189 +
  190 + /**
  191 + * 迭代从后向前扫描,判断目标节点相对于当前节点是否是串行
  192 + * 不存在直接回退到子流程中的情况,但存在从子流程出去到父流程情况
  193 + *
  194 + * @param source 起始节点
  195 + * @param target 目标节点
  196 + * @param visitedElements 已经经过的连线的 ID,用于判断线路是否重复
  197 + * @return 结果
  198 + */
  199 + public static boolean isSequentialReachable(FlowElement source, FlowElement target, Set<String> visitedElements) {
  200 + visitedElements = visitedElements == null ? new HashSet<>() : visitedElements;
  201 + // 不能是开始事件和子流程
  202 + if (source instanceof StartEvent && isInEventSubprocess(source)) {
  203 + return false;
  204 + }
  205 +
  206 + // 根据类型,获取入口连线
  207 + List<SequenceFlow> sequenceFlows = getElementIncomingFlows(source);
  208 + if (CollUtil.isEmpty(sequenceFlows)) {
  209 + return true;
  210 + }
  211 + // 循环找到目标元素
  212 + for (SequenceFlow sequenceFlow : sequenceFlows) {
  213 + // 如果发现连线重复,说明循环了,跳过这个循环
  214 + if (visitedElements.contains(sequenceFlow.getId())) {
  215 + continue;
  216 + }
  217 + // 添加已经走过的连线
  218 + visitedElements.add(sequenceFlow.getId());
  219 + // 这条线路存在目标节点,这条线路完成,进入下个线路
  220 + FlowElement sourceFlowElement = sequenceFlow.getSourceFlowElement();
  221 + if (target.getId().equals(sourceFlowElement.getId())) {
  222 + continue;
  223 + }
  224 + // 如果目标节点为并行网关,则不继续
  225 + if (sourceFlowElement instanceof ParallelGateway) {
  226 + return false;
  227 + }
  228 + // 否则就继续迭代
  229 + if (!isSequentialReachable(sourceFlowElement, target, visitedElements)) {
  230 + return false;
  231 + }
  232 + }
  233 + return true;
  234 + }
  235 +
  236 + /**
  237 + * 判断当前节点是否属于不同的子流程
  238 + *
  239 + * @param flowElement 被判断的节点
  240 + * @return true 表示属于子流程
  241 + */
  242 + private static boolean isInEventSubprocess(FlowElement flowElement) {
  243 + FlowElementsContainer flowElementsContainer = flowElement.getParentContainer();
  244 + while (flowElementsContainer != null) {
  245 + if (flowElementsContainer instanceof EventSubProcess) {
  246 + return true;
  247 + }
  248 +
  249 + if (flowElementsContainer instanceof FlowElement) {
  250 + flowElementsContainer = ((FlowElement) flowElementsContainer).getParentContainer();
  251 + } else {
  252 + flowElementsContainer = null;
  253 + }
  254 + }
  255 + return false;
  256 + }
  257 +
  258 + /**
  259 + * 根据正在运行的任务节点,迭代获取子级任务节点列表,向后找
  260 + *
  261 + * @param source 起始节点
  262 + * @param runTaskKeyList 正在运行的任务 Key,用于校验任务节点是否是正在运行的节点
  263 + * @param hasSequenceFlow 已经经过的连线的 ID,用于判断线路是否重复
  264 + * @param userTaskList 需要撤回的用户任务列表
  265 + * @return 子级任务节点列表
  266 + */
  267 + public static List<UserTask> iteratorFindChildUserTasks(FlowElement source, List<String> runTaskKeyList,
  268 + Set<String> hasSequenceFlow, List<UserTask> userTaskList) {
  269 + hasSequenceFlow = hasSequenceFlow == null ? new HashSet<>() : hasSequenceFlow;
  270 + userTaskList = userTaskList == null ? new ArrayList<>() : userTaskList;
  271 + // 如果该节点为开始节点,且存在上级子节点,则顺着上级子节点继续迭代
  272 + if (source instanceof StartEvent && source.getSubProcess() != null) {
  273 + userTaskList = iteratorFindChildUserTasks(source.getSubProcess(), runTaskKeyList, hasSequenceFlow, userTaskList);
  274 + }
  275 +
  276 + // 根据类型,获取出口连线
  277 + List<SequenceFlow> sequenceFlows = getElementOutgoingFlows(source);
  278 + if (sequenceFlows == null) {
  279 + return userTaskList;
  280 + }
  281 + // 循环找到目标元素
  282 + for (SequenceFlow sequenceFlow : sequenceFlows) {
  283 + // 如果发现连线重复,说明循环了,跳过这个循环
  284 + if (hasSequenceFlow.contains(sequenceFlow.getId())) {
  285 + continue;
  286 + }
  287 + // 添加已经走过的连线
  288 + hasSequenceFlow.add(sequenceFlow.getId());
  289 + // 如果为用户任务类型,且任务节点的 Key 正在运行的任务中存在,添加
  290 + if (sequenceFlow.getTargetFlowElement() instanceof UserTask && runTaskKeyList.contains((sequenceFlow.getTargetFlowElement()).getId())) {
  291 + userTaskList.add((UserTask) sequenceFlow.getTargetFlowElement());
  292 + continue;
  293 + }
  294 + // 如果节点为子流程节点情况,则从节点中的第一个节点开始获取
  295 + if (sequenceFlow.getTargetFlowElement() instanceof SubProcess) {
  296 + List<UserTask> childUserTaskList = iteratorFindChildUserTasks((FlowElement) (((SubProcess) sequenceFlow.getTargetFlowElement()).getFlowElements().toArray()[0]), runTaskKeyList, hasSequenceFlow, null);
  297 + // 如果找到节点,则说明该线路找到节点,不继续向下找,反之继续
  298 + if (CollUtil.isNotEmpty(childUserTaskList)) {
  299 + userTaskList.addAll(childUserTaskList);
  300 + continue;
  301 + }
  302 + }
  303 + // 继续迭代
  304 + userTaskList = iteratorFindChildUserTasks(sequenceFlow.getTargetFlowElement(), runTaskKeyList, hasSequenceFlow, userTaskList);
  305 + }
  306 + return userTaskList;
  307 + }
  308 +
  309 +}
yudao-framework/yudao-spring-boot-starter-flowable/src/main/java/cn/iocoder/yudao/framework/flowable/core/util/FlowableUtils.java
1 package cn.iocoder.yudao.framework.flowable.core.util; 1 package cn.iocoder.yudao.framework.flowable.core.util;
2 2
3 -import org.flowable.bpmn.converter.BpmnXMLConverter;  
4 -import org.flowable.bpmn.model.BpmnModel;  
5 -import org.flowable.bpmn.model.FlowElement;  
6 import org.flowable.common.engine.impl.identity.Authentication; 3 import org.flowable.common.engine.impl.identity.Authentication;
7 4
8 -import java.util.ArrayList;  
9 -import java.util.Arrays;  
10 -import java.util.List;  
11 -  
12 /** 5 /**
13 * Flowable 相关的工具方法 6 * Flowable 相关的工具方法
14 * 7 *
@@ -26,49 +19,6 @@ public class FlowableUtils { @@ -26,49 +19,6 @@ public class FlowableUtils {
26 Authentication.setAuthenticatedUserId(null); 19 Authentication.setAuthenticatedUserId(null);
27 } 20 }
28 21
29 - // ========== BPMN 相关的工具方法 ==========  
30 -  
31 - /**  
32 - * 获得 BPMN 流程中,指定的元素们  
33 - *  
34 - * @param model  
35 - * @param clazz 指定元素。例如说,{@link org.flowable.bpmn.model.UserTask}、{@link org.flowable.bpmn.model.Gateway} 等等  
36 - * @return 元素们  
37 - */  
38 - public static <T extends FlowElement> List<T> getBpmnModelElements(BpmnModel model, Class<T> clazz) {  
39 - List<T> result = new ArrayList<>();  
40 - model.getProcesses().forEach(process -> {  
41 - process.getFlowElements().forEach(flowElement -> {  
42 - if (flowElement.getClass().isAssignableFrom(clazz)) {  
43 - result.add((T) flowElement);  
44 - }  
45 - });  
46 - });  
47 - return result;  
48 - }  
49 -  
50 - /**  
51 - * 比较 两个bpmnModel 是否相同  
52 - * @param oldModel 老的bpmn model  
53 - * @param newModel 新的bpmn model  
54 - */  
55 - public static boolean equals(BpmnModel oldModel, BpmnModel newModel) {  
56 - // 由于 BpmnModel 未提供 equals 方法,所以只能转成字节数组,进行比较  
57 - return Arrays.equals(getBpmnBytes(oldModel), getBpmnBytes(newModel));  
58 - }  
59 -  
60 - /**  
61 - * 把 bpmnModel 转换成 byte[]  
62 - * @param model bpmnModel  
63 - */  
64 - public static byte[] getBpmnBytes(BpmnModel model) {  
65 - if (model == null) {  
66 - return new byte[0];  
67 - }  
68 - BpmnXMLConverter converter = new BpmnXMLConverter();  
69 - return converter.convertToXML(model);  
70 - }  
71 -  
72 // ========== Execution 相关的工具方法 ========== 22 // ========== Execution 相关的工具方法 ==========
73 23
74 public static String formatCollectionVariable(String activityId) { 24 public static String formatCollectionVariable(String activityId) {
yudao-framework/yudao-spring-boot-starter-job/src/main/java/cn/iocoder/yudao/framework/quartz/config/YudaoQuartzAutoConfiguration.java
1 package cn.iocoder.yudao.framework.quartz.config; 1 package cn.iocoder.yudao.framework.quartz.config;
2 2
3 import cn.iocoder.yudao.framework.quartz.core.scheduler.SchedulerManager; 3 import cn.iocoder.yudao.framework.quartz.core.scheduler.SchedulerManager;
  4 +import lombok.extern.slf4j.Slf4j;
4 import org.quartz.Scheduler; 5 import org.quartz.Scheduler;
5 import org.springframework.boot.autoconfigure.AutoConfiguration; 6 import org.springframework.boot.autoconfigure.AutoConfiguration;
6 import org.springframework.context.annotation.Bean; 7 import org.springframework.context.annotation.Bean;
7 import org.springframework.scheduling.annotation.EnableScheduling; 8 import org.springframework.scheduling.annotation.EnableScheduling;
8 9
  10 +import java.util.Optional;
  11 +
9 /** 12 /**
10 * 定时任务 Configuration 13 * 定时任务 Configuration
11 */ 14 */
12 @AutoConfiguration 15 @AutoConfiguration
13 @EnableScheduling // 开启 Spring 自带的定时任务 16 @EnableScheduling // 开启 Spring 自带的定时任务
  17 +@Slf4j
14 public class YudaoQuartzAutoConfiguration { 18 public class YudaoQuartzAutoConfiguration {
15 19
16 @Bean 20 @Bean
17 - public SchedulerManager schedulerManager(Scheduler scheduler) {  
18 - return new SchedulerManager(scheduler); 21 + public SchedulerManager schedulerManager(Optional<Scheduler> scheduler) {
  22 + if (!scheduler.isPresent()) {
  23 + log.info("[定时任务 - 已禁用][参考 https://doc.iocoder.cn/job/ 开启]");
  24 + return new SchedulerManager(null);
  25 + }
  26 + return new SchedulerManager(scheduler.get());
19 } 27 }
20 28
21 } 29 }
yudao-framework/yudao-spring-boot-starter-job/src/main/java/cn/iocoder/yudao/framework/quartz/core/scheduler/SchedulerManager.java
@@ -4,6 +4,9 @@ import cn.iocoder.yudao.framework.quartz.core.enums.JobDataKeyEnum; @@ -4,6 +4,9 @@ import cn.iocoder.yudao.framework.quartz.core.enums.JobDataKeyEnum;
4 import cn.iocoder.yudao.framework.quartz.core.handler.JobHandlerInvoker; 4 import cn.iocoder.yudao.framework.quartz.core.handler.JobHandlerInvoker;
5 import org.quartz.*; 5 import org.quartz.*;
6 6
  7 +import static cn.iocoder.yudao.framework.common.exception.enums.GlobalErrorCodeConstants.NOT_IMPLEMENTED;
  8 +import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception0;
  9 +
7 /** 10 /**
8 * {@link org.quartz.Scheduler} 的管理器,负责创建任务 11 * {@link org.quartz.Scheduler} 的管理器,负责创建任务
9 * 12 *
@@ -37,6 +40,7 @@ public class SchedulerManager { @@ -37,6 +40,7 @@ public class SchedulerManager {
37 public void addJob(Long jobId, String jobHandlerName, String jobHandlerParam, String cronExpression, 40 public void addJob(Long jobId, String jobHandlerName, String jobHandlerParam, String cronExpression,
38 Integer retryCount, Integer retryInterval) 41 Integer retryCount, Integer retryInterval)
39 throws SchedulerException { 42 throws SchedulerException {
  43 + validateScheduler();
40 // 创建 JobDetail 对象 44 // 创建 JobDetail 对象
41 JobDetail jobDetail = JobBuilder.newJob(JobHandlerInvoker.class) 45 JobDetail jobDetail = JobBuilder.newJob(JobHandlerInvoker.class)
42 .usingJobData(JobDataKeyEnum.JOB_ID.name(), jobId) 46 .usingJobData(JobDataKeyEnum.JOB_ID.name(), jobId)
@@ -61,6 +65,7 @@ public class SchedulerManager { @@ -61,6 +65,7 @@ public class SchedulerManager {
61 public void updateJob(String jobHandlerName, String jobHandlerParam, String cronExpression, 65 public void updateJob(String jobHandlerName, String jobHandlerParam, String cronExpression,
62 Integer retryCount, Integer retryInterval) 66 Integer retryCount, Integer retryInterval)
63 throws SchedulerException { 67 throws SchedulerException {
  68 + validateScheduler();
64 // 创建新 Trigger 对象 69 // 创建新 Trigger 对象
65 Trigger newTrigger = this.buildTrigger(jobHandlerName, jobHandlerParam, cronExpression, retryCount, retryInterval); 70 Trigger newTrigger = this.buildTrigger(jobHandlerName, jobHandlerParam, cronExpression, retryCount, retryInterval);
66 // 修改调度 71 // 修改调度
@@ -74,6 +79,7 @@ public class SchedulerManager { @@ -74,6 +79,7 @@ public class SchedulerManager {
74 * @throws SchedulerException 删除异常 79 * @throws SchedulerException 删除异常
75 */ 80 */
76 public void deleteJob(String jobHandlerName) throws SchedulerException { 81 public void deleteJob(String jobHandlerName) throws SchedulerException {
  82 + validateScheduler();
77 scheduler.deleteJob(new JobKey(jobHandlerName)); 83 scheduler.deleteJob(new JobKey(jobHandlerName));
78 } 84 }
79 85
@@ -84,6 +90,7 @@ public class SchedulerManager { @@ -84,6 +90,7 @@ public class SchedulerManager {
84 * @throws SchedulerException 暂停异常 90 * @throws SchedulerException 暂停异常
85 */ 91 */
86 public void pauseJob(String jobHandlerName) throws SchedulerException { 92 public void pauseJob(String jobHandlerName) throws SchedulerException {
  93 + validateScheduler();
87 scheduler.pauseJob(new JobKey(jobHandlerName)); 94 scheduler.pauseJob(new JobKey(jobHandlerName));
88 } 95 }
89 96
@@ -94,6 +101,7 @@ public class SchedulerManager { @@ -94,6 +101,7 @@ public class SchedulerManager {
94 * @throws SchedulerException 启动异常 101 * @throws SchedulerException 启动异常
95 */ 102 */
96 public void resumeJob(String jobHandlerName) throws SchedulerException { 103 public void resumeJob(String jobHandlerName) throws SchedulerException {
  104 + validateScheduler();
97 scheduler.resumeJob(new JobKey(jobHandlerName)); 105 scheduler.resumeJob(new JobKey(jobHandlerName));
98 scheduler.resumeTrigger(new TriggerKey(jobHandlerName)); 106 scheduler.resumeTrigger(new TriggerKey(jobHandlerName));
99 } 107 }
@@ -108,11 +116,12 @@ public class SchedulerManager { @@ -108,11 +116,12 @@ public class SchedulerManager {
108 */ 116 */
109 public void triggerJob(Long jobId, String jobHandlerName, String jobHandlerParam) 117 public void triggerJob(Long jobId, String jobHandlerName, String jobHandlerParam)
110 throws SchedulerException { 118 throws SchedulerException {
  119 + validateScheduler();
  120 + // 触发任务
111 JobDataMap data = new JobDataMap(); // 无需重试,所以不设置 retryCount 和 retryInterval 121 JobDataMap data = new JobDataMap(); // 无需重试,所以不设置 retryCount 和 retryInterval
112 data.put(JobDataKeyEnum.JOB_ID.name(), jobId); 122 data.put(JobDataKeyEnum.JOB_ID.name(), jobId);
113 data.put(JobDataKeyEnum.JOB_HANDLER_NAME.name(), jobHandlerName); 123 data.put(JobDataKeyEnum.JOB_HANDLER_NAME.name(), jobHandlerName);
114 data.put(JobDataKeyEnum.JOB_HANDLER_PARAM.name(), jobHandlerParam); 124 data.put(JobDataKeyEnum.JOB_HANDLER_PARAM.name(), jobHandlerParam);
115 - // 触发任务  
116 scheduler.triggerJob(new JobKey(jobHandlerName), data); 125 scheduler.triggerJob(new JobKey(jobHandlerName), data);
117 } 126 }
118 127
@@ -127,4 +136,11 @@ public class SchedulerManager { @@ -127,4 +136,11 @@ public class SchedulerManager {
127 .build(); 136 .build();
128 } 137 }
129 138
  139 + private void validateScheduler() {
  140 + if (scheduler == null) {
  141 + throw exception0(NOT_IMPLEMENTED.getCode(),
  142 + "[定时任务 - 已禁用][参考 https://doc.iocoder.cn/job/ 开启]");
  143 + }
  144 + }
  145 +
130 } 146 }
yudao-framework/yudao-spring-boot-starter-mybatis/src/main/java/cn/iocoder/yudao/framework/mybatis/core/mapper/BaseMapperX.java
@@ -7,7 +7,6 @@ import cn.iocoder.yudao.framework.mybatis.core.util.MyBatisUtils; @@ -7,7 +7,6 @@ import cn.iocoder.yudao.framework.mybatis.core.util.MyBatisUtils;
7 import com.baomidou.mybatisplus.core.conditions.Wrapper; 7 import com.baomidou.mybatisplus.core.conditions.Wrapper;
8 import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; 8 import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
9 import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; 9 import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
10 -import com.baomidou.mybatisplus.core.mapper.BaseMapper;  
11 import com.baomidou.mybatisplus.core.metadata.IPage; 10 import com.baomidou.mybatisplus.core.metadata.IPage;
12 import com.baomidou.mybatisplus.core.toolkit.support.SFunction; 11 import com.baomidou.mybatisplus.core.toolkit.support.SFunction;
13 import com.baomidou.mybatisplus.extension.toolkit.Db; 12 import com.baomidou.mybatisplus.extension.toolkit.Db;
yudao-framework/yudao-spring-boot-starter-protection/pom.xml
@@ -26,11 +26,13 @@ @@ -26,11 +26,13 @@
26 <dependency> 26 <dependency>
27 <groupId>com.baomidou</groupId> 27 <groupId>com.baomidou</groupId>
28 <artifactId>lock4j-redisson-spring-boot-starter</artifactId> 28 <artifactId>lock4j-redisson-spring-boot-starter</artifactId>
  29 + <optional>true</optional>
29 </dependency> 30 </dependency>
30 31
31 <dependency> 32 <dependency>
32 <groupId>io.github.resilience4j</groupId> 33 <groupId>io.github.resilience4j</groupId>
33 <artifactId>resilience4j-spring-boot2</artifactId> 34 <artifactId>resilience4j-spring-boot2</artifactId>
  35 + <optional>true</optional>
34 </dependency> 36 </dependency>
35 </dependencies> 37 </dependencies>
36 38
yudao-framework/yudao-spring-boot-starter-protection/src/main/java/cn/iocoder/yudao/framework/lock4j/config/YudaoLock4jConfiguration.java
@@ -3,9 +3,11 @@ package cn.iocoder.yudao.framework.lock4j.config; @@ -3,9 +3,11 @@ package cn.iocoder.yudao.framework.lock4j.config;
3 import cn.iocoder.yudao.framework.lock4j.core.DefaultLockFailureStrategy; 3 import cn.iocoder.yudao.framework.lock4j.core.DefaultLockFailureStrategy;
4 import com.baomidou.lock.spring.boot.autoconfigure.LockAutoConfiguration; 4 import com.baomidou.lock.spring.boot.autoconfigure.LockAutoConfiguration;
5 import org.springframework.boot.autoconfigure.AutoConfiguration; 5 import org.springframework.boot.autoconfigure.AutoConfiguration;
  6 +import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
6 import org.springframework.context.annotation.Bean; 7 import org.springframework.context.annotation.Bean;
7 8
8 @AutoConfiguration(before = LockAutoConfiguration.class) 9 @AutoConfiguration(before = LockAutoConfiguration.class)
  10 +@ConditionalOnClass(name = "com.baomidou.lock.annotation.Lock4j")
9 public class YudaoLock4jConfiguration { 11 public class YudaoLock4jConfiguration {
10 12
11 @Bean 13 @Bean
yudao-framework/yudao-spring-boot-starter-redis/pom.xml
@@ -33,12 +33,6 @@ @@ -33,12 +33,6 @@
33 </dependency> 33 </dependency>
34 34
35 <dependency> 35 <dependency>
36 - <groupId>io.netty</groupId>  
37 - <artifactId>netty-all</artifactId>  
38 - </dependency>  
39 -  
40 -  
41 - <dependency>  
42 <groupId>com.fasterxml.jackson.datatype</groupId> 36 <groupId>com.fasterxml.jackson.datatype</groupId>
43 <artifactId>jackson-datatype-jsr310</artifactId> 37 <artifactId>jackson-datatype-jsr310</artifactId>
44 </dependency> 38 </dependency>
yudao-framework/yudao-spring-boot-starter-redis/src/main/java/cn/iocoder/yudao/framework/redis/core/TimeoutRedisCacheManager.java
@@ -45,7 +45,7 @@ public class TimeoutRedisCacheManager extends RedisCacheManager { @@ -45,7 +45,7 @@ public class TimeoutRedisCacheManager extends RedisCacheManager {
45 Duration duration = parseDuration(names[1]); 45 Duration duration = parseDuration(names[1]);
46 cacheConfig = cacheConfig.entryTtl(duration); 46 cacheConfig = cacheConfig.entryTtl(duration);
47 } 47 }
48 - return super.createRedisCache(names[0], cacheConfig); 48 + return super.createRedisCache(name, cacheConfig);
49 } 49 }
50 50
51 /** 51 /**
yudao-framework/yudao-spring-boot-starter-web/pom.xml
@@ -55,13 +55,6 @@ @@ -55,13 +55,6 @@
55 <version>${revision}</version> 55 <version>${revision}</version>
56 </dependency> 56 </dependency>
57 57
58 - <!-- 服务保障相关 -->  
59 - <dependency>  
60 - <groupId>io.github.resilience4j</groupId>  
61 - <artifactId>resilience4j-ratelimiter</artifactId>  
62 - <scope>provided</scope> <!-- 设置为 provided,主要是 GlobalExceptionHandler 使用 -->  
63 - </dependency>  
64 -  
65 <!-- xss --> 58 <!-- xss -->
66 <dependency> 59 <dependency>
67 <groupId>org.jsoup</groupId> 60 <groupId>org.jsoup</groupId>
yudao-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/jackson/config/YudaoJacksonAutoConfiguration.java
1 package cn.iocoder.yudao.framework.jackson.config; 1 package cn.iocoder.yudao.framework.jackson.config;
2 2
  3 +import cn.hutool.core.collection.CollUtil;
3 import cn.iocoder.yudao.framework.common.util.json.JsonUtils; 4 import cn.iocoder.yudao.framework.common.util.json.JsonUtils;
4 import cn.iocoder.yudao.framework.jackson.core.databind.LocalDateTimeDeserializer; 5 import cn.iocoder.yudao.framework.jackson.core.databind.LocalDateTimeDeserializer;
5 import cn.iocoder.yudao.framework.jackson.core.databind.LocalDateTimeSerializer; 6 import cn.iocoder.yudao.framework.jackson.core.databind.LocalDateTimeSerializer;
@@ -11,51 +12,41 @@ import com.fasterxml.jackson.datatype.jsr310.deser.LocalTimeDeserializer; @@ -11,51 +12,41 @@ import com.fasterxml.jackson.datatype.jsr310.deser.LocalTimeDeserializer;
11 import com.fasterxml.jackson.datatype.jsr310.ser.LocalDateSerializer; 12 import com.fasterxml.jackson.datatype.jsr310.ser.LocalDateSerializer;
12 import com.fasterxml.jackson.datatype.jsr310.ser.LocalTimeSerializer; 13 import com.fasterxml.jackson.datatype.jsr310.ser.LocalTimeSerializer;
13 import lombok.extern.slf4j.Slf4j; 14 import lombok.extern.slf4j.Slf4j;
14 -import org.springframework.beans.BeansException;  
15 -import org.springframework.beans.factory.config.BeanPostProcessor;  
16 import org.springframework.boot.autoconfigure.AutoConfiguration; 15 import org.springframework.boot.autoconfigure.AutoConfiguration;
17 import org.springframework.context.annotation.Bean; 16 import org.springframework.context.annotation.Bean;
18 17
19 import java.time.LocalDate; 18 import java.time.LocalDate;
20 import java.time.LocalDateTime; 19 import java.time.LocalDateTime;
21 import java.time.LocalTime; 20 import java.time.LocalTime;
  21 +import java.util.List;
22 22
23 @AutoConfiguration 23 @AutoConfiguration
24 @Slf4j 24 @Slf4j
25 public class YudaoJacksonAutoConfiguration { 25 public class YudaoJacksonAutoConfiguration {
26 26
27 @Bean 27 @Bean
28 - public BeanPostProcessor objectMapperBeanPostProcessor() {  
29 - return new BeanPostProcessor() {  
30 -  
31 - @Override  
32 - public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {  
33 - if (!(bean instanceof ObjectMapper)) {  
34 - return bean;  
35 - }  
36 - ObjectMapper objectMapper = (ObjectMapper) bean;  
37 - SimpleModule simpleModule = new SimpleModule();  
38 - /*  
39 - * 1. 新增Long类型序列化规则,数值超过2^53-1,在JS会出现精度丢失问题,因此Long自动序列化为字符串类型  
40 - * 2. 新增LocalDateTime序列化、反序列化规则  
41 - */  
42 - simpleModule  
43 - .addSerializer(Long.class, NumberSerializer.INSTANCE)  
44 - .addSerializer(Long.TYPE, NumberSerializer.INSTANCE)  
45 - .addSerializer(LocalDate.class, LocalDateSerializer.INSTANCE)  
46 - .addDeserializer(LocalDate.class, LocalDateDeserializer.INSTANCE)  
47 - .addSerializer(LocalTime.class, LocalTimeSerializer.INSTANCE)  
48 - .addDeserializer(LocalTime.class, LocalTimeDeserializer.INSTANCE)  
49 - .addSerializer(LocalDateTime.class, LocalDateTimeSerializer.INSTANCE)  
50 - .addDeserializer(LocalDateTime.class, LocalDateTimeDeserializer.INSTANCE);  
51 -  
52 - objectMapper.registerModules(simpleModule);  
53 -  
54 - JsonUtils.init(objectMapper);  
55 - log.info("初始化 jackson 自动配置");  
56 - return bean;  
57 - }  
58 - }; 28 + @SuppressWarnings("InstantiationOfUtilityClass")
  29 + public JsonUtils jsonUtils(List<ObjectMapper> objectMappers) {
  30 + // 1.1 创建 SimpleModule 对象
  31 + SimpleModule simpleModule = new SimpleModule();
  32 + simpleModule
  33 + // 新增 Long 类型序列化规则,数值超过 2^53-1,在 JS 会出现精度丢失问题,因此 Long 自动序列化为字符串类型
  34 + .addSerializer(Long.class, NumberSerializer.INSTANCE)
  35 + .addSerializer(Long.TYPE, NumberSerializer.INSTANCE)
  36 + .addSerializer(LocalDate.class, LocalDateSerializer.INSTANCE)
  37 + .addDeserializer(LocalDate.class, LocalDateDeserializer.INSTANCE)
  38 + .addSerializer(LocalTime.class, LocalTimeSerializer.INSTANCE)
  39 + .addDeserializer(LocalTime.class, LocalTimeDeserializer.INSTANCE)
  40 + // 新增 LocalDateTime 序列化、反序列化规则
  41 + .addSerializer(LocalDateTime.class, LocalDateTimeSerializer.INSTANCE)
  42 + .addDeserializer(LocalDateTime.class, LocalDateTimeDeserializer.INSTANCE);
  43 + // 1.2 注册到 objectMapper
  44 + objectMappers.forEach(objectMapper -> objectMapper.registerModule(simpleModule));
  45 +
  46 + // 2. 设置 objectMapper 到 JsonUtils {
  47 + JsonUtils.init(CollUtil.getFirst(objectMappers));
  48 + log.info("[init][初始化 JsonUtils 成功]");
  49 + return new JsonUtils();
59 } 50 }
60 51
61 } 52 }
yudao-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/web/core/handler/GlobalExceptionHandler.java
@@ -11,7 +11,6 @@ import cn.iocoder.yudao.framework.common.util.json.JsonUtils; @@ -11,7 +11,6 @@ import cn.iocoder.yudao.framework.common.util.json.JsonUtils;
11 import cn.iocoder.yudao.framework.common.util.monitor.TracerUtils; 11 import cn.iocoder.yudao.framework.common.util.monitor.TracerUtils;
12 import cn.iocoder.yudao.framework.common.util.servlet.ServletUtils; 12 import cn.iocoder.yudao.framework.common.util.servlet.ServletUtils;
13 import cn.iocoder.yudao.framework.web.core.util.WebFrameworkUtils; 13 import cn.iocoder.yudao.framework.web.core.util.WebFrameworkUtils;
14 -import io.github.resilience4j.ratelimiter.RequestNotPermitted;  
15 import lombok.AllArgsConstructor; 14 import lombok.AllArgsConstructor;
16 import lombok.extern.slf4j.Slf4j; 15 import lombok.extern.slf4j.Slf4j;
17 import org.apache.commons.lang3.exception.ExceptionUtils; 16 import org.apache.commons.lang3.exception.ExceptionUtils;
@@ -33,6 +32,7 @@ import javax.validation.ConstraintViolationException; @@ -33,6 +32,7 @@ import javax.validation.ConstraintViolationException;
33 import javax.validation.ValidationException; 32 import javax.validation.ValidationException;
34 import java.time.LocalDateTime; 33 import java.time.LocalDateTime;
35 import java.util.Map; 34 import java.util.Map;
  35 +import java.util.Objects;
36 36
37 import static cn.iocoder.yudao.framework.common.exception.enums.GlobalErrorCodeConstants.*; 37 import static cn.iocoder.yudao.framework.common.exception.enums.GlobalErrorCodeConstants.*;
38 38
@@ -83,9 +83,6 @@ public class GlobalExceptionHandler { @@ -83,9 +83,6 @@ public class GlobalExceptionHandler {
83 if (ex instanceof HttpRequestMethodNotSupportedException) { 83 if (ex instanceof HttpRequestMethodNotSupportedException) {
84 return httpRequestMethodNotSupportedExceptionHandler((HttpRequestMethodNotSupportedException) ex); 84 return httpRequestMethodNotSupportedExceptionHandler((HttpRequestMethodNotSupportedException) ex);
85 } 85 }
86 - if (ex instanceof RequestNotPermitted) {  
87 - return requestNotPermittedExceptionHandler(request, (RequestNotPermitted) ex);  
88 - }  
89 if (ex instanceof ServiceException) { 86 if (ex instanceof ServiceException) {
90 return serviceExceptionHandler((ServiceException) ex); 87 return serviceExceptionHandler((ServiceException) ex);
91 } 88 }
@@ -186,8 +183,7 @@ public class GlobalExceptionHandler { @@ -186,8 +183,7 @@ public class GlobalExceptionHandler {
186 /** 183 /**
187 * 处理 Resilience4j 限流抛出的异常 184 * 处理 Resilience4j 限流抛出的异常
188 */ 185 */
189 - @ExceptionHandler(value = RequestNotPermitted.class)  
190 - public CommonResult<?> requestNotPermittedExceptionHandler(HttpServletRequest req, RequestNotPermitted ex) { 186 + public CommonResult<?> requestNotPermittedExceptionHandler(HttpServletRequest req, Throwable ex) {
191 log.warn("[requestNotPermittedExceptionHandler][url({}) 访问过于频繁]", req.getRequestURL(), ex); 187 log.warn("[requestNotPermittedExceptionHandler][url({}) 访问过于频繁]", req.getRequestURL(), ex);
192 return CommonResult.error(TOO_MANY_REQUESTS); 188 return CommonResult.error(TOO_MANY_REQUESTS);
193 } 189 }
@@ -226,7 +222,12 @@ public class GlobalExceptionHandler { @@ -226,7 +222,12 @@ public class GlobalExceptionHandler {
226 return tableNotExistsResult; 222 return tableNotExistsResult;
227 } 223 }
228 224
229 - // 情况二:处理异常 225 + // 情况二:部分特殊的库的处理
  226 + if (Objects.equals("io.github.resilience4j.ratelimiter.RequestNotPermitted", ex.getClass().getName())) {
  227 + return requestNotPermittedExceptionHandler(req, ex);
  228 + }
  229 +
  230 + // 情况三:处理异常
230 log.error("[defaultExceptionHandler]", ex); 231 log.error("[defaultExceptionHandler]", ex);
231 // 插入异常日志 232 // 插入异常日志
232 this.createExceptionLog(req, ex); 233 this.createExceptionLog(req, ex);
yudao-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/xss/config/YudaoXssAutoConfiguration.java
@@ -21,6 +21,7 @@ import static cn.iocoder.yudao.framework.web.config.YudaoWebAutoConfiguration.cr @@ -21,6 +21,7 @@ import static cn.iocoder.yudao.framework.web.config.YudaoWebAutoConfiguration.cr
21 21
22 @AutoConfiguration 22 @AutoConfiguration
23 @EnableConfigurationProperties(XssProperties.class) 23 @EnableConfigurationProperties(XssProperties.class)
  24 +@ConditionalOnProperty(prefix = "yudao.xss", name = "enable", havingValue = "true", matchIfMissing = true) // 设置为 false 时,禁用
24 public class YudaoXssAutoConfiguration implements WebMvcConfigurer { 25 public class YudaoXssAutoConfiguration implements WebMvcConfigurer {
25 26
26 /** 27 /**
yudao-framework/yudao-spring-boot-starter-web/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports
1 cn.iocoder.yudao.framework.apilog.config.YudaoApiLogAutoConfiguration 1 cn.iocoder.yudao.framework.apilog.config.YudaoApiLogAutoConfiguration
2 cn.iocoder.yudao.framework.jackson.config.YudaoJacksonAutoConfiguration 2 cn.iocoder.yudao.framework.jackson.config.YudaoJacksonAutoConfiguration
3 -com.github.xiaoymin.knife4j.spring.configuration.Knife4jAutoConfiguration  
4 cn.iocoder.yudao.framework.swagger.config.YudaoSwaggerAutoConfiguration 3 cn.iocoder.yudao.framework.swagger.config.YudaoSwaggerAutoConfiguration
5 cn.iocoder.yudao.framework.web.config.YudaoWebAutoConfiguration 4 cn.iocoder.yudao.framework.web.config.YudaoWebAutoConfiguration
6 cn.iocoder.yudao.framework.xss.config.YudaoXssAutoConfiguration 5 cn.iocoder.yudao.framework.xss.config.YudaoXssAutoConfiguration
yudao-module-bpm/yudao-module-bpm-api/src/main/java/cn/iocoder/yudao/module/bpm/enums/ErrorCodeConstants.java
@@ -4,61 +4,66 @@ import cn.iocoder.yudao.framework.common.exception.ErrorCode; @@ -4,61 +4,66 @@ import cn.iocoder.yudao.framework.common.exception.ErrorCode;
4 4
5 /** 5 /**
6 * Bpm 错误码枚举类 6 * Bpm 错误码枚举类
7 - * 7 + * <p>
8 * bpm 系统,使用 1-009-000-000 段 8 * bpm 系统,使用 1-009-000-000 段
9 */ 9 */
10 public interface ErrorCodeConstants { 10 public interface ErrorCodeConstants {
11 11
12 - // ========== 通用流程处理 模块 1009000000 ==========  
13 - ErrorCode HIGHLIGHT_IMG_ERROR = new ErrorCode(1009000002, "获取高亮流程图异常"); 12 + // ========== 通用流程处理 模块 1-009-000-000 ==========
  13 + ErrorCode HIGHLIGHT_IMG_ERROR = new ErrorCode(1_009_000_002, "获取高亮流程图异常");
14 14
15 - // ========== OA 流程模块 1009001000 ==========  
16 - ErrorCode OA_LEAVE_NOT_EXISTS = new ErrorCode(1009001001, "请假申请不存在");  
17 - ErrorCode OA_PM_POST_NOT_EXISTS = new ErrorCode(1009001002, "项目经理岗位未设置");  
18 - ErrorCode OA_DEPART_PM_POST_NOT_EXISTS = new ErrorCode(1009001009, "部门的项目经理不存在");  
19 - ErrorCode OA_BM_POST_NOT_EXISTS = new ErrorCode(1009001004, "部门经理岗位未设置");  
20 - ErrorCode OA_DEPART_BM_POST_NOT_EXISTS = new ErrorCode(1009001005, "部门的部门经理不存在");  
21 - ErrorCode OA_HR_POST_NOT_EXISTS = new ErrorCode(1009001006, "HR岗位未设置");  
22 - ErrorCode OA_DAY_LEAVE_ERROR = new ErrorCode(1009001007, "请假天数必须>=1"); 15 + // ========== OA 流程模块 1-009-001-000 ==========
  16 + ErrorCode OA_LEAVE_NOT_EXISTS = new ErrorCode(1_009_001_001, "请假申请不存在");
  17 + ErrorCode OA_PM_POST_NOT_EXISTS = new ErrorCode(1_009_001_002, "项目经理岗位未设置");
  18 + ErrorCode OA_DEPART_PM_POST_NOT_EXISTS = new ErrorCode(1_009_001_009, "部门的项目经理不存在");
  19 + ErrorCode OA_BM_POST_NOT_EXISTS = new ErrorCode(1_009_001_004, "部门经理岗位未设置");
  20 + ErrorCode OA_DEPART_BM_POST_NOT_EXISTS = new ErrorCode(1_009_001_005, "部门的部门经理不存在");
  21 + ErrorCode OA_HR_POST_NOT_EXISTS = new ErrorCode(1_009_001_006, "HR岗位未设置");
  22 + ErrorCode OA_DAY_LEAVE_ERROR = new ErrorCode(1_009_001_007, "请假天数必须>=1");
23 23
24 - // ========== 流程模型 1009002000 ==========  
25 - ErrorCode MODEL_KEY_EXISTS = new ErrorCode(1009002000, "已经存在流程标识为【{}】的流程");  
26 - ErrorCode MODEL_NOT_EXISTS = new ErrorCode(1009002001, "流程模型不存在");  
27 - ErrorCode MODEL_KEY_VALID = new ErrorCode(1009002002, "流程标识格式不正确,需要以字母或下划线开头,后接任意字母、数字、中划线、下划线、句点!");  
28 - ErrorCode MODEL_DEPLOY_FAIL_FORM_NOT_CONFIG = new ErrorCode(1009002003, "部署流程失败,原因:流程表单未配置,请点击【修改流程】按钮进行配置");  
29 - ErrorCode MODEL_DEPLOY_FAIL_TASK_ASSIGN_RULE_NOT_CONFIG = new ErrorCode(1009002004, "部署流程失败," + 24 + // ========== 流程模型 1-009-002-000 ==========
  25 + ErrorCode MODEL_KEY_EXISTS = new ErrorCode(1_009_002_000, "已经存在流程标识为【{}】的流程");
  26 + ErrorCode MODEL_NOT_EXISTS = new ErrorCode(1_009_002_001, "流程模型不存在");
  27 + ErrorCode MODEL_KEY_VALID = new ErrorCode(1_009_002_002, "流程标识格式不正确,需要以字母或下划线开头,后接任意字母、数字、中划线、下划线、句点!");
  28 + ErrorCode MODEL_DEPLOY_FAIL_FORM_NOT_CONFIG = new ErrorCode(1_009_002_003, "部署流程失败,原因:流程表单未配置,请点击【修改流程】按钮进行配置");
  29 + ErrorCode MODEL_DEPLOY_FAIL_TASK_ASSIGN_RULE_NOT_CONFIG = new ErrorCode(1_009_002_004, "部署流程失败," +
30 "原因:用户任务({})未配置分配规则,请点击【修改流程】按钮进行配置"); 30 "原因:用户任务({})未配置分配规则,请点击【修改流程】按钮进行配置");
31 - ErrorCode MODEL_DEPLOY_FAIL_TASK_INFO_EQUALS = new ErrorCode(1009003005, "流程定义部署失败,原因:信息未发生变化"); 31 + ErrorCode MODEL_DEPLOY_FAIL_TASK_INFO_EQUALS = new ErrorCode(1_009_003_005, "流程定义部署失败,原因:信息未发生变化");
32 32
33 - // ========== 流程定义 1009003000 ==========  
34 - ErrorCode PROCESS_DEFINITION_KEY_NOT_MATCH = new ErrorCode(1009003000, "流程定义的标识期望是({}),当前是({}),请修改 BPMN 流程图");  
35 - ErrorCode PROCESS_DEFINITION_NAME_NOT_MATCH = new ErrorCode(1009003001, "流程定义的名字期望是({}),当前是({}),请修改 BPMN 流程图");  
36 - ErrorCode PROCESS_DEFINITION_NOT_EXISTS = new ErrorCode(1009003002, "流程定义不存在");  
37 - ErrorCode PROCESS_DEFINITION_IS_SUSPENDED = new ErrorCode(1009003003, "流程定义处于挂起状态");  
38 - ErrorCode PROCESS_DEFINITION_BPMN_MODEL_NOT_EXISTS = new ErrorCode(1009003004, "流程定义的模型不存在"); 33 + // ========== 流程定义 1-009-003-000 ==========
  34 + ErrorCode PROCESS_DEFINITION_KEY_NOT_MATCH = new ErrorCode(1_009_003_000, "流程定义的标识期望是({}),当前是({}),请修改 BPMN 流程图");
  35 + ErrorCode PROCESS_DEFINITION_NAME_NOT_MATCH = new ErrorCode(1_009_003_001, "流程定义的名字期望是({}),当前是({}),请修改 BPMN 流程图");
  36 + ErrorCode PROCESS_DEFINITION_NOT_EXISTS = new ErrorCode(1_009_003_002, "流程定义不存在");
  37 + ErrorCode PROCESS_DEFINITION_IS_SUSPENDED = new ErrorCode(1_009_003_003, "流程定义处于挂起状态");
  38 + ErrorCode PROCESS_DEFINITION_BPMN_MODEL_NOT_EXISTS = new ErrorCode(1_009_003_004, "流程定义的模型不存在");
39 39
40 - // ========== 流程实例 1009004000 ==========  
41 - ErrorCode PROCESS_INSTANCE_NOT_EXISTS = new ErrorCode(1009004000, "流程实例不存在");  
42 - ErrorCode PROCESS_INSTANCE_CANCEL_FAIL_NOT_EXISTS = new ErrorCode(1009004001, "流程取消失败,流程不处于运行中");  
43 - ErrorCode PROCESS_INSTANCE_CANCEL_FAIL_NOT_SELF = new ErrorCode(1009004002, "流程取消失败,该流程不是你发起的"); 40 + // ========== 流程实例 1-009-004-000 ==========
  41 + ErrorCode PROCESS_INSTANCE_NOT_EXISTS = new ErrorCode(1_009_004_000, "流程实例不存在");
  42 + ErrorCode PROCESS_INSTANCE_CANCEL_FAIL_NOT_EXISTS = new ErrorCode(1_009_004_001, "流程取消失败,流程不处于运行中");
  43 + ErrorCode PROCESS_INSTANCE_CANCEL_FAIL_NOT_SELF = new ErrorCode(1_009_004_002, "流程取消失败,该流程不是你发起的");
44 44
45 - // ========== 流程任务 1009005000 ==========  
46 - ErrorCode TASK_COMPLETE_FAIL_NOT_EXISTS = new ErrorCode(1009005000, "审批任务失败,原因:该任务不处于未审批");  
47 - ErrorCode TASK_COMPLETE_FAIL_ASSIGN_NOT_SELF = new ErrorCode(1009005001, "审批任务失败,原因:该任务的审批人不是你"); 45 + // ========== 流程任务 1-009-005-000 ==========
  46 + ErrorCode TASK_OPERATE_FAIL_ASSIGN_NOT_SELF = new ErrorCode(1_009_005_001, "操作失败,原因:该任务的审批人不是你");
  47 + ErrorCode TASK_NOT_EXISTS = new ErrorCode(1_009_005_002, "流程任务不存在");
  48 + ErrorCode TASK_IS_PENDING = new ErrorCode(1_009_005_003, "当前任务处于挂起状态,不能操作");
  49 + ErrorCode TASK_TARGET_NODE_NOT_EXISTS = new ErrorCode(1_009_005_004, " 目标节点不存在");
  50 + ErrorCode TASK_RETURN_FAIL_SOURCE_TARGET_ERROR = new ErrorCode(1_009_005_006, "回退任务失败,目标节点是在并行网关上或非同一路线上,不可跳转");
  51 + ErrorCode TASK_DELEGATE_FAIL_USER_REPEAT = new ErrorCode(1_009_005_007, "任务委派失败,委派人和当前审批人为同一人");
  52 + ErrorCode TASK_DELEGATE_FAIL_USER_NOT_EXISTS = new ErrorCode(1_009_005_008, "任务委派失败,被委派人不存在");
48 53
49 - // ========== 流程任务分配规则 1009006000 ==========  
50 - ErrorCode TASK_ASSIGN_RULE_EXISTS = new ErrorCode(1009006000, "流程({}) 的任务({}) 已经存在分配规则");  
51 - ErrorCode TASK_ASSIGN_RULE_NOT_EXISTS = new ErrorCode(1009006001, "流程任务分配规则不存在");  
52 - ErrorCode TASK_UPDATE_FAIL_NOT_MODEL = new ErrorCode(1009006002, "只有流程模型的任务分配规则,才允许被修改");  
53 - ErrorCode TASK_CREATE_FAIL_NO_CANDIDATE_USER = new ErrorCode(1009006003, "操作失败,原因:找不到任务的审批人!");  
54 - ErrorCode TASK_ASSIGN_SCRIPT_NOT_EXISTS = new ErrorCode(1009006004, "操作失败,原因:任务分配脚本({}) 不存在"); 54 + // ========== 流程任务分配规则 1-009-006-000 ==========
  55 + ErrorCode TASK_ASSIGN_RULE_EXISTS = new ErrorCode(1_009_006_000, "流程({}) 的任务({}) 已经存在分配规则");
  56 + ErrorCode TASK_ASSIGN_RULE_NOT_EXISTS = new ErrorCode(1_009_006_001, "流程任务分配规则不存在");
  57 + ErrorCode TASK_UPDATE_FAIL_NOT_MODEL = new ErrorCode(1_009_006_002, "只有流程模型的任务分配规则,才允许被修改");
  58 + ErrorCode TASK_CREATE_FAIL_NO_CANDIDATE_USER = new ErrorCode(1_009_006_003, "操作失败,原因:找不到任务的审批人!");
  59 + ErrorCode TASK_ASSIGN_SCRIPT_NOT_EXISTS = new ErrorCode(1_009_006_004, "操作失败,原因:任务分配脚本({}) 不存在");
55 60
56 - // ========== 动态表单模块 1009010000 ==========  
57 - ErrorCode FORM_NOT_EXISTS = new ErrorCode(1009010000, "动态表单不存在");  
58 - ErrorCode FORM_FIELD_REPEAT = new ErrorCode(1009010001, "表单项({}) 和 ({}) 使用了相同的字段名({})"); 61 + // ========== 动态表单模块 1-009-010-000 ==========
  62 + ErrorCode FORM_NOT_EXISTS = new ErrorCode(1_009_010_000, "动态表单不存在");
  63 + ErrorCode FORM_FIELD_REPEAT = new ErrorCode(1_009_010_001, "表单项({}) 和 ({}) 使用了相同的字段名({})");
59 64
60 - // ========== 用户组模块 1009011000 ==========  
61 - ErrorCode USER_GROUP_NOT_EXISTS = new ErrorCode(1009011000, "用户组不存在");  
62 - ErrorCode USER_GROUP_IS_DISABLE = new ErrorCode(1009011001, "名字为【{}】的用户组已被禁用"); 65 + // ========== 用户组模块 1-009-011-000 ==========
  66 + ErrorCode USER_GROUP_NOT_EXISTS = new ErrorCode(1_009_011_000, "用户组不存在");
  67 + ErrorCode USER_GROUP_IS_DISABLE = new ErrorCode(1_009_011_001, "名字为【{}】的用户组已被禁用");
63 68
64 } 69 }
yudao-module-bpm/yudao-module-bpm-api/src/main/java/cn/iocoder/yudao/module/bpm/enums/task/BpmProcessInstanceResultEnum.java
@@ -20,7 +20,8 @@ public enum BpmProcessInstanceResultEnum { @@ -20,7 +20,8 @@ public enum BpmProcessInstanceResultEnum {
20 20
21 // ========== 流程任务独有的状态 ========== 21 // ========== 流程任务独有的状态 ==========
22 22
23 - BACK(5, "退回/驳回"); 23 + BACK(5, "驳回"), // 退回
  24 + DELEGATE(6, "委派");
24 25
25 /** 26 /**
26 * 结果 27 * 结果
yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/task/BpmTaskController.java
@@ -75,4 +75,29 @@ public class BpmTaskController { @@ -75,4 +75,29 @@ public class BpmTaskController {
75 return success(true); 75 return success(true);
76 } 76 }
77 77
  78 + @GetMapping("/get-return-list")
  79 + @Operation(summary = "获取所有可回退的节点", description = "用于【流程详情】的【回退】按钮")
  80 + @Parameter(name = "taskId", description = "当前任务ID", required = true)
  81 + @PreAuthorize("@ss.hasPermission('bpm:task:update')")
  82 + public CommonResult<List<BpmTaskSimpleRespVO>> getReturnList(@RequestParam("taskId") String taskId) {
  83 + return success(taskService.getReturnTaskList(taskId));
  84 + }
  85 +
  86 + @PutMapping("/return")
  87 + @Operation(summary = "回退任务", description = "用于【流程详情】的【回退】按钮")
  88 + @PreAuthorize("@ss.hasPermission('bpm:task:update')")
  89 + public CommonResult<Boolean> returnTask(@Valid @RequestBody BpmTaskReturnReqVO reqVO) {
  90 + taskService.returnTask(getLoginUserId(), reqVO);
  91 + return success(true);
  92 + }
  93 +
  94 + @PutMapping("/delegate")
  95 + @Operation(summary = "委派任务", description = "用于【流程详情】的【委派】按钮。和向前【加签】有点像,唯一区别是【委托】没有单独创立任务")
  96 + @PreAuthorize("@ss.hasPermission('bpm:task:update')")
  97 + public CommonResult<Boolean> delegateTask(@Valid @RequestBody BpmTaskDelegateReqVO reqVO) {
  98 + // TODO @海:, 后面要有空格
  99 + taskService.delegateTask(reqVO,getLoginUserId());
  100 + return success(true);
  101 + }
  102 +
78 } 103 }
yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/task/vo/task/BpmTaskDelegateReqVO.java 0 → 100644
  1 +package cn.iocoder.yudao.module.bpm.controller.admin.task.vo.task;
  2 +
  3 +import io.swagger.v3.oas.annotations.media.Schema;
  4 +import lombok.Data;
  5 +
  6 +import javax.validation.constraints.NotEmpty;
  7 +import javax.validation.constraints.NotNull;
  8 +
  9 +@Schema(description = "管理后台 - 委派流程任务的 Request VO")
  10 +@Data
  11 +public class BpmTaskDelegateReqVO {
  12 +
  13 + @Schema(description = "任务编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
  14 + @NotEmpty(message = "任务编号不能为空")
  15 + private String id;
  16 +
  17 + @Schema(description = "被委派人 ID", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
  18 + @NotNull(message = "被委派人 ID 不能为空")
  19 + private Long delegateUserId;
  20 +
  21 + @Schema(description = "委派原因", requiredMode = Schema.RequiredMode.REQUIRED, example = "做不了决定,需要你先帮忙瞅瞅")
  22 + @NotEmpty(message = "委派原因不能为空")
  23 + private String reason;
  24 +
  25 +}
yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/task/vo/task/BpmTaskReturnReqVO.java 0 → 100644
  1 +package cn.iocoder.yudao.module.bpm.controller.admin.task.vo.task;
  2 +
  3 +import io.swagger.v3.oas.annotations.media.Schema;
  4 +import lombok.Data;
  5 +
  6 +import javax.validation.constraints.NotEmpty;
  7 +
  8 +@Schema(description = "管理后台 - 回退流程任务的 Request VO")
  9 +@Data
  10 +public class BpmTaskReturnReqVO {
  11 +
  12 + @Schema(description = "任务编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
  13 + @NotEmpty(message = "任务编号不能为空")
  14 + private String id;
  15 +
  16 + @Schema(description = "回退到的任务 Key", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
  17 + @NotEmpty(message = "回退到的任务 Key 不能为空")
  18 + private String targetDefinitionKey;
  19 +
  20 + @Schema(description = "回退意见", requiredMode = Schema.RequiredMode.REQUIRED, example = "我就是想驳回")
  21 + @NotEmpty(message = "回退意见不能为空")
  22 + private String reason;
  23 +
  24 +}
yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/task/vo/task/BpmTaskSimpleRespVO.java 0 → 100644
  1 +package cn.iocoder.yudao.module.bpm.controller.admin.task.vo.task;
  2 +
  3 +import io.swagger.v3.oas.annotations.media.Schema;
  4 +import lombok.Data;
  5 +
  6 +@Schema(description = "管理后台 - 流程任务的精简 Response VO")
  7 +@Data
  8 +public class BpmTaskSimpleRespVO {
  9 +
  10 + @Schema(description = "任务定义的标识", requiredMode = Schema.RequiredMode.REQUIRED, example = "Activity_one")
  11 + private String definitionKey;
  12 +
  13 + @Schema(description = "任务名词", requiredMode = Schema.RequiredMode.REQUIRED, example = "经理审批")
  14 + private String name;
  15 +
  16 +}
yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/convert/task/BpmTaskConvert.java
@@ -6,11 +6,13 @@ import cn.iocoder.yudao.framework.common.util.date.DateUtils; @@ -6,11 +6,13 @@ import cn.iocoder.yudao.framework.common.util.date.DateUtils;
6 import cn.iocoder.yudao.framework.common.util.number.NumberUtils; 6 import cn.iocoder.yudao.framework.common.util.number.NumberUtils;
7 import cn.iocoder.yudao.module.bpm.controller.admin.task.vo.task.BpmTaskDonePageItemRespVO; 7 import cn.iocoder.yudao.module.bpm.controller.admin.task.vo.task.BpmTaskDonePageItemRespVO;
8 import cn.iocoder.yudao.module.bpm.controller.admin.task.vo.task.BpmTaskRespVO; 8 import cn.iocoder.yudao.module.bpm.controller.admin.task.vo.task.BpmTaskRespVO;
  9 +import cn.iocoder.yudao.module.bpm.controller.admin.task.vo.task.BpmTaskSimpleRespVO;
9 import cn.iocoder.yudao.module.bpm.controller.admin.task.vo.task.BpmTaskTodoPageItemRespVO; 10 import cn.iocoder.yudao.module.bpm.controller.admin.task.vo.task.BpmTaskTodoPageItemRespVO;
10 import cn.iocoder.yudao.module.bpm.dal.dataobject.task.BpmTaskExtDO; 11 import cn.iocoder.yudao.module.bpm.dal.dataobject.task.BpmTaskExtDO;
11 import cn.iocoder.yudao.module.bpm.service.message.dto.BpmMessageSendWhenTaskCreatedReqDTO; 12 import cn.iocoder.yudao.module.bpm.service.message.dto.BpmMessageSendWhenTaskCreatedReqDTO;
12 import cn.iocoder.yudao.module.system.api.dept.dto.DeptRespDTO; 13 import cn.iocoder.yudao.module.system.api.dept.dto.DeptRespDTO;
13 import cn.iocoder.yudao.module.system.api.user.dto.AdminUserRespDTO; 14 import cn.iocoder.yudao.module.system.api.user.dto.AdminUserRespDTO;
  15 +import org.flowable.bpmn.model.FlowElement;
14 import org.flowable.common.engine.impl.db.SuspensionState; 16 import org.flowable.common.engine.impl.db.SuspensionState;
15 import org.flowable.engine.history.HistoricProcessInstance; 17 import org.flowable.engine.history.HistoricProcessInstance;
16 import org.flowable.engine.runtime.ProcessInstance; 18 import org.flowable.engine.runtime.ProcessInstance;
@@ -55,8 +57,8 @@ public interface BpmTaskConvert { @@ -55,8 +57,8 @@ public interface BpmTaskConvert {
55 } 57 }
56 58
57 default List<BpmTaskDonePageItemRespVO> convertList2(List<HistoricTaskInstance> tasks, 59 default List<BpmTaskDonePageItemRespVO> convertList2(List<HistoricTaskInstance> tasks,
58 - Map<String, BpmTaskExtDO> bpmTaskExtDOMap, Map<String, HistoricProcessInstance> historicProcessInstanceMap,  
59 - Map<Long, AdminUserRespDTO> userMap) { 60 + Map<String, BpmTaskExtDO> bpmTaskExtDOMap, Map<String, HistoricProcessInstance> historicProcessInstanceMap,
  61 + Map<Long, AdminUserRespDTO> userMap) {
60 return CollectionUtils.convertList(tasks, task -> { 62 return CollectionUtils.convertList(tasks, task -> {
61 BpmTaskDonePageItemRespVO respVO = convert2(task); 63 BpmTaskDonePageItemRespVO respVO = convert2(task);
62 BpmTaskExtDO taskExtDO = bpmTaskExtDOMap.get(task.getId()); 64 BpmTaskExtDO taskExtDO = bpmTaskExtDOMap.get(task.getId());
@@ -82,8 +84,8 @@ public interface BpmTaskConvert { @@ -82,8 +84,8 @@ public interface BpmTaskConvert {
82 BpmTaskTodoPageItemRespVO.ProcessInstance convert(ProcessInstance processInstance, AdminUserRespDTO startUser); 84 BpmTaskTodoPageItemRespVO.ProcessInstance convert(ProcessInstance processInstance, AdminUserRespDTO startUser);
83 85
84 default List<BpmTaskRespVO> convertList3(List<HistoricTaskInstance> tasks, 86 default List<BpmTaskRespVO> convertList3(List<HistoricTaskInstance> tasks,
85 - Map<String, BpmTaskExtDO> bpmTaskExtDOMap, HistoricProcessInstance processInstance,  
86 - Map<Long, AdminUserRespDTO> userMap, Map<Long, DeptRespDTO> deptMap) { 87 + Map<String, BpmTaskExtDO> bpmTaskExtDOMap, HistoricProcessInstance processInstance,
  88 + Map<Long, AdminUserRespDTO> userMap, Map<Long, DeptRespDTO> deptMap) {
87 return CollectionUtils.convertList(tasks, task -> { 89 return CollectionUtils.convertList(tasks, task -> {
88 BpmTaskRespVO respVO = convert3(task); 90 BpmTaskRespVO respVO = convert3(task);
89 BpmTaskExtDO taskExtDO = bpmTaskExtDOMap.get(task.getId()); 91 BpmTaskExtDO taskExtDO = bpmTaskExtDOMap.get(task.getId());
@@ -113,29 +115,34 @@ public interface BpmTaskConvert { @@ -113,29 +115,34 @@ public interface BpmTaskConvert {
113 void copyTo(BpmTaskExtDO from, @MappingTarget BpmTaskDonePageItemRespVO to); 115 void copyTo(BpmTaskExtDO from, @MappingTarget BpmTaskDonePageItemRespVO to);
114 116
115 @Mappings({@Mapping(source = "processInstance.id", target = "id"), 117 @Mappings({@Mapping(source = "processInstance.id", target = "id"),
116 - @Mapping(source = "processInstance.name", target = "name"),  
117 - @Mapping(source = "processInstance.startUserId", target = "startUserId"),  
118 - @Mapping(source = "processInstance.processDefinitionId", target = "processDefinitionId"),  
119 - @Mapping(source = "startUser.nickname", target = "startUserNickname")}) 118 + @Mapping(source = "processInstance.name", target = "name"),
  119 + @Mapping(source = "processInstance.startUserId", target = "startUserId"),
  120 + @Mapping(source = "processInstance.processDefinitionId", target = "processDefinitionId"),
  121 + @Mapping(source = "startUser.nickname", target = "startUserNickname")})
120 BpmTaskTodoPageItemRespVO.ProcessInstance convert(HistoricProcessInstance processInstance, 122 BpmTaskTodoPageItemRespVO.ProcessInstance convert(HistoricProcessInstance processInstance,
121 - AdminUserRespDTO startUser); 123 + AdminUserRespDTO startUser);
122 124
123 default BpmTaskExtDO convert2TaskExt(Task task) { 125 default BpmTaskExtDO convert2TaskExt(Task task) {
124 BpmTaskExtDO taskExtDO = new BpmTaskExtDO().setTaskId(task.getId()) 126 BpmTaskExtDO taskExtDO = new BpmTaskExtDO().setTaskId(task.getId())
125 - .setAssigneeUserId(NumberUtils.parseLong(task.getAssignee())).setName(task.getName())  
126 - .setProcessDefinitionId(task.getProcessDefinitionId()).setProcessInstanceId(task.getProcessInstanceId()); 127 + .setAssigneeUserId(NumberUtils.parseLong(task.getAssignee())).setName(task.getName())
  128 + .setProcessDefinitionId(task.getProcessDefinitionId()).setProcessInstanceId(task.getProcessInstanceId());
127 taskExtDO.setCreateTime(LocalDateTimeUtil.of(task.getCreateTime())); 129 taskExtDO.setCreateTime(LocalDateTimeUtil.of(task.getCreateTime()));
128 return taskExtDO; 130 return taskExtDO;
129 } 131 }
130 132
131 default BpmMessageSendWhenTaskCreatedReqDTO convert(ProcessInstance processInstance, AdminUserRespDTO startUser, 133 default BpmMessageSendWhenTaskCreatedReqDTO convert(ProcessInstance processInstance, AdminUserRespDTO startUser,
132 - Task task) { 134 + Task task) {
133 BpmMessageSendWhenTaskCreatedReqDTO reqDTO = new BpmMessageSendWhenTaskCreatedReqDTO(); 135 BpmMessageSendWhenTaskCreatedReqDTO reqDTO = new BpmMessageSendWhenTaskCreatedReqDTO();
134 reqDTO.setProcessInstanceId(processInstance.getProcessInstanceId()) 136 reqDTO.setProcessInstanceId(processInstance.getProcessInstanceId())
135 - .setProcessInstanceName(processInstance.getName()).setStartUserId(startUser.getId())  
136 - .setStartUserNickname(startUser.getNickname()).setTaskId(task.getId()).setTaskName(task.getName())  
137 - .setAssigneeUserId(NumberUtils.parseLong(task.getAssignee())); 137 + .setProcessInstanceName(processInstance.getName()).setStartUserId(startUser.getId())
  138 + .setStartUserNickname(startUser.getNickname()).setTaskId(task.getId()).setTaskName(task.getName())
  139 + .setAssigneeUserId(NumberUtils.parseLong(task.getAssignee()));
138 return reqDTO; 140 return reqDTO;
139 } 141 }
140 142
  143 + default List<BpmTaskSimpleRespVO> convertList(List<? extends FlowElement> elementList) {
  144 + return CollectionUtils.convertList(elementList, element -> new BpmTaskSimpleRespVO()
  145 + .setName(element.getName())
  146 + .setDefinitionKey(element.getId()));
  147 + }
141 } 148 }
yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/definition/BpmModelService.java
@@ -74,4 +74,12 @@ public interface BpmModelService { @@ -74,4 +74,12 @@ public interface BpmModelService {
74 */ 74 */
75 BpmnModel getBpmnModel(String id); 75 BpmnModel getBpmnModel(String id);
76 76
  77 + /**
  78 + * 获得流程定义编号对应的 BPMN Model
  79 + *
  80 + * @param processDefinitionId 流程定义编号
  81 + * @return BPMN Model
  82 + */
  83 + BpmnModel getBpmnModelByDefinitionId(String processDefinitionId);
  84 +
77 } 85 }
yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/definition/BpmModelServiceImpl.java
@@ -233,6 +233,11 @@ public class BpmModelServiceImpl implements BpmModelService { @@ -233,6 +233,11 @@ public class BpmModelServiceImpl implements BpmModelService {
233 return converter.convertToBpmnModel(new BytesStreamSource(bpmnBytes), true, true); 233 return converter.convertToBpmnModel(new BytesStreamSource(bpmnBytes), true, true);
234 } 234 }
235 235
  236 + @Override
  237 + public BpmnModel getBpmnModelByDefinitionId(String processDefinitionId) {
  238 + return repositoryService.getBpmnModel(processDefinitionId);
  239 + }
  240 +
236 private void checkKeyNCName(String key) { 241 private void checkKeyNCName(String key) {
237 if (!ValidationUtils.isXmlNCName(key)) { 242 if (!ValidationUtils.isXmlNCName(key)) {
238 throw exception(MODEL_KEY_VALID); 243 throw exception(MODEL_KEY_VALID);
yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/definition/BpmProcessDefinitionServiceImpl.java
@@ -5,7 +5,7 @@ import cn.hutool.core.util.ObjectUtil; @@ -5,7 +5,7 @@ import cn.hutool.core.util.ObjectUtil;
5 import cn.hutool.core.util.StrUtil; 5 import cn.hutool.core.util.StrUtil;
6 import cn.iocoder.yudao.framework.common.pojo.PageResult; 6 import cn.iocoder.yudao.framework.common.pojo.PageResult;
7 import cn.iocoder.yudao.framework.common.util.object.PageUtils; 7 import cn.iocoder.yudao.framework.common.util.object.PageUtils;
8 -import cn.iocoder.yudao.framework.flowable.core.util.FlowableUtils; 8 +import cn.iocoder.yudao.framework.flowable.core.util.BpmnModelUtils;
9 import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.process.BpmProcessDefinitionListReqVO; 9 import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.process.BpmProcessDefinitionListReqVO;
10 import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.process.BpmProcessDefinitionPageItemRespVO; 10 import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.process.BpmProcessDefinitionPageItemRespVO;
11 import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.process.BpmProcessDefinitionPageReqVO; 11 import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.process.BpmProcessDefinitionPageReqVO;
@@ -200,7 +200,7 @@ public class BpmProcessDefinitionServiceImpl implements BpmProcessDefinitionServ @@ -200,7 +200,7 @@ public class BpmProcessDefinitionServiceImpl implements BpmProcessDefinitionServ
200 BpmnModel newModel = buildBpmnModel(createReqDTO.getBpmnBytes()); 200 BpmnModel newModel = buildBpmnModel(createReqDTO.getBpmnBytes());
201 BpmnModel oldModel = getBpmnModel(oldProcessDefinition.getId()); 201 BpmnModel oldModel = getBpmnModel(oldProcessDefinition.getId());
202 // 对比字节变化 202 // 对比字节变化
203 - if (!FlowableUtils.equals(oldModel, newModel)) { 203 + if (!BpmnModelUtils.equals(oldModel, newModel)) {
204 return false; 204 return false;
205 } 205 }
206 // 最终发现都一致,则返回 true 206 // 最终发现都一致,则返回 true
yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/definition/BpmTaskAssignRuleServiceImpl.java
@@ -7,7 +7,7 @@ import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; @@ -7,7 +7,7 @@ import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
7 import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils; 7 import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils;
8 import cn.iocoder.yudao.framework.common.util.object.ObjectUtils; 8 import cn.iocoder.yudao.framework.common.util.object.ObjectUtils;
9 import cn.iocoder.yudao.framework.datapermission.core.annotation.DataPermission; 9 import cn.iocoder.yudao.framework.datapermission.core.annotation.DataPermission;
10 -import cn.iocoder.yudao.framework.flowable.core.util.FlowableUtils; 10 +import cn.iocoder.yudao.framework.flowable.core.util.BpmnModelUtils;
11 import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.rule.BpmTaskAssignRuleCreateReqVO; 11 import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.rule.BpmTaskAssignRuleCreateReqVO;
12 import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.rule.BpmTaskAssignRuleRespVO; 12 import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.rule.BpmTaskAssignRuleRespVO;
13 import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.rule.BpmTaskAssignRuleUpdateReqVO; 13 import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.rule.BpmTaskAssignRuleUpdateReqVO;
@@ -114,7 +114,7 @@ public class BpmTaskAssignRuleServiceImpl implements BpmTaskAssignRuleService { @@ -114,7 +114,7 @@ public class BpmTaskAssignRuleServiceImpl implements BpmTaskAssignRuleService {
114 return Collections.emptyList(); 114 return Collections.emptyList();
115 } 115 }
116 // 获得用户任务,只有用户任务才可以设置分配规则 116 // 获得用户任务,只有用户任务才可以设置分配规则
117 - List<UserTask> userTasks = FlowableUtils.getBpmnModelElements(model, UserTask.class); 117 + List<UserTask> userTasks = BpmnModelUtils.getBpmnModelElements(model, UserTask.class);
118 if (CollUtil.isEmpty(userTasks)) { 118 if (CollUtil.isEmpty(userTasks)) {
119 return Collections.emptyList(); 119 return Collections.emptyList();
120 } 120 }
yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/task/BpmTaskService.java
1 package cn.iocoder.yudao.module.bpm.service.task; 1 package cn.iocoder.yudao.module.bpm.service.task;
2 2
3 -import cn.iocoder.yudao.framework.common.pojo.CommonResult;  
4 import cn.iocoder.yudao.framework.common.pojo.PageResult; 3 import cn.iocoder.yudao.framework.common.pojo.PageResult;
5 import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils; 4 import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils;
6 import cn.iocoder.yudao.module.bpm.controller.admin.task.vo.task.*; 5 import cn.iocoder.yudao.module.bpm.controller.admin.task.vo.task.*;
@@ -23,7 +22,6 @@ public interface BpmTaskService { @@ -23,7 +22,6 @@ public interface BpmTaskService {
23 * 22 *
24 * @param userId 用户编号 23 * @param userId 用户编号
25 * @param pageReqVO 分页请求 24 * @param pageReqVO 分页请求
26 - *  
27 * @return 流程任务分页 25 * @return 流程任务分页
28 */ 26 */
29 PageResult<BpmTaskTodoPageItemRespVO> getTodoTaskPage(Long userId, BpmTaskTodoPageReqVO pageReqVO); 27 PageResult<BpmTaskTodoPageItemRespVO> getTodoTaskPage(Long userId, BpmTaskTodoPageReqVO pageReqVO);
@@ -33,7 +31,6 @@ public interface BpmTaskService { @@ -33,7 +31,6 @@ public interface BpmTaskService {
33 * 31 *
34 * @param userId 用户编号 32 * @param userId 用户编号
35 * @param pageReqVO 分页请求 33 * @param pageReqVO 分页请求
36 - *  
37 * @return 流程任务分页 34 * @return 流程任务分页
38 */ 35 */
39 PageResult<BpmTaskDonePageItemRespVO> getDoneTaskPage(Long userId, BpmTaskDonePageReqVO pageReqVO); 36 PageResult<BpmTaskDonePageItemRespVO> getDoneTaskPage(Long userId, BpmTaskDonePageReqVO pageReqVO);
@@ -42,19 +39,17 @@ public interface BpmTaskService { @@ -42,19 +39,17 @@ public interface BpmTaskService {
42 * 获得流程任务 Map 39 * 获得流程任务 Map
43 * 40 *
44 * @param processInstanceIds 流程实例的编号数组 41 * @param processInstanceIds 流程实例的编号数组
45 - *  
46 * @return 流程任务 Map 42 * @return 流程任务 Map
47 */ 43 */
48 default Map<String, List<Task>> getTaskMapByProcessInstanceIds(List<String> processInstanceIds) { 44 default Map<String, List<Task>> getTaskMapByProcessInstanceIds(List<String> processInstanceIds) {
49 return CollectionUtils.convertMultiMap(getTasksByProcessInstanceIds(processInstanceIds), 45 return CollectionUtils.convertMultiMap(getTasksByProcessInstanceIds(processInstanceIds),
50 - Task::getProcessInstanceId); 46 + Task::getProcessInstanceId);
51 } 47 }
52 48
53 /** 49 /**
54 * 获得流程任务列表 50 * 获得流程任务列表
55 * 51 *
56 * @param processInstanceIds 流程实例的编号数组 52 * @param processInstanceIds 流程实例的编号数组
57 - *  
58 * @return 流程任务列表 53 * @return 流程任务列表
59 */ 54 */
60 List<Task> getTasksByProcessInstanceIds(List<String> processInstanceIds); 55 List<Task> getTasksByProcessInstanceIds(List<String> processInstanceIds);
@@ -63,7 +58,6 @@ public interface BpmTaskService { @@ -63,7 +58,6 @@ public interface BpmTaskService {
63 * 获得指令流程实例的流程任务列表,包括所有状态的 58 * 获得指令流程实例的流程任务列表,包括所有状态的
64 * 59 *
65 * @param processInstanceId 流程实例的编号 60 * @param processInstanceId 流程实例的编号
66 - *  
67 * @return 流程任务列表 61 * @return 流程任务列表
68 */ 62 */
69 List<BpmTaskRespVO> getTaskListByProcessInstanceId(String processInstanceId); 63 List<BpmTaskRespVO> getTaskListByProcessInstanceId(String processInstanceId);
@@ -128,4 +122,29 @@ public interface BpmTaskService { @@ -128,4 +122,29 @@ public interface BpmTaskService {
128 */ 122 */
129 void updateTaskExtAssign(Task task); 123 void updateTaskExtAssign(Task task);
130 124
  125 + /**
  126 + * 获取当前任务的可回退的流程集合
  127 + *
  128 + * @param taskId 当前的任务 ID
  129 + * @return 可以回退的节点列表
  130 + */
  131 + List<BpmTaskSimpleRespVO> getReturnTaskList(String taskId);
  132 +
  133 + /**
  134 + * 将任务回退到指定的 targetDefinitionKey 位置
  135 + *
  136 + * @param userId 用户编号
  137 + * @param reqVO 回退的任务key和当前所在的任务ID
  138 + */
  139 + void returnTask(Long userId, BpmTaskReturnReqVO reqVO);
  140 +
  141 + // TODO @海:userId 放前面
  142 + /**
  143 + * 将指定任务委派给其他人处理,等接收人处理后再回到原审批人手中审批
  144 + *
  145 + * @param reqVO 被委派人和被委派的任务编号理由参数
  146 + * @param userId 用户编号
  147 + */
  148 + void delegateTask(BpmTaskDelegateReqVO reqVO, Long userId);
  149 +
131 } 150 }
yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/task/BpmTaskServiceImpl.java
1 package cn.iocoder.yudao.module.bpm.service.task; 1 package cn.iocoder.yudao.module.bpm.service.task;
2 2
3 import cn.hutool.core.collection.CollUtil; 3 import cn.hutool.core.collection.CollUtil;
4 -import cn.hutool.core.collection.ListUtil;  
5 import cn.hutool.core.util.ArrayUtil; 4 import cn.hutool.core.util.ArrayUtil;
6 import cn.hutool.core.util.StrUtil; 5 import cn.hutool.core.util.StrUtil;
7 import cn.iocoder.yudao.framework.common.pojo.PageResult; 6 import cn.iocoder.yudao.framework.common.pojo.PageResult;
8 import cn.iocoder.yudao.framework.common.util.date.DateUtils; 7 import cn.iocoder.yudao.framework.common.util.date.DateUtils;
9 import cn.iocoder.yudao.framework.common.util.number.NumberUtils; 8 import cn.iocoder.yudao.framework.common.util.number.NumberUtils;
10 import cn.iocoder.yudao.framework.common.util.object.PageUtils; 9 import cn.iocoder.yudao.framework.common.util.object.PageUtils;
  10 +import cn.iocoder.yudao.framework.flowable.core.util.BpmnModelUtils;
  11 +import cn.iocoder.yudao.framework.web.core.util.WebFrameworkUtils;
11 import cn.iocoder.yudao.module.bpm.controller.admin.task.vo.task.*; 12 import cn.iocoder.yudao.module.bpm.controller.admin.task.vo.task.*;
12 import cn.iocoder.yudao.module.bpm.convert.task.BpmTaskConvert; 13 import cn.iocoder.yudao.module.bpm.convert.task.BpmTaskConvert;
13 import cn.iocoder.yudao.module.bpm.dal.dataobject.task.BpmTaskExtDO; 14 import cn.iocoder.yudao.module.bpm.dal.dataobject.task.BpmTaskExtDO;
14 import cn.iocoder.yudao.module.bpm.dal.mysql.task.BpmTaskExtMapper; 15 import cn.iocoder.yudao.module.bpm.dal.mysql.task.BpmTaskExtMapper;
15 import cn.iocoder.yudao.module.bpm.enums.task.BpmProcessInstanceDeleteReasonEnum; 16 import cn.iocoder.yudao.module.bpm.enums.task.BpmProcessInstanceDeleteReasonEnum;
16 import cn.iocoder.yudao.module.bpm.enums.task.BpmProcessInstanceResultEnum; 17 import cn.iocoder.yudao.module.bpm.enums.task.BpmProcessInstanceResultEnum;
  18 +import cn.iocoder.yudao.module.bpm.service.definition.BpmModelService;
17 import cn.iocoder.yudao.module.bpm.service.message.BpmMessageService; 19 import cn.iocoder.yudao.module.bpm.service.message.BpmMessageService;
18 import cn.iocoder.yudao.module.system.api.dept.DeptApi; 20 import cn.iocoder.yudao.module.system.api.dept.DeptApi;
19 import cn.iocoder.yudao.module.system.api.dept.dto.DeptRespDTO; 21 import cn.iocoder.yudao.module.system.api.dept.dto.DeptRespDTO;
20 import cn.iocoder.yudao.module.system.api.user.AdminUserApi; 22 import cn.iocoder.yudao.module.system.api.user.AdminUserApi;
21 import cn.iocoder.yudao.module.system.api.user.dto.AdminUserRespDTO; 23 import cn.iocoder.yudao.module.system.api.user.dto.AdminUserRespDTO;
22 import lombok.extern.slf4j.Slf4j; 24 import lombok.extern.slf4j.Slf4j;
  25 +import org.flowable.bpmn.model.BpmnModel;
  26 +import org.flowable.bpmn.model.FlowElement;
  27 +import org.flowable.bpmn.model.UserTask;
23 import org.flowable.engine.HistoryService; 28 import org.flowable.engine.HistoryService;
  29 +import org.flowable.engine.RuntimeService;
24 import org.flowable.engine.TaskService; 30 import org.flowable.engine.TaskService;
25 import org.flowable.engine.history.HistoricProcessInstance; 31 import org.flowable.engine.history.HistoricProcessInstance;
26 import org.flowable.engine.runtime.ProcessInstance; 32 import org.flowable.engine.runtime.ProcessInstance;
  33 +import org.flowable.task.api.DelegationState;
27 import org.flowable.task.api.Task; 34 import org.flowable.task.api.Task;
28 import org.flowable.task.api.TaskQuery; 35 import org.flowable.task.api.TaskQuery;
29 import org.flowable.task.api.history.HistoricTaskInstance; 36 import org.flowable.task.api.history.HistoricTaskInstance;
@@ -32,6 +39,7 @@ import org.springframework.stereotype.Service; @@ -32,6 +39,7 @@ import org.springframework.stereotype.Service;
32 import org.springframework.transaction.annotation.Transactional; 39 import org.springframework.transaction.annotation.Transactional;
33 import org.springframework.transaction.support.TransactionSynchronization; 40 import org.springframework.transaction.support.TransactionSynchronization;
34 import org.springframework.transaction.support.TransactionSynchronizationManager; 41 import org.springframework.transaction.support.TransactionSynchronizationManager;
  42 +import org.springframework.util.Assert;
35 43
36 import javax.annotation.Resource; 44 import javax.annotation.Resource;
37 import javax.validation.Valid; 45 import javax.validation.Valid;
@@ -39,8 +47,7 @@ import java.time.LocalDateTime; @@ -39,8 +47,7 @@ import java.time.LocalDateTime;
39 import java.util.*; 47 import java.util.*;
40 48
41 import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; 49 import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
42 -import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertMap;  
43 -import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet; 50 +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.*;
44 import static cn.iocoder.yudao.module.bpm.enums.ErrorCodeConstants.*; 51 import static cn.iocoder.yudao.module.bpm.enums.ErrorCodeConstants.*;
45 52
46 /** 53 /**
@@ -57,23 +64,29 @@ public class BpmTaskServiceImpl implements BpmTaskService { @@ -57,23 +64,29 @@ public class BpmTaskServiceImpl implements BpmTaskService {
57 private TaskService taskService; 64 private TaskService taskService;
58 @Resource 65 @Resource
59 private HistoryService historyService; 66 private HistoryService historyService;
  67 + @Resource
  68 + private RuntimeService runtimeService;
60 69
61 @Resource 70 @Resource
62 private BpmProcessInstanceService processInstanceService; 71 private BpmProcessInstanceService processInstanceService;
63 @Resource 72 @Resource
  73 + private BpmModelService bpmModelService;
  74 + @Resource
  75 + private BpmMessageService messageService;
  76 +
  77 + @Resource
64 private AdminUserApi adminUserApi; 78 private AdminUserApi adminUserApi;
65 @Resource 79 @Resource
66 private DeptApi deptApi; 80 private DeptApi deptApi;
  81 +
67 @Resource 82 @Resource
68 private BpmTaskExtMapper taskExtMapper; 83 private BpmTaskExtMapper taskExtMapper;
69 - @Resource  
70 - private BpmMessageService messageService;  
71 84
72 @Override 85 @Override
73 public PageResult<BpmTaskTodoPageItemRespVO> getTodoTaskPage(Long userId, BpmTaskTodoPageReqVO pageVO) { 86 public PageResult<BpmTaskTodoPageItemRespVO> getTodoTaskPage(Long userId, BpmTaskTodoPageReqVO pageVO) {
74 // 查询待办任务 87 // 查询待办任务
75 TaskQuery taskQuery = taskService.createTaskQuery().taskAssignee(String.valueOf(userId)) // 分配给自己 88 TaskQuery taskQuery = taskService.createTaskQuery().taskAssignee(String.valueOf(userId)) // 分配给自己
76 - .orderByTaskCreateTime().desc(); // 创建时间倒序 89 + .orderByTaskCreateTime().desc(); // 创建时间倒序
77 if (StrUtil.isNotBlank(pageVO.getName())) { 90 if (StrUtil.isNotBlank(pageVO.getName())) {
78 taskQuery.taskNameLike("%" + pageVO.getName() + "%"); 91 taskQuery.taskNameLike("%" + pageVO.getName() + "%");
79 } 92 }
@@ -91,21 +104,21 @@ public class BpmTaskServiceImpl implements BpmTaskService { @@ -91,21 +104,21 @@ public class BpmTaskServiceImpl implements BpmTaskService {
91 104
92 // 获得 ProcessInstance Map 105 // 获得 ProcessInstance Map
93 Map<String, ProcessInstance> processInstanceMap = 106 Map<String, ProcessInstance> processInstanceMap =
94 - processInstanceService.getProcessInstanceMap(convertSet(tasks, Task::getProcessInstanceId)); 107 + processInstanceService.getProcessInstanceMap(convertSet(tasks, Task::getProcessInstanceId));
95 // 获得 User Map 108 // 获得 User Map
96 Map<Long, AdminUserRespDTO> userMap = adminUserApi.getUserMap( 109 Map<Long, AdminUserRespDTO> userMap = adminUserApi.getUserMap(
97 - convertSet(processInstanceMap.values(), instance -> Long.valueOf(instance.getStartUserId()))); 110 + convertSet(processInstanceMap.values(), instance -> Long.valueOf(instance.getStartUserId())));
98 // 拼接结果 111 // 拼接结果
99 return new PageResult<>(BpmTaskConvert.INSTANCE.convertList1(tasks, processInstanceMap, userMap), 112 return new PageResult<>(BpmTaskConvert.INSTANCE.convertList1(tasks, processInstanceMap, userMap),
100 - taskQuery.count()); 113 + taskQuery.count());
101 } 114 }
102 115
103 @Override 116 @Override
104 public PageResult<BpmTaskDonePageItemRespVO> getDoneTaskPage(Long userId, BpmTaskDonePageReqVO pageVO) { 117 public PageResult<BpmTaskDonePageItemRespVO> getDoneTaskPage(Long userId, BpmTaskDonePageReqVO pageVO) {
105 // 查询已办任务 118 // 查询已办任务
106 HistoricTaskInstanceQuery taskQuery = historyService.createHistoricTaskInstanceQuery().finished() // 已完成 119 HistoricTaskInstanceQuery taskQuery = historyService.createHistoricTaskInstanceQuery().finished() // 已完成
107 - .taskAssignee(String.valueOf(userId)) // 分配给自己  
108 - .orderByHistoricTaskInstanceEndTime().desc(); // 审批时间倒序 120 + .taskAssignee(String.valueOf(userId)) // 分配给自己
  121 + .orderByHistoricTaskInstanceEndTime().desc(); // 审批时间倒序
109 if (StrUtil.isNotBlank(pageVO.getName())) { 122 if (StrUtil.isNotBlank(pageVO.getName())) {
110 taskQuery.taskNameLike("%" + pageVO.getName() + "%"); 123 taskQuery.taskNameLike("%" + pageVO.getName() + "%");
111 } 124 }
@@ -123,19 +136,19 @@ public class BpmTaskServiceImpl implements BpmTaskService { @@ -123,19 +136,19 @@ public class BpmTaskServiceImpl implements BpmTaskService {
123 136
124 // 获得 TaskExtDO Map 137 // 获得 TaskExtDO Map
125 List<BpmTaskExtDO> bpmTaskExtDOs = 138 List<BpmTaskExtDO> bpmTaskExtDOs =
126 - taskExtMapper.selectListByTaskIds(convertSet(tasks, HistoricTaskInstance::getId)); 139 + taskExtMapper.selectListByTaskIds(convertSet(tasks, HistoricTaskInstance::getId));
127 Map<String, BpmTaskExtDO> bpmTaskExtDOMap = convertMap(bpmTaskExtDOs, BpmTaskExtDO::getTaskId); 140 Map<String, BpmTaskExtDO> bpmTaskExtDOMap = convertMap(bpmTaskExtDOs, BpmTaskExtDO::getTaskId);
128 // 获得 ProcessInstance Map 141 // 获得 ProcessInstance Map
129 Map<String, HistoricProcessInstance> historicProcessInstanceMap = 142 Map<String, HistoricProcessInstance> historicProcessInstanceMap =
130 - processInstanceService.getHistoricProcessInstanceMap(  
131 - convertSet(tasks, HistoricTaskInstance::getProcessInstanceId)); 143 + processInstanceService.getHistoricProcessInstanceMap(
  144 + convertSet(tasks, HistoricTaskInstance::getProcessInstanceId));
132 // 获得 User Map 145 // 获得 User Map
133 Map<Long, AdminUserRespDTO> userMap = adminUserApi.getUserMap( 146 Map<Long, AdminUserRespDTO> userMap = adminUserApi.getUserMap(
134 - convertSet(historicProcessInstanceMap.values(), instance -> Long.valueOf(instance.getStartUserId()))); 147 + convertSet(historicProcessInstanceMap.values(), instance -> Long.valueOf(instance.getStartUserId())));
135 // 拼接结果 148 // 拼接结果
136 return new PageResult<>( 149 return new PageResult<>(
137 - BpmTaskConvert.INSTANCE.convertList2(tasks, bpmTaskExtDOMap, historicProcessInstanceMap, userMap),  
138 - taskQuery.count()); 150 + BpmTaskConvert.INSTANCE.convertList2(tasks, bpmTaskExtDOMap, historicProcessInstanceMap, userMap),
  151 + taskQuery.count());
139 } 152 }
140 153
141 @Override 154 @Override
@@ -176,27 +189,58 @@ public class BpmTaskServiceImpl implements BpmTaskService { @@ -176,27 +189,58 @@ public class BpmTaskServiceImpl implements BpmTaskService {
176 @Override 189 @Override
177 @Transactional(rollbackFor = Exception.class) 190 @Transactional(rollbackFor = Exception.class)
178 public void approveTask(Long userId, @Valid BpmTaskApproveReqVO reqVO) { 191 public void approveTask(Long userId, @Valid BpmTaskApproveReqVO reqVO) {
179 - // 校验任务存在  
180 - Task task = checkTask(userId, reqVO.getId());  
181 - // 校验流程实例存在 192 + // 1.1 校验任务存在
  193 + Task task = validateTask(userId, reqVO.getId());
  194 + // 1.2 校验流程实例存在
182 ProcessInstance instance = processInstanceService.getProcessInstance(task.getProcessInstanceId()); 195 ProcessInstance instance = processInstanceService.getProcessInstance(task.getProcessInstanceId());
183 if (instance == null) { 196 if (instance == null) {
184 throw exception(PROCESS_INSTANCE_NOT_EXISTS); 197 throw exception(PROCESS_INSTANCE_NOT_EXISTS);
185 } 198 }
186 199
  200 + // 情况一:被委派的任务,不调用 complete 去完成任务
  201 + if (DelegationState.PENDING.equals(task.getDelegationState())) {
  202 + approveDelegateTask(reqVO, task);
  203 + return;
  204 + }
  205 +
  206 + // 情况二:自己审批的任务,调用 complete 去完成任务
187 // 完成任务,审批通过 207 // 完成任务,审批通过
188 taskService.complete(task.getId(), instance.getProcessVariables()); 208 taskService.complete(task.getId(), instance.getProcessVariables());
189 -  
190 // 更新任务拓展表为通过 209 // 更新任务拓展表为通过
191 taskExtMapper.updateByTaskId( 210 taskExtMapper.updateByTaskId(
192 - new BpmTaskExtDO().setTaskId(task.getId()).setResult(BpmProcessInstanceResultEnum.APPROVE.getResult())  
193 - .setReason(reqVO.getReason())); 211 + new BpmTaskExtDO().setTaskId(task.getId()).setResult(BpmProcessInstanceResultEnum.APPROVE.getResult())
  212 + .setReason(reqVO.getReason()));
  213 + }
  214 +
  215 + /**
  216 + * 审批被委派的任务
  217 + *
  218 + * @param reqVO 前端请求参数,包含当前任务ID,审批意见等
  219 + * @param task 当前被审批的任务
  220 + */
  221 + private void approveDelegateTask(BpmTaskApproveReqVO reqVO, Task task) {
  222 + // 1. 添加审批意见
  223 + AdminUserRespDTO currentUser = adminUserApi.getUser(WebFrameworkUtils.getLoginUserId());
  224 + AdminUserRespDTO sourceApproveUser = adminUserApi.getUser(NumberUtils.parseLong(task.getOwner()));
  225 + Assert.notNull(sourceApproveUser, "委派任务找不到原审批人,需要检查数据");
  226 + String comment = StrUtil.format("[{}]完成委派任务,任务重新回到[{}]手中,审批意见为:{}", currentUser.getNickname(),
  227 + sourceApproveUser.getNickname(), reqVO.getReason());
  228 + taskService.addComment(reqVO.getId(), task.getProcessInstanceId(),
  229 + BpmProcessInstanceResultEnum.DELEGATE.getResult().toString(), comment);
  230 +
  231 + // 2.1 调用 resolveTask 完成任务。
  232 + // 底层调用 TaskHelper.changeTaskAssignee(task, task.getOwner()):将 owner 设置为 assignee
  233 + taskService.resolveTask(task.getId());
  234 + // 2.2 更新任务拓展表为【处理中】
  235 + taskExtMapper.updateByTaskId(
  236 + new BpmTaskExtDO().setTaskId(task.getId()).setResult(BpmProcessInstanceResultEnum.PROCESS.getResult())
  237 + .setReason(reqVO.getReason()));
194 } 238 }
195 239
196 @Override 240 @Override
197 @Transactional(rollbackFor = Exception.class) 241 @Transactional(rollbackFor = Exception.class)
198 public void rejectTask(Long userId, @Valid BpmTaskRejectReqVO reqVO) { 242 public void rejectTask(Long userId, @Valid BpmTaskRejectReqVO reqVO) {
199 - Task task = checkTask(userId, reqVO.getId()); 243 + Task task = validateTask(userId, reqVO.getId());
200 // 校验流程实例存在 244 // 校验流程实例存在
201 ProcessInstance instance = processInstanceService.getProcessInstance(task.getProcessInstanceId()); 245 ProcessInstance instance = processInstanceService.getProcessInstance(task.getProcessInstanceId());
202 if (instance == null) { 246 if (instance == null) {
@@ -208,14 +252,14 @@ public class BpmTaskServiceImpl implements BpmTaskService { @@ -208,14 +252,14 @@ public class BpmTaskServiceImpl implements BpmTaskService {
208 252
209 // 更新任务拓展表为不通过 253 // 更新任务拓展表为不通过
210 taskExtMapper.updateByTaskId( 254 taskExtMapper.updateByTaskId(
211 - new BpmTaskExtDO().setTaskId(task.getId()).setResult(BpmProcessInstanceResultEnum.REJECT.getResult())  
212 - .setEndTime(LocalDateTime.now()).setReason(reqVO.getReason())); 255 + new BpmTaskExtDO().setTaskId(task.getId()).setResult(BpmProcessInstanceResultEnum.REJECT.getResult())
  256 + .setEndTime(LocalDateTime.now()).setReason(reqVO.getReason()));
213 } 257 }
214 258
215 @Override 259 @Override
216 public void updateTaskAssignee(Long userId, BpmTaskUpdateAssigneeReqVO reqVO) { 260 public void updateTaskAssignee(Long userId, BpmTaskUpdateAssigneeReqVO reqVO) {
217 // 校验任务存在 261 // 校验任务存在
218 - Task task = checkTask(userId, reqVO.getId()); 262 + Task task = validateTask(userId, reqVO.getId());
219 // 更新负责人 263 // 更新负责人
220 updateTaskAssignee(task.getId(), reqVO.getAssigneeUserId()); 264 updateTaskAssignee(task.getId(), reqVO.getAssigneeUserId());
221 } 265 }
@@ -231,13 +275,13 @@ public class BpmTaskServiceImpl implements BpmTaskService { @@ -231,13 +275,13 @@ public class BpmTaskServiceImpl implements BpmTaskService {
231 * @param userId 用户 id 275 * @param userId 用户 id
232 * @param taskId task id 276 * @param taskId task id
233 */ 277 */
234 - private Task checkTask(Long userId, String taskId) { 278 + private Task validateTask(Long userId, String taskId) {
235 Task task = getTask(taskId); 279 Task task = getTask(taskId);
236 if (task == null) { 280 if (task == null) {
237 - throw exception(TASK_COMPLETE_FAIL_NOT_EXISTS); 281 + throw exception(TASK_NOT_EXISTS);
238 } 282 }
239 if (!Objects.equals(userId, NumberUtils.parseLong(task.getAssignee()))) { 283 if (!Objects.equals(userId, NumberUtils.parseLong(task.getAssignee()))) {
240 - throw exception(TASK_COMPLETE_FAIL_ASSIGN_NOT_SELF); 284 + throw exception(TASK_OPERATE_FAIL_ASSIGN_NOT_SELF);
241 } 285 }
242 return task; 286 return task;
243 } 287 }
@@ -245,7 +289,7 @@ public class BpmTaskServiceImpl implements BpmTaskService { @@ -245,7 +289,7 @@ public class BpmTaskServiceImpl implements BpmTaskService {
245 @Override 289 @Override
246 public void createTaskExt(Task task) { 290 public void createTaskExt(Task task) {
247 BpmTaskExtDO taskExtDO = 291 BpmTaskExtDO taskExtDO =
248 - BpmTaskConvert.INSTANCE.convert2TaskExt(task).setResult(BpmProcessInstanceResultEnum.PROCESS.getResult()); 292 + BpmTaskConvert.INSTANCE.convert2TaskExt(task).setResult(BpmProcessInstanceResultEnum.PROCESS.getResult());
249 taskExtMapper.insert(taskExtDO); 293 taskExtMapper.insert(taskExtDO);
250 } 294 }
251 295
@@ -293,27 +337,183 @@ public class BpmTaskServiceImpl implements BpmTaskService { @@ -293,27 +337,183 @@ public class BpmTaskServiceImpl implements BpmTaskService {
293 @Override 337 @Override
294 public void updateTaskExtAssign(Task task) { 338 public void updateTaskExtAssign(Task task) {
295 BpmTaskExtDO taskExtDO = 339 BpmTaskExtDO taskExtDO =
296 - new BpmTaskExtDO().setAssigneeUserId(NumberUtils.parseLong(task.getAssignee())).setTaskId(task.getId()); 340 + new BpmTaskExtDO().setAssigneeUserId(NumberUtils.parseLong(task.getAssignee())).setTaskId(task.getId());
297 taskExtMapper.updateByTaskId(taskExtDO); 341 taskExtMapper.updateByTaskId(taskExtDO);
298 // 发送通知。在事务提交时,批量执行操作,所以直接查询会无法查询到 ProcessInstance,所以这里是通过监听事务的提交来实现。 342 // 发送通知。在事务提交时,批量执行操作,所以直接查询会无法查询到 ProcessInstance,所以这里是通过监听事务的提交来实现。
299 TransactionSynchronizationManager.registerSynchronization(new TransactionSynchronization() { 343 TransactionSynchronizationManager.registerSynchronization(new TransactionSynchronization() {
300 @Override 344 @Override
301 public void afterCommit() { 345 public void afterCommit() {
302 ProcessInstance processInstance = 346 ProcessInstance processInstance =
303 - processInstanceService.getProcessInstance(task.getProcessInstanceId()); 347 + processInstanceService.getProcessInstance(task.getProcessInstanceId());
304 AdminUserRespDTO startUser = adminUserApi.getUser(Long.valueOf(processInstance.getStartUserId())); 348 AdminUserRespDTO startUser = adminUserApi.getUser(Long.valueOf(processInstance.getStartUserId()));
305 messageService.sendMessageWhenTaskAssigned( 349 messageService.sendMessageWhenTaskAssigned(
306 - BpmTaskConvert.INSTANCE.convert(processInstance, startUser, task)); 350 + BpmTaskConvert.INSTANCE.convert(processInstance, startUser, task));
307 } 351 }
308 }); 352 });
309 } 353 }
310 354
311 private Task getTask(String id) { 355 private Task getTask(String id) {
312 - return taskService.createTaskQuery().taskId(id).singleResult(); 356 + Task task = taskService.createTaskQuery().taskId(id).singleResult();
  357 + if (null == task) {
  358 + throw exception(TASK_NOT_EXISTS);
  359 + }
  360 + return task;
313 } 361 }
314 362
315 private HistoricTaskInstance getHistoricTask(String id) { 363 private HistoricTaskInstance getHistoricTask(String id) {
316 return historyService.createHistoricTaskInstanceQuery().taskId(id).singleResult(); 364 return historyService.createHistoricTaskInstanceQuery().taskId(id).singleResult();
317 } 365 }
318 366
  367 + @Override
  368 + public List<BpmTaskSimpleRespVO> getReturnTaskList(String taskId) {
  369 + // 1. 校验当前任务 task 存在
  370 + Task task = getTask(taskId);
  371 + if (task == null) {
  372 + throw exception(TASK_NOT_EXISTS);
  373 + }
  374 + // 根据流程定义获取流程模型信息
  375 + BpmnModel bpmnModel = bpmModelService.getBpmnModelByDefinitionId(task.getProcessDefinitionId());
  376 + FlowElement source = BpmnModelUtils.getFlowElementById(bpmnModel, task.getTaskDefinitionKey());
  377 + if (source == null) {
  378 + throw exception(TASK_NOT_EXISTS);
  379 + }
  380 +
  381 + // 2.1 查询该任务的前置任务节点的 key 集合
  382 + List<UserTask> previousUserList = BpmnModelUtils.getPreviousUserTaskList(source, null, null);
  383 + if (CollUtil.isEmpty(previousUserList)) {
  384 + return Collections.emptyList();
  385 + }
  386 + // 2.2 过滤:只有串行可到达的节点,才可以回退。类似非串行、子流程无法退回
  387 + previousUserList.removeIf(userTask -> !BpmnModelUtils.isSequentialReachable(source, userTask, null));
  388 + return BpmTaskConvert.INSTANCE.convertList(previousUserList);
  389 + }
  390 +
  391 + @Override
  392 + @Transactional(rollbackFor = Exception.class)
  393 + public void returnTask(Long userId, BpmTaskReturnReqVO reqVO) {
  394 + // 1.1 当前任务 task
  395 + Task task = validateTask(userId, reqVO.getId());
  396 + if (task.isSuspended()) {
  397 + throw exception(TASK_IS_PENDING);
  398 + }
  399 + // 1.2 校验源头和目标节点的关系,并返回目标元素
  400 + FlowElement targetElement = validateTargetTaskCanReturn(task.getTaskDefinitionKey(), reqVO.getTargetDefinitionKey(), task.getProcessDefinitionId());
  401 +
  402 + // 2. 调用 flowable 框架的回退逻辑
  403 + returnTask0(task, targetElement, reqVO);
  404 +
  405 + // 3. 更新任务扩展表
  406 + taskExtMapper.updateByTaskId(new BpmTaskExtDO().setTaskId(task.getId())
  407 + .setResult(BpmProcessInstanceResultEnum.BACK.getResult())
  408 + .setEndTime(LocalDateTime.now()).setReason(reqVO.getReason()));
  409 + }
  410 +
  411 + /**
  412 + * 回退流程节点时,校验目标任务节点是否可回退
  413 + *
  414 + * @param sourceKey 当前任务节点 Key
  415 + * @param targetKey 目标任务节点 key
  416 + * @param processDefinitionId 当前流程定义 ID
  417 + * @return 目标任务节点元素
  418 + */
  419 + private FlowElement validateTargetTaskCanReturn(String sourceKey, String targetKey, String processDefinitionId) {
  420 + // 1.1 获取流程模型信息
  421 + BpmnModel bpmnModel = bpmModelService.getBpmnModelByDefinitionId(processDefinitionId);
  422 + // 1.3 获取当前任务节点元素
  423 + FlowElement source = BpmnModelUtils.getFlowElementById(bpmnModel, sourceKey);
  424 + // 1.3 获取跳转的节点元素
  425 + FlowElement target = BpmnModelUtils.getFlowElementById(bpmnModel, targetKey);
  426 + if (target == null) {
  427 + throw exception(TASK_TARGET_NODE_NOT_EXISTS);
  428 + }
  429 +
  430 + // 2.2 只有串行可到达的节点,才可以回退。类似非串行、子流程无法退回
  431 + if (!BpmnModelUtils.isSequentialReachable(source, target, null)) {
  432 + throw exception(TASK_RETURN_FAIL_SOURCE_TARGET_ERROR);
  433 + }
  434 + return target;
  435 + }
  436 +
  437 + /**
  438 + * 执行回退逻辑
  439 + *
  440 + * @param currentTask 当前回退的任务
  441 + * @param targetElement 需要回退到的目标任务
  442 + * @param reqVO 前端参数封装
  443 + */
  444 + public void returnTask0(Task currentTask, FlowElement targetElement, BpmTaskReturnReqVO reqVO) {
  445 + // 1. 获得所有需要回撤的任务 taskDefinitionKey,用于稍后的 moveActivityIdsToSingleActivityId 回撤
  446 + // 1.1 获取所有正常进行的任务节点 Key
  447 + List<Task> taskList = taskService.createTaskQuery().processInstanceId(currentTask.getProcessInstanceId()).list();
  448 + List<String> runTaskKeyList = convertList(taskList, Task::getTaskDefinitionKey);
  449 + // 1.2 通过 targetElement 的出口连线,计算在 runTaskKeyList 有哪些 key 需要被撤回
  450 + // 为什么不直接使用 runTaskKeyList 呢?因为可能存在多个审批分支,例如说:A -> B -> C 和 D -> F,而只要 C 撤回到 A,需要排除掉 F
  451 + List<UserTask> returnUserTaskList = BpmnModelUtils.iteratorFindChildUserTasks(targetElement, runTaskKeyList, null, null);
  452 + List<String> returnTaskKeyList = convertList(returnUserTaskList, UserTask::getId);
  453 +
  454 + // 2. 给当前要被回退的 task 数组,设置回退意见
  455 + taskList.forEach(task -> {
  456 + // 需要排除掉,不需要设置回退意见的任务
  457 + if (!returnTaskKeyList.contains(task.getTaskDefinitionKey())) {
  458 + return;
  459 + }
  460 + taskService.addComment(task.getId(), currentTask.getProcessInstanceId(),
  461 + BpmProcessInstanceResultEnum.BACK.getResult().toString(), reqVO.getReason());
  462 + });
  463 +
  464 + // 3. 执行驳回
  465 + runtimeService.createChangeActivityStateBuilder()
  466 + .processInstanceId(currentTask.getProcessInstanceId())
  467 + .moveActivityIdsToSingleActivityId(returnTaskKeyList, // 当前要跳转的节点列表( 1 或多)
  468 + reqVO.getTargetDefinitionKey()) // targetKey 跳转到的节点(1)
  469 + .changeState();
  470 + }
  471 +
  472 + @Override
  473 + @Transactional(rollbackFor = Exception.class)
  474 + public void delegateTask(BpmTaskDelegateReqVO reqVO, Long userId) {
  475 + // 1.1 校验任务
  476 + Task task = validateTaskCanDelegate(userId, reqVO);
  477 + // 1.2 校验目标用户存在
  478 + AdminUserRespDTO delegateUser = adminUserApi.getUser(reqVO.getDelegateUserId());
  479 + if (delegateUser == null) {
  480 + throw exception(TASK_DELEGATE_FAIL_USER_NOT_EXISTS);
  481 + }
  482 +
  483 + // 2. 添加审批意见
  484 + AdminUserRespDTO currentUser = adminUserApi.getUser(userId);
  485 + String comment = StrUtil.format("[{}]将任务委派给[{}],委派理由为:{}", currentUser.getNickname(),
  486 + delegateUser.getNickname(), reqVO.getReason());
  487 + String taskId = reqVO.getId();
  488 + // TODO 海:后面改;感觉 comment 应该 type 做个枚举;不和 result 耦合在一起;
  489 + taskService.addComment(taskId, task.getProcessInstanceId(),
  490 + BpmProcessInstanceResultEnum.DELEGATE.getResult().toString(), comment);
  491 +
  492 + // 3.1 设置任务所有人 (owner) 为原任务的处理人 (assignee)
  493 + taskService.setOwner(taskId, task.getAssignee());
  494 + // 3.2 执行委派,将任务委派给 receiveId
  495 + taskService.delegateTask(taskId, reqVO.getDelegateUserId().toString());
  496 + // 3.3 更新任务拓展表为【委派】
  497 + taskExtMapper.updateByTaskId(
  498 + new BpmTaskExtDO().setTaskId(task.getId()).setResult(BpmProcessInstanceResultEnum.DELEGATE.getResult())
  499 + .setReason(reqVO.getReason()));
  500 + }
  501 +
  502 + /**
  503 + * 校验任务委派参数
  504 + *
  505 + * @param userId 用户编号
  506 + * @param reqVO 任务编号,接收人ID
  507 + * @return 当前任务信息
  508 + */
  509 + private Task validateTaskCanDelegate(Long userId, BpmTaskDelegateReqVO reqVO) {
  510 + // 校验任务
  511 + Task task = validateTask(userId, reqVO.getId());
  512 + // 校验当前审批人和被委派人不是同一人
  513 + if (task.getAssignee().equals(reqVO.getDelegateUserId().toString())) {
  514 + throw exception(TASK_DELEGATE_FAIL_USER_REPEAT);
  515 + }
  516 + return task;
  517 + }
  518 +
319 } 519 }
yudao-module-infra/yudao-module-infra-api/src/main/java/cn/iocoder/yudao/module/infra/enums/ErrorCodeConstants.java
@@ -9,49 +9,49 @@ import cn.iocoder.yudao.framework.common.exception.ErrorCode; @@ -9,49 +9,49 @@ import cn.iocoder.yudao.framework.common.exception.ErrorCode;
9 */ 9 */
10 public interface ErrorCodeConstants { 10 public interface ErrorCodeConstants {
11 11
12 - // ========== 参数配置 1001000000 ==========  
13 - ErrorCode CONFIG_NOT_EXISTS = new ErrorCode(1001000001, "参数配置不存在");  
14 - ErrorCode CONFIG_KEY_DUPLICATE = new ErrorCode(1001000002, "参数配置 key 重复");  
15 - ErrorCode CONFIG_CAN_NOT_DELETE_SYSTEM_TYPE = new ErrorCode(1001000003, "不能删除类型为系统内置的参数配置");  
16 - ErrorCode CONFIG_GET_VALUE_ERROR_IF_VISIBLE = new ErrorCode(1001000004, "获取参数配置失败,原因:不允许获取不可见配置");  
17 -  
18 - // ========== 定时任务 1001001000 ==========  
19 - ErrorCode JOB_NOT_EXISTS = new ErrorCode(1001001000, "定时任务不存在");  
20 - ErrorCode JOB_HANDLER_EXISTS = new ErrorCode(1001001001, "定时任务的处理器已经存在");  
21 - ErrorCode JOB_CHANGE_STATUS_INVALID = new ErrorCode(1001001002, "只允许修改为开启或者关闭状态");  
22 - ErrorCode JOB_CHANGE_STATUS_EQUALS = new ErrorCode(1001001003, "定时任务已经处于该状态,无需修改");  
23 - ErrorCode JOB_UPDATE_ONLY_NORMAL_STATUS = new ErrorCode(1001001004, "只有开启状态的任务,才可以修改");  
24 - ErrorCode JOB_CRON_EXPRESSION_VALID = new ErrorCode(1001001005, "CRON 表达式不正确");  
25 -  
26 - // ========== API 错误日志 1001002000 ==========  
27 - ErrorCode API_ERROR_LOG_NOT_FOUND = new ErrorCode(1001002000, "API 错误日志不存在");  
28 - ErrorCode API_ERROR_LOG_PROCESSED = new ErrorCode(1001002001, "API 错误日志已处理");  
29 -  
30 - // ========= 文件相关 1001003000=================  
31 - ErrorCode FILE_PATH_EXISTS = new ErrorCode(1001003000, "文件路径已存在");  
32 - ErrorCode FILE_NOT_EXISTS = new ErrorCode(1001003001, "文件不存在");  
33 - ErrorCode FILE_IS_EMPTY = new ErrorCode(1001003002, "文件为空");  
34 -  
35 - // ========== 代码生成器 1001004000 ==========  
36 - ErrorCode CODEGEN_TABLE_EXISTS = new ErrorCode(1003001000, "表定义已经存在");  
37 - ErrorCode CODEGEN_IMPORT_TABLE_NULL = new ErrorCode(1003001001, "导入的表不存在");  
38 - ErrorCode CODEGEN_IMPORT_COLUMNS_NULL = new ErrorCode(1003001002, "导入的字段不存在");  
39 - ErrorCode CODEGEN_TABLE_NOT_EXISTS = new ErrorCode(1003001004, "表定义不存在");  
40 - ErrorCode CODEGEN_COLUMN_NOT_EXISTS = new ErrorCode(1003001005, "字段义不存在");  
41 - ErrorCode CODEGEN_SYNC_COLUMNS_NULL = new ErrorCode(1003001006, "同步的字段不存在");  
42 - ErrorCode CODEGEN_SYNC_NONE_CHANGE = new ErrorCode(1003001007, "同步失败,不存在改变");  
43 - ErrorCode CODEGEN_TABLE_INFO_TABLE_COMMENT_IS_NULL = new ErrorCode(1003001008, "数据库的表注释未填写");  
44 - ErrorCode CODEGEN_TABLE_INFO_COLUMN_COMMENT_IS_NULL = new ErrorCode(1003001009, "数据库的表字段({})注释未填写");  
45 -  
46 - // ========== 字典类型(测试)1001005000 ==========  
47 - ErrorCode TEST_DEMO_NOT_EXISTS = new ErrorCode(1001005000, "测试示例不存在");  
48 -  
49 - // ========== 文件配置 1001006000 ==========  
50 - ErrorCode FILE_CONFIG_NOT_EXISTS = new ErrorCode(1001006000, "文件配置不存在");  
51 - ErrorCode FILE_CONFIG_DELETE_FAIL_MASTER = new ErrorCode(1001006001, "该文件配置不允许删除,原因:它是主配置,删除会导致无法上传文件");  
52 -  
53 - // ========== 数据源配置 1001007000 ==========  
54 - ErrorCode DATA_SOURCE_CONFIG_NOT_EXISTS = new ErrorCode(1001007000, "数据源配置不存在");  
55 - ErrorCode DATA_SOURCE_CONFIG_NOT_OK = new ErrorCode(1001007001, "数据源配置不正确,无法进行连接"); 12 + // ========== 参数配置 1-001-000-000 ==========
  13 + ErrorCode CONFIG_NOT_EXISTS = new ErrorCode(1_001_000_001, "参数配置不存在");
  14 + ErrorCode CONFIG_KEY_DUPLICATE = new ErrorCode(1_001_000_002, "参数配置 key 重复");
  15 + ErrorCode CONFIG_CAN_NOT_DELETE_SYSTEM_TYPE = new ErrorCode(1_001_000_003, "不能删除类型为系统内置的参数配置");
  16 + ErrorCode CONFIG_GET_VALUE_ERROR_IF_VISIBLE = new ErrorCode(1_001_000_004, "获取参数配置失败,原因:不允许获取不可见配置");
  17 +
  18 + // ========== 定时任务 1-001-001-000 ==========
  19 + ErrorCode JOB_NOT_EXISTS = new ErrorCode(1_001_001_000, "定时任务不存在");
  20 + ErrorCode JOB_HANDLER_EXISTS = new ErrorCode(1_001_001_001, "定时任务的处理器已经存在");
  21 + ErrorCode JOB_CHANGE_STATUS_INVALID = new ErrorCode(1_001_001_002, "只允许修改为开启或者关闭状态");
  22 + ErrorCode JOB_CHANGE_STATUS_EQUALS = new ErrorCode(1_001_001_003, "定时任务已经处于该状态,无需修改");
  23 + ErrorCode JOB_UPDATE_ONLY_NORMAL_STATUS = new ErrorCode(1_001_001_004, "只有开启状态的任务,才可以修改");
  24 + ErrorCode JOB_CRON_EXPRESSION_VALID = new ErrorCode(1_001_001_005, "CRON 表达式不正确");
  25 +
  26 + // ========== API 错误日志 1-001-002-000 ==========
  27 + ErrorCode API_ERROR_LOG_NOT_FOUND = new ErrorCode(1_001_002_000, "API 错误日志不存在");
  28 + ErrorCode API_ERROR_LOG_PROCESSED = new ErrorCode(1_001_002_001, "API 错误日志已处理");
  29 +
  30 + // ========= 文件相关 1-001-003-000 =================
  31 + ErrorCode FILE_PATH_EXISTS = new ErrorCode(1_001_003_000, "文件路径已存在");
  32 + ErrorCode FILE_NOT_EXISTS = new ErrorCode(1_001_003_001, "文件不存在");
  33 + ErrorCode FILE_IS_EMPTY = new ErrorCode(1_001_003_002, "文件为空");
  34 +
  35 + // ========== 代码生成器 1-001-004-000 ==========
  36 + ErrorCode CODEGEN_TABLE_EXISTS = new ErrorCode(1_003_001_000, "表定义已经存在");
  37 + ErrorCode CODEGEN_IMPORT_TABLE_NULL = new ErrorCode(1_003_001_001, "导入的表不存在");
  38 + ErrorCode CODEGEN_IMPORT_COLUMNS_NULL = new ErrorCode(1_003_001_002, "导入的字段不存在");
  39 + ErrorCode CODEGEN_TABLE_NOT_EXISTS = new ErrorCode(1_003_001_004, "表定义不存在");
  40 + ErrorCode CODEGEN_COLUMN_NOT_EXISTS = new ErrorCode(1_003_001_005, "字段义不存在");
  41 + ErrorCode CODEGEN_SYNC_COLUMNS_NULL = new ErrorCode(1_003_001_006, "同步的字段不存在");
  42 + ErrorCode CODEGEN_SYNC_NONE_CHANGE = new ErrorCode(1_003_001_007, "同步失败,不存在改变");
  43 + ErrorCode CODEGEN_TABLE_INFO_TABLE_COMMENT_IS_NULL = new ErrorCode(1_003_001_008, "数据库的表注释未填写");
  44 + ErrorCode CODEGEN_TABLE_INFO_COLUMN_COMMENT_IS_NULL = new ErrorCode(1_003_001_009, "数据库的表字段({})注释未填写");
  45 +
  46 + // ========== 字典类型(测试)1-001-005-000 ==========
  47 + ErrorCode TEST_DEMO_NOT_EXISTS = new ErrorCode(1_001_005_000, "测试示例不存在");
  48 +
  49 + // ========== 文件配置 1-001-006-000 ==========
  50 + ErrorCode FILE_CONFIG_NOT_EXISTS = new ErrorCode(1_001_006_000, "文件配置不存在");
  51 + ErrorCode FILE_CONFIG_DELETE_FAIL_MASTER = new ErrorCode(1_001_006_001, "该文件配置不允许删除,原因:它是主配置,删除会导致无法上传文件");
  52 +
  53 + // ========== 数据源配置 1-001-007-000 ==========
  54 + ErrorCode DATA_SOURCE_CONFIG_NOT_EXISTS = new ErrorCode(1_001_007_000, "数据源配置不存在");
  55 + ErrorCode DATA_SOURCE_CONFIG_NOT_OK = new ErrorCode(1_001_007_001, "数据源配置不正确,无法进行连接");
56 56
57 } 57 }
yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/dal/mysql/file/FileConfigMapper.java
@@ -6,9 +6,6 @@ import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX; @@ -6,9 +6,6 @@ import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX;
6 import cn.iocoder.yudao.module.infra.controller.admin.file.vo.config.FileConfigPageReqVO; 6 import cn.iocoder.yudao.module.infra.controller.admin.file.vo.config.FileConfigPageReqVO;
7 import cn.iocoder.yudao.module.infra.dal.dataobject.file.FileConfigDO; 7 import cn.iocoder.yudao.module.infra.dal.dataobject.file.FileConfigDO;
8 import org.apache.ibatis.annotations.Mapper; 8 import org.apache.ibatis.annotations.Mapper;
9 -import org.apache.ibatis.annotations.Select;  
10 -  
11 -import java.time.LocalDateTime;  
12 9
13 @Mapper 10 @Mapper
14 public interface FileConfigMapper extends BaseMapperX<FileConfigDO> { 11 public interface FileConfigMapper extends BaseMapperX<FileConfigDO> {
@@ -21,7 +18,8 @@ public interface FileConfigMapper extends BaseMapperX&lt;FileConfigDO&gt; { @@ -21,7 +18,8 @@ public interface FileConfigMapper extends BaseMapperX&lt;FileConfigDO&gt; {
21 .orderByDesc(FileConfigDO::getId)); 18 .orderByDesc(FileConfigDO::getId));
22 } 19 }
23 20
24 - @Select("SELECT COUNT(*) FROM infra_file_config WHERE update_time > #{maxUpdateTime}")  
25 - Long selectCountByUpdateTimeGt(LocalDateTime maxUpdateTime); 21 + default FileConfigDO selectByMaster() {
  22 + return selectOne(FileConfigDO::getMaster, true);
  23 + }
26 24
27 } 25 }
yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/service/file/FileConfigServiceImpl.java
1 package cn.iocoder.yudao.module.infra.service.file; 1 package cn.iocoder.yudao.module.infra.service.file;
2 2
3 -import cn.hutool.core.collection.CollUtil;  
4 import cn.hutool.core.io.resource.ResourceUtil; 3 import cn.hutool.core.io.resource.ResourceUtil;
5 import cn.hutool.core.util.IdUtil; 4 import cn.hutool.core.util.IdUtil;
6 import cn.iocoder.yudao.framework.common.pojo.PageResult; 5 import cn.iocoder.yudao.framework.common.pojo.PageResult;
7 -import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils;  
8 import cn.iocoder.yudao.framework.common.util.json.JsonUtils; 6 import cn.iocoder.yudao.framework.common.util.json.JsonUtils;
9 import cn.iocoder.yudao.framework.common.util.validation.ValidationUtils; 7 import cn.iocoder.yudao.framework.common.util.validation.ValidationUtils;
10 import cn.iocoder.yudao.framework.file.core.client.FileClient; 8 import cn.iocoder.yudao.framework.file.core.client.FileClient;
@@ -17,22 +15,22 @@ import cn.iocoder.yudao.module.infra.controller.admin.file.vo.config.FileConfigU @@ -17,22 +15,22 @@ import cn.iocoder.yudao.module.infra.controller.admin.file.vo.config.FileConfigU
17 import cn.iocoder.yudao.module.infra.convert.file.FileConfigConvert; 15 import cn.iocoder.yudao.module.infra.convert.file.FileConfigConvert;
18 import cn.iocoder.yudao.module.infra.dal.dataobject.file.FileConfigDO; 16 import cn.iocoder.yudao.module.infra.dal.dataobject.file.FileConfigDO;
19 import cn.iocoder.yudao.module.infra.dal.mysql.file.FileConfigMapper; 17 import cn.iocoder.yudao.module.infra.dal.mysql.file.FileConfigMapper;
  18 +import com.google.common.cache.CacheLoader;
  19 +import com.google.common.cache.LoadingCache;
20 import lombok.Getter; 20 import lombok.Getter;
21 import lombok.extern.slf4j.Slf4j; 21 import lombok.extern.slf4j.Slf4j;
22 -import org.springframework.scheduling.annotation.Scheduled;  
23 import org.springframework.stereotype.Service; 22 import org.springframework.stereotype.Service;
24 import org.springframework.transaction.annotation.Transactional; 23 import org.springframework.transaction.annotation.Transactional;
25 import org.springframework.validation.annotation.Validated; 24 import org.springframework.validation.annotation.Validated;
26 25
27 -import javax.annotation.PostConstruct;  
28 import javax.annotation.Resource; 26 import javax.annotation.Resource;
29 import javax.validation.Validator; 27 import javax.validation.Validator;
30 -import java.time.LocalDateTime;  
31 -import java.util.List; 28 +import java.time.Duration;
32 import java.util.Map; 29 import java.util.Map;
33 -import java.util.concurrent.TimeUnit; 30 +import java.util.Objects;
34 31
35 import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; 32 import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
  33 +import static cn.iocoder.yudao.framework.common.util.cache.CacheUtils.buildAsyncReloadingCache;
36 import static cn.iocoder.yudao.module.infra.enums.ErrorCodeConstants.FILE_CONFIG_DELETE_FAIL_MASTER; 34 import static cn.iocoder.yudao.module.infra.enums.ErrorCodeConstants.FILE_CONFIG_DELETE_FAIL_MASTER;
37 import static cn.iocoder.yudao.module.infra.enums.ErrorCodeConstants.FILE_CONFIG_NOT_EXISTS; 35 import static cn.iocoder.yudao.module.infra.enums.ErrorCodeConstants.FILE_CONFIG_NOT_EXISTS;
38 36
@@ -46,19 +44,29 @@ import static cn.iocoder.yudao.module.infra.enums.ErrorCodeConstants.FILE_CONFIG @@ -46,19 +44,29 @@ import static cn.iocoder.yudao.module.infra.enums.ErrorCodeConstants.FILE_CONFIG
46 @Slf4j 44 @Slf4j
47 public class FileConfigServiceImpl implements FileConfigService { 45 public class FileConfigServiceImpl implements FileConfigService {
48 46
49 - @Resource  
50 - private FileClientFactory fileClientFactory; 47 + private static final Long CACHE_MASTER_ID = 0L;
51 48
52 /** 49 /**
53 - * 文件配置的缓存  
54 - */  
55 - @Getter  
56 - private List<FileConfigDO> fileConfigCache;  
57 - /**  
58 - * Master FileClient 对象,有且仅有一个,即 {@link FileConfigDO#getMaster()} 对应的 50 + * {@link FileClient} 缓存,通过它异步刷新 fileClientFactory
59 */ 51 */
60 @Getter 52 @Getter
61 - private FileClient masterFileClient; 53 + private final LoadingCache<Long, FileClient> clientCache = buildAsyncReloadingCache(Duration.ofSeconds(10L),
  54 + new CacheLoader<Long, FileClient>() {
  55 +
  56 + @Override
  57 + public FileClient load(Long id) {
  58 + FileConfigDO config = Objects.equals(CACHE_MASTER_ID, id) ?
  59 + fileConfigMapper.selectByMaster() : fileConfigMapper.selectById(id);
  60 + if (config != null) {
  61 + fileClientFactory.createOrUpdateFileClient(id, config.getStorage(), config.getConfig());
  62 + }
  63 + return fileClientFactory.getFileClient(id);
  64 + }
  65 +
  66 + });
  67 +
  68 + @Resource
  69 + private FileClientFactory fileClientFactory;
62 70
63 @Resource 71 @Resource
64 private FileConfigMapper fileConfigMapper; 72 private FileConfigMapper fileConfigMapper;
@@ -66,53 +74,12 @@ public class FileConfigServiceImpl implements FileConfigService { @@ -66,53 +74,12 @@ public class FileConfigServiceImpl implements FileConfigService {
66 @Resource 74 @Resource
67 private Validator validator; 75 private Validator validator;
68 76
69 - @PostConstruct  
70 - public void initLocalCache() {  
71 - // 第一步:查询数据  
72 - List<FileConfigDO> configs = fileConfigMapper.selectList();  
73 - log.info("[initLocalCache][缓存文件配置,数量为:{}]", configs.size());  
74 -  
75 - // 第二步:构建缓存:创建或更新文件 Client  
76 - configs.forEach(config -> {  
77 - fileClientFactory.createOrUpdateFileClient(config.getId(), config.getStorage(), config.getConfig());  
78 - // 如果是 master,进行设置  
79 - if (Boolean.TRUE.equals(config.getMaster())) {  
80 - masterFileClient = fileClientFactory.getFileClient(config.getId());  
81 - }  
82 - });  
83 - this.fileConfigCache = configs;  
84 - }  
85 -  
86 - /**  
87 - * 通过定时任务轮询,刷新缓存  
88 - *  
89 - * 目的:多节点部署时,通过轮询”通知“所有节点,进行刷新  
90 - */  
91 - @Scheduled(initialDelay = 60, fixedRate = 60, timeUnit = TimeUnit.SECONDS)  
92 - public void refreshLocalCache() {  
93 - // 情况一:如果缓存里没有数据,则直接刷新缓存  
94 - if (CollUtil.isEmpty(fileConfigCache)) {  
95 - initLocalCache();  
96 - return;  
97 - }  
98 -  
99 - // 情况二,如果缓存里数据,则通过 updateTime 判断是否有数据变更,有变更则刷新缓存  
100 - LocalDateTime maxTime = CollectionUtils.getMaxValue(fileConfigCache, FileConfigDO::getUpdateTime);  
101 - if (fileConfigMapper.selectCountByUpdateTimeGt(maxTime) > 0) {  
102 - initLocalCache();  
103 - }  
104 - }  
105 -  
106 @Override 77 @Override
107 public Long createFileConfig(FileConfigCreateReqVO createReqVO) { 78 public Long createFileConfig(FileConfigCreateReqVO createReqVO) {
108 - // 插入  
109 FileConfigDO fileConfig = FileConfigConvert.INSTANCE.convert(createReqVO) 79 FileConfigDO fileConfig = FileConfigConvert.INSTANCE.convert(createReqVO)
110 .setConfig(parseClientConfig(createReqVO.getStorage(), createReqVO.getConfig())) 80 .setConfig(parseClientConfig(createReqVO.getStorage(), createReqVO.getConfig()))
111 .setMaster(false); // 默认非 master 81 .setMaster(false); // 默认非 master
112 fileConfigMapper.insert(fileConfig); 82 fileConfigMapper.insert(fileConfig);
113 -  
114 - // 刷新缓存  
115 - initLocalCache();  
116 return fileConfig.getId(); 83 return fileConfig.getId();
117 } 84 }
118 85
@@ -125,8 +92,8 @@ public class FileConfigServiceImpl implements FileConfigService { @@ -125,8 +92,8 @@ public class FileConfigServiceImpl implements FileConfigService {
125 .setConfig(parseClientConfig(config.getStorage(), updateReqVO.getConfig())); 92 .setConfig(parseClientConfig(config.getStorage(), updateReqVO.getConfig()));
126 fileConfigMapper.updateById(updateObj); 93 fileConfigMapper.updateById(updateObj);
127 94
128 - // 刷新缓存  
129 - initLocalCache(); 95 + // 清空缓存
  96 + clearCache(config.getId(), null);
130 } 97 }
131 98
132 @Override 99 @Override
@@ -139,8 +106,8 @@ public class FileConfigServiceImpl implements FileConfigService { @@ -139,8 +106,8 @@ public class FileConfigServiceImpl implements FileConfigService {
139 // 更新 106 // 更新
140 fileConfigMapper.updateById(new FileConfigDO().setId(id).setMaster(true)); 107 fileConfigMapper.updateById(new FileConfigDO().setId(id).setMaster(true));
141 108
142 - // 刷新缓存  
143 - initLocalCache(); 109 + // 清空缓存
  110 + clearCache(null, true);
144 } 111 }
145 112
146 private FileClientConfig parseClientConfig(Integer storage, Map<String, Object> config) { 113 private FileClientConfig parseClientConfig(Integer storage, Map<String, Object> config) {
@@ -164,8 +131,23 @@ public class FileConfigServiceImpl implements FileConfigService { @@ -164,8 +131,23 @@ public class FileConfigServiceImpl implements FileConfigService {
164 // 删除 131 // 删除
165 fileConfigMapper.deleteById(id); 132 fileConfigMapper.deleteById(id);
166 133
167 - // 刷新缓存  
168 - initLocalCache(); 134 + // 清空缓存
  135 + clearCache(id, null);
  136 + }
  137 +
  138 + /**
  139 + * 清空指定文件配置
  140 + *
  141 + * @param id 配置编号
  142 + * @param master 是否主配置
  143 + */
  144 + private void clearCache(Long id, Boolean master) {
  145 + if (id != null) {
  146 + clientCache.invalidate(id);
  147 + }
  148 + if (Boolean.TRUE.equals(master)) {
  149 + clientCache.invalidate(CACHE_MASTER_ID);
  150 + }
169 } 151 }
170 152
171 private FileConfigDO validateFileConfigExists(Long id) { 153 private FileConfigDO validateFileConfigExists(Long id) {
@@ -192,12 +174,17 @@ public class FileConfigServiceImpl implements FileConfigService { @@ -192,12 +174,17 @@ public class FileConfigServiceImpl implements FileConfigService {
192 validateFileConfigExists(id); 174 validateFileConfigExists(id);
193 // 上传文件 175 // 上传文件
194 byte[] content = ResourceUtil.readBytes("file/erweima.jpg"); 176 byte[] content = ResourceUtil.readBytes("file/erweima.jpg");
195 - return fileClientFactory.getFileClient(id).upload(content, IdUtil.fastSimpleUUID() + ".jpg", "image/jpeg"); 177 + return getFileClient(id).upload(content, IdUtil.fastSimpleUUID() + ".jpg", "image/jpeg");
196 } 178 }
197 179
198 @Override 180 @Override
199 public FileClient getFileClient(Long id) { 181 public FileClient getFileClient(Long id) {
200 - return fileClientFactory.getFileClient(id); 182 + return clientCache.getUnchecked(id);
  183 + }
  184 +
  185 + @Override
  186 + public FileClient getMasterFileClient() {
  187 + return clientCache.getUnchecked(CACHE_MASTER_ID);
201 } 188 }
202 189
203 } 190 }
yudao-module-infra/yudao-module-infra-biz/src/main/resources/codegen/vue3_vben/api/api.ts.vm
@@ -3,27 +3,27 @@ import { defHttp } from &#39;@/utils/http/axios&#39; @@ -3,27 +3,27 @@ import { defHttp } from &#39;@/utils/http/axios&#39;
3 3
4 // 查询${table.classComment}列表 4 // 查询${table.classComment}列表
5 export function get${simpleClassName}Page(params) { 5 export function get${simpleClassName}Page(params) {
6 - return defHttp.get({ url: '${baseURL}/page', params }) 6 + return defHttp.get({ url: '${baseURL}/page', params })
7 } 7 }
8 8
9 // 查询${table.classComment}详情 9 // 查询${table.classComment}详情
10 export function get${simpleClassName}(id: number) { 10 export function get${simpleClassName}(id: number) {
11 - return defHttp.get({ url: '${baseURL}/get?id=' + id }) 11 + return defHttp.get({ url: `${baseURL}/get?id=${id}` })
12 } 12 }
13 13
14 // 新增${table.classComment} 14 // 新增${table.classComment}
15 export function create${simpleClassName}(data) { 15 export function create${simpleClassName}(data) {
16 - return defHttp.post({ url: '${baseURL}/create', data }) 16 + return defHttp.post({ url: '${baseURL}/create', data })
17 } 17 }
18 18
19 // 修改${table.classComment} 19 // 修改${table.classComment}
20 export function update${simpleClassName}(data) { 20 export function update${simpleClassName}(data) {
21 - return defHttp.put({ url: '${baseURL}/update', data }) 21 + return defHttp.put({ url: '${baseURL}/update', data })
22 } 22 }
23 23
24 // 删除${table.classComment} 24 // 删除${table.classComment}
25 export function delete${simpleClassName}(id: number) { 25 export function delete${simpleClassName}(id: number) {
26 - return defHttp.delete({ url: '${baseURL}/delete?id=' + id }) 26 + return defHttp.delete({ url: `${baseURL}/delete?id=${id}` })
27 } 27 }
28 28
29 // 导出${table.classComment} Excel 29 // 导出${table.classComment} Excel
yudao-module-infra/yudao-module-infra-biz/src/main/resources/codegen/vue3_vben/views/data.ts.vm
1 -import { BasicColumn, FormSchema, useRender } from '@/components/Table' 1 +import type { BasicColumn, FormSchema } from '@/components/Table'
  2 +import { useRender } from '@/components/Table'
2 import { DICT_TYPE, getDictOptions } from '@/utils/dict' 3 import { DICT_TYPE, getDictOptions } from '@/utils/dict'
3 4
4 export const columns: BasicColumn[] = [ 5 export const columns: BasicColumn[] = [
@@ -92,13 +93,13 @@ export const createFormSchema: FormSchema[] = [ @@ -92,13 +93,13 @@ export const createFormSchema: FormSchema[] = [
92 #elseif($column.htmlType == "imageUpload")## 图片上传 93 #elseif($column.htmlType == "imageUpload")## 图片上传
93 component: 'FileUpload', 94 component: 'FileUpload',
94 componentProps: { 95 componentProps: {
95 - fileType: 'file', 96 + fileType: 'image',
96 maxCount: 1, 97 maxCount: 1,
97 }, 98 },
98 #elseif($column.htmlType == "fileUpload")## 文件上传 99 #elseif($column.htmlType == "fileUpload")## 文件上传
99 component: 'FileUpload', 100 component: 'FileUpload',
100 componentProps: { 101 componentProps: {
101 - fileType: 'image', 102 + fileType: 'file',
102 maxCount: 1, 103 maxCount: 1,
103 }, 104 },
104 #elseif($column.htmlType == "editor")## 文本编辑器 105 #elseif($column.htmlType == "editor")## 文本编辑器
@@ -132,6 +133,11 @@ export const createFormSchema: FormSchema[] = [ @@ -132,6 +133,11 @@ export const createFormSchema: FormSchema[] = [
132 }, 133 },
133 #elseif($column.htmlType == "datetime")## 时间框 134 #elseif($column.htmlType == "datetime")## 时间框
134 component: 'DatePicker', 135 component: 'DatePicker',
  136 + componentProps: {
  137 + showTime: true,
  138 + format: 'YYYY-MM-DD HH:mm:ss',
  139 + valueFormat: 'x',
  140 + },
135 #elseif($column.htmlType == "textarea")## 文本域 141 #elseif($column.htmlType == "textarea")## 文本域
136 component: 'InputTextArea', 142 component: 'InputTextArea',
137 #end 143 #end
@@ -154,7 +160,7 @@ export const updateFormSchema: FormSchema[] = [ @@ -154,7 +160,7 @@ export const updateFormSchema: FormSchema[] = [
154 #set ($javaField = $column.javaField) 160 #set ($javaField = $column.javaField)
155 #set ($AttrName = $column.javaField.substring(0,1).toUpperCase() + ${column.javaField.substring(1)}) 161 #set ($AttrName = $column.javaField.substring(0,1).toUpperCase() + ${column.javaField.substring(1)})
156 #set ($comment = $column.columnComment) 162 #set ($comment = $column.columnComment)
157 -#if (!$column.primaryKey)## 忽略主键,不用在表单里 163 + #if (!$column.primaryKey)## 忽略主键,不用在表单里
158 { 164 {
159 label: '${comment}', 165 label: '${comment}',
160 field: '${javaField}', 166 field: '${javaField}',
@@ -164,45 +170,57 @@ export const updateFormSchema: FormSchema[] = [ @@ -164,45 +170,57 @@ export const updateFormSchema: FormSchema[] = [
164 #if ($column.htmlType == "input") 170 #if ($column.htmlType == "input")
165 component: 'Input', 171 component: 'Input',
166 #elseif($column.htmlType == "imageUpload")## 图片上传 172 #elseif($column.htmlType == "imageUpload")## 图片上传
167 - component: 'Upload', 173 + component: 'FileUpload',
  174 + componentProps: {
  175 + fileType: 'image',
  176 + maxCount: 1,
  177 + },
168 #elseif($column.htmlType == "fileUpload")## 文件上传 178 #elseif($column.htmlType == "fileUpload")## 文件上传
169 - component: 'Upload',  
170 - #elseif($column.htmlType == "editor")## 文本编辑器  
171 - component: 'Editor', 179 + component: 'FileUpload',
  180 + componentProps: {
  181 + fileType: 'file',
  182 + maxCount: 1,
  183 + },
  184 + #elseif($column.htmlType == "editor")## 文本编辑器component: 'Editor',
172 #elseif($column.htmlType == "select")## 下拉框 185 #elseif($column.htmlType == "select")## 下拉框
173 component: 'Select', 186 component: 'Select',
174 componentProps: { 187 componentProps: {
175 #if ("" != $dictType)## 有数据字典 188 #if ("" != $dictType)## 有数据字典
176 - options: getDictOptions(DICT_TYPE.$dictType.toUpperCase(), 'number'), 189 + options: getDictOptions(DICT_TYPE.$dictType.toUpperCase(), 'number'),
177 #else##没数据字典 190 #else##没数据字典
178 - options:[], 191 + options:[],
179 #end 192 #end
180 }, 193 },
181 #elseif($column.htmlType == "checkbox")## 多选框 194 #elseif($column.htmlType == "checkbox")## 多选框
182 component: 'Checkbox', 195 component: 'Checkbox',
183 componentProps: { 196 componentProps: {
184 #if ("" != $dictType)## 有数据字典 197 #if ("" != $dictType)## 有数据字典
185 - options: getDictOptions(DICT_TYPE.$dictType.toUpperCase(), 'number'), 198 + options: getDictOptions(DICT_TYPE.$dictType.toUpperCase(), 'number'),
186 #else##没数据字典 199 #else##没数据字典
187 - options:[], 200 + options:[],
188 #end 201 #end
189 }, 202 },
190 #elseif($column.htmlType == "radio")## 单选框 203 #elseif($column.htmlType == "radio")## 单选框
191 component: 'RadioButtonGroup', 204 component: 'RadioButtonGroup',
192 componentProps: { 205 componentProps: {
193 #if ("" != $dictType)## 有数据字典 206 #if ("" != $dictType)## 有数据字典
194 - options: getDictOptions(DICT_TYPE.$dictType.toUpperCase(), 'number'), 207 + options: getDictOptions(DICT_TYPE.$dictType.toUpperCase(), 'number'),
195 #else##没数据字典 208 #else##没数据字典
196 - options:[], 209 + options:[],
197 #end 210 #end
198 }, 211 },
199 #elseif($column.htmlType == "datetime")## 时间框 212 #elseif($column.htmlType == "datetime")## 时间框
200 component: 'DatePicker', 213 component: 'DatePicker',
  214 + componentProps: {
  215 + showTime: true,
  216 + format: 'YYYY-MM-DD HH:mm:ss',
  217 + valueFormat: 'x',
  218 + },
201 #elseif($column.htmlType == "textarea")## 文本域 219 #elseif($column.htmlType == "textarea")## 文本域
202 component: 'InputTextArea', 220 component: 'InputTextArea',
203 #end 221 #end
204 }, 222 },
205 -#end 223 + #end
206 #end 224 #end
207 #end 225 #end
208 ] 226 ]
209 \ No newline at end of file 227 \ No newline at end of file
yudao-module-infra/yudao-module-infra-biz/src/main/resources/codegen/vue3_vben/views/form.vue.vm
@@ -9,9 +9,10 @@ import { create${simpleClassName}, get${simpleClassName}, update${simpleClassNam @@ -9,9 +9,10 @@ import { create${simpleClassName}, get${simpleClassName}, update${simpleClassNam
9 9
10 defineOptions({ name: '${table.className}Modal' }) 10 defineOptions({ name: '${table.className}Modal' })
11 11
  12 +const emit = defineEmits(['success', 'register'])
  13 +
12 const { t } = useI18n() 14 const { t } = useI18n()
13 const { createMessage } = useMessage() 15 const { createMessage } = useMessage()
14 -const emit = defineEmits(['success', 'register'])  
15 const isUpdate = ref(true) 16 const isUpdate = ref(true)
16 17
17 const [registerForm, { setFieldsValue, resetFields, resetSchema, validate }] = useForm({ 18 const [registerForm, { setFieldsValue, resetFields, resetSchema, validate }] = useForm({
@@ -37,11 +38,11 @@ async function handleSubmit() { @@ -37,11 +38,11 @@ async function handleSubmit() {
37 try { 38 try {
38 const values = await validate() 39 const values = await validate()
39 setModalProps({ confirmLoading: true }) 40 setModalProps({ confirmLoading: true })
40 - if (unref(isUpdate)) { 41 + if (unref(isUpdate))
41 await update${simpleClassName}(values) 42 await update${simpleClassName}(values)
42 - } else { 43 + else
43 await create${simpleClassName}(values) 44 await create${simpleClassName}(values)
44 - } 45 +
45 closeModal() 46 closeModal()
46 emit('success') 47 emit('success')
47 createMessage.success(t('common.saveSuccessText')) 48 createMessage.success(t('common.saveSuccessText'))
@@ -51,7 +52,7 @@ async function handleSubmit() { @@ -51,7 +52,7 @@ async function handleSubmit() {
51 } 52 }
52 </script> 53 </script>
53 <template> 54 <template>
54 - <BasicModal v-bind="$attrs" @register="registerModal" :title="isUpdate ? t('action.edit') : t('action.create')" @ok="handleSubmit"> 55 + <BasicModal v-bind="$attrs" :title="isUpdate ? t('action.edit') : t('action.create')" @register="registerModal" @ok="handleSubmit">
55 <BasicForm @register="registerForm" /> 56 <BasicForm @register="registerForm" />
56 </BasicModal> 57 </BasicModal>
57 </template> 58 </template>
58 \ No newline at end of file 59 \ No newline at end of file
yudao-module-infra/yudao-module-infra-biz/src/main/resources/codegen/vue3_vben/views/index.vue.vm
1 <script lang="ts" setup> 1 <script lang="ts" setup>
2 -import ${simpleClassName}Modal from './${simpleClassName}Modal.vue' 2 +import ${ simpleClassName }Modal from './${simpleClassName}Modal.vue'
3 import { columns, searchFormSchema } from './${classNameVar}.data' 3 import { columns, searchFormSchema } from './${classNameVar}.data'
4 import { useI18n } from '@/hooks/web/useI18n' 4 import { useI18n } from '@/hooks/web/useI18n'
5 import { useMessage } from '@/hooks/web/useMessage' 5 import { useMessage } from '@/hooks/web/useMessage'
6 import { useModal } from '@/components/Modal' 6 import { useModal } from '@/components/Modal'
7 import { IconEnum } from '@/enums/appEnum' 7 import { IconEnum } from '@/enums/appEnum'
8 import { BasicTable, useTable, TableAction } from '@/components/Table' 8 import { BasicTable, useTable, TableAction } from '@/components/Table'
9 -import { delete${simpleClassName}, export${simpleClassName}, get${simpleClassName}Page } from '@/api/${table.moduleName}/${classNameVar}' 9 +import { delete${ simpleClassName }, export${ simpleClassName }, get${ simpleClassName } Page } from '@/api/${table.moduleName}/${classNameVar}'
10 10
11 defineOptions({ name: '${table.className}' }) 11 defineOptions({ name: '${table.className}' })
12 12
@@ -16,17 +16,17 @@ const [registerModal, { openModal }] = useModal() @@ -16,17 +16,17 @@ const [registerModal, { openModal }] = useModal()
16 16
17 const [registerTable, { getForm, reload }] = useTable({ 17 const [registerTable, { getForm, reload }] = useTable({
18 title: '${table.classComment}列表', 18 title: '${table.classComment}列表',
19 - api: get${simpleClassName}Page,  
20 - columns,  
21 - formConfig: { labelWidth: 120, schemas: searchFormSchema },  
22 - useSearchForm: true,  
23 - showTableSetting: true,  
24 - actionColumn: {  
25 - width: 140,  
26 - title: t('common.action'),  
27 - dataIndex: 'action',  
28 - fixed: 'right',  
29 - }, 19 + api: get${ simpleClassName }Page,
  20 + columns,
  21 + formConfig: { labelWidth: 120, schemas: searchFormSchema },
  22 + useSearchForm: true,
  23 + showTableSetting: true,
  24 + actionColumn: {
  25 + width: 140,
  26 + title: t('common.action'),
  27 + dataIndex: 'action',
  28 + fixed: 'right',
  29 + },
30 }) 30 })
31 31
32 function handleCreate() { 32 function handleCreate() {
@@ -43,14 +43,14 @@ async function handleExport() { @@ -43,14 +43,14 @@ async function handleExport() {
43 iconType: 'warning', 43 iconType: 'warning',
44 content: t('common.exportMessage'), 44 content: t('common.exportMessage'),
45 async onOk() { 45 async onOk() {
46 - await export${simpleClassName}(getForm().getFieldsValue()) 46 + await export${ simpleClassName } (getForm().getFieldsValue())
47 createMessage.success(t('common.exportSuccessText')) 47 createMessage.success(t('common.exportSuccessText'))
48 }, 48 },
49 }) 49 })
50 } 50 }
51 51
52 async function handleDelete(record: Recordable) { 52 async function handleDelete(record: Recordable) {
53 - await delete${simpleClassName}(record.id) 53 + await delete${ simpleClassName } (record.id)
54 createMessage.success(t('common.delSuccessText')) 54 createMessage.success(t('common.delSuccessText'))
55 reload() 55 reload()
56 } 56 }
@@ -89,4 +89,4 @@ async function handleDelete(record: Recordable) { @@ -89,4 +89,4 @@ async function handleDelete(record: Recordable) {
89 </BasicTable> 89 </BasicTable>
90 <${simpleClassName}Modal @register="registerModal" @success="reload()" /> 90 <${simpleClassName}Modal @register="registerModal" @success="reload()" />
91 </div> 91 </div>
92 -</template>  
93 \ No newline at end of file 92 \ No newline at end of file
  93 +</template>
yudao-module-infra/yudao-module-infra-biz/src/test/java/cn/iocoder/yudao/module/infra/service/file/FileConfigServiceImplTest.java
@@ -60,31 +60,6 @@ public class FileConfigServiceImplTest extends BaseDbUnitTest { @@ -60,31 +60,6 @@ public class FileConfigServiceImplTest extends BaseDbUnitTest {
60 private FileClientFactory fileClientFactory; 60 private FileClientFactory fileClientFactory;
61 61
62 @Test 62 @Test
63 - public void testInitLocalCache() {  
64 - // mock 数据  
65 - FileConfigDO configDO1 = randomFileConfigDO().setId(1L).setMaster(true);  
66 - fileConfigMapper.insert(configDO1);  
67 - FileConfigDO configDO2 = randomFileConfigDO().setId(2L).setMaster(false);  
68 - fileConfigMapper.insert(configDO2);  
69 - // mock fileClientFactory 获得 master  
70 - FileClient masterFileClient = mock(FileClient.class);  
71 - when(fileClientFactory.getFileClient(eq(1L))).thenReturn(masterFileClient);  
72 -  
73 - // 调用  
74 - fileConfigService.initLocalCache();  
75 - // 断言 fileClientFactory 调用  
76 - verify(fileClientFactory).createOrUpdateFileClient(eq(1L),  
77 - eq(configDO1.getStorage()), eq(configDO1.getConfig()));  
78 - verify(fileClientFactory).createOrUpdateFileClient(eq(2L),  
79 - eq(configDO2.getStorage()), eq(configDO2.getConfig()));  
80 - assertSame(masterFileClient, fileConfigService.getMasterFileClient());  
81 - // 断言 fileConfigCache 缓存  
82 - assertEquals(2, fileConfigService.getFileConfigCache().size());  
83 - assertEquals(configDO1, fileConfigService.getFileConfigCache().get(0));  
84 - assertEquals(configDO2, fileConfigService.getFileConfigCache().get(1));  
85 - }  
86 -  
87 - @Test  
88 public void testCreateFileConfig_success() { 63 public void testCreateFileConfig_success() {
89 // 准备参数 64 // 准备参数
90 Map<String, Object> config = MapUtil.<String, Object>builder().put("basePath", "/yunai") 65 Map<String, Object> config = MapUtil.<String, Object>builder().put("basePath", "/yunai")
@@ -102,6 +77,8 @@ public class FileConfigServiceImplTest extends BaseDbUnitTest { @@ -102,6 +77,8 @@ public class FileConfigServiceImplTest extends BaseDbUnitTest {
102 assertFalse(fileConfig.getMaster()); 77 assertFalse(fileConfig.getMaster());
103 assertEquals("/yunai", ((LocalFileClientConfig) fileConfig.getConfig()).getBasePath()); 78 assertEquals("/yunai", ((LocalFileClientConfig) fileConfig.getConfig()).getBasePath());
104 assertEquals("https://www.iocoder.cn", ((LocalFileClientConfig) fileConfig.getConfig()).getDomain()); 79 assertEquals("https://www.iocoder.cn", ((LocalFileClientConfig) fileConfig.getConfig()).getDomain());
  80 + // 验证 cache
  81 + assertNull(fileConfigService.getClientCache().getIfPresent(fileConfigId));
105 } 82 }
106 83
107 @Test 84 @Test
@@ -125,6 +102,8 @@ public class FileConfigServiceImplTest extends BaseDbUnitTest { @@ -125,6 +102,8 @@ public class FileConfigServiceImplTest extends BaseDbUnitTest {
125 assertPojoEquals(reqVO, fileConfig, "config"); 102 assertPojoEquals(reqVO, fileConfig, "config");
126 assertEquals("/yunai2", ((LocalFileClientConfig) fileConfig.getConfig()).getBasePath()); 103 assertEquals("/yunai2", ((LocalFileClientConfig) fileConfig.getConfig()).getBasePath());
127 assertEquals("https://doc.iocoder.cn", ((LocalFileClientConfig) fileConfig.getConfig()).getDomain()); 104 assertEquals("https://doc.iocoder.cn", ((LocalFileClientConfig) fileConfig.getConfig()).getDomain());
  105 + // 验证 cache
  106 + assertNull(fileConfigService.getClientCache().getIfPresent(fileConfig.getId()));
128 } 107 }
129 108
130 @Test 109 @Test
@@ -149,6 +128,8 @@ public class FileConfigServiceImplTest extends BaseDbUnitTest { @@ -149,6 +128,8 @@ public class FileConfigServiceImplTest extends BaseDbUnitTest {
149 // 断言数据 128 // 断言数据
150 assertTrue(fileConfigMapper.selectById(dbFileConfig.getId()).getMaster()); 129 assertTrue(fileConfigMapper.selectById(dbFileConfig.getId()).getMaster());
151 assertFalse(fileConfigMapper.selectById(masterFileConfig.getId()).getMaster()); 130 assertFalse(fileConfigMapper.selectById(masterFileConfig.getId()).getMaster());
  131 + // 验证 cache
  132 + assertNull(fileConfigService.getClientCache().getIfPresent(0L));
152 } 133 }
153 134
154 @Test 135 @Test
@@ -169,6 +150,8 @@ public class FileConfigServiceImplTest extends BaseDbUnitTest { @@ -169,6 +150,8 @@ public class FileConfigServiceImplTest extends BaseDbUnitTest {
169 fileConfigService.deleteFileConfig(id); 150 fileConfigService.deleteFileConfig(id);
170 // 校验数据不存在了 151 // 校验数据不存在了
171 assertNull(fileConfigMapper.selectById(id)); 152 assertNull(fileConfigMapper.selectById(id));
  153 + // 验证 cache
  154 + assertNull(fileConfigService.getClientCache().getIfPresent(id));
172 } 155 }
173 156
174 @Test 157 @Test
@@ -250,14 +233,38 @@ public class FileConfigServiceImplTest extends BaseDbUnitTest { @@ -250,14 +233,38 @@ public class FileConfigServiceImplTest extends BaseDbUnitTest {
250 233
251 @Test 234 @Test
252 public void testGetFileClient() { 235 public void testGetFileClient() {
  236 + // mock 数据
  237 + FileConfigDO fileConfig = randomFileConfigDO().setMaster(false);
  238 + fileConfigMapper.insert(fileConfig);
253 // 准备参数 239 // 准备参数
254 - Long id = randomLongId(); 240 + Long id = fileConfig.getId();
255 // mock 获得 Client 241 // mock 获得 Client
256 FileClient fileClient = new LocalFileClient(id, new LocalFileClientConfig()); 242 FileClient fileClient = new LocalFileClient(id, new LocalFileClientConfig());
257 when(fileClientFactory.getFileClient(eq(id))).thenReturn(fileClient); 243 when(fileClientFactory.getFileClient(eq(id))).thenReturn(fileClient);
258 244
259 // 调用,并断言 245 // 调用,并断言
260 assertSame(fileClient, fileConfigService.getFileClient(id)); 246 assertSame(fileClient, fileConfigService.getFileClient(id));
  247 + // 断言缓存
  248 + verify(fileClientFactory).createOrUpdateFileClient(eq(id), eq(fileConfig.getStorage()),
  249 + eq(fileConfig.getConfig()));
  250 + }
  251 +
  252 + @Test
  253 + public void testGetMasterFileClient() {
  254 + // mock 数据
  255 + FileConfigDO fileConfig = randomFileConfigDO().setMaster(true);
  256 + fileConfigMapper.insert(fileConfig);
  257 + // 准备参数
  258 + Long id = fileConfig.getId();
  259 + // mock 获得 Client
  260 + FileClient fileClient = new LocalFileClient(id, new LocalFileClientConfig());
  261 + when(fileClientFactory.getFileClient(eq(0L))).thenReturn(fileClient);
  262 +
  263 + // 调用,并断言
  264 + assertSame(fileClient, fileConfigService.getMasterFileClient());
  265 + // 断言缓存
  266 + verify(fileClientFactory).createOrUpdateFileClient(eq(0L), eq(fileConfig.getStorage()),
  267 + eq(fileConfig.getConfig()));
261 } 268 }
262 269
263 private FileConfigDO randomFileConfigDO() { 270 private FileConfigDO randomFileConfigDO() {
yudao-module-infra/yudao-module-infra-biz/src/test/java/cn/iocoder/yudao/module/infra/service/file/FileServiceImplTest.java
@@ -139,4 +139,5 @@ public class FileServiceImplTest extends BaseDbUnitTest { @@ -139,4 +139,5 @@ public class FileServiceImplTest extends BaseDbUnitTest {
139 // 断言 139 // 断言
140 assertSame(result, content); 140 assertSame(result, content);
141 } 141 }
  142 +
142 } 143 }
yudao-module-mall/yudao-module-product-api/src/main/java/cn/iocoder/yudao/module/product/enums/ErrorCodeConstants.java
@@ -9,47 +9,47 @@ import cn.iocoder.yudao.framework.common.exception.ErrorCode; @@ -9,47 +9,47 @@ import cn.iocoder.yudao.framework.common.exception.ErrorCode;
9 */ 9 */
10 public interface ErrorCodeConstants { 10 public interface ErrorCodeConstants {
11 11
12 - // ========== 商品分类相关 1008001000 ============  
13 - ErrorCode CATEGORY_NOT_EXISTS = new ErrorCode(1008001000, "商品分类不存在");  
14 - ErrorCode CATEGORY_PARENT_NOT_EXISTS = new ErrorCode(1008001001, "父分类不存在");  
15 - ErrorCode CATEGORY_PARENT_NOT_FIRST_LEVEL = new ErrorCode(1008001002, "父分类不能是二级分类");  
16 - ErrorCode CATEGORY_EXISTS_CHILDREN = new ErrorCode(1008001003, "存在子分类,无法删除");  
17 - ErrorCode CATEGORY_DISABLED = new ErrorCode(1008001004, "商品分类({})已禁用,无法使用");  
18 - ErrorCode CATEGORY_HAVE_BIND_SPU = new ErrorCode(1008001005, "类别下存在商品,无法删除");  
19 -  
20 - // ========== 商品品牌相关编号 1008002000 ==========  
21 - ErrorCode BRAND_NOT_EXISTS = new ErrorCode(1008002000, "品牌不存在");  
22 - ErrorCode BRAND_DISABLED = new ErrorCode(1008002001, "品牌已禁用");  
23 - ErrorCode BRAND_NAME_EXISTS = new ErrorCode(1008002002, "品牌名称已存在");  
24 -  
25 - // ========== 商品属性项 1008003000 ==========  
26 - ErrorCode PROPERTY_NOT_EXISTS = new ErrorCode(1008003000, "属性项不存在");  
27 - ErrorCode PROPERTY_EXISTS = new ErrorCode(1008003001, "属性项的名称已存在");  
28 - ErrorCode PROPERTY_DELETE_FAIL_VALUE_EXISTS = new ErrorCode(1008003002, "属性项下存在属性值,无法删除");  
29 -  
30 - // ========== 商品属性值 1008004000 ==========  
31 - ErrorCode PROPERTY_VALUE_NOT_EXISTS = new ErrorCode(1008004000, "属性值不存在");  
32 - ErrorCode PROPERTY_VALUE_EXISTS = new ErrorCode(1008004001, "属性值的名称已存在");  
33 -  
34 - // ========== 商品 SPU 1008005000 ==========  
35 - ErrorCode SPU_NOT_EXISTS = new ErrorCode(1008005000, "商品 SPU 不存在");  
36 - ErrorCode SPU_SAVE_FAIL_CATEGORY_LEVEL_ERROR = new ErrorCode(1008005001, "商品分类不正确,原因:必须使用第二级的商品分类及以下");  
37 - ErrorCode SPU_NOT_ENABLE = new ErrorCode(1008005002, "商品 SPU 不处于上架状态");  
38 - ErrorCode SPU_NOT_RECYCLE = new ErrorCode(1008005003, "商品 SPU 不处于回收站状态");  
39 -  
40 - // ========== 商品 SKU 1008006000 ==========  
41 - ErrorCode SKU_NOT_EXISTS = new ErrorCode(1008006000, "商品 SKU 不存在");  
42 - ErrorCode SKU_PROPERTIES_DUPLICATED = new ErrorCode(1008006001, "商品 SKU 的属性组合存在重复");  
43 - ErrorCode SPU_ATTR_NUMBERS_MUST_BE_EQUALS = new ErrorCode(1008006002, "一个 SPU 下的每个 SKU,其属性项必须一致");  
44 - ErrorCode SPU_SKU_NOT_DUPLICATE = new ErrorCode(1008006003, "一个 SPU 下的每个 SKU,必须不重复");  
45 - ErrorCode SKU_STOCK_NOT_ENOUGH = new ErrorCode(1008006004, "商品 SKU 库存不足");  
46 -  
47 - // ========== 商品 评价 1008007000 ==========  
48 - ErrorCode COMMENT_NOT_EXISTS = new ErrorCode(1008007000, "商品评价不存在");  
49 - ErrorCode COMMENT_ORDER_EXISTS = new ErrorCode(1008007001, "订单的商品评价已存在");  
50 -  
51 - // ========== 商品 收藏 1008008000 ==========  
52 - ErrorCode FAVORITE_EXISTS = new ErrorCode(1008008000, "该商品已经被收藏");  
53 - ErrorCode FAVORITE_NOT_EXISTS = new ErrorCode(1008008001, "商品收藏不存在"); 12 + // ========== 商品分类相关 1-008-001-000 ============
  13 + ErrorCode CATEGORY_NOT_EXISTS = new ErrorCode(1_008_001_000, "商品分类不存在");
  14 + ErrorCode CATEGORY_PARENT_NOT_EXISTS = new ErrorCode(1_008_001_001, "父分类不存在");
  15 + ErrorCode CATEGORY_PARENT_NOT_FIRST_LEVEL = new ErrorCode(1_008_001_002, "父分类不能是二级分类");
  16 + ErrorCode CATEGORY_EXISTS_CHILDREN = new ErrorCode(1_008_001_003, "存在子分类,无法删除");
  17 + ErrorCode CATEGORY_DISABLED = new ErrorCode(1_008_001_004, "商品分类({})已禁用,无法使用");
  18 + ErrorCode CATEGORY_HAVE_BIND_SPU = new ErrorCode(1_008_001_005, "类别下存在商品,无法删除");
  19 +
  20 + // ========== 商品品牌相关编号 1-008-002-000 ==========
  21 + ErrorCode BRAND_NOT_EXISTS = new ErrorCode(1_008_002_000, "品牌不存在");
  22 + ErrorCode BRAND_DISABLED = new ErrorCode(1_008_002_001, "品牌已禁用");
  23 + ErrorCode BRAND_NAME_EXISTS = new ErrorCode(1_008_002_002, "品牌名称已存在");
  24 +
  25 + // ========== 商品属性项 1-008-003-000 ==========
  26 + ErrorCode PROPERTY_NOT_EXISTS = new ErrorCode(1_008_003_000, "属性项不存在");
  27 + ErrorCode PROPERTY_EXISTS = new ErrorCode(1_008_003_001, "属性项的名称已存在");
  28 + ErrorCode PROPERTY_DELETE_FAIL_VALUE_EXISTS = new ErrorCode(1_008_003_002, "属性项下存在属性值,无法删除");
  29 +
  30 + // ========== 商品属性值 1-008-004-000 ==========
  31 + ErrorCode PROPERTY_VALUE_NOT_EXISTS = new ErrorCode(1_008_004_000, "属性值不存在");
  32 + ErrorCode PROPERTY_VALUE_EXISTS = new ErrorCode(1_008_004_001, "属性值的名称已存在");
  33 +
  34 + // ========== 商品 SPU 1-008-005-000 ==========
  35 + ErrorCode SPU_NOT_EXISTS = new ErrorCode(1_008_005_000, "商品 SPU 不存在");
  36 + ErrorCode SPU_SAVE_FAIL_CATEGORY_LEVEL_ERROR = new ErrorCode(1_008_005_001, "商品分类不正确,原因:必须使用第二级的商品分类及以下");
  37 + ErrorCode SPU_NOT_ENABLE = new ErrorCode(1_008_005_002, "商品 SPU 不处于上架状态");
  38 + ErrorCode SPU_NOT_RECYCLE = new ErrorCode(1_008_005_003, "商品 SPU 不处于回收站状态");
  39 +
  40 + // ========== 商品 SKU 1-008-006-000 ==========
  41 + ErrorCode SKU_NOT_EXISTS = new ErrorCode(1_008_006_000, "商品 SKU 不存在");
  42 + ErrorCode SKU_PROPERTIES_DUPLICATED = new ErrorCode(1_008_006_001, "商品 SKU 的属性组合存在重复");
  43 + ErrorCode SPU_ATTR_NUMBERS_MUST_BE_EQUALS = new ErrorCode(1_008_006_002, "一个 SPU 下的每个 SKU,其属性项必须一致");
  44 + ErrorCode SPU_SKU_NOT_DUPLICATE = new ErrorCode(1_008_006_003, "一个 SPU 下的每个 SKU,必须不重复");
  45 + ErrorCode SKU_STOCK_NOT_ENOUGH = new ErrorCode(1_008_006_004, "商品 SKU 库存不足");
  46 +
  47 + // ========== 商品 评价 1-008-007-000 ==========
  48 + ErrorCode COMMENT_NOT_EXISTS = new ErrorCode(1_008_007_000, "商品评价不存在");
  49 + ErrorCode COMMENT_ORDER_EXISTS = new ErrorCode(1_008_007_001, "订单的商品评价已存在");
  50 +
  51 + // ========== 商品 收藏 1-008-008-000 ==========
  52 + ErrorCode FAVORITE_EXISTS = new ErrorCode(1_008_008_000, "该商品已经被收藏");
  53 + ErrorCode FAVORITE_NOT_EXISTS = new ErrorCode(1_008_008_001, "商品收藏不存在");
54 54
55 } 55 }
yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/app/spu/AppProductSpuController.java
@@ -140,4 +140,5 @@ public class AppProductSpuController { @@ -140,4 +140,5 @@ public class AppProductSpuController {
140 return price - newPrice; 140 return price - newPrice;
141 } 141 }
142 142
  143 + // TODO 芋艿:商品的浏览记录;
143 } 144 }
yudao-module-mall/yudao-module-product-biz/src/test/java/cn/iocoder/yudao/module/product/service/comment/ProductCommentServiceImplTest.java
@@ -16,7 +16,6 @@ import cn.iocoder.yudao.module.product.dal.mysql.comment.ProductCommentMapper; @@ -16,7 +16,6 @@ import cn.iocoder.yudao.module.product.dal.mysql.comment.ProductCommentMapper;
16 import cn.iocoder.yudao.module.product.enums.comment.ProductCommentScoresEnum; 16 import cn.iocoder.yudao.module.product.enums.comment.ProductCommentScoresEnum;
17 import cn.iocoder.yudao.module.product.service.sku.ProductSkuService; 17 import cn.iocoder.yudao.module.product.service.sku.ProductSkuService;
18 import cn.iocoder.yudao.module.product.service.spu.ProductSpuService; 18 import cn.iocoder.yudao.module.product.service.spu.ProductSpuService;
19 -import cn.iocoder.yudao.module.trade.api.order.TradeOrderApi;  
20 import org.junit.jupiter.api.Test; 19 import org.junit.jupiter.api.Test;
21 import org.springframework.boot.test.mock.mockito.MockBean; 20 import org.springframework.boot.test.mock.mockito.MockBean;
22 import org.springframework.context.annotation.Import; 21 import org.springframework.context.annotation.Import;
@@ -49,8 +48,6 @@ public class ProductCommentServiceImplTest extends BaseDbUnitTest { @@ -49,8 +48,6 @@ public class ProductCommentServiceImplTest extends BaseDbUnitTest {
49 private ProductCommentServiceImpl productCommentService; 48 private ProductCommentServiceImpl productCommentService;
50 49
51 @MockBean 50 @MockBean
52 - private TradeOrderApi tradeOrderApi;  
53 - @MockBean  
54 private ProductSpuService productSpuService; 51 private ProductSpuService productSpuService;
55 @MockBean 52 @MockBean
56 private ProductSkuService productSkuService; 53 private ProductSkuService productSkuService;
yudao-module-mall/yudao-module-promotion-api/src/main/java/cn/iocoder/yudao/module/promotion/enums/ErrorCodeConstants.java
@@ -9,47 +9,47 @@ import cn.iocoder.yudao.framework.common.exception.ErrorCode; @@ -9,47 +9,47 @@ import cn.iocoder.yudao.framework.common.exception.ErrorCode;
9 */ 9 */
10 public interface ErrorCodeConstants { 10 public interface ErrorCodeConstants {
11 11
12 - // ========== 促销活动相关 1013001000 ============  
13 - ErrorCode DISCOUNT_ACTIVITY_NOT_EXISTS = new ErrorCode(1013001000, "限时折扣活动不存在");  
14 - ErrorCode DISCOUNT_ACTIVITY_SPU_CONFLICTS = new ErrorCode(1013001001, "存在商品参加了其它限时折扣活动");  
15 - ErrorCode DISCOUNT_ACTIVITY_UPDATE_FAIL_STATUS_CLOSED = new ErrorCode(1013001002, "限时折扣活动已关闭,不能修改");  
16 - ErrorCode DISCOUNT_ACTIVITY_DELETE_FAIL_STATUS_NOT_CLOSED = new ErrorCode(1013001003, "限时折扣活动未关闭,不能删除");  
17 - ErrorCode DISCOUNT_ACTIVITY_CLOSE_FAIL_STATUS_CLOSED = new ErrorCode(1013001004, "限时折扣活动已关闭,不能重复关闭");  
18 - ErrorCode DISCOUNT_ACTIVITY_CLOSE_FAIL_STATUS_END = new ErrorCode(1013001005, "限时折扣活动已结束,不能关闭");  
19 -  
20 - // ========== Banner 相关 1013002000 ============  
21 - ErrorCode BANNER_NOT_EXISTS = new ErrorCode(1013002000, "Banner 不存在");  
22 -  
23 - // ========== Coupon 相关 1013003000 ============  
24 - ErrorCode COUPON_NO_MATCH_SPU = new ErrorCode(1013003000, "优惠劵没有可使用的商品!");  
25 - ErrorCode COUPON_NO_MATCH_MIN_PRICE = new ErrorCode(1013003001, "所结算的商品中未满足使用的金额");  
26 -  
27 - // ========== 优惠劵模板 1013004000 ==========  
28 - ErrorCode COUPON_TEMPLATE_NOT_EXISTS = new ErrorCode(1013004000, "优惠劵模板不存在");  
29 - ErrorCode COUPON_TEMPLATE_TOTAL_COUNT_TOO_SMALL = new ErrorCode(1013004001, "发放数量不能小于已领取数量({})");  
30 - ErrorCode COUPON_TEMPLATE_NOT_ENOUGH = new ErrorCode(1013004002, "当前剩余数量不够领取");  
31 - ErrorCode COUPON_TEMPLATE_USER_ALREADY_TAKE = new ErrorCode(1013004003, "用户已领取过此优惠券");  
32 - ErrorCode COUPON_TEMPLATE_EXPIRED = new ErrorCode(1013004004, "优惠券已过期");  
33 - ErrorCode COUPON_TEMPLATE_CANNOT_TAKE = new ErrorCode(1013004005, "领取方式不正确");  
34 -  
35 - // ========== 优惠劵 1013005000 ==========  
36 - ErrorCode COUPON_NOT_EXISTS = new ErrorCode(1013005000, "优惠券不存在");  
37 - ErrorCode COUPON_DELETE_FAIL_USED = new ErrorCode(1013005001, "回收优惠劵失败,优惠劵已被使用");  
38 - ErrorCode COUPON_STATUS_NOT_UNUSED = new ErrorCode(1013005002, "优惠劵不处于待使用状态");  
39 - ErrorCode COUPON_VALID_TIME_NOT_NOW = new ErrorCode(1013005003, "优惠券不在使用时间范围内");  
40 - ErrorCode COUPON_STATUS_NOT_USED = new ErrorCode(1013005004, "优惠劵不是已使用状态");  
41 -  
42 - // ========== 满减送活动 1013006000 ==========  
43 - ErrorCode REWARD_ACTIVITY_NOT_EXISTS = new ErrorCode(1013006000, "满减送活动不存在");  
44 - ErrorCode REWARD_ACTIVITY_SPU_CONFLICTS = new ErrorCode(1013006001, "存在商品参加了其它满减送活动");  
45 - ErrorCode REWARD_ACTIVITY_UPDATE_FAIL_STATUS_CLOSED = new ErrorCode(1013006002, "满减送活动已关闭,不能修改");  
46 - ErrorCode REWARD_ACTIVITY_DELETE_FAIL_STATUS_NOT_CLOSED = new ErrorCode(1013006003, "满减送活动未关闭,不能删除");  
47 - ErrorCode REWARD_ACTIVITY_CLOSE_FAIL_STATUS_CLOSED = new ErrorCode(1013006004, "满减送活动已关闭,不能重复关闭");  
48 - ErrorCode REWARD_ACTIVITY_CLOSE_FAIL_STATUS_END = new ErrorCode(1013006005, "满减送活动已结束,不能关闭");  
49 -  
50 - // ========== TODO 空着 1013007000 ============  
51 -  
52 - // ========== 秒杀活动 1013008000 ========== 12 + // ========== 促销活动相关 1-013-001-000 ============
  13 + ErrorCode DISCOUNT_ACTIVITY_NOT_EXISTS = new ErrorCode(1_013_001_000, "限时折扣活动不存在");
  14 + ErrorCode DISCOUNT_ACTIVITY_SPU_CONFLICTS = new ErrorCode(1_013_001_001, "存在商品参加了其它限时折扣活动");
  15 + ErrorCode DISCOUNT_ACTIVITY_UPDATE_FAIL_STATUS_CLOSED = new ErrorCode(1_013_001_002, "限时折扣活动已关闭,不能修改");
  16 + ErrorCode DISCOUNT_ACTIVITY_DELETE_FAIL_STATUS_NOT_CLOSED = new ErrorCode(1_013_001_003, "限时折扣活动未关闭,不能删除");
  17 + ErrorCode DISCOUNT_ACTIVITY_CLOSE_FAIL_STATUS_CLOSED = new ErrorCode(1_013_001_004, "限时折扣活动已关闭,不能重复关闭");
  18 + ErrorCode DISCOUNT_ACTIVITY_CLOSE_FAIL_STATUS_END = new ErrorCode(1_013_001_005, "限时折扣活动已结束,不能关闭");
  19 +
  20 + // ========== Banner 相关 1-013-002-000 ============
  21 + ErrorCode BANNER_NOT_EXISTS = new ErrorCode(1_013_002_000, "Banner 不存在");
  22 +
  23 + // ========== Coupon 相关 1-013-003-000 ============
  24 + ErrorCode COUPON_NO_MATCH_SPU = new ErrorCode(1_013_003_000, "优惠劵没有可使用的商品!");
  25 + ErrorCode COUPON_NO_MATCH_MIN_PRICE = new ErrorCode(1_013_003_001, "所结算的商品中未满足使用的金额");
  26 +
  27 + // ========== 优惠劵模板 1-013-004-000 ==========
  28 + ErrorCode COUPON_TEMPLATE_NOT_EXISTS = new ErrorCode(1_013_004_000, "优惠劵模板不存在");
  29 + ErrorCode COUPON_TEMPLATE_TOTAL_COUNT_TOO_SMALL = new ErrorCode(1_013_004_001, "发放数量不能小于已领取数量({})");
  30 + ErrorCode COUPON_TEMPLATE_NOT_ENOUGH = new ErrorCode(1_013_004_002, "当前剩余数量不够领取");
  31 + ErrorCode COUPON_TEMPLATE_USER_ALREADY_TAKE = new ErrorCode(1_013_004_003, "用户已领取过此优惠券");
  32 + ErrorCode COUPON_TEMPLATE_EXPIRED = new ErrorCode(1_013_004_004, "优惠券已过期");
  33 + ErrorCode COUPON_TEMPLATE_CANNOT_TAKE = new ErrorCode(1_013_004_005, "领取方式不正确");
  34 +
  35 + // ========== 优惠劵 1-013-005-000 ==========
  36 + ErrorCode COUPON_NOT_EXISTS = new ErrorCode(1_013_005_000, "优惠券不存在");
  37 + ErrorCode COUPON_DELETE_FAIL_USED = new ErrorCode(1_013_005_001, "回收优惠劵失败,优惠劵已被使用");
  38 + ErrorCode COUPON_STATUS_NOT_UNUSED = new ErrorCode(1_013_005_002, "优惠劵不处于待使用状态");
  39 + ErrorCode COUPON_VALID_TIME_NOT_NOW = new ErrorCode(1_013_005_003, "优惠券不在使用时间范围内");
  40 + ErrorCode COUPON_STATUS_NOT_USED = new ErrorCode(1_013_005_004, "优惠劵不是已使用状态");
  41 +
  42 + // ========== 满减送活动 1-013-006-000 ==========
  43 + ErrorCode REWARD_ACTIVITY_NOT_EXISTS = new ErrorCode(1_013_006_000, "满减送活动不存在");
  44 + ErrorCode REWARD_ACTIVITY_SPU_CONFLICTS = new ErrorCode(1_013_006_001, "存在商品参加了其它满减送活动");
  45 + ErrorCode REWARD_ACTIVITY_UPDATE_FAIL_STATUS_CLOSED = new ErrorCode(1_013_006_002, "满减送活动已关闭,不能修改");
  46 + ErrorCode REWARD_ACTIVITY_DELETE_FAIL_STATUS_NOT_CLOSED = new ErrorCode(1_013_006_003, "满减送活动未关闭,不能删除");
  47 + ErrorCode REWARD_ACTIVITY_CLOSE_FAIL_STATUS_CLOSED = new ErrorCode(1_013_006_004, "满减送活动已关闭,不能重复关闭");
  48 + ErrorCode REWARD_ACTIVITY_CLOSE_FAIL_STATUS_END = new ErrorCode(1_013_006_005, "满减送活动已结束,不能关闭");
  49 +
  50 + // ========== TODO 空着 1-013-007-000 ============
  51 +
  52 + // ========== 秒杀活动 1-013-008-000 ==========
53 ErrorCode SECKILL_ACTIVITY_NOT_EXISTS = new ErrorCode(1013008000, "秒杀活动不存在"); 53 ErrorCode SECKILL_ACTIVITY_NOT_EXISTS = new ErrorCode(1013008000, "秒杀活动不存在");
54 ErrorCode SECKILL_ACTIVITY_SPU_CONFLICTS = new ErrorCode(1013008002, "存在商品参加了其它秒杀活动,秒杀时段冲突"); 54 ErrorCode SECKILL_ACTIVITY_SPU_CONFLICTS = new ErrorCode(1013008002, "存在商品参加了其它秒杀活动,秒杀时段冲突");
55 ErrorCode SECKILL_ACTIVITY_UPDATE_FAIL_STATUS_CLOSED = new ErrorCode(1013008003, "秒杀活动已关闭,不能修改"); 55 ErrorCode SECKILL_ACTIVITY_UPDATE_FAIL_STATUS_CLOSED = new ErrorCode(1013008003, "秒杀活动已关闭,不能修改");
@@ -57,19 +57,19 @@ public interface ErrorCodeConstants { @@ -57,19 +57,19 @@ public interface ErrorCodeConstants {
57 ErrorCode SECKILL_ACTIVITY_CLOSE_FAIL_STATUS_CLOSED = new ErrorCode(1013008005, "秒杀活动已关闭,不能重复关闭"); 57 ErrorCode SECKILL_ACTIVITY_CLOSE_FAIL_STATUS_CLOSED = new ErrorCode(1013008005, "秒杀活动已关闭,不能重复关闭");
58 ErrorCode SECKILL_ACTIVITY_UPDATE_STOCK_FAIL = new ErrorCode(1013008006, "秒杀失败,原因秒杀库存不足"); 58 ErrorCode SECKILL_ACTIVITY_UPDATE_STOCK_FAIL = new ErrorCode(1013008006, "秒杀失败,原因秒杀库存不足");
59 59
60 - // ========== 秒杀时段 1013009000 ==========  
61 - ErrorCode SECKILL_CONFIG_NOT_EXISTS = new ErrorCode(1013009000, "秒杀时段不存在");  
62 - ErrorCode SECKILL_CONFIG_TIME_CONFLICTS = new ErrorCode(1013009001, "秒杀时段冲突");  
63 - ErrorCode SECKILL_CONFIG_DISABLE = new ErrorCode(1013009004, "秒杀时段已关闭"); 60 + // ========== 秒杀时段 1-013-009-000 ==========
  61 + ErrorCode SECKILL_CONFIG_NOT_EXISTS = new ErrorCode(1_013_009_000, "秒杀时段不存在");
  62 + ErrorCode SECKILL_CONFIG_TIME_CONFLICTS = new ErrorCode(1_013_009_001, "秒杀时段冲突");
  63 + ErrorCode SECKILL_CONFIG_DISABLE = new ErrorCode(1_013_009_004, "秒杀时段已关闭");
64 64
65 - // ========== 拼团活动 1013010000 ========== 65 + // ========== 拼团活动 1-013-010-000 ==========
66 ErrorCode COMBINATION_ACTIVITY_NOT_EXISTS = new ErrorCode(1013010000, "拼团活动不存在"); 66 ErrorCode COMBINATION_ACTIVITY_NOT_EXISTS = new ErrorCode(1013010000, "拼团活动不存在");
67 ErrorCode COMBINATION_ACTIVITY_SPU_CONFLICTS = new ErrorCode(1013010001, "存在商品参加了其它拼团活动"); 67 ErrorCode COMBINATION_ACTIVITY_SPU_CONFLICTS = new ErrorCode(1013010001, "存在商品参加了其它拼团活动");
68 ErrorCode COMBINATION_ACTIVITY_STATUS_DISABLE_NOT_UPDATE = new ErrorCode(1013010002, "拼团活动已关闭不能修改"); 68 ErrorCode COMBINATION_ACTIVITY_STATUS_DISABLE_NOT_UPDATE = new ErrorCode(1013010002, "拼团活动已关闭不能修改");
69 ErrorCode COMBINATION_ACTIVITY_DELETE_FAIL_STATUS_NOT_CLOSED_OR_END = new ErrorCode(1013010003, "拼团活动未关闭或未结束,不能删除"); 69 ErrorCode COMBINATION_ACTIVITY_DELETE_FAIL_STATUS_NOT_CLOSED_OR_END = new ErrorCode(1013010003, "拼团活动未关闭或未结束,不能删除");
70 ErrorCode COMBINATION_ACTIVITY_STATUS_DISABLE = new ErrorCode(1013010004, "拼团失败,原因:拼团活动已关闭"); 70 ErrorCode COMBINATION_ACTIVITY_STATUS_DISABLE = new ErrorCode(1013010004, "拼团失败,原因:拼团活动已关闭");
71 71
72 - // ========== 拼团记录 1013011000 ========== 72 + // ========== 拼团记录 1-013-011-000 ==========
73 ErrorCode COMBINATION_RECORD_NOT_EXISTS = new ErrorCode(1013011000, "拼团不存在"); 73 ErrorCode COMBINATION_RECORD_NOT_EXISTS = new ErrorCode(1013011000, "拼团不存在");
74 ErrorCode COMBINATION_RECORD_EXISTS = new ErrorCode(1013011001, "拼团失败,已参与过该拼团"); 74 ErrorCode COMBINATION_RECORD_EXISTS = new ErrorCode(1013011001, "拼团失败,已参与过该拼团");
75 ErrorCode COMBINATION_RECORD_HEAD_NOT_EXISTS = new ErrorCode(1013011002, "拼团失败,父拼团不存在"); 75 ErrorCode COMBINATION_RECORD_HEAD_NOT_EXISTS = new ErrorCode(1013011002, "拼团失败,父拼团不存在");
@@ -79,17 +79,17 @@ public interface ErrorCodeConstants { @@ -79,17 +79,17 @@ public interface ErrorCodeConstants {
79 ErrorCode COMBINATION_RECORD_FAILED_SINGLE_LIMIT_COUNT_EXCEED = new ErrorCode(1013011006, "拼团失败,原因:单次限购超出"); 79 ErrorCode COMBINATION_RECORD_FAILED_SINGLE_LIMIT_COUNT_EXCEED = new ErrorCode(1013011006, "拼团失败,原因:单次限购超出");
80 ErrorCode COMBINATION_RECORD_FAILED_TOTAL_LIMIT_COUNT_EXCEED = new ErrorCode(1013011007, "拼团失败,原因:超出总购买次数"); 80 ErrorCode COMBINATION_RECORD_FAILED_TOTAL_LIMIT_COUNT_EXCEED = new ErrorCode(1013011007, "拼团失败,原因:超出总购买次数");
81 81
82 - // ========== 砍价活动 1013012000 ========== 82 + // ========== 砍价活动 1-013-012-000 ==========
83 ErrorCode BARGAIN_ACTIVITY_NOT_EXISTS = new ErrorCode(1013012000, "砍价活动不存在"); 83 ErrorCode BARGAIN_ACTIVITY_NOT_EXISTS = new ErrorCode(1013012000, "砍价活动不存在");
84 ErrorCode BARGAIN_ACTIVITY_SPU_CONFLICTS = new ErrorCode(1013012001, "存在商品参加了其它砍价活动"); 84 ErrorCode BARGAIN_ACTIVITY_SPU_CONFLICTS = new ErrorCode(1013012001, "存在商品参加了其它砍价活动");
85 ErrorCode BARGAIN_ACTIVITY_STATUS_DISABLE = new ErrorCode(1013012002, "砍价活动已关闭不能修改"); 85 ErrorCode BARGAIN_ACTIVITY_STATUS_DISABLE = new ErrorCode(1013012002, "砍价活动已关闭不能修改");
86 ErrorCode BARGAIN_ACTIVITY_DELETE_FAIL_STATUS_NOT_CLOSED_OR_END = new ErrorCode(1013012003, "砍价活动未关闭或未结束,不能删除"); 86 ErrorCode BARGAIN_ACTIVITY_DELETE_FAIL_STATUS_NOT_CLOSED_OR_END = new ErrorCode(1013012003, "砍价活动未关闭或未结束,不能删除");
87 ErrorCode BARGAIN_ACTIVITY_UPDATE_STOCK_FAIL = new ErrorCode(1013012004, "砍价失败,原因:该砍价活动库存不足"); 87 ErrorCode BARGAIN_ACTIVITY_UPDATE_STOCK_FAIL = new ErrorCode(1013012004, "砍价失败,原因:该砍价活动库存不足");
88 88
89 - // ========== 砍价记录 1013013000 ==========  
90 - ErrorCode BARGAIN_RECORD_NOT_EXISTS = new ErrorCode(1013013000, "砍价记录不存在");  
91 - ErrorCode BARGAIN_RECORD_EXISTS = new ErrorCode(1013013001, "砍价失败,已参与过该砍价");  
92 - ErrorCode BARGAIN_RECORD_HEAD_NOT_EXISTS = new ErrorCode(1013013002, "砍价失败,父砍价不存在");  
93 - ErrorCode BARGAIN_RECORD_USER_FULL = new ErrorCode(1013013003, "砍价失败,砍价人数已满"); 89 + // ========== 砍价记录 1-013-013-000 ==========
  90 + ErrorCode BARGAIN_RECORD_NOT_EXISTS = new ErrorCode(1_013_013_000, "砍价记录不存在");
  91 + ErrorCode BARGAIN_RECORD_EXISTS = new ErrorCode(1_013_013_001, "砍价失败,已参与过该砍价");
  92 + ErrorCode BARGAIN_RECORD_HEAD_NOT_EXISTS = new ErrorCode(1_013_013_002, "砍价失败,父砍价不存在");
  93 + ErrorCode BARGAIN_RECORD_USER_FULL = new ErrorCode(1_013_013_003, "砍价失败,砍价人数已满");
94 94
95 } 95 }
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/coupon/CouponController.java
@@ -37,15 +37,6 @@ public class CouponController { @@ -37,15 +37,6 @@ public class CouponController {
37 @Resource 37 @Resource
38 private MemberUserApi memberUserApi; 38 private MemberUserApi memberUserApi;
39 39
40 -// @GetMapping("/get")  
41 -// @Operation(summary = "获得优惠劵")  
42 -// @Parameter(name = "id", description = "编号", required = true, example = "1024")  
43 -// @PreAuthorize("@ss.hasPermission('promotion:coupon:query')")  
44 -// public CommonResult<CouponRespVO> getCoupon(@RequestParam("id") Long id) {  
45 -// CouponDO coupon = couponService.getCoupon(id);  
46 -// return success(CouponConvert.INSTANCE.convert(coupon));  
47 -// }  
48 -  
49 @DeleteMapping("/delete") 40 @DeleteMapping("/delete")
50 @Operation(summary = "回收优惠劵") 41 @Operation(summary = "回收优惠劵")
51 @Parameter(name = "id", description = "编号", required = true) 42 @Parameter(name = "id", description = "编号", required = true)
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/coupon/vo/template/CouponTemplatePageReqVO.java
@@ -44,4 +44,5 @@ public class CouponTemplatePageReqVO extends PageParam { @@ -44,4 +44,5 @@ public class CouponTemplatePageReqVO extends PageParam {
44 44
45 @Schema(description = "商品范围编号", example = "1") 45 @Schema(description = "商品范围编号", example = "1")
46 private Long productScopeValue; 46 private Long productScopeValue;
  47 +
47 } 48 }
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/app/article/vo/article/AppArticleRespVO.java
@@ -9,41 +9,41 @@ import java.time.LocalDateTime; @@ -9,41 +9,41 @@ import java.time.LocalDateTime;
9 @Data 9 @Data
10 public class AppArticleRespVO { 10 public class AppArticleRespVO {
11 11
12 - @Schema(description = "文章编号", required = true, example = "1") 12 + @Schema(description = "文章编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
13 private Long id; 13 private Long id;
14 14
15 - @Schema(description = "文章标题", required = true, example = "芋道源码 - 促销模块") 15 + @Schema(description = "文章标题", requiredMode = Schema.RequiredMode.REQUIRED, example = "芋道源码 - 促销模块")
16 private String title; 16 private String title;
17 17
18 - @Schema(description = "文章作者", required = true, example = "芋道源码") 18 + @Schema(description = "文章作者", requiredMode = Schema.RequiredMode.REQUIRED, example = "芋道源码")
19 private String author; 19 private String author;
20 20
21 - @Schema(description = "分类编号", required = true, example = "2048") 21 + @Schema(description = "分类编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "2048")
22 private Long categoryId; 22 private Long categoryId;
23 23
24 - @Schema(description = "图文封面", required = true, example = "https://www.iocoder.cn/1.png") 24 + @Schema(description = "图文封面", requiredMode = Schema.RequiredMode.REQUIRED, example = "https://www.iocoder.cn/1.png")
25 private String picUrl; 25 private String picUrl;
26 26
27 - @Schema(description = "文章简介", required = true, example = "我是简介") 27 + @Schema(description = "文章简介", requiredMode = Schema.RequiredMode.REQUIRED, example = "我是简介")
28 private String introduction; 28 private String introduction;
29 29
30 - @Schema(description = "文章内容", required = true, example = "我是详细") 30 + @Schema(description = "文章内容", requiredMode = Schema.RequiredMode.REQUIRED, example = "我是详细")
31 private String description; 31 private String description;
32 32
33 - @Schema(description = "发布时间", required = true) 33 + @Schema(description = "发布时间", requiredMode = Schema.RequiredMode.REQUIRED)
34 private LocalDateTime createTime; 34 private LocalDateTime createTime;
35 35
36 - @Schema(description = "浏览量", required = true, example = "1024") 36 + @Schema(description = "浏览量", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
37 private Integer browseCount; 37 private Integer browseCount;
38 38
39 @Schema(description = "关联的商品 SPU 编号", example = "1024") 39 @Schema(description = "关联的商品 SPU 编号", example = "1024")
40 private Long spuId; 40 private Long spuId;
41 41
42 // TODO 芋艿:下面 2 个字段,后端要存储,前端不用返回; 42 // TODO 芋艿:下面 2 个字段,后端要存储,前端不用返回;
43 -// @Schema(description = "是否热卖推荐", required = true, example = "true") 43 +// @Schema(description = "是否热卖推荐", requiredMode = Schema.RequiredMode.REQUIRED, example = "true")
44 // private Boolean recommendHot; 44 // private Boolean recommendHot;
45 // 45 //
46 -// @Schema(description = "是否 Banner 推荐", required = true, example = "true") 46 +// @Schema(description = "是否 Banner 推荐", requiredMode = Schema.RequiredMode.REQUIRED, example = "true")
47 // private Boolean recommendBanner; 47 // private Boolean recommendBanner;
48 48
49 } 49 }
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/app/article/vo/category/AppArticleCategoryRespVO.java
@@ -7,20 +7,20 @@ import lombok.Data; @@ -7,20 +7,20 @@ import lombok.Data;
7 @Data 7 @Data
8 public class AppArticleCategoryRespVO { 8 public class AppArticleCategoryRespVO {
9 9
10 - @Schema(description = "分类编号", required = true, example = "1") 10 + @Schema(description = "分类编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
11 private Long id; 11 private Long id;
12 12
13 - @Schema(description = "分类名称", required = true, example = "技术") 13 + @Schema(description = "分类名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "技术")
14 private String name; 14 private String name;
15 15
16 - @Schema(description = "分类图标", required = true, example = "https://www.iocoder.cn/1.png") 16 + @Schema(description = "分类图标", requiredMode = Schema.RequiredMode.REQUIRED, example = "https://www.iocoder.cn/1.png")
17 private String picUrl; 17 private String picUrl;
18 18
19 // TODO 芋艿:下面 2 个字段,后端要存储,前端不用返回; 19 // TODO 芋艿:下面 2 个字段,后端要存储,前端不用返回;
20 -// @Schema(description = "状态", required = true, example = "1") 20 +// @Schema(description = "状态", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
21 // private Integer status; 21 // private Integer status;
22 // 22 //
23 -// @Schema(description = "排序", required = true, example = "1024") 23 +// @Schema(description = "排序", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
24 // private Integer sort; 24 // private Integer sort;
25 25
26 } 26 }
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/app/bargain/vo/activity/AppBargainActivityDetailRespVO.java
@@ -9,46 +9,46 @@ import java.time.LocalDateTime; @@ -9,46 +9,46 @@ import java.time.LocalDateTime;
9 @Data 9 @Data
10 public class AppBargainActivityDetailRespVO { 10 public class AppBargainActivityDetailRespVO {
11 11
12 - @Schema(description = "砍价活动编号", required = true, example = "1024") 12 + @Schema(description = "砍价活动编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
13 private Long id; 13 private Long id;
14 14
15 - @Schema(description = "砍价活动名称", required = true, example = "618 大砍价") 15 + @Schema(description = "砍价活动名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "618 大砍价")
16 private String name; 16 private String name;
17 17
18 - @Schema(description = "活动开始时间", required = true) 18 + @Schema(description = "活动开始时间", requiredMode = Schema.RequiredMode.REQUIRED)
19 private LocalDateTime startTime; 19 private LocalDateTime startTime;
20 20
21 - @Schema(description = "活动结束时间", required = true) 21 + @Schema(description = "活动结束时间", requiredMode = Schema.RequiredMode.REQUIRED)
22 private LocalDateTime endTime; 22 private LocalDateTime endTime;
23 23
24 - @Schema(description = "商品 SPU 编号", required = true, example = "2048") 24 + @Schema(description = "商品 SPU 编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "2048")
25 private Long spuId; 25 private Long spuId;
26 26
27 - @Schema(description = "商品 SKU 编号", required = true, example = "1024") 27 + @Schema(description = "商品 SKU 编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
28 private Long skuId; 28 private Long skuId;
29 29
30 - @Schema(description = "商品价格,单位:分", required = true, example = "100") 30 + @Schema(description = "商品价格,单位:分", requiredMode = Schema.RequiredMode.REQUIRED, example = "100")
31 private Integer price; 31 private Integer price;
32 32
33 - @Schema(description = "商品描述", required = true, example = "我要吃西红柿") 33 + @Schema(description = "商品描述", requiredMode = Schema.RequiredMode.REQUIRED, example = "我要吃西红柿")
34 private String description; 34 private String description;
35 35
36 - @Schema(description = "砍价库存", required = true, example = "512") 36 + @Schema(description = "砍价库存", requiredMode = Schema.RequiredMode.REQUIRED, example = "512")
37 private Integer stock; 37 private Integer stock;
38 38
39 - @Schema(description = "商品图片", required = true, example = "4096") // 从 SPU 的 picUrl 读取 39 + @Schema(description = "商品图片", requiredMode = Schema.RequiredMode.REQUIRED, example = "4096") // 从 SPU 的 picUrl 读取
40 private String picUrl; 40 private String picUrl;
41 41
42 - @Schema(description = "商品市场价,单位:分", required = true, example = "50") // 从 SPU 的 marketPrice 读取 42 + @Schema(description = "商品市场价,单位:分", requiredMode = Schema.RequiredMode.REQUIRED, example = "50") // 从 SPU 的 marketPrice 读取
43 private Integer marketPrice; 43 private Integer marketPrice;
44 44
45 - @Schema(description = "商品单位", required = true, example = "个") // 从 SPU 的 unit 读取,然后转换 45 + @Schema(description = "商品单位", requiredMode = Schema.RequiredMode.REQUIRED, example = "个") // 从 SPU 的 unit 读取,然后转换
46 private String unitName; 46 private String unitName;
47 47
48 - @Schema(description = "砍价最低金额,单位:分", required = true, example = "100") 48 + @Schema(description = "砍价最低金额,单位:分", requiredMode = Schema.RequiredMode.REQUIRED, example = "100")
49 private Integer bargainPrice; 49 private Integer bargainPrice;
50 50
51 - @Schema(description = "砍价成功数量", required = true, example = "100") 51 + @Schema(description = "砍价成功数量", requiredMode = Schema.RequiredMode.REQUIRED, example = "100")
52 private Integer successCount; 52 private Integer successCount;
53 53
54 } 54 }
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/app/bargain/vo/activity/AppBargainActivityRespVO.java
@@ -9,34 +9,34 @@ import java.time.LocalDateTime; @@ -9,34 +9,34 @@ import java.time.LocalDateTime;
9 @Data 9 @Data
10 public class AppBargainActivityRespVO { 10 public class AppBargainActivityRespVO {
11 11
12 - @Schema(description = "砍价活动编号", required = true, example = "1024") 12 + @Schema(description = "砍价活动编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
13 private Long id; 13 private Long id;
14 14
15 - @Schema(description = "砍价活动名称", required = true, example = "618 大砍价") 15 + @Schema(description = "砍价活动名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "618 大砍价")
16 private String name; 16 private String name;
17 17
18 - @Schema(description = "活动开始时间", required = true) 18 + @Schema(description = "活动开始时间", requiredMode = Schema.RequiredMode.REQUIRED)
19 private LocalDateTime startTime; 19 private LocalDateTime startTime;
20 20
21 - @Schema(description = "活动结束时间", required = true) 21 + @Schema(description = "活动结束时间", requiredMode = Schema.RequiredMode.REQUIRED)
22 private LocalDateTime endTime; 22 private LocalDateTime endTime;
23 23
24 - @Schema(description = "商品 SPU 编号", required = true, example = "2048") 24 + @Schema(description = "商品 SPU 编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "2048")
25 private Long spuId; 25 private Long spuId;
26 26
27 - @Schema(description = "商品 SKU 编号", required = true, example = "1024") 27 + @Schema(description = "商品 SKU 编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
28 private Long skuId; 28 private Long skuId;
29 29
30 - @Schema(description = "砍价库存", required = true, example = "512") 30 + @Schema(description = "砍价库存", requiredMode = Schema.RequiredMode.REQUIRED, example = "512")
31 private Integer stock; 31 private Integer stock;
32 32
33 - @Schema(description = "商品图片", required = true, example = "4096") // 从 SPU 的 picUrl 读取 33 + @Schema(description = "商品图片", requiredMode = Schema.RequiredMode.REQUIRED, example = "4096") // 从 SPU 的 picUrl 读取
34 private String picUrl; 34 private String picUrl;
35 35
36 - @Schema(description = "商品市场价,单位:分", required = true, example = "50") // 从 SPU 的 marketPrice 读取 36 + @Schema(description = "商品市场价,单位:分", requiredMode = Schema.RequiredMode.REQUIRED, example = "50") // 从 SPU 的 marketPrice 读取
37 private Integer marketPrice; 37 private Integer marketPrice;
38 38
39 - @Schema(description = "砍价最低金额,单位:分", required = true, example = "100") 39 + @Schema(description = "砍价最低金额,单位:分", requiredMode = Schema.RequiredMode.REQUIRED, example = "100")
40 private Integer bargainPrice; 40 private Integer bargainPrice;
41 41
42 } 42 }
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/app/bargain/vo/help/AppBargainHelpCreateReqVO.java
@@ -9,7 +9,7 @@ import javax.validation.constraints.NotNull; @@ -9,7 +9,7 @@ import javax.validation.constraints.NotNull;
9 @Data 9 @Data
10 public class AppBargainHelpCreateReqVO { 10 public class AppBargainHelpCreateReqVO {
11 11
12 - @Schema(description = "砍价记录编号", required = true, example = "1024") 12 + @Schema(description = "砍价记录编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
13 @NotNull(message = "砍价记录编号不能为空") 13 @NotNull(message = "砍价记录编号不能为空")
14 private Long recordId; 14 private Long recordId;
15 15
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/app/bargain/vo/help/AppBargainHelpRespVO.java
@@ -9,16 +9,16 @@ import java.time.LocalDateTime; @@ -9,16 +9,16 @@ import java.time.LocalDateTime;
9 @Data 9 @Data
10 public class AppBargainHelpRespVO { 10 public class AppBargainHelpRespVO {
11 11
12 - @Schema(description = "助力用户的昵称", required = true, example = "1024") 12 + @Schema(description = "助力用户的昵称", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
13 private String nickname; 13 private String nickname;
14 14
15 - @Schema(description = "助力用户的头像", required = true, example = "1024") 15 + @Schema(description = "助力用户的头像", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
16 private String avatar; 16 private String avatar;
17 17
18 - @Schema(description = "助力用户的砍价金额", required = true, example = "1024") 18 + @Schema(description = "助力用户的砍价金额", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
19 private Integer reducePrice; 19 private Integer reducePrice;
20 20
21 - @Schema(description = "创建时间", required = true, example = "1024") 21 + @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
22 private LocalDateTime createTime; 22 private LocalDateTime createTime;
23 23
24 } 24 }
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/app/bargain/vo/record/AppBargainRecordCreateReqVO.java
@@ -9,7 +9,7 @@ import javax.validation.constraints.NotNull; @@ -9,7 +9,7 @@ import javax.validation.constraints.NotNull;
9 @Data 9 @Data
10 public class AppBargainRecordCreateReqVO { 10 public class AppBargainRecordCreateReqVO {
11 11
12 - @Schema(description = "砍价活动编号", required = true, example = "1024") 12 + @Schema(description = "砍价活动编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
13 @NotNull(message = "砍价活动编号不能为空") 13 @NotNull(message = "砍价活动编号不能为空")
14 private Long activityId; 14 private Long activityId;
15 15
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/app/bargain/vo/record/AppBargainRecordSummaryRespVO.java
@@ -9,23 +9,23 @@ import java.util.List; @@ -9,23 +9,23 @@ import java.util.List;
9 @Data 9 @Data
10 public class AppBargainRecordSummaryRespVO { 10 public class AppBargainRecordSummaryRespVO {
11 11
12 - @Schema(description = "砍价用户数量", required = true, example = "1024") 12 + @Schema(description = "砍价用户数量", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
13 private Integer userCount; 13 private Integer userCount;
14 14
15 - @Schema(description = "成功砍价的记录", required = true) // 只返回最近的 7 个 15 + @Schema(description = "成功砍价的记录", requiredMode = Schema.RequiredMode.REQUIRED) // 只返回最近的 7 个
16 private List<Record> successRecords; 16 private List<Record> successRecords;
17 17
18 @Schema(description = "成功砍价记录") 18 @Schema(description = "成功砍价记录")
19 @Data 19 @Data
20 public static class Record { 20 public static class Record {
21 21
22 - @Schema(description = "用户昵称", required = true, example = "王**") 22 + @Schema(description = "用户昵称", requiredMode = Schema.RequiredMode.REQUIRED, example = "王**")
23 private String nickname; 23 private String nickname;
24 24
25 - @Schema(description = "用户头像", required = true, example = "https://www.iocoder.cn/xxx.jpg") 25 + @Schema(description = "用户头像", requiredMode = Schema.RequiredMode.REQUIRED, example = "https://www.iocoder.cn/xxx.jpg")
26 private String avatar; 26 private String avatar;
27 27
28 - @Schema(description = "活动名称", required = true, example = "天蚕土豆") 28 + @Schema(description = "活动名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "天蚕土豆")
29 private String activityName; 29 private String activityName;
30 30
31 } 31 }
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/app/coupon/AppCouponController.java
@@ -40,14 +40,17 @@ public class AppCouponController { @@ -40,14 +40,17 @@ public class AppCouponController {
40 @PostMapping("/take") 40 @PostMapping("/take")
41 @Operation(summary = "领取优惠劵") 41 @Operation(summary = "领取优惠劵")
42 @Parameter(name = "templateId", description = "优惠券模板编号", required = true, example = "1024") 42 @Parameter(name = "templateId", description = "优惠券模板编号", required = true, example = "1024")
  43 + @PreAuthenticated
43 public CommonResult<Boolean> takeCoupon(@Valid @RequestBody AppCouponTakeReqVO reqVO) { 44 public CommonResult<Boolean> takeCoupon(@Valid @RequestBody AppCouponTakeReqVO reqVO) {
  45 + // 1. 领取优惠劵
44 Long userId = getLoginUserId(); 46 Long userId = getLoginUserId();
45 - // 领取  
46 couponService.takeCoupon(reqVO.getTemplateId(), CollUtil.newHashSet(userId), CouponTakeTypeEnum.USER); 47 couponService.takeCoupon(reqVO.getTemplateId(), CollUtil.newHashSet(userId), CouponTakeTypeEnum.USER);
47 - // 检查是否可以继续领取 48 +
  49 + // 2. 检查是否可以继续领取
48 CouponTemplateDO couponTemplate = couponTemplateService.getCouponTemplate(reqVO.getTemplateId()); 50 CouponTemplateDO couponTemplate = couponTemplateService.getCouponTemplate(reqVO.getTemplateId());
49 boolean canTakeAgain = true; 51 boolean canTakeAgain = true;
50 if (couponTemplate.getTakeLimitCount() != null && couponTemplate.getTakeLimitCount() > 0) { 52 if (couponTemplate.getTakeLimitCount() != null && couponTemplate.getTakeLimitCount() > 0) {
  53 + // TODO @疯狂:要不要搞个 getTakeCount 方法?
51 Integer takeCount = MapUtil.getInt(couponService.getTakeCountMapByTemplateIds( 54 Integer takeCount = MapUtil.getInt(couponService.getTakeCountMapByTemplateIds(
52 Collections.singleton(reqVO.getTemplateId()), userId), reqVO.getTemplateId(), 0); 55 Collections.singleton(reqVO.getTemplateId()), userId), reqVO.getTemplateId(), 0);
53 canTakeAgain = takeCount < couponTemplate.getTakeLimitCount(); 56 canTakeAgain = takeCount < couponTemplate.getTakeLimitCount();
@@ -56,15 +59,16 @@ public class AppCouponController { @@ -56,15 +59,16 @@ public class AppCouponController {
56 } 59 }
57 60
58 @GetMapping("/match-list") 61 @GetMapping("/match-list")
59 - @Operation(summary = "获得匹配指定商品的优惠劵列表") 62 + @Operation(summary = "获得匹配指定商品的优惠劵列表", description = "用于下单页,展示优惠劵列表")
60 public CommonResult<List<AppCouponMatchRespVO>> getMatchCouponList(AppCouponMatchReqVO matchReqVO) { 63 public CommonResult<List<AppCouponMatchRespVO>> getMatchCouponList(AppCouponMatchReqVO matchReqVO) {
61 - // todo: 优惠金额倒序 64 + // todo: 优化:优惠金额倒序
62 return success(CouponConvert.INSTANCE.convertList(couponService.getMatchCouponList(getLoginUserId(), matchReqVO))); 65 return success(CouponConvert.INSTANCE.convertList(couponService.getMatchCouponList(getLoginUserId(), matchReqVO)));
63 } 66 }
64 67
65 @GetMapping("/page") 68 @GetMapping("/page")
66 - @Operation(summary = "优惠劵列表", description = "我的优惠劵")  
67 - public CommonResult<PageResult<AppCouponRespVO>> takeCoupon(AppCouponPageReqVO pageReqVO) { 69 + @Operation(summary = "我的优惠劵列表")
  70 + @PreAuthenticated
  71 + public CommonResult<PageResult<AppCouponRespVO>> getCouponPage(AppCouponPageReqVO pageReqVO) {
68 PageResult<CouponDO> pageResult = couponService.getCouponPage( 72 PageResult<CouponDO> pageResult = couponService.getCouponPage(
69 CouponConvert.INSTANCE.convert(pageReqVO, Collections.singleton(getLoginUserId()))); 73 CouponConvert.INSTANCE.convert(pageReqVO, Collections.singleton(getLoginUserId())));
70 return success(CouponConvert.INSTANCE.convertAppPage(pageResult)); 74 return success(CouponConvert.INSTANCE.convertAppPage(pageResult));
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/app/coupon/AppCouponTemplateController.java
@@ -3,6 +3,7 @@ package cn.iocoder.yudao.module.promotion.controller.app.coupon; @@ -3,6 +3,7 @@ package cn.iocoder.yudao.module.promotion.controller.app.coupon;
3 import cn.hutool.core.util.ObjUtil; 3 import cn.hutool.core.util.ObjUtil;
4 import cn.iocoder.yudao.framework.common.pojo.CommonResult; 4 import cn.iocoder.yudao.framework.common.pojo.CommonResult;
5 import cn.iocoder.yudao.framework.common.pojo.PageResult; 5 import cn.iocoder.yudao.framework.common.pojo.PageResult;
  6 +import cn.iocoder.yudao.framework.common.util.object.ObjectUtils;
6 import cn.iocoder.yudao.module.product.api.spu.ProductSpuApi; 7 import cn.iocoder.yudao.module.product.api.spu.ProductSpuApi;
7 import cn.iocoder.yudao.module.product.api.spu.dto.ProductSpuRespDTO; 8 import cn.iocoder.yudao.module.product.api.spu.dto.ProductSpuRespDTO;
8 import cn.iocoder.yudao.module.promotion.controller.app.coupon.vo.template.AppCouponTemplatePageReqVO; 9 import cn.iocoder.yudao.module.promotion.controller.app.coupon.vo.template.AppCouponTemplatePageReqVO;
@@ -14,13 +15,17 @@ import cn.iocoder.yudao.module.promotion.enums.coupon.CouponTakeTypeEnum; @@ -14,13 +15,17 @@ import cn.iocoder.yudao.module.promotion.enums.coupon.CouponTakeTypeEnum;
14 import cn.iocoder.yudao.module.promotion.service.coupon.CouponService; 15 import cn.iocoder.yudao.module.promotion.service.coupon.CouponService;
15 import cn.iocoder.yudao.module.promotion.service.coupon.CouponTemplateService; 16 import cn.iocoder.yudao.module.promotion.service.coupon.CouponTemplateService;
16 import io.swagger.v3.oas.annotations.Operation; 17 import io.swagger.v3.oas.annotations.Operation;
  18 +import io.swagger.v3.oas.annotations.Parameter;
  19 +import io.swagger.v3.oas.annotations.Parameters;
17 import io.swagger.v3.oas.annotations.tags.Tag; 20 import io.swagger.v3.oas.annotations.tags.Tag;
18 import org.springframework.validation.annotation.Validated; 21 import org.springframework.validation.annotation.Validated;
19 import org.springframework.web.bind.annotation.GetMapping; 22 import org.springframework.web.bind.annotation.GetMapping;
20 import org.springframework.web.bind.annotation.RequestMapping; 23 import org.springframework.web.bind.annotation.RequestMapping;
  24 +import org.springframework.web.bind.annotation.RequestParam;
21 import org.springframework.web.bind.annotation.RestController; 25 import org.springframework.web.bind.annotation.RestController;
22 26
23 import javax.annotation.Resource; 27 import javax.annotation.Resource;
  28 +import java.time.LocalDateTime;
24 import java.util.*; 29 import java.util.*;
25 30
26 import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; 31 import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
@@ -41,16 +46,63 @@ public class AppCouponTemplateController { @@ -41,16 +46,63 @@ public class AppCouponTemplateController {
41 @Resource 46 @Resource
42 private ProductSpuApi productSpuApi; 47 private ProductSpuApi productSpuApi;
43 48
  49 + // TODO 疯狂:这里应该还有个 list 接口哈;获得优惠劵模版列表,用于首页、商品页的优惠劵
  50 + @GetMapping("/list")
  51 + @Operation(summary = "获得优惠劵模版列表")
  52 + @Parameters({
  53 + @Parameter(name = "spuId", description = "商品 SPU 编号"), // 目前主要给商品详情使用
  54 + @Parameter(name = "useType", description = "使用类型"),
  55 + @Parameter(name = "count", description = "数量", required = true)
  56 + })
  57 + public CommonResult<List<AppCouponTemplateRespVO>> getCouponTemplateList(
  58 + @RequestParam(value = "spuId", required = false) Long spuId,
  59 + @RequestParam(value = "useType", required = false) Integer useType,
  60 + @RequestParam(value = "count", required = false, defaultValue = "10") Integer count) {
  61 + List<AppCouponTemplateRespVO> list = new ArrayList<>();
  62 + Random random = new Random();
  63 + for (int i = 0; i < 10; i++) {
  64 + AppCouponTemplateRespVO vo = new AppCouponTemplateRespVO();
  65 + vo.setId(i + 1L);
  66 + vo.setName("优惠劵" + (i + 1));
  67 + vo.setTakeLimitCount(random.nextInt(10) + 1);
  68 + vo.setUsePrice(random.nextInt(100) * 100);
  69 + vo.setValidityType(random.nextInt(2) + 1);
  70 + if (vo.getValidityType() == 1) {
  71 + vo.setValidStartTime(LocalDateTime.now().plusDays(random.nextInt(10)));
  72 + vo.setValidEndTime(LocalDateTime.now().plusDays(random.nextInt(20) + 10));
  73 + } else {
  74 + vo.setFixedStartTerm(random.nextInt(10));
  75 + vo.setFixedEndTerm(random.nextInt(10) + vo.getFixedStartTerm() + 1);
  76 + }
  77 + vo.setDiscountType(random.nextInt(2) + 1);
  78 + if (vo.getDiscountType() == 1) {
  79 + vo.setDiscountPercent(null);
  80 + vo.setDiscountPrice(random.nextInt(50) * 100);
  81 + vo.setDiscountLimitPrice(null);
  82 + } else {
  83 + vo.setDiscountPercent(random.nextInt(90) + 10);
  84 + vo.setDiscountPrice(null);
  85 + vo.setDiscountLimitPrice(random.nextInt(200) * 100);
  86 + }
  87 + // TODO @疯狂:是否已领取,要不在 TemplateService 搞个 static 方法,让它基于 countMap 这种去计算,这样好点?
  88 + vo.setTakeStatus(random.nextBoolean());
  89 + list.add(vo);
  90 + }
  91 + return success(list);
  92 + }
  93 +
44 @GetMapping("/page") 94 @GetMapping("/page")
45 @Operation(summary = "获得优惠劵模版分页") 95 @Operation(summary = "获得优惠劵模版分页")
46 public CommonResult<PageResult<AppCouponTemplateRespVO>> getCouponTemplatePage(AppCouponTemplatePageReqVO pageReqVO) { 96 public CommonResult<PageResult<AppCouponTemplateRespVO>> getCouponTemplatePage(AppCouponTemplatePageReqVO pageReqVO) {
47 // 1.1 处理查询条件:商品范围编号 97 // 1.1 处理查询条件:商品范围编号
48 - Long productScopeValue = getaProductScopeValue(pageReqVO);  
49 - // 1.2 处理查询条件:领取方式=直接领取 98 + Long productScopeValue = getProductScopeValue(pageReqVO);
  99 + // 1.2 处理查询条件:领取方式 = 直接领取
50 List<Integer> canTakeTypes = Collections.singletonList(CouponTakeTypeEnum.USER.getValue()); 100 List<Integer> canTakeTypes = Collections.singletonList(CouponTakeTypeEnum.USER.getValue());
  101 +
51 // 2. 分页查询 102 // 2. 分页查询
52 PageResult<CouponTemplateDO> pageResult = couponTemplateService.getCouponTemplatePage( 103 PageResult<CouponTemplateDO> pageResult = couponTemplateService.getCouponTemplatePage(
53 CouponTemplateConvert.INSTANCE.convert(pageReqVO, canTakeTypes, pageReqVO.getProductScope(), productScopeValue)); 104 CouponTemplateConvert.INSTANCE.convert(pageReqVO, canTakeTypes, pageReqVO.getProductScope(), productScopeValue));
  105 +
54 // 3.1 领取数量 106 // 3.1 领取数量
55 Map<Long, Integer> couponTakeCountMap = new HashMap<>(0); 107 Map<Long, Integer> couponTakeCountMap = new HashMap<>(0);
56 Long userId = getLoginUserId(); 108 Long userId = getLoginUserId();
@@ -63,17 +115,24 @@ public class AppCouponTemplateController { @@ -63,17 +115,24 @@ public class AppCouponTemplateController {
63 return success(CouponTemplateConvert.INSTANCE.convertAppPage(pageResult, couponTakeCountMap)); 115 return success(CouponTemplateConvert.INSTANCE.convertAppPage(pageResult, couponTakeCountMap));
64 } 116 }
65 117
66 - private Long getaProductScopeValue(AppCouponTemplatePageReqVO pageReqVO) {  
67 - Long productScopeValue = pageReqVO.getSpuId();  
68 - if (pageReqVO.getProductScope() == null || Objects.equals(pageReqVO.getProductScope(), PromotionProductScopeEnum.ALL.getScope())) {  
69 - // 通用券:清除商品范围  
70 - productScopeValue = null;  
71 - } else if (Objects.equals(pageReqVO.getProductScope(), PromotionProductScopeEnum.CATEGORY.getScope()) && pageReqVO.getSpuId() != null) {  
72 - // 品类券:查询商品的品类  
73 - productScopeValue = Optional.ofNullable(productSpuApi.getSpu(pageReqVO.getSpuId())) 118 + /**
  119 + * 获得分页查询的商品范围
  120 + *
  121 + * @param pageReqVO 分页查询
  122 + * @return 商品范围
  123 + */
  124 + private Long getProductScopeValue(AppCouponTemplatePageReqVO pageReqVO) {
  125 + // 通用券:清除商品范围
  126 + if (pageReqVO.getProductScope() == null || ObjectUtils.equalsAny(pageReqVO.getProductScope(), PromotionProductScopeEnum.ALL.getScope(), null)) {
  127 + return null;
  128 + }
  129 + // 品类券:查询商品的品类
  130 + if (Objects.equals(pageReqVO.getProductScope(), PromotionProductScopeEnum.CATEGORY.getScope()) && pageReqVO.getSpuId() != null) {
  131 + return Optional.ofNullable(productSpuApi.getSpu(pageReqVO.getSpuId()))
74 .map(ProductSpuRespDTO::getCategoryId).orElse(null); 132 .map(ProductSpuRespDTO::getCategoryId).orElse(null);
75 } 133 }
76 - return productScopeValue; 134 + // 商品卷:直接返回
  135 + return pageReqVO.getSpuId();
77 } 136 }
78 137
79 } 138 }
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/app/coupon/vo/template/AppCouponTemplatePageReqVO.java
@@ -20,4 +20,5 @@ public class AppCouponTemplatePageReqVO extends PageParam { @@ -20,4 +20,5 @@ public class AppCouponTemplatePageReqVO extends PageParam {
20 20
21 @Schema(description = "商品标号", example = "1") 21 @Schema(description = "商品标号", example = "1")
22 private Long spuId; 22 private Long spuId;
  23 +
23 } 24 }
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/app/coupon/vo/template/AppCouponTemplateRespVO.java
@@ -23,14 +23,6 @@ public class AppCouponTemplateRespVO { @@ -23,14 +23,6 @@ public class AppCouponTemplateRespVO {
23 // 单位:分;0 - 不限制 23 // 单位:分;0 - 不限制
24 private Integer usePrice; 24 private Integer usePrice;
25 25
26 - // TODO 芋艿:这两要改的  
27 -// @Schema(description = "商品范围", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")  
28 -// @InEnum(PromotionProductScopeEnum.class)  
29 -// private Integer productScope;  
30 -//  
31 -// @Schema(description = "商品范围编号的数组", example = "1,3")  
32 -// private List<Long> productScopeValues;  
33 -  
34 @Schema(description = "生效日期类型", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") 26 @Schema(description = "生效日期类型", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
35 private Integer validityType; 27 private Integer validityType;
36 28
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/convert/coupon/CouponConvert.java
@@ -61,4 +61,5 @@ public interface CouponConvert { @@ -61,4 +61,5 @@ public interface CouponConvert {
61 PageResult<AppCouponRespVO> convertAppPage(PageResult<CouponDO> pageResult); 61 PageResult<AppCouponRespVO> convertAppPage(PageResult<CouponDO> pageResult);
62 62
63 List<AppCouponMatchRespVO> convertList(List<CouponDO> list); 63 List<AppCouponMatchRespVO> convertList(List<CouponDO> list);
  64 +
64 } 65 }
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/convert/coupon/CouponTemplateConvert.java
@@ -42,16 +42,16 @@ public interface CouponTemplateConvert { @@ -42,16 +42,16 @@ public interface CouponTemplateConvert {
42 if (MapUtil.isEmpty(couponTakeCountMap)) { 42 if (MapUtil.isEmpty(couponTakeCountMap)) {
43 return result; 43 return result;
44 } 44 }
45 -  
46 - for (AppCouponTemplateRespVO vo : result.getList()) { 45 + for (AppCouponTemplateRespVO template : result.getList()) {
47 // 每人领取数量无限制 46 // 每人领取数量无限制
48 - if (vo.getTakeLimitCount() == -1) {  
49 - vo.setTakeStatus(false); 47 + if (template.getTakeLimitCount() == -1) {
  48 + template.setTakeStatus(false);
50 continue; 49 continue;
51 } 50 }
52 // 检查已领取数量是否超过限领数量 51 // 检查已领取数量是否超过限领数量
53 - vo.setTakeStatus(MapUtil.getInt(couponTakeCountMap, vo.getId(), 0) >= vo.getTakeLimitCount()); 52 + template.setTakeStatus(MapUtil.getInt(couponTakeCountMap, template.getId(), 0) >= template.getTakeLimitCount());
54 } 53 }
55 return result; 54 return result;
56 } 55 }
  56 +
57 } 57 }
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/dal/mysql/coupon/CouponMapper.java
@@ -70,6 +70,7 @@ public interface CouponMapper extends BaseMapperX&lt;CouponDO&gt; { @@ -70,6 +70,7 @@ public interface CouponMapper extends BaseMapperX&lt;CouponDO&gt; {
70 ); 70 );
71 } 71 }
72 72
  73 + // TODO @疯狂:这个是不是搞个 Map 就可以呀?
73 default List<CouponTakeCountBO> selectCountByUserIdAndTemplateIdIn(Long userId, Collection<Long> templateIds) { 74 default List<CouponTakeCountBO> selectCountByUserIdAndTemplateIdIn(Long userId, Collection<Long> templateIds) {
74 return BeanUtil.copyToList(selectMaps(MPJWrappers.lambdaJoin(CouponDO.class) 75 return BeanUtil.copyToList(selectMaps(MPJWrappers.lambdaJoin(CouponDO.class)
75 .select(CouponDO::getTemplateId) 76 .select(CouponDO::getTemplateId)
@@ -81,18 +82,17 @@ public interface CouponMapper extends BaseMapperX&lt;CouponDO&gt; { @@ -81,18 +82,17 @@ public interface CouponMapper extends BaseMapperX&lt;CouponDO&gt; {
81 82
82 default List<CouponDO> selectListByUserIdAndStatusAndUsePriceLeAndProductScope( 83 default List<CouponDO> selectListByUserIdAndStatusAndUsePriceLeAndProductScope(
83 Long userId, Integer status, Integer usePrice, List<Long> spuIds, List<Long> categoryIds) { 84 Long userId, Integer status, Integer usePrice, List<Long> spuIds, List<Long> categoryIds) {
84 -  
85 Function<List<Long>, String> productScopeValuesFindInSetFunc = ids -> ids.stream() 85 Function<List<Long>, String> productScopeValuesFindInSetFunc = ids -> ids.stream()
86 .map(id -> StrUtil.format("FIND_IN_SET({}, product_scope_values) ", id)) 86 .map(id -> StrUtil.format("FIND_IN_SET({}, product_scope_values) ", id))
87 .collect(Collectors.joining(" OR ")); 87 .collect(Collectors.joining(" OR "));
88 return selectList(new LambdaQueryWrapperX<CouponDO>() 88 return selectList(new LambdaQueryWrapperX<CouponDO>()
89 .eq(CouponDO::getUserId, userId) 89 .eq(CouponDO::getUserId, userId)
90 .eq(CouponDO::getStatus, status) 90 .eq(CouponDO::getStatus, status)
91 - .le(CouponDO::getUsePrice, usePrice)  
92 - .and(w -> w.eq(CouponDO::getProductScope, PromotionProductScopeEnum.ALL.getScope())  
93 - .or(ww -> ww.eq(CouponDO::getProductScope, PromotionProductScopeEnum.SPU.getScope()) 91 + .le(CouponDO::getUsePrice, usePrice) // 价格小于等于,满足价格使用条件
  92 + .and(w -> w.eq(CouponDO::getProductScope, PromotionProductScopeEnum.ALL.getScope()) // 商品范围一:全部
  93 + .or(ww -> ww.eq(CouponDO::getProductScope, PromotionProductScopeEnum.SPU.getScope()) // 商品范围二:满足指定商品
94 .apply(productScopeValuesFindInSetFunc.apply(spuIds))) 94 .apply(productScopeValuesFindInSetFunc.apply(spuIds)))
95 - .or(ww -> ww.eq(CouponDO::getProductScope, PromotionProductScopeEnum.CATEGORY.getScope()) 95 + .or(ww -> ww.eq(CouponDO::getProductScope, PromotionProductScopeEnum.CATEGORY.getScope()) // 商品范围三:满足指定分类
96 .apply(productScopeValuesFindInSetFunc.apply(categoryIds))))); 96 .apply(productScopeValuesFindInSetFunc.apply(categoryIds)))));
97 } 97 }
98 98
@@ -102,4 +102,5 @@ public interface CouponMapper extends BaseMapperX&lt;CouponDO&gt; { @@ -102,4 +102,5 @@ public interface CouponMapper extends BaseMapperX&lt;CouponDO&gt; {
102 .le(CouponDO::getValidEndTime, validEndTime) 102 .le(CouponDO::getValidEndTime, validEndTime)
103 ); 103 );
104 } 104 }
  105 +
105 } 106 }
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/job/CouponExpireJob.java renamed to yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/job/coupon/CouponExpireJob.java
1 -package cn.iocoder.yudao.module.promotion.job; 1 +package cn.iocoder.yudao.module.promotion.job.coupon;
2 2
3 import cn.hutool.core.util.StrUtil; 3 import cn.hutool.core.util.StrUtil;
4 import cn.iocoder.yudao.framework.quartz.core.handler.JobHandler; 4 import cn.iocoder.yudao.framework.quartz.core.handler.JobHandler;
@@ -8,19 +8,20 @@ import org.springframework.stereotype.Component; @@ -8,19 +8,20 @@ import org.springframework.stereotype.Component;
8 8
9 import javax.annotation.Resource; 9 import javax.annotation.Resource;
10 10
  11 +// TODO 芋艿:配置一个 Job
11 /** 12 /**
12 * 优惠券过期 Job 13 * 优惠券过期 Job
13 * 14 *
14 * @author owen 15 * @author owen
15 */ 16 */
16 @Component 17 @Component
17 -@TenantJob  
18 public class CouponExpireJob implements JobHandler { 18 public class CouponExpireJob implements JobHandler {
19 19
20 @Resource 20 @Resource
21 private CouponService couponService; 21 private CouponService couponService;
22 22
23 @Override 23 @Override
  24 + @TenantJob
24 public String execute(String param) { 25 public String execute(String param) {
25 int count = couponService.expireCoupon(); 26 int count = couponService.expireCoupon();
26 return StrUtil.format("过期优惠券 {} 个", count); 27 return StrUtil.format("过期优惠券 {} 个", count);
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/job/package-info.java renamed to yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/job/package-info.java
1 /** 1 /**
2 - * 占位文件,无特殊用途 2 + * TODO 占位,无具体含义
3 */ 3 */
4 -package cn.iocoder.yudao.module.trade.job; 4 +package cn.iocoder.yudao.module.promotion.job;
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/coupon/CouponService.java
@@ -137,7 +137,8 @@ public interface CouponService { @@ -137,7 +137,8 @@ public interface CouponService {
137 * @return 领取优惠券的数量 137 * @return 领取优惠券的数量
138 */ 138 */
139 default Map<Long, Integer> getTakeCountMapByTemplateIds(Collection<Long> templateIds, Long userId) { 139 default Map<Long, Integer> getTakeCountMapByTemplateIds(Collection<Long> templateIds, Long userId) {
140 - return convertMap(getTakeCountListByTemplateIds(templateIds, userId), CouponTakeCountBO::getTemplateId, CouponTakeCountBO::getCount); 140 + return convertMap(getTakeCountListByTemplateIds(templateIds, userId),
  141 + CouponTakeCountBO::getTemplateId, CouponTakeCountBO::getCount);
141 } 142 }
142 143
143 /** 144 /**
@@ -164,4 +165,5 @@ public interface CouponService { @@ -164,4 +165,5 @@ public interface CouponService {
164 * @return 过期数量 165 * @return 过期数量
165 */ 166 */
166 int expireCoupon(); 167 int expireCoupon();
  168 +
167 } 169 }
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/coupon/CouponServiceImpl.java
@@ -40,6 +40,7 @@ import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils. @@ -40,6 +40,7 @@ import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.
40 import static cn.iocoder.yudao.module.promotion.enums.ErrorCodeConstants.*; 40 import static cn.iocoder.yudao.module.promotion.enums.ErrorCodeConstants.*;
41 import static java.util.Arrays.asList; 41 import static java.util.Arrays.asList;
42 42
  43 +// TODO @疯狂:注册时,赠送用户优惠劵;为了解耦,可以考虑注册时发个 MQ 消息;然后营销这里监听后消费;
43 /** 44 /**
44 * 优惠劵 Service 实现类 45 * 优惠劵 Service 实现类
45 * 46 *
@@ -192,7 +193,8 @@ public class CouponServiceImpl implements CouponService { @@ -192,7 +193,8 @@ public class CouponServiceImpl implements CouponService {
192 193
193 @Override 194 @Override
194 public List<CouponDO> getMatchCouponList(Long userId, AppCouponMatchReqVO matchReqVO) { 195 public List<CouponDO> getMatchCouponList(Long userId, AppCouponMatchReqVO matchReqVO) {
195 - return couponMapper.selectListByUserIdAndStatusAndUsePriceLeAndProductScope(userId, CouponStatusEnum.UNUSED.getStatus(), 196 + return couponMapper.selectListByUserIdAndStatusAndUsePriceLeAndProductScope(userId,
  197 + CouponStatusEnum.UNUSED.getStatus(),
196 matchReqVO.getPrice(), matchReqVO.getSpuIds(), matchReqVO.getCategoryIds()); 198 matchReqVO.getPrice(), matchReqVO.getSpuIds(), matchReqVO.getCategoryIds());
197 } 199 }
198 200
@@ -220,15 +222,20 @@ public class CouponServiceImpl implements CouponService { @@ -220,15 +222,20 @@ public class CouponServiceImpl implements CouponService {
220 return count; 222 return count;
221 } 223 }
222 224
  225 + /**
  226 + * 过期单个优惠劵
  227 + *
  228 + * @param coupon 优惠劵
  229 + * @return 是否过期成功
  230 + */
223 private boolean expireCoupon(CouponDO coupon) { 231 private boolean expireCoupon(CouponDO coupon) {
224 // 更新记录状态 232 // 更新记录状态
225 - CouponDO updateObj = new CouponDO().setStatus(CouponStatusEnum.EXPIRE.getStatus());  
226 - int updateRows = couponMapper.updateByIdAndStatus(coupon.getId(), CouponStatusEnum.UNUSED.getStatus(), updateObj); 233 + int updateRows = couponMapper.updateByIdAndStatus(coupon.getId(), CouponStatusEnum.UNUSED.getStatus(),
  234 + new CouponDO().setStatus(CouponStatusEnum.EXPIRE.getStatus()));
227 if (updateRows == 0) { 235 if (updateRows == 0) {
228 log.error("[expireCoupon][coupon({}) 更新为已过期失败]", coupon.getId()); 236 log.error("[expireCoupon][coupon({}) 更新为已过期失败]", coupon.getId());
229 return false; 237 return false;
230 } 238 }
231 -  
232 log.info("[expireCoupon][coupon({}) 更新为已过期成功]", coupon.getId()); 239 log.info("[expireCoupon][coupon({}) 更新为已过期成功]", coupon.getId());
233 return true; 240 return true;
234 } 241 }
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/coupon/CouponTemplateServiceImpl.java
@@ -29,6 +29,7 @@ public class CouponTemplateServiceImpl implements CouponTemplateService { @@ -29,6 +29,7 @@ public class CouponTemplateServiceImpl implements CouponTemplateService {
29 @Resource 29 @Resource
30 private CouponTemplateMapper couponTemplateMapper; 30 private CouponTemplateMapper couponTemplateMapper;
31 31
  32 + // TODO @疯狂:新增/修改时,需要校验对应的商品、分类是否存在
32 @Override 33 @Override
33 public Long createCouponTemplate(CouponTemplateCreateReqVO createReqVO) { 34 public Long createCouponTemplate(CouponTemplateCreateReqVO createReqVO) {
34 // 插入 35 // 插入
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/coupon/bo/CouponTakeCountBO.java
@@ -9,6 +9,7 @@ import lombok.Data; @@ -9,6 +9,7 @@ import lombok.Data;
9 */ 9 */
10 @Data 10 @Data
11 public class CouponTakeCountBO { 11 public class CouponTakeCountBO {
  12 +
12 /** 13 /**
13 * 优惠劵模板编号 14 * 优惠劵模板编号
14 */ 15 */
@@ -17,4 +18,5 @@ public class CouponTakeCountBO { @@ -17,4 +18,5 @@ public class CouponTakeCountBO {
17 * 领取数量 18 * 领取数量
18 */ 19 */
19 private Integer count; 20 private Integer count;
  21 +
20 } 22 }
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,7 +11,7 @@ import cn.iocoder.yudao.framework.common.exception.ErrorCode;
11 */ 11 */
12 public interface ErrorCodeConstants { 12 public interface ErrorCodeConstants {
13 13
14 - // ========== Order 模块 1011000000 ========== 14 + // ========== Order 模块 1-011-000-000 ==========
15 ErrorCode ORDER_ITEM_NOT_FOUND = new ErrorCode(1011000010, "交易订单项不存在"); 15 ErrorCode ORDER_ITEM_NOT_FOUND = new ErrorCode(1011000010, "交易订单项不存在");
16 ErrorCode ORDER_NOT_FOUND = new ErrorCode(1011000011, "交易订单不存在"); 16 ErrorCode ORDER_NOT_FOUND = new ErrorCode(1011000011, "交易订单不存在");
17 ErrorCode ORDER_ITEM_UPDATE_AFTER_SALE_STATUS_FAIL = new ErrorCode(1011000012, "交易订单项更新售后状态失败,请重试"); 17 ErrorCode ORDER_ITEM_UPDATE_AFTER_SALE_STATUS_FAIL = new ErrorCode(1011000012, "交易订单项更新售后状态失败,请重试");
@@ -33,45 +33,44 @@ public interface ErrorCodeConstants { @@ -33,45 +33,44 @@ public interface ErrorCodeConstants {
33 ErrorCode ORDER_UPDATE_PRICE_FAIL_PRICE_ERROR = new ErrorCode(1011000028, "支付订单调价失败,原因:调整后支付价格不能小于 0.01 元"); 33 ErrorCode ORDER_UPDATE_PRICE_FAIL_PRICE_ERROR = new ErrorCode(1011000028, "支付订单调价失败,原因:调整后支付价格不能小于 0.01 元");
34 ErrorCode ORDER_DELETE_FAIL_STATUS_NOT_CANCEL = new ErrorCode(1011000029, "交易订单删除失败,订单不是【已取消】状态"); 34 ErrorCode ORDER_DELETE_FAIL_STATUS_NOT_CANCEL = new ErrorCode(1011000029, "交易订单删除失败,订单不是【已取消】状态");
35 35
36 - // ========== After Sale 模块 1011000100 ==========  
37 - ErrorCode AFTER_SALE_NOT_FOUND = new ErrorCode(1011000100, "售后单不存在");  
38 - ErrorCode AFTER_SALE_CREATE_FAIL_REFUND_PRICE_ERROR = new ErrorCode(1011000101, "申请退款金额错误");  
39 - ErrorCode AFTER_SALE_CREATE_FAIL_ORDER_STATUS_CANCELED = new ErrorCode(1011000102, "订单已关闭,无法申请售后");  
40 - ErrorCode AFTER_SALE_CREATE_FAIL_ORDER_STATUS_NO_PAID = new ErrorCode(1011000103, "订单未支付,无法申请售后");  
41 - ErrorCode AFTER_SALE_CREATE_FAIL_ORDER_STATUS_NO_DELIVERED = new ErrorCode(1011000104, "订单未发货,无法申请【退货退款】售后");  
42 - ErrorCode AFTER_SALE_CREATE_FAIL_ORDER_ITEM_APPLIED = new ErrorCode(1011000105, "订单项已申请售后,无法重复申请");  
43 - ErrorCode AFTER_SALE_AUDIT_FAIL_STATUS_NOT_APPLY = new ErrorCode(1011000106, "审批失败,售后状态不处于审批中");  
44 - ErrorCode AFTER_SALE_UPDATE_STATUS_FAIL = new ErrorCode(1011000107, "操作售后单失败,请刷新后重试");  
45 - ErrorCode AFTER_SALE_DELIVERY_FAIL_STATUS_NOT_SELLER_AGREE = new ErrorCode(1011000108, "退货失败,售后单状态不处于【待买家退货】");  
46 - ErrorCode AFTER_SALE_CONFIRM_FAIL_STATUS_NOT_BUYER_DELIVERY = new ErrorCode(1011000109, "确认收货失败,售后单状态不处于【待确认收货】");  
47 - ErrorCode AFTER_SALE_REFUND_FAIL_STATUS_NOT_WAIT_REFUND = new ErrorCode(1011000110, "退款失败,售后单状态不是【待退款】"); 36 + // ========== After Sale 模块 1-011-000-100 ==========
  37 + ErrorCode AFTER_SALE_NOT_FOUND = new ErrorCode(1_011_000_100, "售后单不存在");
  38 + ErrorCode AFTER_SALE_CREATE_FAIL_REFUND_PRICE_ERROR = new ErrorCode(1_011_000_101, "申请退款金额错误");
  39 + ErrorCode AFTER_SALE_CREATE_FAIL_ORDER_STATUS_CANCELED = new ErrorCode(1_011_000_102, "订单已关闭,无法申请售后");
  40 + ErrorCode AFTER_SALE_CREATE_FAIL_ORDER_STATUS_NO_PAID = new ErrorCode(1_011_000_103, "订单未支付,无法申请售后");
  41 + ErrorCode AFTER_SALE_CREATE_FAIL_ORDER_STATUS_NO_DELIVERED = new ErrorCode(1_011_000_104, "订单未发货,无法申请【退货退款】售后");
  42 + ErrorCode AFTER_SALE_CREATE_FAIL_ORDER_ITEM_APPLIED = new ErrorCode(1_011_000_105, "订单项已申请售后,无法重复申请");
  43 + ErrorCode AFTER_SALE_AUDIT_FAIL_STATUS_NOT_APPLY = new ErrorCode(1_011_000_106, "审批失败,售后状态不处于审批中");
  44 + ErrorCode AFTER_SALE_UPDATE_STATUS_FAIL = new ErrorCode(1_011_000_107, "操作售后单失败,请刷新后重试");
  45 + ErrorCode AFTER_SALE_DELIVERY_FAIL_STATUS_NOT_SELLER_AGREE = new ErrorCode(1_011_000_108, "退货失败,售后单状态不处于【待买家退货】");
  46 + ErrorCode AFTER_SALE_CONFIRM_FAIL_STATUS_NOT_BUYER_DELIVERY = new ErrorCode(1_011_000_109, "确认收货失败,售后单状态不处于【待确认收货】");
  47 + ErrorCode AFTER_SALE_REFUND_FAIL_STATUS_NOT_WAIT_REFUND = new ErrorCode(1_011_000_110, "退款失败,售后单状态不是【待退款】");
48 ErrorCode AFTER_SALE_CANCEL_FAIL_STATUS_NOT_APPLY_OR_AGREE_OR_BUYER_DELIVERY = 48 ErrorCode AFTER_SALE_CANCEL_FAIL_STATUS_NOT_APPLY_OR_AGREE_OR_BUYER_DELIVERY =
49 - new ErrorCode(1011000111, "取消售后单失败,售后单状态不是【待审核】或【卖家同意】或【商家待收货】"); 49 + new ErrorCode(1_011_000_111, "取消售后单失败,售后单状态不是【待审核】或【卖家同意】或【商家待收货】");
50 50
51 - // ========== Cart 模块 1011002000 ==========  
52 - ErrorCode CARD_ITEM_NOT_FOUND = new ErrorCode(1011002000, "购物车项不存在"); 51 + // ========== Cart 模块 1-011-002-000 ==========
  52 + ErrorCode CARD_ITEM_NOT_FOUND = new ErrorCode(1_011_002_000, "购物车项不存在");
53 53
54 - // ========== Price 相关 1011003000 ============ 54 + // ========== Price 相关 1-011-003-000 ============
55 ErrorCode PRICE_CALCULATE_PAY_PRICE_ILLEGAL = new ErrorCode(1011003000, "支付价格计算异常,原因:价格小于等于 0"); 55 ErrorCode PRICE_CALCULATE_PAY_PRICE_ILLEGAL = new ErrorCode(1011003000, "支付价格计算异常,原因:价格小于等于 0");
56 ErrorCode PRICE_CALCULATE_DELIVERY_PRICE_TEMPLATE_NOT_FOUND = new ErrorCode(1011003002, "计算快递运费异常,找不到对应的运费模板"); 56 ErrorCode PRICE_CALCULATE_DELIVERY_PRICE_TEMPLATE_NOT_FOUND = new ErrorCode(1011003002, "计算快递运费异常,找不到对应的运费模板");
57 ErrorCode PRICE_CALCULATE_COUPON_NOT_MATCH_NORMAL_ORDER = new ErrorCode(1011003004, "参与秒杀、拼团、砍价的营销商品,无法使用优惠劵"); 57 ErrorCode PRICE_CALCULATE_COUPON_NOT_MATCH_NORMAL_ORDER = new ErrorCode(1011003004, "参与秒杀、拼团、砍价的营销商品,无法使用优惠劵");
58 58
59 - // ========== 物流 Express 模块 1011004000 ==========  
60 - ErrorCode EXPRESS_NOT_EXISTS = new ErrorCode(1011004000, "快递公司不存在");  
61 - ErrorCode EXPRESS_CODE_DUPLICATE = new ErrorCode(1011004001, "已经存在该编码的快递公司");  
62 - ErrorCode EXPRESS_CLIENT_NOT_PROVIDE = new ErrorCode(1011004002, "需要接入快递服务商,比如【快递100】");  
63 - ErrorCode EXPRESS_STATUS_NOT_ENABLE = new ErrorCode(1011004003, "快递公司未启用"); 59 + // ========== 物流 Express 模块 1-011-004-000 ==========
  60 + ErrorCode EXPRESS_NOT_EXISTS = new ErrorCode(1_011_004_000, "快递公司不存在");
  61 + ErrorCode EXPRESS_CODE_DUPLICATE = new ErrorCode(1_011_004_001, "已经存在该编码的快递公司");
  62 + ErrorCode EXPRESS_CLIENT_NOT_PROVIDE = new ErrorCode(1_011_004_002, "需要接入快递服务商,比如【快递100】");
  63 + ErrorCode EXPRESS_STATUS_NOT_ENABLE = new ErrorCode(1_011_004_003, "快递公司未启用");
64 64
65 - ErrorCode EXPRESS_API_QUERY_ERROR = new ErrorCode(1011004101, "快递查询接口异常");  
66 - ErrorCode EXPRESS_API_QUERY_FAILED = new ErrorCode(1011004102, "快递查询返回失败,原因:{}"); 65 + ErrorCode EXPRESS_API_QUERY_ERROR = new ErrorCode(1_011_004_101, "快递查询接口异常");
  66 + ErrorCode EXPRESS_API_QUERY_FAILED = new ErrorCode(1_011_004_102, "快递查询返回失败,原因:{}");
67 67
68 - // ========== 物流 Template 模块 1011005000 ==========  
69 - ErrorCode EXPRESS_TEMPLATE_NAME_DUPLICATE = new ErrorCode(1011005000, "已经存在该运费模板名");  
70 - ErrorCode EXPRESS_TEMPLATE_NOT_EXISTS = new ErrorCode(1011005001, "运费模板不存在");  
71 -  
72 - // ========== 物流 PICK_UP 模块 1011006000 ==========  
73 - ErrorCode PICK_UP_STORE_NOT_EXISTS = new ErrorCode(1011006000, "自提门店不存在"); 68 + // ========== 物流 Template 模块 1-011-005-000 ==========
  69 + ErrorCode EXPRESS_TEMPLATE_NAME_DUPLICATE = new ErrorCode(1_011_005_000, "已经存在该运费模板名");
  70 + ErrorCode EXPRESS_TEMPLATE_NOT_EXISTS = new ErrorCode(1_011_005_001, "运费模板不存在");
74 71
  72 + // ========== 物流 PICK_UP 模块 1-011-006-000 ==========
  73 + ErrorCode PICK_UP_STORE_NOT_EXISTS = new ErrorCode(1_011_006_000, "自提门店不存在");
75 74
76 // ========== 分销用户 模块 1011007000 ========== 75 // ========== 分销用户 模块 1011007000 ==========
77 ErrorCode BROKERAGE_USER_NOT_EXISTS = new ErrorCode(1011007000, "分销用户不存在"); 76 ErrorCode BROKERAGE_USER_NOT_EXISTS = new ErrorCode(1011007000, "分销用户不存在");
yudao-module-mall/yudao-module-trade-api/src/main/java/cn/iocoder/yudao/module/trade/enums/aftersale/AfterSaleOperateTypeEnum.java
1 package cn.iocoder.yudao.module.trade.enums.aftersale; 1 package cn.iocoder.yudao.module.trade.enums.aftersale;
2 2
  3 +import lombok.Getter;
  4 +import lombok.RequiredArgsConstructor;
  5 +
3 /** 6 /**
4 * 售后操作类型的枚举 7 * 售后操作类型的枚举
5 * 8 *
6 * @author 陈賝 9 * @author 陈賝
7 * @since 2023/6/13 13:53 10 * @since 2023/6/13 13:53
8 */ 11 */
9 -// TODO @chenchen:可以 lombok 简化构造方法,和 get 方法 12 +@RequiredArgsConstructor
  13 +@Getter
10 public enum AfterSaleOperateTypeEnum { 14 public enum AfterSaleOperateTypeEnum {
11 15
12 - /**  
13 - * 用户申请  
14 - */  
15 - APPLY("用户申请"), 16 + MEMBER_CREATE(10, "会员申请退款"),
  17 + ADMIN_AGREE_APPLY(11, "商家同意退款"),
  18 + ADMIN_DISAGREE_APPLY(12, "商家拒绝退款"),
  19 + MEMBER_DELIVERY(20, "会员填写退货物流信息,快递公司:{deliveryName},快递单号:{logisticsNo}"),
  20 + ADMIN_AGREE_RECEIVE(21, "商家收货"),
  21 + ADMIN_DISAGREE_RECEIVE(22, "商家拒绝收货,原因:{reason}"),
  22 + ADMIN_REFUND(30, "商家退款"),
  23 + MEMBER_CANCEL(40, "会员取消退款"),
16 ; 24 ;
17 25
18 - private final String description;  
19 -  
20 - AfterSaleOperateTypeEnum(String description) {  
21 - this.description = description;  
22 - }  
23 -  
24 - public String description() {  
25 - return description;  
26 - } 26 + /**
  27 + * 操作类型
  28 + */
  29 + private final Integer type;
  30 + /**
  31 + * 操作描述
  32 + */
  33 + private final String content;
27 34
28 } 35 }
yudao-module-mall/yudao-module-trade-api/src/main/java/cn/iocoder/yudao/module/trade/enums/brokerage/BrokerageBindModeEnum.java
@@ -18,15 +18,15 @@ public enum BrokerageBindModeEnum implements IntArrayValuable { @@ -18,15 +18,15 @@ public enum BrokerageBindModeEnum implements IntArrayValuable {
18 /** 18 /**
19 * 只要用户没有推广人,随时都可以绑定分销关系 19 * 只要用户没有推广人,随时都可以绑定分销关系
20 */ 20 */
21 - ANYTIME(1, "没有推广人"), 21 + ANYTIME(1, "首次绑定"),
22 /** 22 /**
23 * 仅新用户注册时才能绑定推广关系 23 * 仅新用户注册时才能绑定推广关系
24 */ 24 */
25 - REGISTER(2, "新用户"), 25 + REGISTER(2, "注册绑定"),
26 /** 26 /**
27 * 每次扫码都覆盖 27 * 每次扫码都覆盖
28 */ 28 */
29 - OVERRIDE(3, "扫码覆盖"), 29 + OVERRIDE(3, "覆盖绑定"),
30 ; 30 ;
31 31
32 public static final int[] ARRAYS = Arrays.stream(values()).mapToInt(BrokerageBindModeEnum::getMode).toArray(); 32 public static final int[] ARRAYS = Arrays.stream(values()).mapToInt(BrokerageBindModeEnum::getMode).toArray();
yudao-module-mall/yudao-module-trade-api/src/main/java/cn/iocoder/yudao/module/trade/enums/brokerage/BrokerageRecordBizTypeEnum.java
@@ -17,7 +17,7 @@ public enum BrokerageRecordBizTypeEnum implements IntArrayValuable { @@ -17,7 +17,7 @@ public enum BrokerageRecordBizTypeEnum implements IntArrayValuable {
17 17
18 ORDER(1, "获得推广佣金", "获得推广佣金 {}", true), 18 ORDER(1, "获得推广佣金", "获得推广佣金 {}", true),
19 WITHDRAW(2, "提现申请", "提现申请扣除佣金 {}", false), 19 WITHDRAW(2, "提现申请", "提现申请扣除佣金 {}", false),
20 - WITHDRAW_REJECT(3, "提现申请驳回", "提现申请驳回返还佣金 {}", true), 20 + WITHDRAW_REJECT(3, "提现申请驳回", "提现申请驳回,返还佣金 {}", true),
21 ; 21 ;
22 22
23 public static final int[] ARRAYS = Arrays.stream(values()).mapToInt(BrokerageRecordBizTypeEnum::getType).toArray(); 23 public static final int[] ARRAYS = Arrays.stream(values()).mapToInt(BrokerageRecordBizTypeEnum::getType).toArray();
yudao-module-mall/yudao-module-trade-api/src/main/java/cn/iocoder/yudao/module/trade/enums/brokerage/BrokerageWithdrawStatusEnum.java
@@ -6,6 +6,7 @@ import lombok.Getter; @@ -6,6 +6,7 @@ import lombok.Getter;
6 6
7 import java.util.Arrays; 7 import java.util.Arrays;
8 8
  9 +// TODO 芋艿:提现的打通,在纠结下;
9 /** 10 /**
10 * 佣金提现状态枚举 11 * 佣金提现状态枚举
11 * 12 *
yudao-module-mall/yudao-module-trade-api/src/main/java/cn/iocoder/yudao/module/trade/enums/order/TradeOrderOperateTypeEnum.java
@@ -24,15 +24,16 @@ public enum TradeOrderOperateTypeEnum { @@ -24,15 +24,16 @@ public enum TradeOrderOperateTypeEnum {
24 MEMBER_CANCEL(40, "取消订单"), 24 MEMBER_CANCEL(40, "取消订单"),
25 SYSTEM_CANCEL(41, "到期未支付,系统自动取消订单"), 25 SYSTEM_CANCEL(41, "到期未支付,系统自动取消订单"),
26 // 42 预留:管理员取消订单 26 // 42 预留:管理员取消订单
27 - MEMBER_DELETE(43, "删除订单"), 27 + ADMIN_CANCEL_AFTER_SALE(43, "订单全部售后,管理员自动取消订单"),
  28 + MEMBER_DELETE(49, "删除订单"),
28 ; 29 ;
29 30
30 /** 31 /**
31 - * 类型 32 + * 操作类型
32 */ 33 */
33 private final Integer type; 34 private final Integer type;
34 /** 35 /**
35 - * 类型 36 + * 操作描述
36 */ 37 */
37 private final String content; 38 private final String content;
38 39
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/brokerage/BrokerageUserController.java
@@ -13,8 +13,8 @@ import cn.iocoder.yudao.module.trade.enums.brokerage.BrokerageWithdrawStatusEnum @@ -13,8 +13,8 @@ import cn.iocoder.yudao.module.trade.enums.brokerage.BrokerageWithdrawStatusEnum
13 import cn.iocoder.yudao.module.trade.service.brokerage.BrokerageRecordService; 13 import cn.iocoder.yudao.module.trade.service.brokerage.BrokerageRecordService;
14 import cn.iocoder.yudao.module.trade.service.brokerage.BrokerageUserService; 14 import cn.iocoder.yudao.module.trade.service.brokerage.BrokerageUserService;
15 import cn.iocoder.yudao.module.trade.service.brokerage.BrokerageWithdrawService; 15 import cn.iocoder.yudao.module.trade.service.brokerage.BrokerageWithdrawService;
16 -import cn.iocoder.yudao.module.trade.service.brokerage.bo.UserBrokerageSummaryBO;  
17 -import cn.iocoder.yudao.module.trade.service.brokerage.bo.UserWithdrawSummaryBO; 16 +import cn.iocoder.yudao.module.trade.service.brokerage.bo.UserBrokerageSummaryRespBO;
  17 +import cn.iocoder.yudao.module.trade.service.brokerage.bo.BrokerageWithdrawSummaryRespBO;
18 import io.swagger.v3.oas.annotations.Operation; 18 import io.swagger.v3.oas.annotations.Operation;
19 import io.swagger.v3.oas.annotations.Parameter; 19 import io.swagger.v3.oas.annotations.Parameter;
20 import io.swagger.v3.oas.annotations.tags.Tag; 20 import io.swagger.v3.oas.annotations.tags.Tag;
@@ -88,24 +88,24 @@ public class BrokerageUserController { @@ -88,24 +88,24 @@ public class BrokerageUserController {
88 // 分页查询 88 // 分页查询
89 PageResult<BrokerageUserDO> pageResult = brokerageUserService.getBrokerageUserPage(pageVO); 89 PageResult<BrokerageUserDO> pageResult = brokerageUserService.getBrokerageUserPage(pageVO);
90 90
91 - // 涉及到的用户  
92 - Set<Long> userIds = convertSet(pageResult.getList(), BrokerageUserDO::getId);  
93 // 查询用户信息 91 // 查询用户信息
  92 + Set<Long> userIds = convertSet(pageResult.getList(), BrokerageUserDO::getId);
94 Map<Long, MemberUserRespDTO> userMap = memberUserApi.getUserMap(userIds); 93 Map<Long, MemberUserRespDTO> userMap = memberUserApi.getUserMap(userIds);
95 - // 合计分佣订单  
96 - Map<Long, UserBrokerageSummaryBO> userOrderSummaryMap = brokerageRecordService.getUserBrokerageSummaryMapByUserId( 94 + // 合计分佣的推广订单
  95 + Map<Long, UserBrokerageSummaryRespBO> brokerageOrderSummaryMap = brokerageRecordService.getUserBrokerageSummaryMapByUserId(
97 userIds, BrokerageRecordBizTypeEnum.ORDER.getType(), BrokerageRecordStatusEnum.SETTLEMENT.getStatus()); 96 userIds, BrokerageRecordBizTypeEnum.ORDER.getType(), BrokerageRecordStatusEnum.SETTLEMENT.getStatus());
98 - // TODO @芋艿:看看下面 getBrokerageUserCountByBindUserId 有没可能一次性出结果,不然 n 次有点太花性能了;  
99 - // 合计推广用户数量 97 + // 合计分佣的推广用户
  98 + // TODO @疯狂:转成 map 批量读取
100 Map<Long, Long> brokerageUserCountMap = convertMap(userIds, 99 Map<Long, Long> brokerageUserCountMap = convertMap(userIds,
101 userId -> userId, 100 userId -> userId,
102 userId -> brokerageUserService.getBrokerageUserCountByBindUserId(userId, null)); 101 userId -> brokerageUserService.getBrokerageUserCountByBindUserId(userId, null));
103 - // 合计提现  
104 - Map<Long, UserWithdrawSummaryBO> withdrawMap = brokerageWithdrawService.getWithdrawSummaryMapByUserId(userIds,  
105 - BrokerageWithdrawStatusEnum.AUDIT_SUCCESS); 102 + // 合计分佣的提现
  103 + // TODO @疯狂:如果未来支持了打款这个动作,可能 status 会不对;
  104 + Map<Long, BrokerageWithdrawSummaryRespBO> withdrawMap = brokerageWithdrawService.getWithdrawSummaryMapByUserId(
  105 + userIds, BrokerageWithdrawStatusEnum.AUDIT_SUCCESS);
106 // 拼接返回 106 // 拼接返回
107 return success(BrokerageUserConvert.INSTANCE.convertPage(pageResult, userMap, brokerageUserCountMap, 107 return success(BrokerageUserConvert.INSTANCE.convertPage(pageResult, userMap, brokerageUserCountMap,
108 - userOrderSummaryMap, withdrawMap)); 108 + brokerageOrderSummaryMap, withdrawMap));
109 } 109 }
110 110
111 } 111 }
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/brokerage/vo/user/BrokerageUserRespVO.java
@@ -21,25 +21,25 @@ public class BrokerageUserRespVO extends BrokerageUserBaseVO { @@ -21,25 +21,25 @@ public class BrokerageUserRespVO extends BrokerageUserBaseVO {
21 21
22 // ========== 用户信息 ========== 22 // ========== 用户信息 ==========
23 23
24 - @Schema(description = "用户头像", example = "https://www.iocoder.cn/xxx.png") 24 + @Schema(description = "用户头像", requiredMode = Schema.RequiredMode.REQUIRED, example = "https://www.iocoder.cn/xxx.png")
25 private String avatar; 25 private String avatar;
26 - @Schema(description = "用户昵称", example = "李四") 26 + @Schema(description = "用户昵称", requiredMode = Schema.RequiredMode.REQUIRED, example = "李四")
27 private String nickname; 27 private String nickname;
28 28
29 // ========== 推广信息 ========== 29 // ========== 推广信息 ==========
30 30
31 - @Schema(description = "推广用户数量", example = "20019") 31 + @Schema(description = "推广用户数量", requiredMode = Schema.RequiredMode.REQUIRED, example = "20019")
32 private Integer brokerageUserCount; 32 private Integer brokerageUserCount;
33 - @Schema(description = "推广订单数量", example = "20019") 33 + @Schema(description = "推广订单数量", requiredMode = Schema.RequiredMode.REQUIRED, example = "20019")
34 private Integer brokerageOrderCount; 34 private Integer brokerageOrderCount;
35 - @Schema(description = "推广订单金额", example = "20019") 35 + @Schema(description = "推广订单金额", requiredMode = Schema.RequiredMode.REQUIRED, example = "20019")
36 private Integer brokerageOrderPrice; 36 private Integer brokerageOrderPrice;
37 37
38 // ========== 提现信息 ========== 38 // ========== 提现信息 ==========
39 39
40 - @Schema(description = "已提现金额", example = "20019") 40 + @Schema(description = "已提现金额", requiredMode = Schema.RequiredMode.REQUIRED, example = "20019")
41 private Integer withdrawPrice; 41 private Integer withdrawPrice;
42 - @Schema(description = "已提现次数", example = "20019") 42 + @Schema(description = "已提现次数", requiredMode = Schema.RequiredMode.REQUIRED, example = "20019")
43 private Integer withdrawCount; 43 private Integer withdrawCount;
44 44
45 } 45 }
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/config/vo/TradeConfigBaseVO.java
@@ -19,6 +19,19 @@ import java.util.List; @@ -19,6 +19,19 @@ import java.util.List;
19 */ 19 */
20 @Data 20 @Data
21 public class TradeConfigBaseVO { 21 public class TradeConfigBaseVO {
  22 +
  23 + // ========== 售后相关 ==========
  24 +
  25 + @Schema(description = "售后的退款理由", requiredMode = Schema.RequiredMode.REQUIRED)
  26 + @NotEmpty(message = "售后的退款理由不能为空")
  27 + private List<String> afterSaleRefundReasons;
  28 +
  29 + @Schema(description = "售后的退货理由", requiredMode = Schema.RequiredMode.REQUIRED)
  30 + @NotEmpty(message = "售后的退货理由不能为空")
  31 + private List<String> afterSaleReturnReasons;
  32 +
  33 + // ========== 配送相关 ==========
  34 +
22 /** 35 /**
23 * 是否启用全场包邮 36 * 是否启用全场包邮
24 */ 37 */
@@ -80,7 +93,7 @@ public class TradeConfigBaseVO { @@ -80,7 +93,7 @@ public class TradeConfigBaseVO {
80 private Integer brokerageFrozenDays; 93 private Integer brokerageFrozenDays;
81 94
82 @Schema(description = "提现方式", requiredMode = Schema.RequiredMode.REQUIRED, example = "[0, 1]") 95 @Schema(description = "提现方式", requiredMode = Schema.RequiredMode.REQUIRED, example = "[0, 1]")
83 - @NotNull(message = "提现方式不能为空") 96 + @NotEmpty(message = "提现方式不能为空")
84 @InEnum(value = BrokerageWithdrawTypeEnum.class, message = "提现方式必须是 {value}") 97 @InEnum(value = BrokerageWithdrawTypeEnum.class, message = "提现方式必须是 {value}")
85 private List<Integer> brokerageWithdrawTypes; 98 private List<Integer> brokerageWithdrawTypes;
86 99