Commit 929ff4286afe6f42e1c6fa4785a34e3e9c9adb3c
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 | 15 | * 启动文档:<https://doc.iocoder.cn/quick-start/> |
| 16 | 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 | 22 | **芋道**,以开发者为中心,打造中国第一流的快速开发平台,全部开源,个人与企业可 100% 免费使用。 |
| ... | ... | @@ -62,18 +64,18 @@ |
| 62 | 64 | | [yudao-ui-admin](https://gitee.com/zhijiantianya/ruoyi-vue-pro/tree/master/yudao-ui-admin) | [](https://gitee.com/zhijiantianya/ruoyi-vue-pro/tree/master/yudao-ui-admin) [](https://github.com/YunaiV/ruoyi-vue-pro/tree/master/yudao-ui-admin) | 基于 Vue2 + element-ui 实现的管理后台 | |
| 63 | 65 | | [yudao-ui-admin-uniapp](https://gitee.com/zhijiantianya/ruoyi-vue-pro/tree/master/yudao-ui-admin-uniapp) | [](https://gitee.com/zhijiantianya/ruoyi-vue-pro/tree/master/yudao-ui-admin-uniapp) [](https://github.com/YunaiV/ruoyi-vue-pro/tree/master/yudao-ui-admin-uniapp) | 基于 uni-app + uni-ui 实现的管理后台的小程序 | |
| 64 | 66 | | [yudao-ui-go-view](https://gitee.com/yudaocode/yudao-ui-go-view) | [](https://gitee.com/yudaocode/yudao-ui-go-view) [](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) | [](https://gitee.com/zhijiantianya/ruoyi-vue-pro/tree/master/yudao-ui-app) [](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) | [](https://gitee.com/yudaocode/yudao-mall-uniapp) [](https://github.com/yudaocode/yudao-mall-uniapp) | 基于 uni-app 实现的商城小程序 | | |
| 66 | 68 | |
| 67 | 69 | ## 🐰 分支说明 |
| 68 | 70 | |
| 69 | 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 | 74 | | 说明 | 包括所有功能 | 只保留核心功能 | 适配 Spring Boot 3.X | |
| 73 | 75 | | 系统功能 | √ | √ | √ | |
| 74 | 76 | | 基础设施 | √ | √ | √ | |
| 75 | 77 | | 会员中心 | √ | √ | √ | |
| 76 | -| 工作流程 | √ | x | 适配中 | | |
| 78 | +| 工作流程 | √ | x | √ | | |
| 77 | 79 | | 数据报表 | √ | x | 适配中 | |
| 78 | 80 | | 商城系统 | √ | x | √ | |
| 79 | 81 | | 微信公众号 | √ | x | √ | |
| ... | ... | @@ -218,6 +220,10 @@ |
| 218 | 220 | |
| 219 | 221 |  |
| 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 | 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 | ... | ... |
pom.xml
| ... | ... | @@ -30,7 +30,7 @@ |
| 30 | 30 | <url>https://github.com/YunaiV/ruoyi-vue-pro</url> |
| 31 | 31 | |
| 32 | 32 | <properties> |
| 33 | - <revision>1.8.1-snapshot</revision> | |
| 33 | + <revision>1.8.2-snapshot</revision> | |
| 34 | 34 | <!-- Maven 相关 --> |
| 35 | 35 | <java.version>1.8</java.version> |
| 36 | 36 | <maven.compiler.source>${java.version}</maven.compiler.source> |
| ... | ... | @@ -39,8 +39,8 @@ |
| 39 | 39 | <maven-compiler-plugin.version>3.8.1</maven-compiler-plugin.version> |
| 40 | 40 | <flatten-maven-plugin.version>1.5.0</flatten-maven-plugin.version> |
| 41 | 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 | 44 | <mapstruct.version>1.5.5.Final</mapstruct.version> |
| 45 | 45 | <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> |
| 46 | 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
sql/mysql/pay_wallet.sql
| ... | ... | @@ -73,3 +73,81 @@ CREATE TABLE `pay_wallet_recharge` |
| 73 | 73 | PRIMARY KEY (`id`) USING BTREE |
| 74 | 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 | 11 | Target Server Version : 80034 |
| 12 | 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 | 17 | SET NAMES utf8mb4; |
| ... | ... | @@ -72,6 +72,7 @@ CREATE TABLE `QRTZ_CRON_TRIGGERS` ( |
| 72 | 72 | -- Records of QRTZ_CRON_TRIGGERS |
| 73 | 73 | -- ---------------------------- |
| 74 | 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 | 76 | INSERT INTO `QRTZ_CRON_TRIGGERS` (`SCHED_NAME`, `TRIGGER_NAME`, `TRIGGER_GROUP`, `CRON_EXPRESSION`, `TIME_ZONE_ID`) VALUES ('schedulerName', 'payNotifyJob', 'DEFAULT', '* * * * * ?', 'Asia/Shanghai'); |
| 76 | 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 | 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 | 136 | -- Records of QRTZ_JOB_DETAILS |
| 136 | 137 | -- ---------------------------- |
| 137 | 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 | 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 | 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 | 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 | 193 | -- Records of QRTZ_SCHEDULER_STATE |
| 192 | 194 | -- ---------------------------- |
| 193 | 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 | 197 | COMMIT; |
| 196 | 198 | |
| 197 | 199 | -- ---------------------------- |
| ... | ... | @@ -285,6 +287,7 @@ CREATE TABLE `QRTZ_TRIGGERS` ( |
| 285 | 287 | -- Records of QRTZ_TRIGGERS |
| 286 | 288 | -- ---------------------------- |
| 287 | 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 | 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 | 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 | 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 | 363 | `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除', |
| 361 | 364 | `tenant_id` bigint NOT NULL DEFAULT 0 COMMENT '租户编号', |
| 362 | 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 | 369 | -- Records of infra_api_error_log |
| ... | ... | @@ -398,7 +401,7 @@ CREATE TABLE `infra_codegen_column` ( |
| 398 | 401 | `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间', |
| 399 | 402 | `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除', |
| 400 | 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 | 407 | -- Records of infra_codegen_column |
| ... | ... | @@ -514,7 +517,7 @@ CREATE TABLE `infra_file` ( |
| 514 | 517 | `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间', |
| 515 | 518 | `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除', |
| 516 | 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 | 523 | -- Records of infra_file |
| ... | ... | @@ -545,12 +548,7 @@ CREATE TABLE `infra_file_config` ( |
| 545 | 548 | -- Records of infra_file_config |
| 546 | 549 | -- ---------------------------- |
| 547 | 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 | 552 | COMMIT; |
| 555 | 553 | |
| 556 | 554 | -- ---------------------------- |
| ... | ... | @@ -568,7 +566,7 @@ CREATE TABLE `infra_file_content` ( |
| 568 | 566 | `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间', |
| 569 | 567 | `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除', |
| 570 | 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 | 572 | -- Records of infra_file_content |
| ... | ... | @@ -596,17 +594,17 @@ CREATE TABLE `infra_job` ( |
| 596 | 594 | `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间', |
| 597 | 595 | `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除', |
| 598 | 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 | 600 | -- Records of infra_job |
| 603 | 601 | -- ---------------------------- |
| 604 | 602 | BEGIN; |
| 605 | 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 | 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 | 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 | 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 | 608 | COMMIT; |
| 611 | 609 | |
| 612 | 610 | -- ---------------------------- |
| ... | ... | @@ -630,7 +628,7 @@ CREATE TABLE `infra_job_log` ( |
| 630 | 628 | `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间', |
| 631 | 629 | `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除', |
| 632 | 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 | 634 | -- Records of infra_job_log |
| ... | ... | @@ -803,7 +801,7 @@ CREATE TABLE `member_level_record` ( |
| 803 | 801 | `tenant_id` bigint NOT NULL DEFAULT 0 COMMENT '租户编号', |
| 804 | 802 | PRIMARY KEY (`id`) USING BTREE, |
| 805 | 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 | 807 | -- Records of member_level_record |
| ... | ... | @@ -828,7 +826,7 @@ CREATE TABLE `member_point_config` ( |
| 828 | 826 | `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除', |
| 829 | 827 | `tenant_id` bigint NOT NULL DEFAULT 0 COMMENT '租户编号', |
| 830 | 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 | 832 | -- Records of member_point_config |
| ... | ... | @@ -844,10 +842,10 @@ DROP TABLE IF EXISTS `member_point_record`; |
| 844 | 842 | CREATE TABLE `member_point_record` ( |
| 845 | 843 | `id` bigint NOT NULL AUTO_INCREMENT COMMENT '自增主键', |
| 846 | 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 | 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 | 849 | `point` int NOT NULL COMMENT '积分', |
| 852 | 850 | `total_point` int NOT NULL COMMENT '变动后的积分', |
| 853 | 851 | `creator` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT '' COMMENT '创建者', |
| ... | ... | @@ -859,7 +857,7 @@ CREATE TABLE `member_point_record` ( |
| 859 | 857 | PRIMARY KEY (`id`) USING BTREE, |
| 860 | 858 | INDEX `index_userId`(`user_id` ASC) USING BTREE, |
| 861 | 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 | 863 | -- Records of member_point_record |
| ... | ... | @@ -872,6 +870,15 @@ INSERT INTO `member_point_record` (`id`, `user_id`, `biz_id`, `biz_type`, `title |
| 872 | 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 | 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 | 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 | 882 | COMMIT; |
| 876 | 883 | |
| 877 | 884 | -- ---------------------------- |
| ... | ... | @@ -890,7 +897,7 @@ CREATE TABLE `member_sign_in_config` ( |
| 890 | 897 | `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除', |
| 891 | 898 | `tenant_id` bigint NOT NULL DEFAULT 0 COMMENT '租户编号', |
| 892 | 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 | 903 | -- Records of member_sign_in_config |
| ... | ... | @@ -919,20 +926,23 @@ CREATE TABLE `member_sign_in_record` ( |
| 919 | 926 | `user_id` int NULL DEFAULT NULL COMMENT '签到用户', |
| 920 | 927 | `day` int NULL DEFAULT NULL COMMENT '第几天签到', |
| 921 | 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 | 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 | 939 | -- Records of member_sign_in_record |
| 933 | 940 | -- ---------------------------- |
| 934 | 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 | 946 | COMMIT; |
| 937 | 947 | |
| 938 | 948 | -- ---------------------------- |
| ... | ... | @@ -972,7 +982,7 @@ CREATE TABLE `member_user` ( |
| 972 | 982 | `login_ip` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT '' COMMENT '最后登录IP', |
| 973 | 983 | `login_date` datetime NULL DEFAULT NULL COMMENT '最后登录时间', |
| 974 | 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 | 986 | `name` varchar(30) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT '' COMMENT '真实名字', |
| 977 | 987 | `sex` tinyint NULL DEFAULT 0 COMMENT '用户性别', |
| 978 | 988 | `area_id` bigint NULL DEFAULT NULL COMMENT '所在地', |
| ... | ... | @@ -989,9 +999,8 @@ CREATE TABLE `member_user` ( |
| 989 | 999 | `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间', |
| 990 | 1000 | `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除', |
| 991 | 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 | 1006 | -- Records of member_user |
| ... | ... | @@ -1305,7 +1314,7 @@ CREATE TABLE `system_dict_type` ( |
| 1305 | 1314 | `deleted_time` datetime NULL DEFAULT NULL COMMENT '删除时间', |
| 1306 | 1315 | PRIMARY KEY (`id`) USING BTREE, |
| 1307 | 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 | 1320 | -- Records of system_dict_type |
| ... | ... | @@ -1389,7 +1398,7 @@ CREATE TABLE `system_error_code` ( |
| 1389 | 1398 | `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间', |
| 1390 | 1399 | `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除', |
| 1391 | 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 | 1404 | -- Records of system_error_code |
| ... | ... | @@ -1418,7 +1427,7 @@ CREATE TABLE `system_login_log` ( |
| 1418 | 1427 | `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除', |
| 1419 | 1428 | `tenant_id` bigint NOT NULL DEFAULT 0 COMMENT '租户编号', |
| 1420 | 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 | 1433 | -- Records of system_login_log |
| ... | ... | @@ -1483,7 +1492,7 @@ CREATE TABLE `system_mail_log` ( |
| 1483 | 1492 | `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间', |
| 1484 | 1493 | `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除', |
| 1485 | 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 | 1498 | -- Records of system_mail_log |
| ... | ... | @@ -2116,7 +2125,7 @@ CREATE TABLE `system_oauth2_access_token` ( |
| 2116 | 2125 | `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除', |
| 2117 | 2126 | `tenant_id` bigint NOT NULL DEFAULT 0 COMMENT '租户编号', |
| 2118 | 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 | 2131 | -- Records of system_oauth2_access_token |
| ... | ... | @@ -2238,7 +2247,7 @@ CREATE TABLE `system_oauth2_refresh_token` ( |
| 2238 | 2247 | `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除', |
| 2239 | 2248 | `tenant_id` bigint NOT NULL DEFAULT 0 COMMENT '租户编号', |
| 2240 | 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 | 2253 | -- Records of system_oauth2_refresh_token |
| ... | ... | @@ -2278,7 +2287,7 @@ CREATE TABLE `system_operate_log` ( |
| 2278 | 2287 | `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除', |
| 2279 | 2288 | `tenant_id` bigint NOT NULL DEFAULT 0 COMMENT '租户编号', |
| 2280 | 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 | 2293 | -- Records of system_operate_log |
| ... | ... | @@ -3286,7 +3295,7 @@ CREATE TABLE `system_sms_code` ( |
| 3286 | 3295 | `tenant_id` bigint NOT NULL DEFAULT 0 COMMENT '租户编号', |
| 3287 | 3296 | PRIMARY KEY (`id`) USING BTREE, |
| 3288 | 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 | 3301 | -- Records of system_sms_code |
| ... | ... | @@ -3329,7 +3338,7 @@ CREATE TABLE `system_sms_log` ( |
| 3329 | 3338 | `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间', |
| 3330 | 3339 | `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除', |
| 3331 | 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 | 3344 | -- Records of system_sms_log |
| ... | ... | @@ -3401,7 +3410,7 @@ CREATE TABLE `system_social_user` ( |
| 3401 | 3410 | `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除', |
| 3402 | 3411 | `tenant_id` bigint NOT NULL DEFAULT 0 COMMENT '租户编号', |
| 3403 | 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 | 3416 | -- Records of system_social_user |
| ... | ... | @@ -3426,7 +3435,7 @@ CREATE TABLE `system_social_user_bind` ( |
| 3426 | 3435 | `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除', |
| 3427 | 3436 | `tenant_id` bigint NOT NULL DEFAULT 0 COMMENT '租户编号', |
| 3428 | 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 | 3441 | -- Records of system_social_user_bind |
| ... | ... | @@ -3462,8 +3471,8 @@ CREATE TABLE `system_tenant` ( |
| 3462 | 3471 | -- ---------------------------- |
| 3463 | 3472 | BEGIN; |
| 3464 | 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 | 3476 | COMMIT; |
| 3468 | 3477 | |
| 3469 | 3478 | -- ---------------------------- |
| ... | ... | @@ -3602,10 +3611,10 @@ CREATE TABLE `system_users` ( |
| 3602 | 3611 | -- Records of system_users |
| 3603 | 3612 | -- ---------------------------- |
| 3604 | 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 | 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 | 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 | 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 | 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 | 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
yudao-dependencies/pom.xml
| ... | ... | @@ -14,16 +14,16 @@ |
| 14 | 14 | <url>https://github.com/YunaiV/ruoyi-vue-pro</url> |
| 15 | 15 | |
| 16 | 16 | <properties> |
| 17 | - <revision>1.8.1-snapshot</revision> | |
| 17 | + <revision>1.8.2-snapshot</revision> | |
| 18 | 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 | 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 | 24 | <servlet.versoin>2.5</servlet.versoin> |
| 25 | 25 | <!-- DB 相关 --> |
| 26 | - <druid.version>1.2.18</druid.version> | |
| 26 | + <druid.version>1.2.19</druid.version> | |
| 27 | 27 | <mybatis-plus.version>3.5.3.2</mybatis-plus.version> |
| 28 | 28 | <mybatis-plus-generator.version>3.5.3.2</mybatis-plus-generator.version> |
| 29 | 29 | <dynamic-datasource.version>3.6.1</dynamic-datasource.version> |
| ... | ... | @@ -44,33 +44,32 @@ |
| 44 | 44 | <!-- Bpm 工作流相关 --> |
| 45 | 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 | 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 | 52 | <easyexcel.verion>3.3.2</easyexcel.verion> |
| 53 | 53 | <velocity.version>2.3</velocity.version> |
| 54 | 54 | <screw.version>1.0.5</screw.version> |
| 55 | 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 | 57 | <guice.version>5.1.0</guice.version> |
| 58 | 58 | <transmittable-thread-local.version>2.14.2</transmittable-thread-local.version> |
| 59 | 59 | <commons-net.version>3.9.0</commons-net.version> |
| 60 | 60 | <jsch.version>0.1.55</jsch.version> |
| 61 | 61 | <tika-core.version>2.7.0</tika-core.version> |
| 62 | - <netty-all.version>4.1.90.Final</netty-all.version> | |
| 63 | 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 | 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 | 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 | 73 | <xercesImpl.version>2.12.2</xercesImpl.version> |
| 75 | 74 | <weixin-java.version>4.5.0</weixin-java.version> |
| 76 | 75 | </properties> |
| ... | ... | @@ -233,6 +232,12 @@ |
| 233 | 232 | <groupId>org.redisson</groupId> |
| 234 | 233 | <artifactId>redisson-spring-boot-starter</artifactId> |
| 235 | 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 | 241 | </dependency> |
| 237 | 242 | |
| 238 | 243 | <dependency> |
| ... | ... | @@ -337,6 +342,12 @@ |
| 337 | 342 | <groupId>de.codecentric</groupId> |
| 338 | 343 | <artifactId>spring-boot-admin-starter-server</artifactId> <!-- 实现 Spring Boot Admin Server 服务端 --> |
| 339 | 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 | 351 | </dependency> |
| 341 | 352 | <dependency> |
| 342 | 353 | <groupId>de.codecentric</groupId> |
| ... | ... | @@ -520,12 +531,6 @@ |
| 520 | 531 | </dependency> |
| 521 | 532 | |
| 522 | 533 | <dependency> |
| 523 | - <groupId>io.netty</groupId> | |
| 524 | - <artifactId>netty-all</artifactId> | |
| 525 | - <version>${netty-all.version}</version> | |
| 526 | - </dependency> | |
| 527 | - | |
| 528 | - <dependency> | |
| 529 | 534 | <groupId>com.xingyuv</groupId> |
| 530 | 535 | <artifactId>spring-boot-starter-captcha-plus</artifactId> |
| 531 | 536 | <version>${captcha-plus.version}</version> | ... | ... |
yudao-example/yudao-sso-demo-by-code/pom.xml
| ... | ... | @@ -21,7 +21,7 @@ |
| 21 | 21 | <maven.compiler.target>8</maven.compiler.target> |
| 22 | 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 | 25 | </properties> |
| 26 | 26 | |
| 27 | 27 | <dependencyManagement> |
| ... | ... | @@ -52,7 +52,7 @@ |
| 52 | 52 | <dependency> |
| 53 | 53 | <groupId>cn.hutool</groupId> |
| 54 | 54 | <artifactId>hutool-all</artifactId> |
| 55 | - <version>5.8.20</version> | |
| 55 | + <version>5.8.22</version> | |
| 56 | 56 | </dependency> |
| 57 | 57 | |
| 58 | 58 | <dependency> | ... | ... |
yudao-example/yudao-sso-demo-by-password/pom.xml
| ... | ... | @@ -21,7 +21,7 @@ |
| 21 | 21 | <maven.compiler.target>8</maven.compiler.target> |
| 22 | 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 | 25 | </properties> |
| 26 | 26 | |
| 27 | 27 | <dependencyManagement> |
| ... | ... | @@ -52,7 +52,7 @@ |
| 52 | 52 | <dependency> |
| 53 | 53 | <groupId>cn.hutool</groupId> |
| 54 | 54 | <artifactId>hutool-all</artifactId> |
| 55 | - <version>5.8.20</version> | |
| 55 | + <version>5.8.22</version> | |
| 56 | 56 | </dependency> |
| 57 | 57 | |
| 58 | 58 | <dependency> | ... | ... |
yudao-framework/yudao-common/pom.xml
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 | 10 | import com.fasterxml.jackson.databind.SerializationFeature; |
| 11 | 11 | import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule; |
| 12 | 12 | import lombok.SneakyThrows; |
| 13 | -import lombok.experimental.UtilityClass; | |
| 14 | 13 | import lombok.extern.slf4j.Slf4j; |
| 15 | 14 | |
| 16 | 15 | import java.io.IOException; |
| ... | ... | @@ -23,7 +22,6 @@ import java.util.List; |
| 23 | 22 | * |
| 24 | 23 | * @author 芋道源码 |
| 25 | 24 | */ |
| 26 | -@UtilityClass | |
| 27 | 25 | @Slf4j |
| 28 | 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 | 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 | 71 | PayTransferRespDTO respDTO = new PayTransferRespDTO(); |
| 72 | - respDTO.status = PayTransferStatusRespEnum.FAILURE.getStatus(); | |
| 72 | + respDTO.status = PayTransferStatusRespEnum.CLOSED.getStatus(); | |
| 73 | 73 | respDTO.channelErrorCode = channelErrorCode; |
| 74 | 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
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<Config extends PayClientConfig> implemen |
| 50 | 50 | */ |
| 51 | 51 | public final void init() { |
| 52 | 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 | 51 | model.setProductCode("TRANS_ACCOUNT_NO_PWD"); // 销售产品码。单笔无密转账固定为 TRANS_ACCOUNT_NO_PWD |
| 52 | 52 | model.setBizScene("DIRECT_TRANSFER"); // 业务场景 单笔无密转账固定为 DIRECT_TRANSFER。 |
| 53 | 53 | model.setBusinessParams(JsonUtils.toJsonString(reqDTO.getChannelExtras())); |
| 54 | - PayTransferTypeEnum transferType = PayTransferTypeEnum.valueOf(reqDTO.getType()); | |
| 54 | + PayTransferTypeEnum transferType = PayTransferTypeEnum.ofType(reqDTO.getType()); | |
| 55 | 55 | switch(transferType){ |
| 56 | 56 | case WX_BALANCE : |
| 57 | 57 | case WALLET_BALANCE : { |
| ... | ... | @@ -84,7 +84,7 @@ public class AlipayTransferClient extends AbstractAlipayPayClient { |
| 84 | 84 | if (ObjectUtils.equalsAny(response.getSubCode(), "SYSTEM_ERROR", "ACQ.SYSTEM_ERROR")) { |
| 85 | 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 | 88 | reqDTO.getOutTransferNo(), response); |
| 89 | 89 | } |
| 90 | 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 | 3 | import lombok.AllArgsConstructor; |
| 4 | 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 | 14 | @AllArgsConstructor |
| 13 | 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 | 31 | private final Integer status; |
| 20 | 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 | 20 | BANK_CARD(3, "银行卡"), |
| 21 | 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 | 26 | private final Integer type; |
| 24 | 27 | private final String name; |
| 25 | 28 | |
| ... | ... | @@ -30,7 +33,7 @@ public enum PayTransferTypeEnum implements IntArrayValuable { |
| 30 | 33 | return ARRAYS; |
| 31 | 34 | } |
| 32 | 35 | |
| 33 | - public static PayTransferTypeEnum valueOf(Integer type) { | |
| 36 | + public static PayTransferTypeEnum ofType(Integer type) { | |
| 34 | 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
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 | 1 | package cn.iocoder.yudao.framework.tenant.config; |
| 2 | 2 | |
| 3 | -import cn.hutool.core.annotation.AnnotationUtil; | |
| 4 | 3 | import cn.iocoder.yudao.framework.common.enums.WebFilterOrderEnum; |
| 5 | 4 | import cn.iocoder.yudao.framework.mybatis.core.util.MyBatisUtils; |
| 6 | -import cn.iocoder.yudao.framework.quartz.core.handler.JobHandler; | |
| 7 | 5 | import cn.iocoder.yudao.framework.redis.config.YudaoCacheProperties; |
| 8 | 6 | import cn.iocoder.yudao.framework.tenant.core.aop.TenantIgnoreAspect; |
| 9 | 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 | 9 | import cn.iocoder.yudao.framework.tenant.core.mq.TenantRedisMessageInterceptor; |
| 13 | 10 | import cn.iocoder.yudao.framework.tenant.core.redis.TenantRedisCacheManager; |
| 14 | 11 | import cn.iocoder.yudao.framework.tenant.core.security.TenantSecurityWebFilter; |
| ... | ... | @@ -20,8 +17,6 @@ import cn.iocoder.yudao.framework.web.core.handler.GlobalExceptionHandler; |
| 20 | 17 | import cn.iocoder.yudao.module.system.api.tenant.TenantApi; |
| 21 | 18 | import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor; |
| 22 | 19 | import com.baomidou.mybatisplus.extension.plugins.inner.TenantLineInnerInterceptor; |
| 23 | -import org.springframework.beans.BeansException; | |
| 24 | -import org.springframework.beans.factory.config.BeanPostProcessor; | |
| 25 | 20 | import org.springframework.boot.autoconfigure.AutoConfiguration; |
| 26 | 21 | import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; |
| 27 | 22 | import org.springframework.boot.context.properties.EnableConfigurationProperties; |
| ... | ... | @@ -100,25 +95,8 @@ public class YudaoTenantAutoConfiguration { |
| 100 | 95 | // ========== Job ========== |
| 101 | 96 | |
| 102 | 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 | 102 | // ========== Redis ========== | ... | ... |
yudao-framework/yudao-spring-boot-starter-biz-tenant/src/main/java/cn/iocoder/yudao/framework/tenant/core/job/TenantJob.java
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 | 1 | package cn.iocoder.yudao.framework.tenant.core.job; |
| 2 | 2 | |
| 3 | 3 | import cn.hutool.core.collection.CollUtil; |
| 4 | +import cn.hutool.core.exceptions.ExceptionUtil; | |
| 4 | 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 | 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 | 14 | import java.util.List; |
| 11 | 15 | import java.util.Map; |
| 12 | 16 | import java.util.concurrent.ConcurrentHashMap; |
| 13 | 17 | |
| 14 | 18 | /** |
| 15 | - * 多租户 JobHandler 装饰器 | |
| 19 | + * 多租户 JobHandler AOP | |
| 16 | 20 | * 任务执行时,会按照租户逐个执行 Job 的逻辑 |
| 17 | 21 | * |
| 18 | 22 | * 注意,需要保证 JobHandler 的幂等性。因为 Job 因为某个租户执行失败重试时,之前执行成功的租户也会再次执行。 |
| 19 | 23 | * |
| 20 | 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 | 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 | 36 | List<Long> tenantIds = tenantFrameworkService.getTenantIds(); |
| 35 | 37 | if (CollUtil.isEmpty(tenantIds)) { |
| ... | ... | @@ -38,19 +40,15 @@ public class TenantJobHandlerDecorator implements JobHandler { |
| 38 | 40 | |
| 39 | 41 | // 逐个租户,执行 Job |
| 40 | 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 | 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 | 1 | package cn.iocoder.yudao.framework.tenant.core.redis; |
| 2 | 2 | |
| 3 | +import cn.iocoder.yudao.framework.redis.core.TimeoutRedisCacheManager; | |
| 3 | 4 | import cn.iocoder.yudao.framework.tenant.core.context.TenantContextHolder; |
| 4 | 5 | import lombok.extern.slf4j.Slf4j; |
| 5 | 6 | import org.springframework.cache.Cache; |
| ... | ... | @@ -15,7 +16,7 @@ import org.springframework.data.redis.cache.RedisCacheWriter; |
| 15 | 16 | * @author airhead |
| 16 | 17 | */ |
| 17 | 18 | @Slf4j |
| 18 | -public class TenantRedisCacheManager extends RedisCacheManager { | |
| 19 | +public class TenantRedisCacheManager extends TimeoutRedisCacheManager { | |
| 19 | 20 | |
| 20 | 21 | public TenantRedisCacheManager(RedisCacheWriter cacheWriter, |
| 21 | 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 | 9 | import java.util.concurrent.CopyOnWriteArrayList; |
| 10 | 10 | |
| 11 | 11 | @Component |
| 12 | -@TenantJob // 标记多租户 | |
| 13 | 12 | public class TestJob implements JobHandler { |
| 14 | 13 | |
| 15 | 14 | private final List<Long> tenantIds = new CopyOnWriteArrayList<>(); |
| 16 | 15 | |
| 17 | 16 | @Override |
| 17 | + @TenantJob // 标记多租户 | |
| 18 | 18 | public String execute(String param) throws Exception { |
| 19 | 19 | tenantIds.add(TenantContextHolder.getTenantId()); |
| 20 | 20 | return "success"; |
| ... | ... | @@ -24,4 +24,5 @@ public class TestJob implements JobHandler { |
| 24 | 24 | CollUtil.sort(tenantIds, Long::compareTo); |
| 25 | 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
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 | 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 | 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 | 6 | * Flowable 相关的工具方法 |
| 14 | 7 | * |
| ... | ... | @@ -26,49 +19,6 @@ public class FlowableUtils { |
| 26 | 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 | 22 | // ========== Execution 相关的工具方法 ========== |
| 73 | 23 | |
| 74 | 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 | 1 | package cn.iocoder.yudao.framework.quartz.config; |
| 2 | 2 | |
| 3 | 3 | import cn.iocoder.yudao.framework.quartz.core.scheduler.SchedulerManager; |
| 4 | +import lombok.extern.slf4j.Slf4j; | |
| 4 | 5 | import org.quartz.Scheduler; |
| 5 | 6 | import org.springframework.boot.autoconfigure.AutoConfiguration; |
| 6 | 7 | import org.springframework.context.annotation.Bean; |
| 7 | 8 | import org.springframework.scheduling.annotation.EnableScheduling; |
| 8 | 9 | |
| 10 | +import java.util.Optional; | |
| 11 | + | |
| 9 | 12 | /** |
| 10 | 13 | * 定时任务 Configuration |
| 11 | 14 | */ |
| 12 | 15 | @AutoConfiguration |
| 13 | 16 | @EnableScheduling // 开启 Spring 自带的定时任务 |
| 17 | +@Slf4j | |
| 14 | 18 | public class YudaoQuartzAutoConfiguration { |
| 15 | 19 | |
| 16 | 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 | 4 | import cn.iocoder.yudao.framework.quartz.core.handler.JobHandlerInvoker; |
| 5 | 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 | 11 | * {@link org.quartz.Scheduler} 的管理器,负责创建任务 |
| 9 | 12 | * |
| ... | ... | @@ -37,6 +40,7 @@ public class SchedulerManager { |
| 37 | 40 | public void addJob(Long jobId, String jobHandlerName, String jobHandlerParam, String cronExpression, |
| 38 | 41 | Integer retryCount, Integer retryInterval) |
| 39 | 42 | throws SchedulerException { |
| 43 | + validateScheduler(); | |
| 40 | 44 | // 创建 JobDetail 对象 |
| 41 | 45 | JobDetail jobDetail = JobBuilder.newJob(JobHandlerInvoker.class) |
| 42 | 46 | .usingJobData(JobDataKeyEnum.JOB_ID.name(), jobId) |
| ... | ... | @@ -61,6 +65,7 @@ public class SchedulerManager { |
| 61 | 65 | public void updateJob(String jobHandlerName, String jobHandlerParam, String cronExpression, |
| 62 | 66 | Integer retryCount, Integer retryInterval) |
| 63 | 67 | throws SchedulerException { |
| 68 | + validateScheduler(); | |
| 64 | 69 | // 创建新 Trigger 对象 |
| 65 | 70 | Trigger newTrigger = this.buildTrigger(jobHandlerName, jobHandlerParam, cronExpression, retryCount, retryInterval); |
| 66 | 71 | // 修改调度 |
| ... | ... | @@ -74,6 +79,7 @@ public class SchedulerManager { |
| 74 | 79 | * @throws SchedulerException 删除异常 |
| 75 | 80 | */ |
| 76 | 81 | public void deleteJob(String jobHandlerName) throws SchedulerException { |
| 82 | + validateScheduler(); | |
| 77 | 83 | scheduler.deleteJob(new JobKey(jobHandlerName)); |
| 78 | 84 | } |
| 79 | 85 | |
| ... | ... | @@ -84,6 +90,7 @@ public class SchedulerManager { |
| 84 | 90 | * @throws SchedulerException 暂停异常 |
| 85 | 91 | */ |
| 86 | 92 | public void pauseJob(String jobHandlerName) throws SchedulerException { |
| 93 | + validateScheduler(); | |
| 87 | 94 | scheduler.pauseJob(new JobKey(jobHandlerName)); |
| 88 | 95 | } |
| 89 | 96 | |
| ... | ... | @@ -94,6 +101,7 @@ public class SchedulerManager { |
| 94 | 101 | * @throws SchedulerException 启动异常 |
| 95 | 102 | */ |
| 96 | 103 | public void resumeJob(String jobHandlerName) throws SchedulerException { |
| 104 | + validateScheduler(); | |
| 97 | 105 | scheduler.resumeJob(new JobKey(jobHandlerName)); |
| 98 | 106 | scheduler.resumeTrigger(new TriggerKey(jobHandlerName)); |
| 99 | 107 | } |
| ... | ... | @@ -108,11 +116,12 @@ public class SchedulerManager { |
| 108 | 116 | */ |
| 109 | 117 | public void triggerJob(Long jobId, String jobHandlerName, String jobHandlerParam) |
| 110 | 118 | throws SchedulerException { |
| 119 | + validateScheduler(); | |
| 120 | + // 触发任务 | |
| 111 | 121 | JobDataMap data = new JobDataMap(); // 无需重试,所以不设置 retryCount 和 retryInterval |
| 112 | 122 | data.put(JobDataKeyEnum.JOB_ID.name(), jobId); |
| 113 | 123 | data.put(JobDataKeyEnum.JOB_HANDLER_NAME.name(), jobHandlerName); |
| 114 | 124 | data.put(JobDataKeyEnum.JOB_HANDLER_PARAM.name(), jobHandlerParam); |
| 115 | - // 触发任务 | |
| 116 | 125 | scheduler.triggerJob(new JobKey(jobHandlerName), data); |
| 117 | 126 | } |
| 118 | 127 | |
| ... | ... | @@ -127,4 +136,11 @@ public class SchedulerManager { |
| 127 | 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 | import com.baomidou.mybatisplus.core.conditions.Wrapper; |
| 8 | 8 | import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; |
| 9 | 9 | import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; |
| 10 | -import com.baomidou.mybatisplus.core.mapper.BaseMapper; | |
| 11 | 10 | import com.baomidou.mybatisplus.core.metadata.IPage; |
| 12 | 11 | import com.baomidou.mybatisplus.core.toolkit.support.SFunction; |
| 13 | 12 | import com.baomidou.mybatisplus.extension.toolkit.Db; | ... | ... |
yudao-framework/yudao-spring-boot-starter-protection/pom.xml
| ... | ... | @@ -26,11 +26,13 @@ |
| 26 | 26 | <dependency> |
| 27 | 27 | <groupId>com.baomidou</groupId> |
| 28 | 28 | <artifactId>lock4j-redisson-spring-boot-starter</artifactId> |
| 29 | + <optional>true</optional> | |
| 29 | 30 | </dependency> |
| 30 | 31 | |
| 31 | 32 | <dependency> |
| 32 | 33 | <groupId>io.github.resilience4j</groupId> |
| 33 | 34 | <artifactId>resilience4j-spring-boot2</artifactId> |
| 35 | + <optional>true</optional> | |
| 34 | 36 | </dependency> |
| 35 | 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 | 3 | import cn.iocoder.yudao.framework.lock4j.core.DefaultLockFailureStrategy; |
| 4 | 4 | import com.baomidou.lock.spring.boot.autoconfigure.LockAutoConfiguration; |
| 5 | 5 | import org.springframework.boot.autoconfigure.AutoConfiguration; |
| 6 | +import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; | |
| 6 | 7 | import org.springframework.context.annotation.Bean; |
| 7 | 8 | |
| 8 | 9 | @AutoConfiguration(before = LockAutoConfiguration.class) |
| 10 | +@ConditionalOnClass(name = "com.baomidou.lock.annotation.Lock4j") | |
| 9 | 11 | public class YudaoLock4jConfiguration { |
| 10 | 12 | |
| 11 | 13 | @Bean | ... | ... |
yudao-framework/yudao-spring-boot-starter-redis/pom.xml
| ... | ... | @@ -33,12 +33,6 @@ |
| 33 | 33 | </dependency> |
| 34 | 34 | |
| 35 | 35 | <dependency> |
| 36 | - <groupId>io.netty</groupId> | |
| 37 | - <artifactId>netty-all</artifactId> | |
| 38 | - </dependency> | |
| 39 | - | |
| 40 | - | |
| 41 | - <dependency> | |
| 42 | 36 | <groupId>com.fasterxml.jackson.datatype</groupId> |
| 43 | 37 | <artifactId>jackson-datatype-jsr310</artifactId> |
| 44 | 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 | 45 | Duration duration = parseDuration(names[1]); |
| 46 | 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 | 55 | <version>${revision}</version> |
| 56 | 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 | 58 | <!-- xss --> |
| 66 | 59 | <dependency> |
| 67 | 60 | <groupId>org.jsoup</groupId> | ... | ... |
yudao-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/jackson/config/YudaoJacksonAutoConfiguration.java
| 1 | 1 | package cn.iocoder.yudao.framework.jackson.config; |
| 2 | 2 | |
| 3 | +import cn.hutool.core.collection.CollUtil; | |
| 3 | 4 | import cn.iocoder.yudao.framework.common.util.json.JsonUtils; |
| 4 | 5 | import cn.iocoder.yudao.framework.jackson.core.databind.LocalDateTimeDeserializer; |
| 5 | 6 | import cn.iocoder.yudao.framework.jackson.core.databind.LocalDateTimeSerializer; |
| ... | ... | @@ -11,51 +12,41 @@ import com.fasterxml.jackson.datatype.jsr310.deser.LocalTimeDeserializer; |
| 11 | 12 | import com.fasterxml.jackson.datatype.jsr310.ser.LocalDateSerializer; |
| 12 | 13 | import com.fasterxml.jackson.datatype.jsr310.ser.LocalTimeSerializer; |
| 13 | 14 | import lombok.extern.slf4j.Slf4j; |
| 14 | -import org.springframework.beans.BeansException; | |
| 15 | -import org.springframework.beans.factory.config.BeanPostProcessor; | |
| 16 | 15 | import org.springframework.boot.autoconfigure.AutoConfiguration; |
| 17 | 16 | import org.springframework.context.annotation.Bean; |
| 18 | 17 | |
| 19 | 18 | import java.time.LocalDate; |
| 20 | 19 | import java.time.LocalDateTime; |
| 21 | 20 | import java.time.LocalTime; |
| 21 | +import java.util.List; | |
| 22 | 22 | |
| 23 | 23 | @AutoConfiguration |
| 24 | 24 | @Slf4j |
| 25 | 25 | public class YudaoJacksonAutoConfiguration { |
| 26 | 26 | |
| 27 | 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 | 11 | import cn.iocoder.yudao.framework.common.util.monitor.TracerUtils; |
| 12 | 12 | import cn.iocoder.yudao.framework.common.util.servlet.ServletUtils; |
| 13 | 13 | import cn.iocoder.yudao.framework.web.core.util.WebFrameworkUtils; |
| 14 | -import io.github.resilience4j.ratelimiter.RequestNotPermitted; | |
| 15 | 14 | import lombok.AllArgsConstructor; |
| 16 | 15 | import lombok.extern.slf4j.Slf4j; |
| 17 | 16 | import org.apache.commons.lang3.exception.ExceptionUtils; |
| ... | ... | @@ -33,6 +32,7 @@ import javax.validation.ConstraintViolationException; |
| 33 | 32 | import javax.validation.ValidationException; |
| 34 | 33 | import java.time.LocalDateTime; |
| 35 | 34 | import java.util.Map; |
| 35 | +import java.util.Objects; | |
| 36 | 36 | |
| 37 | 37 | import static cn.iocoder.yudao.framework.common.exception.enums.GlobalErrorCodeConstants.*; |
| 38 | 38 | |
| ... | ... | @@ -83,9 +83,6 @@ public class GlobalExceptionHandler { |
| 83 | 83 | if (ex instanceof HttpRequestMethodNotSupportedException) { |
| 84 | 84 | return httpRequestMethodNotSupportedExceptionHandler((HttpRequestMethodNotSupportedException) ex); |
| 85 | 85 | } |
| 86 | - if (ex instanceof RequestNotPermitted) { | |
| 87 | - return requestNotPermittedExceptionHandler(request, (RequestNotPermitted) ex); | |
| 88 | - } | |
| 89 | 86 | if (ex instanceof ServiceException) { |
| 90 | 87 | return serviceExceptionHandler((ServiceException) ex); |
| 91 | 88 | } |
| ... | ... | @@ -186,8 +183,7 @@ public class GlobalExceptionHandler { |
| 186 | 183 | /** |
| 187 | 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 | 187 | log.warn("[requestNotPermittedExceptionHandler][url({}) 访问过于频繁]", req.getRequestURL(), ex); |
| 192 | 188 | return CommonResult.error(TOO_MANY_REQUESTS); |
| 193 | 189 | } |
| ... | ... | @@ -226,7 +222,12 @@ public class GlobalExceptionHandler { |
| 226 | 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 | 231 | log.error("[defaultExceptionHandler]", ex); |
| 231 | 232 | // 插入异常日志 |
| 232 | 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 | 21 | |
| 22 | 22 | @AutoConfiguration |
| 23 | 23 | @EnableConfigurationProperties(XssProperties.class) |
| 24 | +@ConditionalOnProperty(prefix = "yudao.xss", name = "enable", havingValue = "true", matchIfMissing = true) // 设置为 false 时,禁用 | |
| 24 | 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 | 1 | cn.iocoder.yudao.framework.apilog.config.YudaoApiLogAutoConfiguration |
| 2 | 2 | cn.iocoder.yudao.framework.jackson.config.YudaoJacksonAutoConfiguration |
| 3 | -com.github.xiaoymin.knife4j.spring.configuration.Knife4jAutoConfiguration | |
| 4 | 3 | cn.iocoder.yudao.framework.swagger.config.YudaoSwaggerAutoConfiguration |
| 5 | 4 | cn.iocoder.yudao.framework.web.config.YudaoWebAutoConfiguration |
| 6 | 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 | 4 | |
| 5 | 5 | /** |
| 6 | 6 | * Bpm 错误码枚举类 |
| 7 | - * | |
| 7 | + * <p> | |
| 8 | 8 | * bpm 系统,使用 1-009-000-000 段 |
| 9 | 9 | */ |
| 10 | 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
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 | 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 | 6 | import cn.iocoder.yudao.framework.common.util.number.NumberUtils; |
| 7 | 7 | import cn.iocoder.yudao.module.bpm.controller.admin.task.vo.task.BpmTaskDonePageItemRespVO; |
| 8 | 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 | 10 | import cn.iocoder.yudao.module.bpm.controller.admin.task.vo.task.BpmTaskTodoPageItemRespVO; |
| 10 | 11 | import cn.iocoder.yudao.module.bpm.dal.dataobject.task.BpmTaskExtDO; |
| 11 | 12 | import cn.iocoder.yudao.module.bpm.service.message.dto.BpmMessageSendWhenTaskCreatedReqDTO; |
| 12 | 13 | import cn.iocoder.yudao.module.system.api.dept.dto.DeptRespDTO; |
| 13 | 14 | import cn.iocoder.yudao.module.system.api.user.dto.AdminUserRespDTO; |
| 15 | +import org.flowable.bpmn.model.FlowElement; | |
| 14 | 16 | import org.flowable.common.engine.impl.db.SuspensionState; |
| 15 | 17 | import org.flowable.engine.history.HistoricProcessInstance; |
| 16 | 18 | import org.flowable.engine.runtime.ProcessInstance; |
| ... | ... | @@ -55,8 +57,8 @@ public interface BpmTaskConvert { |
| 55 | 57 | } |
| 56 | 58 | |
| 57 | 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 | 62 | return CollectionUtils.convertList(tasks, task -> { |
| 61 | 63 | BpmTaskDonePageItemRespVO respVO = convert2(task); |
| 62 | 64 | BpmTaskExtDO taskExtDO = bpmTaskExtDOMap.get(task.getId()); |
| ... | ... | @@ -82,8 +84,8 @@ public interface BpmTaskConvert { |
| 82 | 84 | BpmTaskTodoPageItemRespVO.ProcessInstance convert(ProcessInstance processInstance, AdminUserRespDTO startUser); |
| 83 | 85 | |
| 84 | 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 | 89 | return CollectionUtils.convertList(tasks, task -> { |
| 88 | 90 | BpmTaskRespVO respVO = convert3(task); |
| 89 | 91 | BpmTaskExtDO taskExtDO = bpmTaskExtDOMap.get(task.getId()); |
| ... | ... | @@ -113,29 +115,34 @@ public interface BpmTaskConvert { |
| 113 | 115 | void copyTo(BpmTaskExtDO from, @MappingTarget BpmTaskDonePageItemRespVO to); |
| 114 | 116 | |
| 115 | 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 | 122 | BpmTaskTodoPageItemRespVO.ProcessInstance convert(HistoricProcessInstance processInstance, |
| 121 | - AdminUserRespDTO startUser); | |
| 123 | + AdminUserRespDTO startUser); | |
| 122 | 124 | |
| 123 | 125 | default BpmTaskExtDO convert2TaskExt(Task task) { |
| 124 | 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 | 129 | taskExtDO.setCreateTime(LocalDateTimeUtil.of(task.getCreateTime())); |
| 128 | 130 | return taskExtDO; |
| 129 | 131 | } |
| 130 | 132 | |
| 131 | 133 | default BpmMessageSendWhenTaskCreatedReqDTO convert(ProcessInstance processInstance, AdminUserRespDTO startUser, |
| 132 | - Task task) { | |
| 134 | + Task task) { | |
| 133 | 135 | BpmMessageSendWhenTaskCreatedReqDTO reqDTO = new BpmMessageSendWhenTaskCreatedReqDTO(); |
| 134 | 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 | 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 | 74 | */ |
| 75 | 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 | 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 | 241 | private void checkKeyNCName(String key) { |
| 237 | 242 | if (!ValidationUtils.isXmlNCName(key)) { |
| 238 | 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 | 5 | import cn.hutool.core.util.StrUtil; |
| 6 | 6 | import cn.iocoder.yudao.framework.common.pojo.PageResult; |
| 7 | 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 | 9 | import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.process.BpmProcessDefinitionListReqVO; |
| 10 | 10 | import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.process.BpmProcessDefinitionPageItemRespVO; |
| 11 | 11 | import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.process.BpmProcessDefinitionPageReqVO; |
| ... | ... | @@ -200,7 +200,7 @@ public class BpmProcessDefinitionServiceImpl implements BpmProcessDefinitionServ |
| 200 | 200 | BpmnModel newModel = buildBpmnModel(createReqDTO.getBpmnBytes()); |
| 201 | 201 | BpmnModel oldModel = getBpmnModel(oldProcessDefinition.getId()); |
| 202 | 202 | // 对比字节变化 |
| 203 | - if (!FlowableUtils.equals(oldModel, newModel)) { | |
| 203 | + if (!BpmnModelUtils.equals(oldModel, newModel)) { | |
| 204 | 204 | return false; |
| 205 | 205 | } |
| 206 | 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 | import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils; |
| 8 | 8 | import cn.iocoder.yudao.framework.common.util.object.ObjectUtils; |
| 9 | 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 | 11 | import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.rule.BpmTaskAssignRuleCreateReqVO; |
| 12 | 12 | import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.rule.BpmTaskAssignRuleRespVO; |
| 13 | 13 | import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.rule.BpmTaskAssignRuleUpdateReqVO; |
| ... | ... | @@ -114,7 +114,7 @@ public class BpmTaskAssignRuleServiceImpl implements BpmTaskAssignRuleService { |
| 114 | 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 | 118 | if (CollUtil.isEmpty(userTasks)) { |
| 119 | 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 | 1 | package cn.iocoder.yudao.module.bpm.service.task; |
| 2 | 2 | |
| 3 | -import cn.iocoder.yudao.framework.common.pojo.CommonResult; | |
| 4 | 3 | import cn.iocoder.yudao.framework.common.pojo.PageResult; |
| 5 | 4 | import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils; |
| 6 | 5 | import cn.iocoder.yudao.module.bpm.controller.admin.task.vo.task.*; |
| ... | ... | @@ -23,7 +22,6 @@ public interface BpmTaskService { |
| 23 | 22 | * |
| 24 | 23 | * @param userId 用户编号 |
| 25 | 24 | * @param pageReqVO 分页请求 |
| 26 | - * | |
| 27 | 25 | * @return 流程任务分页 |
| 28 | 26 | */ |
| 29 | 27 | PageResult<BpmTaskTodoPageItemRespVO> getTodoTaskPage(Long userId, BpmTaskTodoPageReqVO pageReqVO); |
| ... | ... | @@ -33,7 +31,6 @@ public interface BpmTaskService { |
| 33 | 31 | * |
| 34 | 32 | * @param userId 用户编号 |
| 35 | 33 | * @param pageReqVO 分页请求 |
| 36 | - * | |
| 37 | 34 | * @return 流程任务分页 |
| 38 | 35 | */ |
| 39 | 36 | PageResult<BpmTaskDonePageItemRespVO> getDoneTaskPage(Long userId, BpmTaskDonePageReqVO pageReqVO); |
| ... | ... | @@ -42,19 +39,17 @@ public interface BpmTaskService { |
| 42 | 39 | * 获得流程任务 Map |
| 43 | 40 | * |
| 44 | 41 | * @param processInstanceIds 流程实例的编号数组 |
| 45 | - * | |
| 46 | 42 | * @return 流程任务 Map |
| 47 | 43 | */ |
| 48 | 44 | default Map<String, List<Task>> getTaskMapByProcessInstanceIds(List<String> processInstanceIds) { |
| 49 | 45 | return CollectionUtils.convertMultiMap(getTasksByProcessInstanceIds(processInstanceIds), |
| 50 | - Task::getProcessInstanceId); | |
| 46 | + Task::getProcessInstanceId); | |
| 51 | 47 | } |
| 52 | 48 | |
| 53 | 49 | /** |
| 54 | 50 | * 获得流程任务列表 |
| 55 | 51 | * |
| 56 | 52 | * @param processInstanceIds 流程实例的编号数组 |
| 57 | - * | |
| 58 | 53 | * @return 流程任务列表 |
| 59 | 54 | */ |
| 60 | 55 | List<Task> getTasksByProcessInstanceIds(List<String> processInstanceIds); |
| ... | ... | @@ -63,7 +58,6 @@ public interface BpmTaskService { |
| 63 | 58 | * 获得指令流程实例的流程任务列表,包括所有状态的 |
| 64 | 59 | * |
| 65 | 60 | * @param processInstanceId 流程实例的编号 |
| 66 | - * | |
| 67 | 61 | * @return 流程任务列表 |
| 68 | 62 | */ |
| 69 | 63 | List<BpmTaskRespVO> getTaskListByProcessInstanceId(String processInstanceId); |
| ... | ... | @@ -128,4 +122,29 @@ public interface BpmTaskService { |
| 128 | 122 | */ |
| 129 | 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 | 1 | package cn.iocoder.yudao.module.bpm.service.task; |
| 2 | 2 | |
| 3 | 3 | import cn.hutool.core.collection.CollUtil; |
| 4 | -import cn.hutool.core.collection.ListUtil; | |
| 5 | 4 | import cn.hutool.core.util.ArrayUtil; |
| 6 | 5 | import cn.hutool.core.util.StrUtil; |
| 7 | 6 | import cn.iocoder.yudao.framework.common.pojo.PageResult; |
| 8 | 7 | import cn.iocoder.yudao.framework.common.util.date.DateUtils; |
| 9 | 8 | import cn.iocoder.yudao.framework.common.util.number.NumberUtils; |
| 10 | 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 | 12 | import cn.iocoder.yudao.module.bpm.controller.admin.task.vo.task.*; |
| 12 | 13 | import cn.iocoder.yudao.module.bpm.convert.task.BpmTaskConvert; |
| 13 | 14 | import cn.iocoder.yudao.module.bpm.dal.dataobject.task.BpmTaskExtDO; |
| 14 | 15 | import cn.iocoder.yudao.module.bpm.dal.mysql.task.BpmTaskExtMapper; |
| 15 | 16 | import cn.iocoder.yudao.module.bpm.enums.task.BpmProcessInstanceDeleteReasonEnum; |
| 16 | 17 | import cn.iocoder.yudao.module.bpm.enums.task.BpmProcessInstanceResultEnum; |
| 18 | +import cn.iocoder.yudao.module.bpm.service.definition.BpmModelService; | |
| 17 | 19 | import cn.iocoder.yudao.module.bpm.service.message.BpmMessageService; |
| 18 | 20 | import cn.iocoder.yudao.module.system.api.dept.DeptApi; |
| 19 | 21 | import cn.iocoder.yudao.module.system.api.dept.dto.DeptRespDTO; |
| 20 | 22 | import cn.iocoder.yudao.module.system.api.user.AdminUserApi; |
| 21 | 23 | import cn.iocoder.yudao.module.system.api.user.dto.AdminUserRespDTO; |
| 22 | 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 | 28 | import org.flowable.engine.HistoryService; |
| 29 | +import org.flowable.engine.RuntimeService; | |
| 24 | 30 | import org.flowable.engine.TaskService; |
| 25 | 31 | import org.flowable.engine.history.HistoricProcessInstance; |
| 26 | 32 | import org.flowable.engine.runtime.ProcessInstance; |
| 33 | +import org.flowable.task.api.DelegationState; | |
| 27 | 34 | import org.flowable.task.api.Task; |
| 28 | 35 | import org.flowable.task.api.TaskQuery; |
| 29 | 36 | import org.flowable.task.api.history.HistoricTaskInstance; |
| ... | ... | @@ -32,6 +39,7 @@ import org.springframework.stereotype.Service; |
| 32 | 39 | import org.springframework.transaction.annotation.Transactional; |
| 33 | 40 | import org.springframework.transaction.support.TransactionSynchronization; |
| 34 | 41 | import org.springframework.transaction.support.TransactionSynchronizationManager; |
| 42 | +import org.springframework.util.Assert; | |
| 35 | 43 | |
| 36 | 44 | import javax.annotation.Resource; |
| 37 | 45 | import javax.validation.Valid; |
| ... | ... | @@ -39,8 +47,7 @@ import java.time.LocalDateTime; |
| 39 | 47 | import java.util.*; |
| 40 | 48 | |
| 41 | 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 | 51 | import static cn.iocoder.yudao.module.bpm.enums.ErrorCodeConstants.*; |
| 45 | 52 | |
| 46 | 53 | /** |
| ... | ... | @@ -57,23 +64,29 @@ public class BpmTaskServiceImpl implements BpmTaskService { |
| 57 | 64 | private TaskService taskService; |
| 58 | 65 | @Resource |
| 59 | 66 | private HistoryService historyService; |
| 67 | + @Resource | |
| 68 | + private RuntimeService runtimeService; | |
| 60 | 69 | |
| 61 | 70 | @Resource |
| 62 | 71 | private BpmProcessInstanceService processInstanceService; |
| 63 | 72 | @Resource |
| 73 | + private BpmModelService bpmModelService; | |
| 74 | + @Resource | |
| 75 | + private BpmMessageService messageService; | |
| 76 | + | |
| 77 | + @Resource | |
| 64 | 78 | private AdminUserApi adminUserApi; |
| 65 | 79 | @Resource |
| 66 | 80 | private DeptApi deptApi; |
| 81 | + | |
| 67 | 82 | @Resource |
| 68 | 83 | private BpmTaskExtMapper taskExtMapper; |
| 69 | - @Resource | |
| 70 | - private BpmMessageService messageService; | |
| 71 | 84 | |
| 72 | 85 | @Override |
| 73 | 86 | public PageResult<BpmTaskTodoPageItemRespVO> getTodoTaskPage(Long userId, BpmTaskTodoPageReqVO pageVO) { |
| 74 | 87 | // 查询待办任务 |
| 75 | 88 | TaskQuery taskQuery = taskService.createTaskQuery().taskAssignee(String.valueOf(userId)) // 分配给自己 |
| 76 | - .orderByTaskCreateTime().desc(); // 创建时间倒序 | |
| 89 | + .orderByTaskCreateTime().desc(); // 创建时间倒序 | |
| 77 | 90 | if (StrUtil.isNotBlank(pageVO.getName())) { |
| 78 | 91 | taskQuery.taskNameLike("%" + pageVO.getName() + "%"); |
| 79 | 92 | } |
| ... | ... | @@ -91,21 +104,21 @@ public class BpmTaskServiceImpl implements BpmTaskService { |
| 91 | 104 | |
| 92 | 105 | // 获得 ProcessInstance Map |
| 93 | 106 | Map<String, ProcessInstance> processInstanceMap = |
| 94 | - processInstanceService.getProcessInstanceMap(convertSet(tasks, Task::getProcessInstanceId)); | |
| 107 | + processInstanceService.getProcessInstanceMap(convertSet(tasks, Task::getProcessInstanceId)); | |
| 95 | 108 | // 获得 User Map |
| 96 | 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 | 112 | return new PageResult<>(BpmTaskConvert.INSTANCE.convertList1(tasks, processInstanceMap, userMap), |
| 100 | - taskQuery.count()); | |
| 113 | + taskQuery.count()); | |
| 101 | 114 | } |
| 102 | 115 | |
| 103 | 116 | @Override |
| 104 | 117 | public PageResult<BpmTaskDonePageItemRespVO> getDoneTaskPage(Long userId, BpmTaskDonePageReqVO pageVO) { |
| 105 | 118 | // 查询已办任务 |
| 106 | 119 | HistoricTaskInstanceQuery taskQuery = historyService.createHistoricTaskInstanceQuery().finished() // 已完成 |
| 107 | - .taskAssignee(String.valueOf(userId)) // 分配给自己 | |
| 108 | - .orderByHistoricTaskInstanceEndTime().desc(); // 审批时间倒序 | |
| 120 | + .taskAssignee(String.valueOf(userId)) // 分配给自己 | |
| 121 | + .orderByHistoricTaskInstanceEndTime().desc(); // 审批时间倒序 | |
| 109 | 122 | if (StrUtil.isNotBlank(pageVO.getName())) { |
| 110 | 123 | taskQuery.taskNameLike("%" + pageVO.getName() + "%"); |
| 111 | 124 | } |
| ... | ... | @@ -123,19 +136,19 @@ public class BpmTaskServiceImpl implements BpmTaskService { |
| 123 | 136 | |
| 124 | 137 | // 获得 TaskExtDO Map |
| 125 | 138 | List<BpmTaskExtDO> bpmTaskExtDOs = |
| 126 | - taskExtMapper.selectListByTaskIds(convertSet(tasks, HistoricTaskInstance::getId)); | |
| 139 | + taskExtMapper.selectListByTaskIds(convertSet(tasks, HistoricTaskInstance::getId)); | |
| 127 | 140 | Map<String, BpmTaskExtDO> bpmTaskExtDOMap = convertMap(bpmTaskExtDOs, BpmTaskExtDO::getTaskId); |
| 128 | 141 | // 获得 ProcessInstance Map |
| 129 | 142 | Map<String, HistoricProcessInstance> historicProcessInstanceMap = |
| 130 | - processInstanceService.getHistoricProcessInstanceMap( | |
| 131 | - convertSet(tasks, HistoricTaskInstance::getProcessInstanceId)); | |
| 143 | + processInstanceService.getHistoricProcessInstanceMap( | |
| 144 | + convertSet(tasks, HistoricTaskInstance::getProcessInstanceId)); | |
| 132 | 145 | // 获得 User Map |
| 133 | 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 | 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 | 154 | @Override |
| ... | ... | @@ -176,27 +189,58 @@ public class BpmTaskServiceImpl implements BpmTaskService { |
| 176 | 189 | @Override |
| 177 | 190 | @Transactional(rollbackFor = Exception.class) |
| 178 | 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 | 195 | ProcessInstance instance = processInstanceService.getProcessInstance(task.getProcessInstanceId()); |
| 183 | 196 | if (instance == null) { |
| 184 | 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 | 208 | taskService.complete(task.getId(), instance.getProcessVariables()); |
| 189 | - | |
| 190 | 209 | // 更新任务拓展表为通过 |
| 191 | 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 | 240 | @Override |
| 197 | 241 | @Transactional(rollbackFor = Exception.class) |
| 198 | 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 | 245 | ProcessInstance instance = processInstanceService.getProcessInstance(task.getProcessInstanceId()); |
| 202 | 246 | if (instance == null) { |
| ... | ... | @@ -208,14 +252,14 @@ public class BpmTaskServiceImpl implements BpmTaskService { |
| 208 | 252 | |
| 209 | 253 | // 更新任务拓展表为不通过 |
| 210 | 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 | 259 | @Override |
| 216 | 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 | 264 | updateTaskAssignee(task.getId(), reqVO.getAssigneeUserId()); |
| 221 | 265 | } |
| ... | ... | @@ -231,13 +275,13 @@ public class BpmTaskServiceImpl implements BpmTaskService { |
| 231 | 275 | * @param userId 用户 id |
| 232 | 276 | * @param taskId task id |
| 233 | 277 | */ |
| 234 | - private Task checkTask(Long userId, String taskId) { | |
| 278 | + private Task validateTask(Long userId, String taskId) { | |
| 235 | 279 | Task task = getTask(taskId); |
| 236 | 280 | if (task == null) { |
| 237 | - throw exception(TASK_COMPLETE_FAIL_NOT_EXISTS); | |
| 281 | + throw exception(TASK_NOT_EXISTS); | |
| 238 | 282 | } |
| 239 | 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 | 286 | return task; |
| 243 | 287 | } |
| ... | ... | @@ -245,7 +289,7 @@ public class BpmTaskServiceImpl implements BpmTaskService { |
| 245 | 289 | @Override |
| 246 | 290 | public void createTaskExt(Task task) { |
| 247 | 291 | BpmTaskExtDO taskExtDO = |
| 248 | - BpmTaskConvert.INSTANCE.convert2TaskExt(task).setResult(BpmProcessInstanceResultEnum.PROCESS.getResult()); | |
| 292 | + BpmTaskConvert.INSTANCE.convert2TaskExt(task).setResult(BpmProcessInstanceResultEnum.PROCESS.getResult()); | |
| 249 | 293 | taskExtMapper.insert(taskExtDO); |
| 250 | 294 | } |
| 251 | 295 | |
| ... | ... | @@ -293,27 +337,183 @@ public class BpmTaskServiceImpl implements BpmTaskService { |
| 293 | 337 | @Override |
| 294 | 338 | public void updateTaskExtAssign(Task task) { |
| 295 | 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 | 341 | taskExtMapper.updateByTaskId(taskExtDO); |
| 298 | 342 | // 发送通知。在事务提交时,批量执行操作,所以直接查询会无法查询到 ProcessInstance,所以这里是通过监听事务的提交来实现。 |
| 299 | 343 | TransactionSynchronizationManager.registerSynchronization(new TransactionSynchronization() { |
| 300 | 344 | @Override |
| 301 | 345 | public void afterCommit() { |
| 302 | 346 | ProcessInstance processInstance = |
| 303 | - processInstanceService.getProcessInstance(task.getProcessInstanceId()); | |
| 347 | + processInstanceService.getProcessInstance(task.getProcessInstanceId()); | |
| 304 | 348 | AdminUserRespDTO startUser = adminUserApi.getUser(Long.valueOf(processInstance.getStartUserId())); |
| 305 | 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 | 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 | 363 | private HistoricTaskInstance getHistoricTask(String id) { |
| 316 | 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 | 9 | */ |
| 10 | 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 | 6 | import cn.iocoder.yudao.module.infra.controller.admin.file.vo.config.FileConfigPageReqVO; |
| 7 | 7 | import cn.iocoder.yudao.module.infra.dal.dataobject.file.FileConfigDO; |
| 8 | 8 | import org.apache.ibatis.annotations.Mapper; |
| 9 | -import org.apache.ibatis.annotations.Select; | |
| 10 | - | |
| 11 | -import java.time.LocalDateTime; | |
| 12 | 9 | |
| 13 | 10 | @Mapper |
| 14 | 11 | public interface FileConfigMapper extends BaseMapperX<FileConfigDO> { |
| ... | ... | @@ -21,7 +18,8 @@ public interface FileConfigMapper extends BaseMapperX<FileConfigDO> { |
| 21 | 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 | 1 | package cn.iocoder.yudao.module.infra.service.file; |
| 2 | 2 | |
| 3 | -import cn.hutool.core.collection.CollUtil; | |
| 4 | 3 | import cn.hutool.core.io.resource.ResourceUtil; |
| 5 | 4 | import cn.hutool.core.util.IdUtil; |
| 6 | 5 | import cn.iocoder.yudao.framework.common.pojo.PageResult; |
| 7 | -import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils; | |
| 8 | 6 | import cn.iocoder.yudao.framework.common.util.json.JsonUtils; |
| 9 | 7 | import cn.iocoder.yudao.framework.common.util.validation.ValidationUtils; |
| 10 | 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 | 15 | import cn.iocoder.yudao.module.infra.convert.file.FileConfigConvert; |
| 18 | 16 | import cn.iocoder.yudao.module.infra.dal.dataobject.file.FileConfigDO; |
| 19 | 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 | 20 | import lombok.Getter; |
| 21 | 21 | import lombok.extern.slf4j.Slf4j; |
| 22 | -import org.springframework.scheduling.annotation.Scheduled; | |
| 23 | 22 | import org.springframework.stereotype.Service; |
| 24 | 23 | import org.springframework.transaction.annotation.Transactional; |
| 25 | 24 | import org.springframework.validation.annotation.Validated; |
| 26 | 25 | |
| 27 | -import javax.annotation.PostConstruct; | |
| 28 | 26 | import javax.annotation.Resource; |
| 29 | 27 | import javax.validation.Validator; |
| 30 | -import java.time.LocalDateTime; | |
| 31 | -import java.util.List; | |
| 28 | +import java.time.Duration; | |
| 32 | 29 | import java.util.Map; |
| 33 | -import java.util.concurrent.TimeUnit; | |
| 30 | +import java.util.Objects; | |
| 34 | 31 | |
| 35 | 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 | 34 | import static cn.iocoder.yudao.module.infra.enums.ErrorCodeConstants.FILE_CONFIG_DELETE_FAIL_MASTER; |
| 37 | 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 | 44 | @Slf4j |
| 47 | 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 | 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 | 71 | @Resource |
| 64 | 72 | private FileConfigMapper fileConfigMapper; |
| ... | ... | @@ -66,53 +74,12 @@ public class FileConfigServiceImpl implements FileConfigService { |
| 66 | 74 | @Resource |
| 67 | 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 | 77 | @Override |
| 107 | 78 | public Long createFileConfig(FileConfigCreateReqVO createReqVO) { |
| 108 | - // 插入 | |
| 109 | 79 | FileConfigDO fileConfig = FileConfigConvert.INSTANCE.convert(createReqVO) |
| 110 | 80 | .setConfig(parseClientConfig(createReqVO.getStorage(), createReqVO.getConfig())) |
| 111 | 81 | .setMaster(false); // 默认非 master |
| 112 | 82 | fileConfigMapper.insert(fileConfig); |
| 113 | - | |
| 114 | - // 刷新缓存 | |
| 115 | - initLocalCache(); | |
| 116 | 83 | return fileConfig.getId(); |
| 117 | 84 | } |
| 118 | 85 | |
| ... | ... | @@ -125,8 +92,8 @@ public class FileConfigServiceImpl implements FileConfigService { |
| 125 | 92 | .setConfig(parseClientConfig(config.getStorage(), updateReqVO.getConfig())); |
| 126 | 93 | fileConfigMapper.updateById(updateObj); |
| 127 | 94 | |
| 128 | - // 刷新缓存 | |
| 129 | - initLocalCache(); | |
| 95 | + // 清空缓存 | |
| 96 | + clearCache(config.getId(), null); | |
| 130 | 97 | } |
| 131 | 98 | |
| 132 | 99 | @Override |
| ... | ... | @@ -139,8 +106,8 @@ public class FileConfigServiceImpl implements FileConfigService { |
| 139 | 106 | // 更新 |
| 140 | 107 | fileConfigMapper.updateById(new FileConfigDO().setId(id).setMaster(true)); |
| 141 | 108 | |
| 142 | - // 刷新缓存 | |
| 143 | - initLocalCache(); | |
| 109 | + // 清空缓存 | |
| 110 | + clearCache(null, true); | |
| 144 | 111 | } |
| 145 | 112 | |
| 146 | 113 | private FileClientConfig parseClientConfig(Integer storage, Map<String, Object> config) { |
| ... | ... | @@ -164,8 +131,23 @@ public class FileConfigServiceImpl implements FileConfigService { |
| 164 | 131 | // 删除 |
| 165 | 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 | 153 | private FileConfigDO validateFileConfigExists(Long id) { |
| ... | ... | @@ -192,12 +174,17 @@ public class FileConfigServiceImpl implements FileConfigService { |
| 192 | 174 | validateFileConfigExists(id); |
| 193 | 175 | // 上传文件 |
| 194 | 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 | 180 | @Override |
| 199 | 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 '@/utils/http/axios' |
| 3 | 3 | |
| 4 | 4 | // 查询${table.classComment}列表 |
| 5 | 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 | 9 | // 查询${table.classComment}详情 |
| 10 | 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 | 14 | // 新增${table.classComment} |
| 15 | 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 | 19 | // 修改${table.classComment} |
| 20 | 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 | 24 | // 删除${table.classComment} |
| 25 | 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 | 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 | 3 | import { DICT_TYPE, getDictOptions } from '@/utils/dict' |
| 3 | 4 | |
| 4 | 5 | export const columns: BasicColumn[] = [ |
| ... | ... | @@ -92,13 +93,13 @@ export const createFormSchema: FormSchema[] = [ |
| 92 | 93 | #elseif($column.htmlType == "imageUpload")## 图片上传 |
| 93 | 94 | component: 'FileUpload', |
| 94 | 95 | componentProps: { |
| 95 | - fileType: 'file', | |
| 96 | + fileType: 'image', | |
| 96 | 97 | maxCount: 1, |
| 97 | 98 | }, |
| 98 | 99 | #elseif($column.htmlType == "fileUpload")## 文件上传 |
| 99 | 100 | component: 'FileUpload', |
| 100 | 101 | componentProps: { |
| 101 | - fileType: 'image', | |
| 102 | + fileType: 'file', | |
| 102 | 103 | maxCount: 1, |
| 103 | 104 | }, |
| 104 | 105 | #elseif($column.htmlType == "editor")## 文本编辑器 |
| ... | ... | @@ -132,6 +133,11 @@ export const createFormSchema: FormSchema[] = [ |
| 132 | 133 | }, |
| 133 | 134 | #elseif($column.htmlType == "datetime")## 时间框 |
| 134 | 135 | component: 'DatePicker', |
| 136 | + componentProps: { | |
| 137 | + showTime: true, | |
| 138 | + format: 'YYYY-MM-DD HH:mm:ss', | |
| 139 | + valueFormat: 'x', | |
| 140 | + }, | |
| 135 | 141 | #elseif($column.htmlType == "textarea")## 文本域 |
| 136 | 142 | component: 'InputTextArea', |
| 137 | 143 | #end |
| ... | ... | @@ -154,7 +160,7 @@ export const updateFormSchema: FormSchema[] = [ |
| 154 | 160 | #set ($javaField = $column.javaField) |
| 155 | 161 | #set ($AttrName = $column.javaField.substring(0,1).toUpperCase() + ${column.javaField.substring(1)}) |
| 156 | 162 | #set ($comment = $column.columnComment) |
| 157 | -#if (!$column.primaryKey)## 忽略主键,不用在表单里 | |
| 163 | + #if (!$column.primaryKey)## 忽略主键,不用在表单里 | |
| 158 | 164 | { |
| 159 | 165 | label: '${comment}', |
| 160 | 166 | field: '${javaField}', |
| ... | ... | @@ -164,45 +170,57 @@ export const updateFormSchema: FormSchema[] = [ |
| 164 | 170 | #if ($column.htmlType == "input") |
| 165 | 171 | component: 'Input', |
| 166 | 172 | #elseif($column.htmlType == "imageUpload")## 图片上传 |
| 167 | - component: 'Upload', | |
| 173 | + component: 'FileUpload', | |
| 174 | + componentProps: { | |
| 175 | + fileType: 'image', | |
| 176 | + maxCount: 1, | |
| 177 | + }, | |
| 168 | 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 | 185 | #elseif($column.htmlType == "select")## 下拉框 |
| 173 | 186 | component: 'Select', |
| 174 | 187 | componentProps: { |
| 175 | 188 | #if ("" != $dictType)## 有数据字典 |
| 176 | - options: getDictOptions(DICT_TYPE.$dictType.toUpperCase(), 'number'), | |
| 189 | + options: getDictOptions(DICT_TYPE.$dictType.toUpperCase(), 'number'), | |
| 177 | 190 | #else##没数据字典 |
| 178 | - options:[], | |
| 191 | + options:[], | |
| 179 | 192 | #end |
| 180 | 193 | }, |
| 181 | 194 | #elseif($column.htmlType == "checkbox")## 多选框 |
| 182 | 195 | component: 'Checkbox', |
| 183 | 196 | componentProps: { |
| 184 | 197 | #if ("" != $dictType)## 有数据字典 |
| 185 | - options: getDictOptions(DICT_TYPE.$dictType.toUpperCase(), 'number'), | |
| 198 | + options: getDictOptions(DICT_TYPE.$dictType.toUpperCase(), 'number'), | |
| 186 | 199 | #else##没数据字典 |
| 187 | - options:[], | |
| 200 | + options:[], | |
| 188 | 201 | #end |
| 189 | 202 | }, |
| 190 | 203 | #elseif($column.htmlType == "radio")## 单选框 |
| 191 | 204 | component: 'RadioButtonGroup', |
| 192 | 205 | componentProps: { |
| 193 | 206 | #if ("" != $dictType)## 有数据字典 |
| 194 | - options: getDictOptions(DICT_TYPE.$dictType.toUpperCase(), 'number'), | |
| 207 | + options: getDictOptions(DICT_TYPE.$dictType.toUpperCase(), 'number'), | |
| 195 | 208 | #else##没数据字典 |
| 196 | - options:[], | |
| 209 | + options:[], | |
| 197 | 210 | #end |
| 198 | 211 | }, |
| 199 | 212 | #elseif($column.htmlType == "datetime")## 时间框 |
| 200 | 213 | component: 'DatePicker', |
| 214 | + componentProps: { | |
| 215 | + showTime: true, | |
| 216 | + format: 'YYYY-MM-DD HH:mm:ss', | |
| 217 | + valueFormat: 'x', | |
| 218 | + }, | |
| 201 | 219 | #elseif($column.htmlType == "textarea")## 文本域 |
| 202 | 220 | component: 'InputTextArea', |
| 203 | 221 | #end |
| 204 | 222 | }, |
| 205 | -#end | |
| 223 | + #end | |
| 206 | 224 | #end |
| 207 | 225 | #end |
| 208 | 226 | ] |
| 209 | 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 | |
| 10 | 10 | defineOptions({ name: '${table.className}Modal' }) |
| 11 | 11 | |
| 12 | +const emit = defineEmits(['success', 'register']) | |
| 13 | + | |
| 12 | 14 | const { t } = useI18n() |
| 13 | 15 | const { createMessage } = useMessage() |
| 14 | -const emit = defineEmits(['success', 'register']) | |
| 15 | 16 | const isUpdate = ref(true) |
| 16 | 17 | |
| 17 | 18 | const [registerForm, { setFieldsValue, resetFields, resetSchema, validate }] = useForm({ |
| ... | ... | @@ -37,11 +38,11 @@ async function handleSubmit() { |
| 37 | 38 | try { |
| 38 | 39 | const values = await validate() |
| 39 | 40 | setModalProps({ confirmLoading: true }) |
| 40 | - if (unref(isUpdate)) { | |
| 41 | + if (unref(isUpdate)) | |
| 41 | 42 | await update${simpleClassName}(values) |
| 42 | - } else { | |
| 43 | + else | |
| 43 | 44 | await create${simpleClassName}(values) |
| 44 | - } | |
| 45 | + | |
| 45 | 46 | closeModal() |
| 46 | 47 | emit('success') |
| 47 | 48 | createMessage.success(t('common.saveSuccessText')) |
| ... | ... | @@ -51,7 +52,7 @@ async function handleSubmit() { |
| 51 | 52 | } |
| 52 | 53 | </script> |
| 53 | 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 | 56 | <BasicForm @register="registerForm" /> |
| 56 | 57 | </BasicModal> |
| 57 | 58 | </template> |
| 58 | 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 | 1 | <script lang="ts" setup> |
| 2 | -import ${simpleClassName}Modal from './${simpleClassName}Modal.vue' | |
| 2 | +import ${ simpleClassName }Modal from './${simpleClassName}Modal.vue' | |
| 3 | 3 | import { columns, searchFormSchema } from './${classNameVar}.data' |
| 4 | 4 | import { useI18n } from '@/hooks/web/useI18n' |
| 5 | 5 | import { useMessage } from '@/hooks/web/useMessage' |
| 6 | 6 | import { useModal } from '@/components/Modal' |
| 7 | 7 | import { IconEnum } from '@/enums/appEnum' |
| 8 | 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 | 11 | defineOptions({ name: '${table.className}' }) |
| 12 | 12 | |
| ... | ... | @@ -16,17 +16,17 @@ const [registerModal, { openModal }] = useModal() |
| 16 | 16 | |
| 17 | 17 | const [registerTable, { getForm, reload }] = useTable({ |
| 18 | 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 | 32 | function handleCreate() { |
| ... | ... | @@ -43,14 +43,14 @@ async function handleExport() { |
| 43 | 43 | iconType: 'warning', |
| 44 | 44 | content: t('common.exportMessage'), |
| 45 | 45 | async onOk() { |
| 46 | - await export${simpleClassName}(getForm().getFieldsValue()) | |
| 46 | + await export${ simpleClassName } (getForm().getFieldsValue()) | |
| 47 | 47 | createMessage.success(t('common.exportSuccessText')) |
| 48 | 48 | }, |
| 49 | 49 | }) |
| 50 | 50 | } |
| 51 | 51 | |
| 52 | 52 | async function handleDelete(record: Recordable) { |
| 53 | - await delete${simpleClassName}(record.id) | |
| 53 | + await delete${ simpleClassName } (record.id) | |
| 54 | 54 | createMessage.success(t('common.delSuccessText')) |
| 55 | 55 | reload() |
| 56 | 56 | } |
| ... | ... | @@ -89,4 +89,4 @@ async function handleDelete(record: Recordable) { |
| 89 | 89 | </BasicTable> |
| 90 | 90 | <${simpleClassName}Modal @register="registerModal" @success="reload()" /> |
| 91 | 91 | </div> |
| 92 | -</template> | |
| 93 | 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 | 60 | private FileClientFactory fileClientFactory; |
| 61 | 61 | |
| 62 | 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 | 63 | public void testCreateFileConfig_success() { |
| 89 | 64 | // 准备参数 |
| 90 | 65 | Map<String, Object> config = MapUtil.<String, Object>builder().put("basePath", "/yunai") |
| ... | ... | @@ -102,6 +77,8 @@ public class FileConfigServiceImplTest extends BaseDbUnitTest { |
| 102 | 77 | assertFalse(fileConfig.getMaster()); |
| 103 | 78 | assertEquals("/yunai", ((LocalFileClientConfig) fileConfig.getConfig()).getBasePath()); |
| 104 | 79 | assertEquals("https://www.iocoder.cn", ((LocalFileClientConfig) fileConfig.getConfig()).getDomain()); |
| 80 | + // 验证 cache | |
| 81 | + assertNull(fileConfigService.getClientCache().getIfPresent(fileConfigId)); | |
| 105 | 82 | } |
| 106 | 83 | |
| 107 | 84 | @Test |
| ... | ... | @@ -125,6 +102,8 @@ public class FileConfigServiceImplTest extends BaseDbUnitTest { |
| 125 | 102 | assertPojoEquals(reqVO, fileConfig, "config"); |
| 126 | 103 | assertEquals("/yunai2", ((LocalFileClientConfig) fileConfig.getConfig()).getBasePath()); |
| 127 | 104 | assertEquals("https://doc.iocoder.cn", ((LocalFileClientConfig) fileConfig.getConfig()).getDomain()); |
| 105 | + // 验证 cache | |
| 106 | + assertNull(fileConfigService.getClientCache().getIfPresent(fileConfig.getId())); | |
| 128 | 107 | } |
| 129 | 108 | |
| 130 | 109 | @Test |
| ... | ... | @@ -149,6 +128,8 @@ public class FileConfigServiceImplTest extends BaseDbUnitTest { |
| 149 | 128 | // 断言数据 |
| 150 | 129 | assertTrue(fileConfigMapper.selectById(dbFileConfig.getId()).getMaster()); |
| 151 | 130 | assertFalse(fileConfigMapper.selectById(masterFileConfig.getId()).getMaster()); |
| 131 | + // 验证 cache | |
| 132 | + assertNull(fileConfigService.getClientCache().getIfPresent(0L)); | |
| 152 | 133 | } |
| 153 | 134 | |
| 154 | 135 | @Test |
| ... | ... | @@ -169,6 +150,8 @@ public class FileConfigServiceImplTest extends BaseDbUnitTest { |
| 169 | 150 | fileConfigService.deleteFileConfig(id); |
| 170 | 151 | // 校验数据不存在了 |
| 171 | 152 | assertNull(fileConfigMapper.selectById(id)); |
| 153 | + // 验证 cache | |
| 154 | + assertNull(fileConfigService.getClientCache().getIfPresent(id)); | |
| 172 | 155 | } |
| 173 | 156 | |
| 174 | 157 | @Test |
| ... | ... | @@ -250,14 +233,38 @@ public class FileConfigServiceImplTest extends BaseDbUnitTest { |
| 250 | 233 | |
| 251 | 234 | @Test |
| 252 | 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 | 241 | // mock 获得 Client |
| 256 | 242 | FileClient fileClient = new LocalFileClient(id, new LocalFileClientConfig()); |
| 257 | 243 | when(fileClientFactory.getFileClient(eq(id))).thenReturn(fileClient); |
| 258 | 244 | |
| 259 | 245 | // 调用,并断言 |
| 260 | 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 | 270 | private FileConfigDO randomFileConfigDO() { | ... | ... |
yudao-module-infra/yudao-module-infra-biz/src/test/java/cn/iocoder/yudao/module/infra/service/file/FileServiceImplTest.java
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 | 9 | */ |
| 10 | 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
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 | 16 | import cn.iocoder.yudao.module.product.enums.comment.ProductCommentScoresEnum; |
| 17 | 17 | import cn.iocoder.yudao.module.product.service.sku.ProductSkuService; |
| 18 | 18 | import cn.iocoder.yudao.module.product.service.spu.ProductSpuService; |
| 19 | -import cn.iocoder.yudao.module.trade.api.order.TradeOrderApi; | |
| 20 | 19 | import org.junit.jupiter.api.Test; |
| 21 | 20 | import org.springframework.boot.test.mock.mockito.MockBean; |
| 22 | 21 | import org.springframework.context.annotation.Import; |
| ... | ... | @@ -49,8 +48,6 @@ public class ProductCommentServiceImplTest extends BaseDbUnitTest { |
| 49 | 48 | private ProductCommentServiceImpl productCommentService; |
| 50 | 49 | |
| 51 | 50 | @MockBean |
| 52 | - private TradeOrderApi tradeOrderApi; | |
| 53 | - @MockBean | |
| 54 | 51 | private ProductSpuService productSpuService; |
| 55 | 52 | @MockBean |
| 56 | 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 | 9 | */ |
| 10 | 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 | 53 | ErrorCode SECKILL_ACTIVITY_NOT_EXISTS = new ErrorCode(1013008000, "秒杀活动不存在"); |
| 54 | 54 | ErrorCode SECKILL_ACTIVITY_SPU_CONFLICTS = new ErrorCode(1013008002, "存在商品参加了其它秒杀活动,秒杀时段冲突"); |
| 55 | 55 | ErrorCode SECKILL_ACTIVITY_UPDATE_FAIL_STATUS_CLOSED = new ErrorCode(1013008003, "秒杀活动已关闭,不能修改"); |
| ... | ... | @@ -57,19 +57,19 @@ public interface ErrorCodeConstants { |
| 57 | 57 | ErrorCode SECKILL_ACTIVITY_CLOSE_FAIL_STATUS_CLOSED = new ErrorCode(1013008005, "秒杀活动已关闭,不能重复关闭"); |
| 58 | 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 | 66 | ErrorCode COMBINATION_ACTIVITY_NOT_EXISTS = new ErrorCode(1013010000, "拼团活动不存在"); |
| 67 | 67 | ErrorCode COMBINATION_ACTIVITY_SPU_CONFLICTS = new ErrorCode(1013010001, "存在商品参加了其它拼团活动"); |
| 68 | 68 | ErrorCode COMBINATION_ACTIVITY_STATUS_DISABLE_NOT_UPDATE = new ErrorCode(1013010002, "拼团活动已关闭不能修改"); |
| 69 | 69 | ErrorCode COMBINATION_ACTIVITY_DELETE_FAIL_STATUS_NOT_CLOSED_OR_END = new ErrorCode(1013010003, "拼团活动未关闭或未结束,不能删除"); |
| 70 | 70 | ErrorCode COMBINATION_ACTIVITY_STATUS_DISABLE = new ErrorCode(1013010004, "拼团失败,原因:拼团活动已关闭"); |
| 71 | 71 | |
| 72 | - // ========== 拼团记录 1013011000 ========== | |
| 72 | + // ========== 拼团记录 1-013-011-000 ========== | |
| 73 | 73 | ErrorCode COMBINATION_RECORD_NOT_EXISTS = new ErrorCode(1013011000, "拼团不存在"); |
| 74 | 74 | ErrorCode COMBINATION_RECORD_EXISTS = new ErrorCode(1013011001, "拼团失败,已参与过该拼团"); |
| 75 | 75 | ErrorCode COMBINATION_RECORD_HEAD_NOT_EXISTS = new ErrorCode(1013011002, "拼团失败,父拼团不存在"); |
| ... | ... | @@ -79,17 +79,17 @@ public interface ErrorCodeConstants { |
| 79 | 79 | ErrorCode COMBINATION_RECORD_FAILED_SINGLE_LIMIT_COUNT_EXCEED = new ErrorCode(1013011006, "拼团失败,原因:单次限购超出"); |
| 80 | 80 | ErrorCode COMBINATION_RECORD_FAILED_TOTAL_LIMIT_COUNT_EXCEED = new ErrorCode(1013011007, "拼团失败,原因:超出总购买次数"); |
| 81 | 81 | |
| 82 | - // ========== 砍价活动 1013012000 ========== | |
| 82 | + // ========== 砍价活动 1-013-012-000 ========== | |
| 83 | 83 | ErrorCode BARGAIN_ACTIVITY_NOT_EXISTS = new ErrorCode(1013012000, "砍价活动不存在"); |
| 84 | 84 | ErrorCode BARGAIN_ACTIVITY_SPU_CONFLICTS = new ErrorCode(1013012001, "存在商品参加了其它砍价活动"); |
| 85 | 85 | ErrorCode BARGAIN_ACTIVITY_STATUS_DISABLE = new ErrorCode(1013012002, "砍价活动已关闭不能修改"); |
| 86 | 86 | ErrorCode BARGAIN_ACTIVITY_DELETE_FAIL_STATUS_NOT_CLOSED_OR_END = new ErrorCode(1013012003, "砍价活动未关闭或未结束,不能删除"); |
| 87 | 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 | 37 | @Resource |
| 38 | 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 | 40 | @DeleteMapping("/delete") |
| 50 | 41 | @Operation(summary = "回收优惠劵") |
| 51 | 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
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 | 9 | @Data |
| 10 | 10 | public class AppArticleRespVO { |
| 11 | 11 | |
| 12 | - @Schema(description = "文章编号", required = true, example = "1") | |
| 12 | + @Schema(description = "文章编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") | |
| 13 | 13 | private Long id; |
| 14 | 14 | |
| 15 | - @Schema(description = "文章标题", required = true, example = "芋道源码 - 促销模块") | |
| 15 | + @Schema(description = "文章标题", requiredMode = Schema.RequiredMode.REQUIRED, example = "芋道源码 - 促销模块") | |
| 16 | 16 | private String title; |
| 17 | 17 | |
| 18 | - @Schema(description = "文章作者", required = true, example = "芋道源码") | |
| 18 | + @Schema(description = "文章作者", requiredMode = Schema.RequiredMode.REQUIRED, example = "芋道源码") | |
| 19 | 19 | private String author; |
| 20 | 20 | |
| 21 | - @Schema(description = "分类编号", required = true, example = "2048") | |
| 21 | + @Schema(description = "分类编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "2048") | |
| 22 | 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 | 25 | private String picUrl; |
| 26 | 26 | |
| 27 | - @Schema(description = "文章简介", required = true, example = "我是简介") | |
| 27 | + @Schema(description = "文章简介", requiredMode = Schema.RequiredMode.REQUIRED, example = "我是简介") | |
| 28 | 28 | private String introduction; |
| 29 | 29 | |
| 30 | - @Schema(description = "文章内容", required = true, example = "我是详细") | |
| 30 | + @Schema(description = "文章内容", requiredMode = Schema.RequiredMode.REQUIRED, example = "我是详细") | |
| 31 | 31 | private String description; |
| 32 | 32 | |
| 33 | - @Schema(description = "发布时间", required = true) | |
| 33 | + @Schema(description = "发布时间", requiredMode = Schema.RequiredMode.REQUIRED) | |
| 34 | 34 | private LocalDateTime createTime; |
| 35 | 35 | |
| 36 | - @Schema(description = "浏览量", required = true, example = "1024") | |
| 36 | + @Schema(description = "浏览量", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") | |
| 37 | 37 | private Integer browseCount; |
| 38 | 38 | |
| 39 | 39 | @Schema(description = "关联的商品 SPU 编号", example = "1024") |
| 40 | 40 | private Long spuId; |
| 41 | 41 | |
| 42 | 42 | // TODO 芋艿:下面 2 个字段,后端要存储,前端不用返回; |
| 43 | -// @Schema(description = "是否热卖推荐", required = true, example = "true") | |
| 43 | +// @Schema(description = "是否热卖推荐", requiredMode = Schema.RequiredMode.REQUIRED, example = "true") | |
| 44 | 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 | 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 | 7 | @Data |
| 8 | 8 | public class AppArticleCategoryRespVO { |
| 9 | 9 | |
| 10 | - @Schema(description = "分类编号", required = true, example = "1") | |
| 10 | + @Schema(description = "分类编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") | |
| 11 | 11 | private Long id; |
| 12 | 12 | |
| 13 | - @Schema(description = "分类名称", required = true, example = "技术") | |
| 13 | + @Schema(description = "分类名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "技术") | |
| 14 | 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 | 17 | private String picUrl; |
| 18 | 18 | |
| 19 | 19 | // TODO 芋艿:下面 2 个字段,后端要存储,前端不用返回; |
| 20 | -// @Schema(description = "状态", required = true, example = "1") | |
| 20 | +// @Schema(description = "状态", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") | |
| 21 | 21 | // private Integer status; |
| 22 | 22 | // |
| 23 | -// @Schema(description = "排序", required = true, example = "1024") | |
| 23 | +// @Schema(description = "排序", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") | |
| 24 | 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 | 9 | @Data |
| 10 | 10 | public class AppBargainActivityDetailRespVO { |
| 11 | 11 | |
| 12 | - @Schema(description = "砍价活动编号", required = true, example = "1024") | |
| 12 | + @Schema(description = "砍价活动编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") | |
| 13 | 13 | private Long id; |
| 14 | 14 | |
| 15 | - @Schema(description = "砍价活动名称", required = true, example = "618 大砍价") | |
| 15 | + @Schema(description = "砍价活动名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "618 大砍价") | |
| 16 | 16 | private String name; |
| 17 | 17 | |
| 18 | - @Schema(description = "活动开始时间", required = true) | |
| 18 | + @Schema(description = "活动开始时间", requiredMode = Schema.RequiredMode.REQUIRED) | |
| 19 | 19 | private LocalDateTime startTime; |
| 20 | 20 | |
| 21 | - @Schema(description = "活动结束时间", required = true) | |
| 21 | + @Schema(description = "活动结束时间", requiredMode = Schema.RequiredMode.REQUIRED) | |
| 22 | 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 | 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 | 28 | private Long skuId; |
| 29 | 29 | |
| 30 | - @Schema(description = "商品价格,单位:分", required = true, example = "100") | |
| 30 | + @Schema(description = "商品价格,单位:分", requiredMode = Schema.RequiredMode.REQUIRED, example = "100") | |
| 31 | 31 | private Integer price; |
| 32 | 32 | |
| 33 | - @Schema(description = "商品描述", required = true, example = "我要吃西红柿") | |
| 33 | + @Schema(description = "商品描述", requiredMode = Schema.RequiredMode.REQUIRED, example = "我要吃西红柿") | |
| 34 | 34 | private String description; |
| 35 | 35 | |
| 36 | - @Schema(description = "砍价库存", required = true, example = "512") | |
| 36 | + @Schema(description = "砍价库存", requiredMode = Schema.RequiredMode.REQUIRED, example = "512") | |
| 37 | 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 | 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 | 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 | 46 | private String unitName; |
| 47 | 47 | |
| 48 | - @Schema(description = "砍价最低金额,单位:分", required = true, example = "100") | |
| 48 | + @Schema(description = "砍价最低金额,单位:分", requiredMode = Schema.RequiredMode.REQUIRED, example = "100") | |
| 49 | 49 | private Integer bargainPrice; |
| 50 | 50 | |
| 51 | - @Schema(description = "砍价成功数量", required = true, example = "100") | |
| 51 | + @Schema(description = "砍价成功数量", requiredMode = Schema.RequiredMode.REQUIRED, example = "100") | |
| 52 | 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 | 9 | @Data |
| 10 | 10 | public class AppBargainActivityRespVO { |
| 11 | 11 | |
| 12 | - @Schema(description = "砍价活动编号", required = true, example = "1024") | |
| 12 | + @Schema(description = "砍价活动编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") | |
| 13 | 13 | private Long id; |
| 14 | 14 | |
| 15 | - @Schema(description = "砍价活动名称", required = true, example = "618 大砍价") | |
| 15 | + @Schema(description = "砍价活动名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "618 大砍价") | |
| 16 | 16 | private String name; |
| 17 | 17 | |
| 18 | - @Schema(description = "活动开始时间", required = true) | |
| 18 | + @Schema(description = "活动开始时间", requiredMode = Schema.RequiredMode.REQUIRED) | |
| 19 | 19 | private LocalDateTime startTime; |
| 20 | 20 | |
| 21 | - @Schema(description = "活动结束时间", required = true) | |
| 21 | + @Schema(description = "活动结束时间", requiredMode = Schema.RequiredMode.REQUIRED) | |
| 22 | 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 | 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 | 28 | private Long skuId; |
| 29 | 29 | |
| 30 | - @Schema(description = "砍价库存", required = true, example = "512") | |
| 30 | + @Schema(description = "砍价库存", requiredMode = Schema.RequiredMode.REQUIRED, example = "512") | |
| 31 | 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 | 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 | 37 | private Integer marketPrice; |
| 38 | 38 | |
| 39 | - @Schema(description = "砍价最低金额,单位:分", required = true, example = "100") | |
| 39 | + @Schema(description = "砍价最低金额,单位:分", requiredMode = Schema.RequiredMode.REQUIRED, example = "100") | |
| 40 | 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 | 9 | @Data |
| 10 | 10 | public class AppBargainHelpCreateReqVO { |
| 11 | 11 | |
| 12 | - @Schema(description = "砍价记录编号", required = true, example = "1024") | |
| 12 | + @Schema(description = "砍价记录编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") | |
| 13 | 13 | @NotNull(message = "砍价记录编号不能为空") |
| 14 | 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 | 9 | @Data |
| 10 | 10 | public class AppBargainHelpRespVO { |
| 11 | 11 | |
| 12 | - @Schema(description = "助力用户的昵称", required = true, example = "1024") | |
| 12 | + @Schema(description = "助力用户的昵称", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") | |
| 13 | 13 | private String nickname; |
| 14 | 14 | |
| 15 | - @Schema(description = "助力用户的头像", required = true, example = "1024") | |
| 15 | + @Schema(description = "助力用户的头像", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") | |
| 16 | 16 | private String avatar; |
| 17 | 17 | |
| 18 | - @Schema(description = "助力用户的砍价金额", required = true, example = "1024") | |
| 18 | + @Schema(description = "助力用户的砍价金额", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") | |
| 19 | 19 | private Integer reducePrice; |
| 20 | 20 | |
| 21 | - @Schema(description = "创建时间", required = true, example = "1024") | |
| 21 | + @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") | |
| 22 | 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 | 9 | @Data |
| 10 | 10 | public class AppBargainRecordCreateReqVO { |
| 11 | 11 | |
| 12 | - @Schema(description = "砍价活动编号", required = true, example = "1024") | |
| 12 | + @Schema(description = "砍价活动编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") | |
| 13 | 13 | @NotNull(message = "砍价活动编号不能为空") |
| 14 | 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 | 9 | @Data |
| 10 | 10 | public class AppBargainRecordSummaryRespVO { |
| 11 | 11 | |
| 12 | - @Schema(description = "砍价用户数量", required = true, example = "1024") | |
| 12 | + @Schema(description = "砍价用户数量", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") | |
| 13 | 13 | private Integer userCount; |
| 14 | 14 | |
| 15 | - @Schema(description = "成功砍价的记录", required = true) // 只返回最近的 7 个 | |
| 15 | + @Schema(description = "成功砍价的记录", requiredMode = Schema.RequiredMode.REQUIRED) // 只返回最近的 7 个 | |
| 16 | 16 | private List<Record> successRecords; |
| 17 | 17 | |
| 18 | 18 | @Schema(description = "成功砍价记录") |
| 19 | 19 | @Data |
| 20 | 20 | public static class Record { |
| 21 | 21 | |
| 22 | - @Schema(description = "用户昵称", required = true, example = "王**") | |
| 22 | + @Schema(description = "用户昵称", requiredMode = Schema.RequiredMode.REQUIRED, example = "王**") | |
| 23 | 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 | 26 | private String avatar; |
| 27 | 27 | |
| 28 | - @Schema(description = "活动名称", required = true, example = "天蚕土豆") | |
| 28 | + @Schema(description = "活动名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "天蚕土豆") | |
| 29 | 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 | 40 | @PostMapping("/take") |
| 41 | 41 | @Operation(summary = "领取优惠劵") |
| 42 | 42 | @Parameter(name = "templateId", description = "优惠券模板编号", required = true, example = "1024") |
| 43 | + @PreAuthenticated | |
| 43 | 44 | public CommonResult<Boolean> takeCoupon(@Valid @RequestBody AppCouponTakeReqVO reqVO) { |
| 45 | + // 1. 领取优惠劵 | |
| 44 | 46 | Long userId = getLoginUserId(); |
| 45 | - // 领取 | |
| 46 | 47 | couponService.takeCoupon(reqVO.getTemplateId(), CollUtil.newHashSet(userId), CouponTakeTypeEnum.USER); |
| 47 | - // 检查是否可以继续领取 | |
| 48 | + | |
| 49 | + // 2. 检查是否可以继续领取 | |
| 48 | 50 | CouponTemplateDO couponTemplate = couponTemplateService.getCouponTemplate(reqVO.getTemplateId()); |
| 49 | 51 | boolean canTakeAgain = true; |
| 50 | 52 | if (couponTemplate.getTakeLimitCount() != null && couponTemplate.getTakeLimitCount() > 0) { |
| 53 | + // TODO @疯狂:要不要搞个 getTakeCount 方法? | |
| 51 | 54 | Integer takeCount = MapUtil.getInt(couponService.getTakeCountMapByTemplateIds( |
| 52 | 55 | Collections.singleton(reqVO.getTemplateId()), userId), reqVO.getTemplateId(), 0); |
| 53 | 56 | canTakeAgain = takeCount < couponTemplate.getTakeLimitCount(); |
| ... | ... | @@ -56,15 +59,16 @@ public class AppCouponController { |
| 56 | 59 | } |
| 57 | 60 | |
| 58 | 61 | @GetMapping("/match-list") |
| 59 | - @Operation(summary = "获得匹配指定商品的优惠劵列表") | |
| 62 | + @Operation(summary = "获得匹配指定商品的优惠劵列表", description = "用于下单页,展示优惠劵列表") | |
| 60 | 63 | public CommonResult<List<AppCouponMatchRespVO>> getMatchCouponList(AppCouponMatchReqVO matchReqVO) { |
| 61 | - // todo: 优惠金额倒序 | |
| 64 | + // todo: 优化:优惠金额倒序 | |
| 62 | 65 | return success(CouponConvert.INSTANCE.convertList(couponService.getMatchCouponList(getLoginUserId(), matchReqVO))); |
| 63 | 66 | } |
| 64 | 67 | |
| 65 | 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 | 72 | PageResult<CouponDO> pageResult = couponService.getCouponPage( |
| 69 | 73 | CouponConvert.INSTANCE.convert(pageReqVO, Collections.singleton(getLoginUserId()))); |
| 70 | 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 | 3 | import cn.hutool.core.util.ObjUtil; |
| 4 | 4 | import cn.iocoder.yudao.framework.common.pojo.CommonResult; |
| 5 | 5 | import cn.iocoder.yudao.framework.common.pojo.PageResult; |
| 6 | +import cn.iocoder.yudao.framework.common.util.object.ObjectUtils; | |
| 6 | 7 | import cn.iocoder.yudao.module.product.api.spu.ProductSpuApi; |
| 7 | 8 | import cn.iocoder.yudao.module.product.api.spu.dto.ProductSpuRespDTO; |
| 8 | 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 | 15 | import cn.iocoder.yudao.module.promotion.service.coupon.CouponService; |
| 15 | 16 | import cn.iocoder.yudao.module.promotion.service.coupon.CouponTemplateService; |
| 16 | 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 | 20 | import io.swagger.v3.oas.annotations.tags.Tag; |
| 18 | 21 | import org.springframework.validation.annotation.Validated; |
| 19 | 22 | import org.springframework.web.bind.annotation.GetMapping; |
| 20 | 23 | import org.springframework.web.bind.annotation.RequestMapping; |
| 24 | +import org.springframework.web.bind.annotation.RequestParam; | |
| 21 | 25 | import org.springframework.web.bind.annotation.RestController; |
| 22 | 26 | |
| 23 | 27 | import javax.annotation.Resource; |
| 28 | +import java.time.LocalDateTime; | |
| 24 | 29 | import java.util.*; |
| 25 | 30 | |
| 26 | 31 | import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; |
| ... | ... | @@ -41,16 +46,63 @@ public class AppCouponTemplateController { |
| 41 | 46 | @Resource |
| 42 | 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 | 94 | @GetMapping("/page") |
| 45 | 95 | @Operation(summary = "获得优惠劵模版分页") |
| 46 | 96 | public CommonResult<PageResult<AppCouponTemplateRespVO>> getCouponTemplatePage(AppCouponTemplatePageReqVO pageReqVO) { |
| 47 | 97 | // 1.1 处理查询条件:商品范围编号 |
| 48 | - Long productScopeValue = getaProductScopeValue(pageReqVO); | |
| 49 | - // 1.2 处理查询条件:领取方式=直接领取 | |
| 98 | + Long productScopeValue = getProductScopeValue(pageReqVO); | |
| 99 | + // 1.2 处理查询条件:领取方式 = 直接领取 | |
| 50 | 100 | List<Integer> canTakeTypes = Collections.singletonList(CouponTakeTypeEnum.USER.getValue()); |
| 101 | + | |
| 51 | 102 | // 2. 分页查询 |
| 52 | 103 | PageResult<CouponTemplateDO> pageResult = couponTemplateService.getCouponTemplatePage( |
| 53 | 104 | CouponTemplateConvert.INSTANCE.convert(pageReqVO, canTakeTypes, pageReqVO.getProductScope(), productScopeValue)); |
| 105 | + | |
| 54 | 106 | // 3.1 领取数量 |
| 55 | 107 | Map<Long, Integer> couponTakeCountMap = new HashMap<>(0); |
| 56 | 108 | Long userId = getLoginUserId(); |
| ... | ... | @@ -63,17 +115,24 @@ public class AppCouponTemplateController { |
| 63 | 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 | 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
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 | 23 | // 单位:分;0 - 不限制 |
| 24 | 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 | 26 | @Schema(description = "生效日期类型", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") |
| 35 | 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
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 | 42 | if (MapUtil.isEmpty(couponTakeCountMap)) { |
| 43 | 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 | 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 | 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<CouponDO> { |
| 70 | 70 | ); |
| 71 | 71 | } |
| 72 | 72 | |
| 73 | + // TODO @疯狂:这个是不是搞个 Map 就可以呀? | |
| 73 | 74 | default List<CouponTakeCountBO> selectCountByUserIdAndTemplateIdIn(Long userId, Collection<Long> templateIds) { |
| 74 | 75 | return BeanUtil.copyToList(selectMaps(MPJWrappers.lambdaJoin(CouponDO.class) |
| 75 | 76 | .select(CouponDO::getTemplateId) |
| ... | ... | @@ -81,18 +82,17 @@ public interface CouponMapper extends BaseMapperX<CouponDO> { |
| 81 | 82 | |
| 82 | 83 | default List<CouponDO> selectListByUserIdAndStatusAndUsePriceLeAndProductScope( |
| 83 | 84 | Long userId, Integer status, Integer usePrice, List<Long> spuIds, List<Long> categoryIds) { |
| 84 | - | |
| 85 | 85 | Function<List<Long>, String> productScopeValuesFindInSetFunc = ids -> ids.stream() |
| 86 | 86 | .map(id -> StrUtil.format("FIND_IN_SET({}, product_scope_values) ", id)) |
| 87 | 87 | .collect(Collectors.joining(" OR ")); |
| 88 | 88 | return selectList(new LambdaQueryWrapperX<CouponDO>() |
| 89 | 89 | .eq(CouponDO::getUserId, userId) |
| 90 | 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 | 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 | 96 | .apply(productScopeValuesFindInSetFunc.apply(categoryIds))))); |
| 97 | 97 | } |
| 98 | 98 | |
| ... | ... | @@ -102,4 +102,5 @@ public interface CouponMapper extends BaseMapperX<CouponDO> { |
| 102 | 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 | 3 | import cn.hutool.core.util.StrUtil; |
| 4 | 4 | import cn.iocoder.yudao.framework.quartz.core.handler.JobHandler; |
| ... | ... | @@ -8,19 +8,20 @@ import org.springframework.stereotype.Component; |
| 8 | 8 | |
| 9 | 9 | import javax.annotation.Resource; |
| 10 | 10 | |
| 11 | +// TODO 芋艿:配置一个 Job | |
| 11 | 12 | /** |
| 12 | 13 | * 优惠券过期 Job |
| 13 | 14 | * |
| 14 | 15 | * @author owen |
| 15 | 16 | */ |
| 16 | 17 | @Component |
| 17 | -@TenantJob | |
| 18 | 18 | public class CouponExpireJob implements JobHandler { |
| 19 | 19 | |
| 20 | 20 | @Resource |
| 21 | 21 | private CouponService couponService; |
| 22 | 22 | |
| 23 | 23 | @Override |
| 24 | + @TenantJob | |
| 24 | 25 | public String execute(String param) { |
| 25 | 26 | int count = couponService.expireCoupon(); |
| 26 | 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
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 | 137 | * @return 领取优惠券的数量 |
| 138 | 138 | */ |
| 139 | 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 | 165 | * @return 过期数量 |
| 165 | 166 | */ |
| 166 | 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 | 40 | import static cn.iocoder.yudao.module.promotion.enums.ErrorCodeConstants.*; |
| 41 | 41 | import static java.util.Arrays.asList; |
| 42 | 42 | |
| 43 | +// TODO @疯狂:注册时,赠送用户优惠劵;为了解耦,可以考虑注册时发个 MQ 消息;然后营销这里监听后消费; | |
| 43 | 44 | /** |
| 44 | 45 | * 优惠劵 Service 实现类 |
| 45 | 46 | * |
| ... | ... | @@ -192,7 +193,8 @@ public class CouponServiceImpl implements CouponService { |
| 192 | 193 | |
| 193 | 194 | @Override |
| 194 | 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 | 198 | matchReqVO.getPrice(), matchReqVO.getSpuIds(), matchReqVO.getCategoryIds()); |
| 197 | 199 | } |
| 198 | 200 | |
| ... | ... | @@ -220,15 +222,20 @@ public class CouponServiceImpl implements CouponService { |
| 220 | 222 | return count; |
| 221 | 223 | } |
| 222 | 224 | |
| 225 | + /** | |
| 226 | + * 过期单个优惠劵 | |
| 227 | + * | |
| 228 | + * @param coupon 优惠劵 | |
| 229 | + * @return 是否过期成功 | |
| 230 | + */ | |
| 223 | 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 | 235 | if (updateRows == 0) { |
| 228 | 236 | log.error("[expireCoupon][coupon({}) 更新为已过期失败]", coupon.getId()); |
| 229 | 237 | return false; |
| 230 | 238 | } |
| 231 | - | |
| 232 | 239 | log.info("[expireCoupon][coupon({}) 更新为已过期成功]", coupon.getId()); |
| 233 | 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 | 29 | @Resource |
| 30 | 30 | private CouponTemplateMapper couponTemplateMapper; |
| 31 | 31 | |
| 32 | + // TODO @疯狂:新增/修改时,需要校验对应的商品、分类是否存在 | |
| 32 | 33 | @Override |
| 33 | 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
yudao-module-mall/yudao-module-trade-api/src/main/java/cn/iocoder/yudao/module/trade/enums/ErrorCodeConstants.java
| ... | ... | @@ -11,7 +11,7 @@ import cn.iocoder.yudao.framework.common.exception.ErrorCode; |
| 11 | 11 | */ |
| 12 | 12 | public interface ErrorCodeConstants { |
| 13 | 13 | |
| 14 | - // ========== Order 模块 1011000000 ========== | |
| 14 | + // ========== Order 模块 1-011-000-000 ========== | |
| 15 | 15 | ErrorCode ORDER_ITEM_NOT_FOUND = new ErrorCode(1011000010, "交易订单项不存在"); |
| 16 | 16 | ErrorCode ORDER_NOT_FOUND = new ErrorCode(1011000011, "交易订单不存在"); |
| 17 | 17 | ErrorCode ORDER_ITEM_UPDATE_AFTER_SALE_STATUS_FAIL = new ErrorCode(1011000012, "交易订单项更新售后状态失败,请重试"); |
| ... | ... | @@ -33,45 +33,44 @@ public interface ErrorCodeConstants { |
| 33 | 33 | ErrorCode ORDER_UPDATE_PRICE_FAIL_PRICE_ERROR = new ErrorCode(1011000028, "支付订单调价失败,原因:调整后支付价格不能小于 0.01 元"); |
| 34 | 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 | 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 | 55 | ErrorCode PRICE_CALCULATE_PAY_PRICE_ILLEGAL = new ErrorCode(1011003000, "支付价格计算异常,原因:价格小于等于 0"); |
| 56 | 56 | ErrorCode PRICE_CALCULATE_DELIVERY_PRICE_TEMPLATE_NOT_FOUND = new ErrorCode(1011003002, "计算快递运费异常,找不到对应的运费模板"); |
| 57 | 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 | 75 | // ========== 分销用户 模块 1011007000 ========== |
| 77 | 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 | 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 | 9 | * @author 陈賝 |
| 7 | 10 | * @since 2023/6/13 13:53 |
| 8 | 11 | */ |
| 9 | -// TODO @chenchen:可以 lombok 简化构造方法,和 get 方法 | |
| 12 | +@RequiredArgsConstructor | |
| 13 | +@Getter | |
| 10 | 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 | 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 | 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 | 17 | |
| 18 | 18 | ORDER(1, "获得推广佣金", "获得推广佣金 {}", true), |
| 19 | 19 | WITHDRAW(2, "提现申请", "提现申请扣除佣金 {}", false), |
| 20 | - WITHDRAW_REJECT(3, "提现申请驳回", "提现申请驳回返还佣金 {}", true), | |
| 20 | + WITHDRAW_REJECT(3, "提现申请驳回", "提现申请驳回,返还佣金 {}", true), | |
| 21 | 21 | ; |
| 22 | 22 | |
| 23 | 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
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 | 24 | MEMBER_CANCEL(40, "取消订单"), |
| 25 | 25 | SYSTEM_CANCEL(41, "到期未支付,系统自动取消订单"), |
| 26 | 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 | 34 | private final Integer type; |
| 34 | 35 | /** |
| 35 | - * 类型 | |
| 36 | + * 操作描述 | |
| 36 | 37 | */ |
| 37 | 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 | 13 | import cn.iocoder.yudao.module.trade.service.brokerage.BrokerageRecordService; |
| 14 | 14 | import cn.iocoder.yudao.module.trade.service.brokerage.BrokerageUserService; |
| 15 | 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 | 18 | import io.swagger.v3.oas.annotations.Operation; |
| 19 | 19 | import io.swagger.v3.oas.annotations.Parameter; |
| 20 | 20 | import io.swagger.v3.oas.annotations.tags.Tag; |
| ... | ... | @@ -88,24 +88,24 @@ public class BrokerageUserController { |
| 88 | 88 | // 分页查询 |
| 89 | 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 | 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 | 96 | userIds, BrokerageRecordBizTypeEnum.ORDER.getType(), BrokerageRecordStatusEnum.SETTLEMENT.getStatus()); |
| 98 | - // TODO @芋艿:看看下面 getBrokerageUserCountByBindUserId 有没可能一次性出结果,不然 n 次有点太花性能了; | |
| 99 | - // 合计推广用户数量 | |
| 97 | + // 合计分佣的推广用户 | |
| 98 | + // TODO @疯狂:转成 map 批量读取 | |
| 100 | 99 | Map<Long, Long> brokerageUserCountMap = convertMap(userIds, |
| 101 | 100 | userId -> userId, |
| 102 | 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 | 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 | 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 | 25 | private String avatar; |
| 26 | - @Schema(description = "用户昵称", example = "李四") | |
| 26 | + @Schema(description = "用户昵称", requiredMode = Schema.RequiredMode.REQUIRED, example = "李四") | |
| 27 | 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 | 32 | private Integer brokerageUserCount; |
| 33 | - @Schema(description = "推广订单数量", example = "20019") | |
| 33 | + @Schema(description = "推广订单数量", requiredMode = Schema.RequiredMode.REQUIRED, example = "20019") | |
| 34 | 34 | private Integer brokerageOrderCount; |
| 35 | - @Schema(description = "推广订单金额", example = "20019") | |
| 35 | + @Schema(description = "推广订单金额", requiredMode = Schema.RequiredMode.REQUIRED, example = "20019") | |
| 36 | 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 | 41 | private Integer withdrawPrice; |
| 42 | - @Schema(description = "已提现次数", example = "20019") | |
| 42 | + @Schema(description = "已提现次数", requiredMode = Schema.RequiredMode.REQUIRED, example = "20019") | |
| 43 | 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 | 19 | */ |
| 20 | 20 | @Data |
| 21 | 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 | 93 | private Integer brokerageFrozenDays; |
| 81 | 94 | |
| 82 | 95 | @Schema(description = "提现方式", requiredMode = Schema.RequiredMode.REQUIRED, example = "[0, 1]") |
| 83 | - @NotNull(message = "提现方式不能为空") | |
| 96 | + @NotEmpty(message = "提现方式不能为空") | |
| 84 | 97 | @InEnum(value = BrokerageWithdrawTypeEnum.class, message = "提现方式必须是 {value}") |
| 85 | 98 | private List<Integer> brokerageWithdrawTypes; |
| 86 | 99 | ... | ... |