Merge remote-tracking branch 'origin/feature/1.8.0-uniapp' into ly_uniapp
# Conflicts: # yudao-module-mall/yudao-module-market-biz/src/main/java/cn/iocoder/yudao/module/market/api/price/PriceApiImpl.java # yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/api/sku/ProductSkuApiImpl.java # yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/api/spu/ProductSpuApiImpl.java # yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/convert/sku/ProductSkuConvert.java # yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/dal/mysql/sku/ProductSkuMapper.java # yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/convert/order/TradeOrderConvert.java # yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/convert/order/TradeOrderItemConvert.java # yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/order/TradeOrderServiceImpl.java # yudao-server/src/main/resources/application.yaml
90
README.md
@ -23,8 +23,8 @@
|
||||
>
|
||||
> 😜 给项目点点 Star 吧,这对我们真的很重要!
|
||||
|
||||
* 前端 Vue2 版本采用 [vue-element-admin](https://github.com/PanJiaChen/vue-element-admin)
|
||||
* 前端 Vue3 版本采用 [vue-element-plus-admin](https://gitee.com/kailong110120130/vue-element-plus-admin)
|
||||
* 管理后台的 Vue3 版本采用 [vue-element-plus-admin](https://gitee.com/kailong110120130/vue-element-plus-admin) ,Vue2 版本采用 [vue-element-admin](https://github.com/PanJiaChen/vue-element-admin)
|
||||
* 管理后台的移动端采用 [uni-app](https://github.com/dcloudio/uni-app) 方案,一份代码多终端适配,同时支持 APP、小程序、H5!
|
||||
* 后端采用 Spring Boot、MySQL + MyBatis Plus、Redis + Redisson
|
||||
* 数据库可使用 MySQL、Oracle、PostgreSQL、SQL Server、MariaDB、国产达梦 DM、TiDB 等
|
||||
* 权限认证使用 Spring Security & Token & Redis,支持多终端、多种用户的认证系统,支持 SSO 单点登录
|
||||
@ -156,8 +156,9 @@ ps:核心功能已经实现,正在对接微信小程序中...
|
||||
| `yudao-dependencies` | Maven 依赖版本管理 |
|
||||
| `yudao-framework` | Java 框架拓展 |
|
||||
| `yudao-server` | 管理后台 + 用户 APP 的服务端 |
|
||||
| `yudao-ui-admin` | Vue2 管理后台的 UI 界面 |
|
||||
| `yudao-ui-admin-vue3` | Vue3 管理后台的 UI 界面 |
|
||||
| `yudao-ui-admin` | 管理后台的 Vue2 前端项目 |
|
||||
| `yudao-ui-admin-vue3` | 管理后台的 Vue3 前端项目 |
|
||||
| `yudao-ui-admin-uniapp` | 管理后台的 uni-app 多端项目 |
|
||||
| `yudao-ui-app` | 用户 APP 的 UI 界面 |
|
||||
| `yudao-module-system` | 系统功能的 Module 模块 |
|
||||
| `yudao-module-member` | 会员中心的 Module 模块 |
|
||||
@ -169,48 +170,55 @@ ps:核心功能已经实现,正在对接微信小程序中...
|
||||
### 后端
|
||||
|
||||
| 框架 | 说明 | 版本 | 学习指南 |
|
||||
|---------------------------------------------------------------------------------------------|-----------------------|-----------|----------------------------------------------------------------|
|
||||
| [Spring Boot](https://spring.io/projects/spring-boot) | 应用开发框架 | 2.6.10 | [文档](https://github.com/YunaiV/SpringBoot-Labs) |
|
||||
| [MySQL](https://www.mysql.com/cn/) | 数据库服务器 | 5.7 | |
|
||||
| [Druid](https://github.com/alibaba/druid) | JDBC 连接池、监控组件 | 1.2.11 | [文档](http://www.iocoder.cn/Spring-Boot/datasource-pool/?yudao) |
|
||||
| [MyBatis Plus](https://mp.baomidou.com/) | MyBatis 增强工具包 | 3.5.2 | [文档](http://www.iocoder.cn/Spring-Boot/MyBatis/?yudao) |
|
||||
| [Dynamic Datasource](https://dynamic-datasource.com/) | 动态数据源 | 3.5.0 | [文档](http://www.iocoder.cn/Spring-Boot/datasource-pool/?yudao) |
|
||||
| [Redis](https://redis.io/) | key-value 数据库 | 5.0 | |
|
||||
| [Redisson](https://github.com/redisson/redisson) | Redis 客户端 | 3.17.4 | [文档](http://www.iocoder.cn/Spring-Boot/Redis/?yudao) |
|
||||
| [Spring MVC](https://github.com/spring-projects/spring-framework/tree/master/spring-webmvc) | MVC 框架 | 5.3.20 | [文档](http://www.iocoder.cn/SpringMVC/MVC/?yudao) |
|
||||
| [Spring Security](https://github.com/spring-projects/spring-security) | Spring 安全框架 | 5.6.5 | [文档](http://www.iocoder.cn/Spring-Boot/Spring-Security/?yudao) |
|
||||
| [Hibernate Validator](https://github.com/hibernate/hibernate-validator) | 参数校验组件 | 6.2.3 | [文档](http://www.iocoder.cn/Spring-Boot/Validation/?yudao) |
|
||||
| [Flowable](https://github.com/flowable/flowable-engine) | 工作流引擎 | 6.7.0 | [文档](https://doc.iocoder.cn/bpm/) |
|
||||
| [Quartz](https://github.com/quartz-scheduler) | 任务调度组件 | 2.3.2 | [文档](http://www.iocoder.cn/Spring-Boot/Job/?yudao) |
|
||||
| [Knife4j](https://gitee.com/xiaoym/knife4j) | Swagger 增强 UI 实现 | 3.0.3 | [文档](http://www.iocoder.cn/Spring-Boot/Swagger/?yudao) |
|
||||
| [Resilience4j](https://github.com/resilience4j/resilience4j) | 服务保障组件 | 1.7.1 | [文档](http://www.iocoder.cn/Spring-Boot/Resilience4j/?yudao) |
|
||||
| [SkyWalking](https://skywalking.apache.org/) | 分布式应用追踪系统 | 8.5.0 | [文档](http://www.iocoder.cn/Spring-Boot/SkyWalking/?yudao) |
|
||||
| [Spring Boot Admin](https://github.com/codecentric/spring-boot-admin) | Spring Boot 监控平台 | 2.6.7 | [文档](http://www.iocoder.cn/Spring-Boot/Admin/?yudao) |
|
||||
| [Jackson](https://github.com/FasterXML/jackson) | JSON 工具库 | 2.13.3 | |
|
||||
| [MapStruct](https://mapstruct.org/) | Java Bean 转换 | 1.4.1 | [文档](http://www.iocoder.cn/Spring-Boot/MapStruct/?yudao) |
|
||||
| [Lombok](https://projectlombok.org/) | 消除冗长的 Java 代码 | 1.16.14 | [文档](http://www.iocoder.cn/Spring-Boot/Lombok/?yudao) |
|
||||
| [JUnit](https://junit.org/junit5/) | Java 单元测试框架 | 5.8.2 | - |
|
||||
| [Mockito](https://github.com/mockito/mockito) | Java Mock 框架 | 4.0.0 | - |
|
||||
|---------------------------------------------------------------------------------------------|-----------------------|---------|----------------------------------------------------------------|
|
||||
| [Spring Boot](https://spring.io/projects/spring-boot) | 应用开发框架 | 2.6.10 | [文档](https://github.com/YunaiV/SpringBoot-Labs) |
|
||||
| [MySQL](https://www.mysql.com/cn/) | 数据库服务器 | 5.7 | |
|
||||
| [Druid](https://github.com/alibaba/druid) | JDBC 连接池、监控组件 | 1.2.11 | [文档](http://www.iocoder.cn/Spring-Boot/datasource-pool/?yudao) |
|
||||
| [MyBatis Plus](https://mp.baomidou.com/) | MyBatis 增强工具包 | 3.5.2 | [文档](http://www.iocoder.cn/Spring-Boot/MyBatis/?yudao) |
|
||||
| [Dynamic Datasource](https://dynamic-datasource.com/) | 动态数据源 | 3.5.0 | [文档](http://www.iocoder.cn/Spring-Boot/datasource-pool/?yudao) |
|
||||
| [Redis](https://redis.io/) | key-value 数据库 | 5.0 | |
|
||||
| [Redisson](https://github.com/redisson/redisson) | Redis 客户端 | 3.17.4 | [文档](http://www.iocoder.cn/Spring-Boot/Redis/?yudao) |
|
||||
| [Spring MVC](https://github.com/spring-projects/spring-framework/tree/master/spring-webmvc) | MVC 框架 | 5.3.20 | [文档](http://www.iocoder.cn/SpringMVC/MVC/?yudao) |
|
||||
| [Spring Security](https://github.com/spring-projects/spring-security) | Spring 安全框架 | 5.6.5 | [文档](http://www.iocoder.cn/Spring-Boot/Spring-Security/?yudao) |
|
||||
| [Hibernate Validator](https://github.com/hibernate/hibernate-validator) | 参数校验组件 | 6.2.3 | [文档](http://www.iocoder.cn/Spring-Boot/Validation/?yudao) |
|
||||
| [Flowable](https://github.com/flowable/flowable-engine) | 工作流引擎 | 6.7.2 | [文档](https://doc.iocoder.cn/bpm/) |
|
||||
| [Quartz](https://github.com/quartz-scheduler) | 任务调度组件 | 2.3.2 | [文档](http://www.iocoder.cn/Spring-Boot/Job/?yudao) |
|
||||
| [Knife4j](https://gitee.com/xiaoym/knife4j) | Swagger 增强 UI 实现 | 3.0.3 | [文档](http://www.iocoder.cn/Spring-Boot/Swagger/?yudao) |
|
||||
| [Resilience4j](https://github.com/resilience4j/resilience4j) | 服务保障组件 | 1.7.1 | [文档](http://www.iocoder.cn/Spring-Boot/Resilience4j/?yudao) |
|
||||
| [SkyWalking](https://skywalking.apache.org/) | 分布式应用追踪系统 | 8.5.0 | [文档](http://www.iocoder.cn/Spring-Boot/SkyWalking/?yudao) |
|
||||
| [Spring Boot Admin](https://github.com/codecentric/spring-boot-admin) | Spring Boot 监控平台 | 2.6.7 | [文档](http://www.iocoder.cn/Spring-Boot/Admin/?yudao) |
|
||||
| [Jackson](https://github.com/FasterXML/jackson) | JSON 工具库 | 2.13.3 | |
|
||||
| [MapStruct](https://mapstruct.org/) | Java Bean 转换 | 1.4.1 | [文档](http://www.iocoder.cn/Spring-Boot/MapStruct/?yudao) |
|
||||
| [Lombok](https://projectlombok.org/) | 消除冗长的 Java 代码 | 1.16.14 | [文档](http://www.iocoder.cn/Spring-Boot/Lombok/?yudao) |
|
||||
| [JUnit](https://junit.org/junit5/) | Java 单元测试框架 | 5.8.2 | - |
|
||||
| [Mockito](https://github.com/mockito/mockito) | Java Mock 框架 | 4.0.0 | - |
|
||||
|
||||
### Vue2 前端
|
||||
### [管理后台 Vue2 前端](./yudao-ui-admin)
|
||||
|
||||
| 框架 | 说明 | 版本 |
|
||||
|------------------------------------------------------------------------------|---------------|--------|
|
||||
| [Vue](https://cn.vuejs.org/index.html) | JavaScript 框架 | 2.6.12 |
|
||||
| [Vue Element Admin](https://panjiachen.github.io/vue-element-admin-site/zh/) | 后台前端解决方案 | - |
|
||||
|
||||
### Vue3 前端
|
||||
### [管理后台 Vue3 前端](./yudao-ui-admin-vue3)
|
||||
|
||||
| 框架 | 说明 | 版本 |
|
||||
|----------------------------------------------------------------------|-----------------|--------|
|
||||
| [Vue](https://staging-cn.vuejs.org/) | Vue 框架 | 3.2.37 |
|
||||
| [Vite](https://cn.vitejs.dev//) | 开发与构建工具 | 3.0.4 |
|
||||
| [Element Plus](https://element-plus.org/zh-CN/) | Element Plus | 2.2.12 |
|
||||
| [TypeScript](https://www.typescriptlang.org/docs/) | TypeScript | 4.7.4 |
|
||||
| [pinia](https://pinia.vuejs.org/) | vuex5 | 2.0.17 |
|
||||
| [vue-i18n](https://kazupon.github.io/vue-i18n/zh/introduction.html/) | 国际化 | 9.2.2 |
|
||||
| [windicss](https://cn.windicss.org/) | 下一代工具优先的 CSS 框架 | 3.5.6 |
|
||||
| [iconify](https://icon-sets.iconify.design/) | 在线图标库 | 2.2.1 |
|
||||
|
||||
### [管理后台 uni-app 跨端](./yudao-ui-admin-uniapp)
|
||||
|
||||
| 框架 | 说明 | 版本 |
|
||||
|----------------------------------------------------------------------|------------------|--------|
|
||||
| [Vue](https://staging-cn.vuejs.org/) | Vue 框架 | 3.2.37 |
|
||||
| [Vite](https://cn.vitejs.dev//) | 开发与构建工具 | 3.0.3 |
|
||||
| [Element Plus](https://element-plus.org/zh-CN/) | Element Plus | 2.2.11 |
|
||||
| [TypeScript](https://www.typescriptlang.org/docs/) | TypeScript | 4.7.4 |
|
||||
| [pinia](https://pinia.vuejs.org/) | Vue 存储库 替代 vuex5 | 2.0.17 |
|
||||
| [vue-i18n](https://kazupon.github.io/vue-i18n/zh/introduction.html/) | 国际化 | 9.1.10 |
|
||||
| [windicss](https://cn.windicss.org/) | 下一代工具优先的 CSS 框架 | 3.5.6 |
|
||||
| [iconify](https://icon-sets.iconify.design/) | 在线图标库 | 2.2.1 |
|
||||
| [uni-app](hhttps://github.com/dcloudio/uni-app) | 跨平台框架 | 2.0.0 |
|
||||
| [uni-ui](https://github.com/dcloudio/uni-ui) | 基于 uni-app 的 UI 框架 | 1.4.20 |
|
||||
|
||||
## 🐷 演示图
|
||||
|
||||
@ -262,3 +270,13 @@ ps:核心功能已经实现,正在对接微信小程序中...
|
||||
| 模块 | biu | biu | biu |
|
||||
|---------|------------------------------------------------------------------|------------------------------------------------------------------------|------------------------------------------------------------------------|
|
||||
| 报表设计器 | ![数据报表](https://static.iocoder.cn/images/ruoyi-vue-pro/报表设计器-数据报表.jpg?imageView2/2/format/webp/w/1280) | ![图形报表](https://static.iocoder.cn/images/ruoyi-vue-pro/报表设计器-图形报表.jpg?imageView2/2/format/webp/w/1280) | ![报表设计器-打印设计](https://static.iocoder.cn/images/ruoyi-vue-pro/报表设计器-打印设计.jpg?imageView2/2/format/webp/w/1280) |
|
||||
|
||||
### 移动端(管理后台)
|
||||
|
||||
| biu | biu | biu |
|
||||
|------------------------------------------------------------------|------------------------------------------------------------------------|------------------------------------------------------------------------|
|
||||
| ![](https://static.iocoder.cn/images/ruoyi-vue-pro/admin-uniapp/01.png?imageView2/2/format/webp) | ![](https://static.iocoder.cn/images/ruoyi-vue-pro/admin-uniapp/02.png?imageView2/2/format/webp) | ![](https://static.iocoder.cn/images/ruoyi-vue-pro/admin-uniapp/03.png?imageView2/2/format/webp) |
|
||||
| ![](https://static.iocoder.cn/images/ruoyi-vue-pro/admin-uniapp/04.png?imageView2/2/format/webp) | ![](https://static.iocoder.cn/images/ruoyi-vue-pro/admin-uniapp/05.png?imageView2/2/format/webp) | ![](https://static.iocoder.cn/images/ruoyi-vue-pro/admin-uniapp/06.png?imageView2/2/format/webp) |
|
||||
| ![](https://static.iocoder.cn/images/ruoyi-vue-pro/admin-uniapp/07.png?imageView2/2/format/webp) | ![](https://static.iocoder.cn/images/ruoyi-vue-pro/admin-uniapp/08.png?imageView2/2/format/webp) | ![](https://static.iocoder.cn/images/ruoyi-vue-pro/admin-uniapp/09.png?imageView2/2/format/webp) |
|
||||
|
||||
目前已经实现登录、我的、工作台、编辑资料、头像修改、密码修改、常见问题、关于我们等基础功能。
|
||||
|
2
pom.xml
@ -27,7 +27,7 @@
|
||||
<url>https://github.com/YunaiV/ruoyi-vue-pro</url>
|
||||
|
||||
<properties>
|
||||
<revision>1.6.3-snapshot</revision>
|
||||
<revision>1.6.4-snapshot</revision>
|
||||
<!-- Maven 相关 -->
|
||||
<java.version>1.8</java.version>
|
||||
<maven.compiler.source>${java.version}</maven.compiler.source>
|
||||
|
@ -2657,8 +2657,3 @@ INSERT INTO `system_users` (`id`, `username`, `password`, `nickname`, `remark`,
|
||||
COMMIT;
|
||||
|
||||
SET FOREIGN_KEY_CHECKS = 1;
|
||||
|
||||
|
||||
-- 积木报表菜单
|
||||
INSERT INTO `system_menu` VALUES (1281, '可视化报表', '', 1, 12, 0, '/visualization', 'chart', NULL, 0, b'1', b'1', '1', '2022-07-10 20:22:15', '1', '2022-07-10 20:33:30', b'0');
|
||||
INSERT INTO `system_menu` VALUES (1282, '积木报表', '', 2, 1, 1281, 'jm-report', '#', 'visualization/jm/index', 0, b'1', b'1', '1', '2022-07-10 20:26:36', '1', '2022-07-10 20:33:26', b'0');
|
7
sql/mysql/update.sql
Normal file
@ -0,0 +1,7 @@
|
||||
-- ----------------------------
|
||||
-- 升级SQL文件,全新安装只需要执行ruoyi-vue-pro.sql文件即可
|
||||
-- 1.6.2 ==> 1.6.3
|
||||
-- ----------------------------
|
||||
-- 积木报表菜单
|
||||
INSERT INTO `system_menu` VALUES (1281, '可视化报表', '', 1, 12, 0, '/visualization', 'chart', NULL, 0, b'1', b'1', '1', '2022-07-10 20:22:15', '1', '2022-07-10 20:33:30', b'0');
|
||||
INSERT INTO `system_menu` VALUES (1282, '积木报表', '', 2, 1, 1281, 'jm-report', '#', 'visualization/jm/index', 0, b'1', b'1', '1', '2022-07-10 20:26:36', '1', '2022-07-10 20:33:26', b'0');
|
@ -257,5 +257,7 @@ INSERT INTO `system_menu` VALUES (1264, '客户端查询', 'system:oauth2-client
|
||||
INSERT INTO `system_menu` VALUES (1265, '客户端创建', 'system:oauth2-client:create', 3, 2, 1263, '', '', '', 0, b'1', b'1', '', '2022-05-10 16:26:33', '1', '2022-05-11 00:31:23', b'0');
|
||||
INSERT INTO `system_menu` VALUES (1266, '客户端更新', 'system:oauth2-client:update', 3, 3, 1263, '', '', '', 0, b'1', b'1', '', '2022-05-10 16:26:33', '1', '2022-05-11 00:31:28', b'0');
|
||||
INSERT INTO `system_menu` VALUES (1267, '客户端删除', 'system:oauth2-client:delete', 3, 4, 1263, '', '', '', 0, b'1', b'1', '', '2022-05-10 16:26:33', '1', '2022-05-11 00:31:33', b'0');
|
||||
INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `status`, `visible`, `keep_alive`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1281, '可视化报表', '', 1, 12, 0, '/visualization', 'ep:histogram', NULL, 0, b'1', b'1', '1', '2022-07-10 20:22:15', '1', '2022-07-10 20:33:30', b'0');
|
||||
INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `status`, `visible`, `keep_alive`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1282, '积木报表', '', 2, 1, 1281, 'jimu-report', 'ep:histogram', 'visualization/jmreport/index', 0, b'1', b'1', '1', '2022-07-10 20:26:36', '1', '2022-07-28 21:17:34', b'0');
|
||||
|
||||
SET FOREIGN_KEY_CHECKS = 1;
|
||||
|
@ -22,24 +22,24 @@ SET FOREIGN_KEY_CHECKS = 0;
|
||||
-- ----------------------------
|
||||
DROP TABLE IF EXISTS `market_activity`;
|
||||
CREATE TABLE `market_activity` (
|
||||
`id` bigint NOT NULL AUTO_INCREMENT COMMENT '活动编号',
|
||||
`title` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL DEFAULT '' COMMENT '活动标题',
|
||||
`activity_type` tinyint NOT NULL COMMENT '活动类型',
|
||||
`status` tinyint NOT NULL DEFAULT -1 COMMENT '活动状态',
|
||||
`start_time` datetime NOT NULL COMMENT '开始时间',
|
||||
`end_time` datetime NOT NULL COMMENT '结束时间',
|
||||
`invalid_time` datetime NULL DEFAULT NULL COMMENT '失效时间',
|
||||
`delete_time` datetime NULL DEFAULT NULL COMMENT '删除时间',
|
||||
`time_limited_discount` varchar(2000) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '限制折扣字符串,使用 JSON 序列化成字符串存储',
|
||||
`full_privilege` varchar(2000) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '限制折扣字符串,使用 JSON 序列化成字符串存储',
|
||||
`creator` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT '' COMMENT '创建者',
|
||||
`create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
|
||||
`updater` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT '' COMMENT '更新者',
|
||||
`update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
|
||||
`deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除',
|
||||
`tenant_id` bigint NOT NULL DEFAULT 0 COMMENT '租户编号',
|
||||
PRIMARY KEY (`id`) USING BTREE
|
||||
) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci COMMENT = '促销活动';
|
||||
`id` bigint NOT NULL AUTO_INCREMENT COMMENT '活动编号',
|
||||
`title` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL DEFAULT '' COMMENT '活动标题',
|
||||
`activity_type` tinyint NOT NULL COMMENT '活动类型',
|
||||
`status` tinyint NOT NULL DEFAULT -1 COMMENT '活动状态',
|
||||
`start_time` datetime NOT NULL COMMENT '开始时间',
|
||||
`end_time` datetime NOT NULL COMMENT '结束时间',
|
||||
`invalid_time` datetime NULL DEFAULT NULL COMMENT '失效时间',
|
||||
`delete_time` datetime NULL DEFAULT NULL COMMENT '删除时间',
|
||||
`time_limited_discount` varchar(2000) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '限制折扣字符串,使用 JSON 序列化成字符串存储',
|
||||
`full_privilege` varchar(2000) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '限制折扣字符串,使用 JSON 序列化成字符串存储',
|
||||
`creator` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT '' COMMENT '创建者',
|
||||
`create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
|
||||
`updater` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT '' COMMENT '更新者',
|
||||
`update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
|
||||
`deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除',
|
||||
`tenant_id` bigint NOT NULL DEFAULT 0 COMMENT '租户编号',
|
||||
PRIMARY KEY (`id`) USING BTREE
|
||||
) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '促销活动';
|
||||
|
||||
-- ----------------------------
|
||||
-- Records of market_activity
|
||||
@ -52,21 +52,21 @@ COMMIT;
|
||||
-- ----------------------------
|
||||
DROP TABLE IF EXISTS `market_banner`;
|
||||
CREATE TABLE `market_banner` (
|
||||
`id` bigint NOT NULL AUTO_INCREMENT COMMENT 'Banner编号',
|
||||
`title` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL DEFAULT '' COMMENT 'Banner标题',
|
||||
`pic_url` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '图片URL',
|
||||
`status` tinyint NOT NULL DEFAULT -1 COMMENT '活动状态',
|
||||
`url` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '跳转地址',
|
||||
`creator` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT '' COMMENT '创建者',
|
||||
`create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
|
||||
`updater` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT '' COMMENT '更新者',
|
||||
`update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
|
||||
`deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除',
|
||||
`tenant_id` bigint NOT NULL DEFAULT 0 COMMENT '租户编号',
|
||||
`sort` tinyint NULL DEFAULT NULL COMMENT '排序',
|
||||
`memo` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '描述',
|
||||
PRIMARY KEY (`id`) USING BTREE
|
||||
) ENGINE = InnoDB AUTO_INCREMENT = 3 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci COMMENT = 'Banner管理';
|
||||
`id` bigint NOT NULL AUTO_INCREMENT COMMENT 'Banner编号',
|
||||
`title` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL DEFAULT '' COMMENT 'Banner标题',
|
||||
`pic_url` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '图片URL',
|
||||
`status` tinyint NOT NULL DEFAULT -1 COMMENT '活动状态',
|
||||
`url` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '跳转地址',
|
||||
`creator` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT '' COMMENT '创建者',
|
||||
`create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
|
||||
`updater` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT '' COMMENT '更新者',
|
||||
`update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
|
||||
`deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除',
|
||||
`tenant_id` bigint NOT NULL DEFAULT 0 COMMENT '租户编号',
|
||||
`sort` tinyint NULL DEFAULT NULL COMMENT '排序',
|
||||
`memo` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '描述',
|
||||
PRIMARY KEY (`id`) USING BTREE
|
||||
) ENGINE = InnoDB AUTO_INCREMENT = 3 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = 'Banner管理';
|
||||
|
||||
-- ----------------------------
|
||||
-- Records of market_banner
|
||||
@ -79,22 +79,22 @@ COMMIT;
|
||||
-- ----------------------------
|
||||
DROP TABLE IF EXISTS `member_address`;
|
||||
CREATE TABLE `member_address` (
|
||||
`id` bigint NOT NULL AUTO_INCREMENT COMMENT '收件地址编号',
|
||||
`user_id` bigint NOT NULL COMMENT '用户编号',
|
||||
`name` varchar(10) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL COMMENT '收件人名称',
|
||||
`mobile` varchar(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL COMMENT '手机号',
|
||||
`area_id` bigint NOT NULL COMMENT '地区编码',
|
||||
`post_code` varchar(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL COMMENT '邮编',
|
||||
`detail_address` varchar(250) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL COMMENT '收件详细地址',
|
||||
`defaulted` bit(1) NOT NULL COMMENT '是否默认',
|
||||
`creator` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT '' COMMENT '创建者',
|
||||
`create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
|
||||
`updater` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT '' COMMENT '更新者',
|
||||
`update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
|
||||
`deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除',
|
||||
`tenant_id` bigint NOT NULL DEFAULT 0 COMMENT '租户编号',
|
||||
PRIMARY KEY (`id`) USING BTREE,
|
||||
INDEX `idx_userId`(`user_id` ASC) USING BTREE
|
||||
`id` bigint NOT NULL AUTO_INCREMENT COMMENT '收件地址编号',
|
||||
`user_id` bigint NOT NULL COMMENT '用户编号',
|
||||
`name` varchar(10) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL COMMENT '收件人名称',
|
||||
`mobile` varchar(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL COMMENT '手机号',
|
||||
`area_id` bigint NOT NULL COMMENT '地区编码',
|
||||
`post_code` varchar(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL COMMENT '邮编',
|
||||
`detail_address` varchar(250) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL COMMENT '收件详细地址',
|
||||
`defaulted` bit(1) NOT NULL COMMENT '是否默认',
|
||||
`creator` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT '' COMMENT '创建者',
|
||||
`create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
|
||||
`updater` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT '' COMMENT '更新者',
|
||||
`update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
|
||||
`deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除',
|
||||
`tenant_id` bigint NOT NULL DEFAULT 0 COMMENT '租户编号',
|
||||
PRIMARY KEY (`id`) USING BTREE,
|
||||
INDEX `idx_userId`(`user_id` ASC) USING BTREE
|
||||
) ENGINE = InnoDB AUTO_INCREMENT = 21 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_bin COMMENT = '用户收件地址';
|
||||
|
||||
-- ----------------------------
|
||||
@ -109,19 +109,19 @@ COMMIT;
|
||||
-- ----------------------------
|
||||
DROP TABLE IF EXISTS `product_brand`;
|
||||
CREATE TABLE `product_brand` (
|
||||
`id` bigint NOT NULL AUTO_INCREMENT COMMENT '品牌编号',
|
||||
`name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '品牌名称',
|
||||
`pic_url` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '品牌图片',
|
||||
`sort` int NULL DEFAULT 0 COMMENT '品牌排序',
|
||||
`description` varchar(1024) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '品牌描述',
|
||||
`status` tinyint NOT NULL COMMENT '状态',
|
||||
`creator` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT '' COMMENT '创建者',
|
||||
`create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
|
||||
`updater` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT '' COMMENT '更新者',
|
||||
`update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
|
||||
`deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除',
|
||||
`tenant_id` bigint NOT NULL DEFAULT 0 COMMENT '租户编号',
|
||||
PRIMARY KEY (`id`) USING BTREE
|
||||
`id` bigint NOT NULL AUTO_INCREMENT COMMENT '品牌编号',
|
||||
`name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '品牌名称',
|
||||
`pic_url` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '品牌图片',
|
||||
`sort` int NULL DEFAULT 0 COMMENT '品牌排序',
|
||||
`description` varchar(1024) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '品牌描述',
|
||||
`status` tinyint NOT NULL COMMENT '状态',
|
||||
`creator` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT '' COMMENT '创建者',
|
||||
`create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
|
||||
`updater` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT '' COMMENT '更新者',
|
||||
`update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
|
||||
`deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除',
|
||||
`tenant_id` bigint NOT NULL DEFAULT 0 COMMENT '租户编号',
|
||||
PRIMARY KEY (`id`) USING BTREE
|
||||
) ENGINE = InnoDB AUTO_INCREMENT = 2 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '商品品牌';
|
||||
|
||||
-- ----------------------------
|
||||
@ -136,20 +136,20 @@ COMMIT;
|
||||
-- ----------------------------
|
||||
DROP TABLE IF EXISTS `product_category`;
|
||||
CREATE TABLE `product_category` (
|
||||
`id` bigint NOT NULL AUTO_INCREMENT COMMENT '分类编号',
|
||||
`parent_id` bigint NOT NULL COMMENT '父分类编号',
|
||||
`name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '分类名称',
|
||||
`pic_url` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '分类图片',
|
||||
`sort` int NULL DEFAULT 0 COMMENT '分类排序',
|
||||
`description` varchar(1024) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '分类描述',
|
||||
`status` tinyint NOT NULL COMMENT '开启状态',
|
||||
`creator` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT '' COMMENT '创建者',
|
||||
`create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
|
||||
`updater` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT '' COMMENT '更新者',
|
||||
`update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
|
||||
`deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除',
|
||||
`tenant_id` bigint NOT NULL DEFAULT 0 COMMENT '租户编号',
|
||||
PRIMARY KEY (`id`) USING BTREE
|
||||
`id` bigint NOT NULL AUTO_INCREMENT COMMENT '分类编号',
|
||||
`parent_id` bigint NOT NULL COMMENT '父分类编号',
|
||||
`name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '分类名称',
|
||||
`pic_url` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '分类图片',
|
||||
`sort` int NULL DEFAULT 0 COMMENT '分类排序',
|
||||
`description` varchar(1024) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '分类描述',
|
||||
`status` tinyint NOT NULL COMMENT '开启状态',
|
||||
`creator` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT '' COMMENT '创建者',
|
||||
`create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
|
||||
`updater` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT '' COMMENT '更新者',
|
||||
`update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
|
||||
`deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除',
|
||||
`tenant_id` bigint NOT NULL DEFAULT 0 COMMENT '租户编号',
|
||||
PRIMARY KEY (`id`) USING BTREE
|
||||
) ENGINE = InnoDB AUTO_INCREMENT = 8 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '商品分类';
|
||||
|
||||
-- ----------------------------
|
||||
@ -164,17 +164,17 @@ COMMIT;
|
||||
-- ----------------------------
|
||||
DROP TABLE IF EXISTS `product_property`;
|
||||
CREATE TABLE `product_property` (
|
||||
`id` bigint NOT NULL AUTO_INCREMENT COMMENT '主键',
|
||||
`name` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '规格名称',
|
||||
`status` tinyint NULL DEFAULT NULL COMMENT '状态: 0 开启 ,1 禁用',
|
||||
`create_time` datetime NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
|
||||
`update_time` datetime NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
|
||||
`creator` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '创建人',
|
||||
`updater` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '更新人',
|
||||
`tenant_id` bigint NOT NULL DEFAULT 0 COMMENT '租户编号',
|
||||
`deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除',
|
||||
PRIMARY KEY (`id`) USING BTREE,
|
||||
INDEX `idx_name`(`name`(32) ASC) USING BTREE COMMENT '规格名称索引'
|
||||
`id` bigint NOT NULL AUTO_INCREMENT COMMENT '主键',
|
||||
`name` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '规格名称',
|
||||
`status` tinyint NULL DEFAULT NULL COMMENT '状态: 0 开启 ,1 禁用',
|
||||
`create_time` datetime NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
|
||||
`update_time` datetime NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
|
||||
`creator` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '创建人',
|
||||
`updater` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '更新人',
|
||||
`tenant_id` bigint NOT NULL DEFAULT 0 COMMENT '租户编号',
|
||||
`deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除',
|
||||
PRIMARY KEY (`id`) USING BTREE,
|
||||
INDEX `idx_name`(`name`(32) ASC) USING BTREE COMMENT '规格名称索引'
|
||||
) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci COMMENT = '规格名称';
|
||||
|
||||
-- ----------------------------
|
||||
@ -188,17 +188,17 @@ COMMIT;
|
||||
-- ----------------------------
|
||||
DROP TABLE IF EXISTS `product_property_value`;
|
||||
CREATE TABLE `product_property_value` (
|
||||
`id` bigint NOT NULL AUTO_INCREMENT COMMENT '主键',
|
||||
`property_id` bigint NULL DEFAULT NULL COMMENT '规格键id',
|
||||
`name` varchar(128) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '规格值名字',
|
||||
`status` tinyint NULL DEFAULT NULL COMMENT '状态: 1 开启 ,2 禁用',
|
||||
`create_time` datetime NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
|
||||
`update_time` datetime NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
|
||||
`creator` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '创建人',
|
||||
`updater` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '更新人',
|
||||
`tenant_id` bigint NOT NULL DEFAULT 0 COMMENT '租户编号',
|
||||
`deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除',
|
||||
PRIMARY KEY (`id`) USING BTREE
|
||||
`id` bigint NOT NULL AUTO_INCREMENT COMMENT '主键',
|
||||
`property_id` bigint NULL DEFAULT NULL COMMENT '规格键id',
|
||||
`name` varchar(128) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '规格值名字',
|
||||
`status` tinyint NULL DEFAULT NULL COMMENT '状态: 1 开启 ,2 禁用',
|
||||
`create_time` datetime NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
|
||||
`update_time` datetime NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
|
||||
`creator` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '创建人',
|
||||
`updater` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '更新人',
|
||||
`tenant_id` bigint NOT NULL DEFAULT 0 COMMENT '租户编号',
|
||||
`deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除',
|
||||
PRIMARY KEY (`id`) USING BTREE
|
||||
) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci COMMENT = '规格值';
|
||||
|
||||
-- ----------------------------
|
||||
@ -212,25 +212,25 @@ COMMIT;
|
||||
-- ----------------------------
|
||||
DROP TABLE IF EXISTS `product_sku`;
|
||||
CREATE TABLE `product_sku` (
|
||||
`id` bigint NOT NULL AUTO_INCREMENT COMMENT '主键',
|
||||
`spu_id` bigint NOT NULL COMMENT 'spu编号',
|
||||
`tenant_id` bigint NOT NULL DEFAULT '0' COMMENT '租户编号',
|
||||
`name` varchar(128) DEFAULT NULL COMMENT '商品 SKU 名字',
|
||||
`properties` varchar(128) DEFAULT NULL COMMENT '规格值数组-json格式, [{propertId: , valueId: }, {propertId: , valueId: }]',
|
||||
`price` int NOT NULL DEFAULT '-1' COMMENT '销售价格,单位:分',
|
||||
`market_price` int DEFAULT NULL COMMENT '市场价',
|
||||
`cost_price` int NOT NULL DEFAULT '-1' COMMENT '成本价,单位: 分',
|
||||
`pic_url` varchar(128) NOT NULL COMMENT '图片地址',
|
||||
`stock` int DEFAULT NULL COMMENT '库存',
|
||||
`warn_stock` int DEFAULT NULL COMMENT '预警库存',
|
||||
`volume` double DEFAULT NULL COMMENT '商品体积',
|
||||
`weight` double DEFAULT NULL COMMENT '商品重量',
|
||||
`bar_code` varchar(64) DEFAULT NULL COMMENT '条形码',
|
||||
`status` tinyint DEFAULT NULL COMMENT '状态: 0-正常 1-禁用',
|
||||
`create_time` datetime DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
|
||||
`update_time` datetime DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
|
||||
`creator` varchar(64) DEFAULT NULL COMMENT '创建人',
|
||||
`updater` double(64,0) DEFAULT NULL COMMENT '更新人',
|
||||
`id` bigint NOT NULL AUTO_INCREMENT COMMENT '主键',
|
||||
`spu_id` bigint NOT NULL COMMENT 'spu编号',
|
||||
`tenant_id` bigint NOT NULL DEFAULT '0' COMMENT '租户编号',
|
||||
`name` varchar(128) DEFAULT NULL COMMENT '商品 SKU 名字',
|
||||
`properties` varchar(128) DEFAULT NULL COMMENT '规格值数组-json格式, [{propertId: , valueId: }, {propertId: , valueId: }]',
|
||||
`price` int NOT NULL DEFAULT '-1' COMMENT '销售价格,单位:分',
|
||||
`market_price` int DEFAULT NULL COMMENT '市场价',
|
||||
`cost_price` int NOT NULL DEFAULT '-1' COMMENT '成本价,单位: 分',
|
||||
`pic_url` varchar(128) NOT NULL COMMENT '图片地址',
|
||||
`stock` int DEFAULT NULL COMMENT '库存',
|
||||
`warn_stock` int DEFAULT NULL COMMENT '预警库存',
|
||||
`volume` double DEFAULT NULL COMMENT '商品体积',
|
||||
`weight` double DEFAULT NULL COMMENT '商品重量',
|
||||
`bar_code` varchar(64) DEFAULT NULL COMMENT '条形码',
|
||||
`status` tinyint DEFAULT NULL COMMENT '状态: 0-正常 1-禁用',
|
||||
`create_time` datetime DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
|
||||
`update_time` datetime DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
|
||||
`creator` varchar(64) DEFAULT NULL COMMENT '创建人',
|
||||
`updater` double(64,0) DEFAULT NULL COMMENT '更新人',
|
||||
`deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除',
|
||||
PRIMARY KEY (`id`) USING BTREE
|
||||
) ENGINE=InnoDB COMMENT='商品sku';
|
||||
@ -246,33 +246,33 @@ COMMIT;
|
||||
-- ----------------------------
|
||||
DROP TABLE IF EXISTS `product_spu`;
|
||||
CREATE TABLE `product_spu` (
|
||||
`id` bigint NOT NULL AUTO_INCREMENT COMMENT '主键',
|
||||
`tenant_id` bigint NOT NULL DEFAULT '0' COMMENT '租户编号',
|
||||
`brand_id` int DEFAULT NULL COMMENT '商品品牌编号',
|
||||
`category_id` bigint NOT NULL COMMENT '分类id',
|
||||
`spec_type` int NOT NULL COMMENT '规格类型:0 单规格 1 多规格',
|
||||
`code` varchar(128) DEFAULT NULL COMMENT '商品编码',
|
||||
`name` varchar(128) NOT NULL COMMENT '商品名称',
|
||||
`sell_point` varchar(128) DEFAULT NULL COMMENT '卖点',
|
||||
`description` text COMMENT '描述',
|
||||
`pic_urls` varchar(1024) DEFAULT '' COMMENT '商品轮播图地址\n 数组,以逗号分隔\n 最多上传15张',
|
||||
`video_url` varchar(128) DEFAULT NULL COMMENT '商品视频',
|
||||
`market_price` int DEFAULT NULL COMMENT '市场价,单位使用:分',
|
||||
`min_price` int DEFAULT NULL COMMENT '最小价格,单位使用:分',
|
||||
`max_price` int DEFAULT NULL COMMENT '最大价格,单位使用:分',
|
||||
`total_stock` int NOT NULL DEFAULT '0' COMMENT '总库存',
|
||||
`show_stock` int DEFAULT '0' COMMENT '是否展示库存',
|
||||
`sales_count` int DEFAULT '0' COMMENT '商品销量',
|
||||
`virtual_sales_count` int DEFAULT '0' COMMENT '虚拟销量',
|
||||
`click_count` int DEFAULT '0' COMMENT '商品点击量',
|
||||
`status` bit(1) DEFAULT NULL COMMENT '上下架状态: 0 上架(开启) 1 下架(禁用)-1 回收',
|
||||
`sort` int NOT NULL DEFAULT '0' COMMENT '排序字段',
|
||||
`create_time` datetime DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
|
||||
`update_time` datetime DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
|
||||
`creator` varchar(64) DEFAULT NULL COMMENT '创建人',
|
||||
`updater` varchar(64) DEFAULT NULL COMMENT '更新人',
|
||||
`deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除',
|
||||
PRIMARY KEY (`id`) USING BTREE
|
||||
`id` bigint NOT NULL AUTO_INCREMENT COMMENT '主键',
|
||||
`tenant_id` bigint NOT NULL DEFAULT '0' COMMENT '租户编号',
|
||||
`brand_id` int DEFAULT NULL COMMENT '商品品牌编号',
|
||||
`category_id` bigint NOT NULL COMMENT '分类id',
|
||||
`spec_type` int NOT NULL COMMENT '规格类型:0 单规格 1 多规格',
|
||||
`code` varchar(128) DEFAULT NULL COMMENT '商品编码',
|
||||
`name` varchar(128) NOT NULL COMMENT '商品名称',
|
||||
`sell_point` varchar(128) DEFAULT NULL COMMENT '卖点',
|
||||
`description` text COMMENT '描述',
|
||||
`pic_urls` varchar(1024) DEFAULT '' COMMENT '商品轮播图地址\n 数组,以逗号分隔\n 最多上传15张',
|
||||
`video_url` varchar(128) DEFAULT NULL COMMENT '商品视频',
|
||||
`market_price` int DEFAULT NULL COMMENT '市场价,单位使用:分',
|
||||
`min_price` int DEFAULT NULL COMMENT '最小价格,单位使用:分',
|
||||
`max_price` int DEFAULT NULL COMMENT '最大价格,单位使用:分',
|
||||
`total_stock` int NOT NULL DEFAULT '0' COMMENT '总库存',
|
||||
`show_stock` int DEFAULT '0' COMMENT '是否展示库存',
|
||||
`sales_count` int DEFAULT '0' COMMENT '商品销量',
|
||||
`virtual_sales_count` int DEFAULT '0' COMMENT '虚拟销量',
|
||||
`click_count` int DEFAULT '0' COMMENT '商品点击量',
|
||||
`status` bit(1) DEFAULT NULL COMMENT '上下架状态: 0 上架(开启) 1 下架(禁用)-1 回收',
|
||||
`sort` int NOT NULL DEFAULT '0' COMMENT '排序字段',
|
||||
`create_time` datetime DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
|
||||
`update_time` datetime DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
|
||||
`creator` varchar(64) DEFAULT NULL COMMENT '创建人',
|
||||
`updater` varchar(64) DEFAULT NULL COMMENT '更新人',
|
||||
`deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除',
|
||||
PRIMARY KEY (`id`) USING BTREE
|
||||
) ENGINE=InnoDB COMMENT='商品spu';
|
||||
|
||||
-- ----------------------------
|
||||
|
@ -14,7 +14,7 @@
|
||||
<url>https://github.com/YunaiV/ruoyi-vue-pro</url>
|
||||
|
||||
<properties>
|
||||
<revision>1.6.3-snapshot</revision>
|
||||
<revision>1.6.4-snapshot</revision>
|
||||
<!-- 统一依赖管理 -->
|
||||
<spring.boot.version>2.6.10</spring.boot.version>
|
||||
<!-- Web 相关 -->
|
||||
@ -41,14 +41,14 @@
|
||||
<jedis-mock.version>0.1.16</jedis-mock.version>
|
||||
<mockito-inline.version>4.0.0</mockito-inline.version>
|
||||
<!-- Bpm 工作流相关 -->
|
||||
<flowable.version>6.7.0</flowable.version>
|
||||
<flowable.version>6.7.2</flowable.version>
|
||||
<!-- 工具类相关 -->
|
||||
<jasypt-spring-boot-starter.version>3.0.4</jasypt-spring-boot-starter.version>
|
||||
<lombok.version>1.18.20</lombok.version>
|
||||
<mapstruct.version>1.4.1.Final</mapstruct.version>
|
||||
<hutool.version>5.7.22</hutool.version>
|
||||
<hutool.version>5.8.5</hutool.version>
|
||||
<easyexcel.verion>3.1.1</easyexcel.verion>
|
||||
<velocity.version>2.2</velocity.version>
|
||||
<velocity.version>2.3</velocity.version>
|
||||
<screw.version>1.0.5</screw.version>
|
||||
<fastjson.version>1.2.83</fastjson.version>
|
||||
<guava.version>30.1.1-jre</guava.version>
|
||||
@ -57,14 +57,16 @@
|
||||
<commons-net.version>3.8.0</commons-net.version>
|
||||
<jsch.version>0.1.55</jsch.version>
|
||||
<tika-core.version>2.4.1</tika-core.version>
|
||||
<aj-captcha.version>1.3.0</aj-captcha.version>
|
||||
<!-- 三方云服务相关 -->
|
||||
<minio.version>8.2.2</minio.version>
|
||||
<aliyun-java-sdk-core.version>4.5.25</aliyun-java-sdk-core.version>
|
||||
<aliyun-java-sdk-dysmsapi.version>2.1.0</aliyun-java-sdk-dysmsapi.version>
|
||||
<tencentcloud-sdk-java.version>3.1.471</tencentcloud-sdk-java.version>
|
||||
<aliyun-java-sdk-core.version>4.6.0</aliyun-java-sdk-core.version>
|
||||
<aliyun-java-sdk-dysmsapi.version>2.2.1</aliyun-java-sdk-dysmsapi.version>
|
||||
<tencentcloud-sdk-java.version>3.1.561</tencentcloud-sdk-java.version>
|
||||
<yunpian-java-sdk.version>1.2.7</yunpian-java-sdk.version>
|
||||
<justauth.version>1.4.0</justauth.version>
|
||||
<jimureport.version>1.5.2</jimureport.version>
|
||||
<xercesImpl.version>2.12.0</xercesImpl.version>
|
||||
</properties>
|
||||
|
||||
<dependencyManagement>
|
||||
@ -129,6 +131,11 @@
|
||||
<artifactId>yudao-spring-boot-starter-biz-error-code</artifactId>
|
||||
<version>${revision}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>cn.iocoder.boot</groupId>
|
||||
<artifactId>yudao-spring-boot-starter-captcha</artifactId>
|
||||
<version>${revision}</version>
|
||||
</dependency>
|
||||
|
||||
<!-- Spring 核心 -->
|
||||
<dependency>
|
||||
@ -451,6 +458,12 @@
|
||||
<version>${tika-core.version}</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.anji-plus</groupId>
|
||||
<artifactId>spring-boot-starter-captcha</artifactId>
|
||||
<version>${aj-captcha.version}</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.apache.velocity</groupId>
|
||||
<artifactId>velocity-engine-core</artifactId>
|
||||
@ -565,6 +578,11 @@
|
||||
<artifactId>jimureport-spring-boot-starter</artifactId>
|
||||
<version>${jimureport.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>xerces</groupId>
|
||||
<artifactId>xercesImpl</artifactId>
|
||||
<version>${xercesImpl.version}</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</dependencyManagement>
|
||||
|
||||
|
@ -39,6 +39,7 @@
|
||||
<module>yudao-spring-boot-starter-biz-error-code</module>
|
||||
|
||||
<module>yudao-spring-boot-starter-flowable</module>
|
||||
<module>yudao-spring-boot-starter-captcha</module>
|
||||
</modules>
|
||||
|
||||
<artifactId>yudao-framework</artifactId>
|
||||
|
@ -1,6 +1,7 @@
|
||||
package cn.iocoder.yudao.framework.common.util.collection;
|
||||
|
||||
import cn.hutool.core.collection.CollectionUtil;
|
||||
import cn.hutool.core.collection.IterUtil;
|
||||
import cn.hutool.core.util.ArrayUtil;
|
||||
|
||||
import java.util.Collection;
|
||||
@ -44,7 +45,7 @@ public class ArrayUtils {
|
||||
if (CollectionUtil.isEmpty(from)) {
|
||||
return (T[]) (new Object[0]);
|
||||
}
|
||||
return ArrayUtil.toArray(from, (Class<T>) CollectionUtil.getElementType(from.iterator()));
|
||||
return ArrayUtil.toArray(from, (Class<T>) IterUtil.getElementType(from.iterator()));
|
||||
}
|
||||
|
||||
public static <T> T get(T[] array, int index) {
|
||||
|
@ -17,16 +17,15 @@ import java.util.regex.Pattern;
|
||||
*/
|
||||
public class ValidationUtils {
|
||||
|
||||
private static final Pattern PATTERN_MOBILE = Pattern.compile("^(?:(?:\\+|00)86)?1(?:(?:3[\\d])|(?:4[5-79])|(?:5[0-35-9])|(?:6[5-7])|(?:7[0-8])|(?:8[\\d])|(?:9[189]))\\d{8}$");
|
||||
|
||||
private static final Pattern PATTERN_URL = Pattern.compile("^(https?|ftp|file)://[-a-zA-Z0-9+&@#/%?=~_|!:,.;]*[-a-zA-Z0-9+&@#/%=~_|]");
|
||||
|
||||
private static final Pattern PATTERN_XML_NCNAME = Pattern.compile("[a-zA-Z_][\\-_.0-9_a-zA-Z$]*");
|
||||
|
||||
public static boolean isMobile(String mobile) {
|
||||
if (StrUtil.length(mobile) != 11) {
|
||||
return false;
|
||||
}
|
||||
// TODO 芋艿,后面完善手机校验
|
||||
return true;
|
||||
return StringUtils.hasText(mobile)
|
||||
&& PATTERN_MOBILE.matcher(mobile).matches();
|
||||
}
|
||||
|
||||
public static boolean isURL(String url) {
|
||||
|
@ -18,7 +18,6 @@ import net.sf.jsqlparser.expression.operators.conditional.OrExpression;
|
||||
import net.sf.jsqlparser.expression.operators.relational.ExistsExpression;
|
||||
import net.sf.jsqlparser.expression.operators.relational.ExpressionList;
|
||||
import net.sf.jsqlparser.expression.operators.relational.InExpression;
|
||||
import net.sf.jsqlparser.expression.operators.relational.ItemsList;
|
||||
import net.sf.jsqlparser.schema.Table;
|
||||
import net.sf.jsqlparser.statement.delete.Delete;
|
||||
import net.sf.jsqlparser.statement.select.*;
|
||||
@ -37,7 +36,7 @@ import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
/**
|
||||
* 数据权限拦截器,通过 {@link DataPermissionRule} 数据权限规则,重写 SQL 的方式来实现
|
||||
* 主要的 SQL 重写方法,可见 {@link #builderExpression(Expression, Table)} 方法
|
||||
* 主要的 SQL 重写方法,可见 {@link #builderExpression(Expression, List)} 方法
|
||||
*
|
||||
* 整体的代码实现上,参考 {@link com.baomidou.mybatisplus.extension.plugins.inner.TenantLineInnerInterceptor} 实现。
|
||||
* 所以每次 MyBatis Plus 升级时,需要 Review 下其具体的实现是否有变更!
|
||||
@ -53,8 +52,7 @@ public class DataPermissionDatabaseInterceptor extends JsqlParserSupport impleme
|
||||
private final MappedStatementCache mappedStatementCache = new MappedStatementCache();
|
||||
|
||||
@Override // SELECT 场景
|
||||
public void beforeQuery(Executor executor, MappedStatement ms, Object parameter,
|
||||
RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) {
|
||||
public void beforeQuery(Executor executor, MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) {
|
||||
// 获得 Mapper 对应的数据权限的规则
|
||||
List<DataPermissionRule> rules = ruleFactory.getDataPermissionRule(ms.getId());
|
||||
if (mappedStatementCache.noRewritable(ms, rules)) { // 如果无需重写,则跳过
|
||||
@ -68,12 +66,14 @@ public class DataPermissionDatabaseInterceptor extends JsqlParserSupport impleme
|
||||
// 处理 SQL
|
||||
mpBs.sql(parserSingle(mpBs.sql(), null));
|
||||
} finally {
|
||||
// 添加是否需要重写的缓存
|
||||
addMappedStatementCache(ms);
|
||||
// 清空上下文
|
||||
ContextHolder.clear();
|
||||
}
|
||||
}
|
||||
|
||||
@Override // 只处理 UPDATE / DELETE 场景,不处理 INSERT 场景
|
||||
@Override // 只处理 UPDATE / DELETE 场景,不处理 INSERT 场景(因为 INSERT 不需要数据权限)
|
||||
public void beforePrepare(StatementHandler sh, Connection connection, Integer transactionTimeout) {
|
||||
PluginUtils.MPStatementHandler mpSh = PluginUtils.mpStatementHandler(sh);
|
||||
MappedStatement ms = mpSh.mappedStatement();
|
||||
@ -92,7 +92,9 @@ public class DataPermissionDatabaseInterceptor extends JsqlParserSupport impleme
|
||||
// 处理 SQL
|
||||
mpBs.sql(parserMulti(mpBs.sql(), null));
|
||||
} finally {
|
||||
// 添加是否需要重写的缓存
|
||||
addMappedStatementCache(ms);
|
||||
// 清空上下文
|
||||
ContextHolder.clear();
|
||||
}
|
||||
}
|
||||
@ -107,24 +109,6 @@ public class DataPermissionDatabaseInterceptor extends JsqlParserSupport impleme
|
||||
}
|
||||
}
|
||||
|
||||
protected void processSelectBody(SelectBody selectBody) {
|
||||
if (selectBody == null) {
|
||||
return;
|
||||
}
|
||||
if (selectBody instanceof PlainSelect) {
|
||||
processPlainSelect((PlainSelect) selectBody);
|
||||
} else if (selectBody instanceof WithItem) {
|
||||
WithItem withItem = (WithItem) selectBody;
|
||||
processSelectBody(withItem.getSubSelect().getSelectBody());
|
||||
} else {
|
||||
SetOperationList operationList = (SetOperationList) selectBody;
|
||||
List<SelectBody> selectBodys = operationList.getSelects();
|
||||
if (CollectionUtils.isNotEmpty(selectBodys)) {
|
||||
selectBodys.forEach(this::processSelectBody);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* update 语句处理
|
||||
*/
|
||||
@ -142,28 +126,77 @@ public class DataPermissionDatabaseInterceptor extends JsqlParserSupport impleme
|
||||
delete.setWhere(this.builderExpression(delete.getWhere(), delete.getTable()));
|
||||
}
|
||||
|
||||
// ========== 和 TenantLineInnerInterceptor 一致的逻辑 ==========
|
||||
|
||||
protected void processSelectBody(SelectBody selectBody) {
|
||||
if (selectBody == null) {
|
||||
return;
|
||||
}
|
||||
if (selectBody instanceof PlainSelect) {
|
||||
processPlainSelect((PlainSelect) selectBody);
|
||||
} else if (selectBody instanceof WithItem) {
|
||||
WithItem withItem = (WithItem) selectBody;
|
||||
processSelectBody(withItem.getSubSelect().getSelectBody());
|
||||
} else {
|
||||
SetOperationList operationList = (SetOperationList) selectBody;
|
||||
List<SelectBody> selectBodyList = operationList.getSelects();
|
||||
if (CollectionUtils.isNotEmpty(selectBodyList)) {
|
||||
selectBodyList.forEach(this::processSelectBody);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 处理 PlainSelect
|
||||
*/
|
||||
protected void processPlainSelect(PlainSelect plainSelect) {
|
||||
FromItem fromItem = plainSelect.getFromItem();
|
||||
Expression where = plainSelect.getWhere();
|
||||
processWhereSubSelect(where);
|
||||
if (fromItem instanceof Table) {
|
||||
Table fromTable = (Table) fromItem;
|
||||
plainSelect.setWhere(builderExpression(where, fromTable));
|
||||
} else {
|
||||
processFromItem(fromItem);
|
||||
}
|
||||
//#3087 github
|
||||
List<SelectItem> selectItems = plainSelect.getSelectItems();
|
||||
if (CollectionUtils.isNotEmpty(selectItems)) {
|
||||
selectItems.forEach(this::processSelectItem);
|
||||
}
|
||||
|
||||
// 处理 where 中的子查询
|
||||
Expression where = plainSelect.getWhere();
|
||||
processWhereSubSelect(where);
|
||||
|
||||
// 处理 fromItem
|
||||
FromItem fromItem = plainSelect.getFromItem();
|
||||
List<Table> list = processFromItem(fromItem);
|
||||
List<Table> mainTables = new ArrayList<>(list);
|
||||
|
||||
// 处理 join
|
||||
List<Join> joins = plainSelect.getJoins();
|
||||
if (CollectionUtils.isNotEmpty(joins)) {
|
||||
processJoins(joins);
|
||||
mainTables = processJoins(mainTables, joins);
|
||||
}
|
||||
|
||||
// 当有 mainTable 时,进行 where 条件追加
|
||||
if (CollectionUtils.isNotEmpty(mainTables)) {
|
||||
plainSelect.setWhere(builderExpression(where, mainTables));
|
||||
}
|
||||
}
|
||||
|
||||
private List<Table> processFromItem(FromItem fromItem) {
|
||||
// 处理括号括起来的表达式
|
||||
while (fromItem instanceof ParenthesisFromItem) {
|
||||
fromItem = ((ParenthesisFromItem) fromItem).getFromItem();
|
||||
}
|
||||
|
||||
List<Table> mainTables = new ArrayList<>();
|
||||
// 无 join 时的处理逻辑
|
||||
if (fromItem instanceof Table) {
|
||||
Table fromTable = (Table) fromItem;
|
||||
mainTables.add(fromTable);
|
||||
} else if (fromItem instanceof SubJoin) {
|
||||
// SubJoin 类型则还需要添加上 where 条件
|
||||
List<Table> tables = processSubJoin((SubJoin) fromItem);
|
||||
mainTables.addAll(tables);
|
||||
} else {
|
||||
// 处理下 fromItem
|
||||
processOtherFromItem(fromItem);
|
||||
}
|
||||
return mainTables;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -191,7 +224,7 @@ public class DataPermissionDatabaseInterceptor extends JsqlParserSupport impleme
|
||||
return;
|
||||
}
|
||||
if (where instanceof FromItem) {
|
||||
processFromItem((FromItem) where);
|
||||
processOtherFromItem((FromItem) where);
|
||||
return;
|
||||
}
|
||||
if (where.toString().indexOf("SELECT") > 0) {
|
||||
@ -204,9 +237,9 @@ public class DataPermissionDatabaseInterceptor extends JsqlParserSupport impleme
|
||||
} else if (where instanceof InExpression) {
|
||||
// in
|
||||
InExpression expression = (InExpression) where;
|
||||
ItemsList itemsList = expression.getRightItemsList();
|
||||
if (itemsList instanceof SubSelect) {
|
||||
processSelectBody(((SubSelect) itemsList).getSelectBody());
|
||||
Expression inExpression = expression.getRightExpression();
|
||||
if (inExpression instanceof SubSelect) {
|
||||
processSelectBody(((SubSelect) inExpression).getSelectBody());
|
||||
}
|
||||
} else if (where instanceof ExistsExpression) {
|
||||
// exists
|
||||
@ -239,7 +272,7 @@ public class DataPermissionDatabaseInterceptor extends JsqlParserSupport impleme
|
||||
* <p>支持: 1. select fun(args..) 2. select fun1(fun2(args..),args..)<p>
|
||||
* <p> fixed gitee pulls/141</p>
|
||||
*
|
||||
* @param function 函数
|
||||
* @param function
|
||||
*/
|
||||
protected void processFunction(Function function) {
|
||||
ExpressionList parameters = function.getParameters();
|
||||
@ -257,22 +290,19 @@ public class DataPermissionDatabaseInterceptor extends JsqlParserSupport impleme
|
||||
/**
|
||||
* 处理子查询等
|
||||
*/
|
||||
protected void processFromItem(FromItem fromItem) {
|
||||
if (fromItem instanceof SubJoin) {
|
||||
SubJoin subJoin = (SubJoin) fromItem;
|
||||
if (subJoin.getJoinList() != null) {
|
||||
processJoins(subJoin.getJoinList());
|
||||
}
|
||||
if (subJoin.getLeft() != null) {
|
||||
processFromItem(subJoin.getLeft());
|
||||
}
|
||||
} else if (fromItem instanceof SubSelect) {
|
||||
protected void processOtherFromItem(FromItem fromItem) {
|
||||
// 去除括号
|
||||
while (fromItem instanceof ParenthesisFromItem) {
|
||||
fromItem = ((ParenthesisFromItem) fromItem).getFromItem();
|
||||
}
|
||||
|
||||
if (fromItem instanceof SubSelect) {
|
||||
SubSelect subSelect = (SubSelect) fromItem;
|
||||
if (subSelect.getSelectBody() != null) {
|
||||
processSelectBody(subSelect.getSelectBody());
|
||||
}
|
||||
} else if (fromItem instanceof ValuesList) {
|
||||
logger.debug("Perform a subquery, if you do not give us feedback");
|
||||
logger.debug("Perform a subQuery, if you do not give us feedback");
|
||||
} else if (fromItem instanceof LateralSubSelect) {
|
||||
LateralSubSelect lateralSubSelect = (LateralSubSelect) fromItem;
|
||||
if (lateralSubSelect.getSubSelect() != null) {
|
||||
@ -284,75 +314,176 @@ public class DataPermissionDatabaseInterceptor extends JsqlParserSupport impleme
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 处理 sub join
|
||||
*
|
||||
* @param subJoin subJoin
|
||||
* @return Table subJoin 中的主表
|
||||
*/
|
||||
private List<Table> processSubJoin(SubJoin subJoin) {
|
||||
List<Table> mainTables = new ArrayList<>();
|
||||
if (subJoin.getJoinList() != null) {
|
||||
List<Table> list = processFromItem(subJoin.getLeft());
|
||||
mainTables.addAll(list);
|
||||
mainTables = processJoins(mainTables, subJoin.getJoinList());
|
||||
}
|
||||
return mainTables;
|
||||
}
|
||||
|
||||
/**
|
||||
* 处理 joins
|
||||
*
|
||||
* @param joins join 集合
|
||||
* @param mainTables 可以为 null
|
||||
* @param joins join 集合
|
||||
* @return List<Table> 右连接查询的 Table 列表
|
||||
*/
|
||||
private void processJoins(List<Join> joins) {
|
||||
private List<Table> processJoins(List<Table> mainTables, List<Join> joins) {
|
||||
// join 表达式中最终的主表
|
||||
Table mainTable = null;
|
||||
// 当前 join 的左表
|
||||
Table leftTable = null;
|
||||
|
||||
if (mainTables == null) {
|
||||
mainTables = new ArrayList<>();
|
||||
} else if (mainTables.size() == 1) {
|
||||
mainTable = mainTables.get(0);
|
||||
leftTable = mainTable;
|
||||
}
|
||||
|
||||
//对于 on 表达式写在最后的 join,需要记录下前面多个 on 的表名
|
||||
Deque<Table> tables = new LinkedList<>();
|
||||
Deque<List<Table>> onTableDeque = new LinkedList<>();
|
||||
for (Join join : joins) {
|
||||
// 处理 on 表达式
|
||||
FromItem fromItem = join.getRightItem();
|
||||
if (fromItem instanceof Table) {
|
||||
Table fromTable = (Table) fromItem;
|
||||
FromItem joinItem = join.getRightItem();
|
||||
|
||||
// 获取当前 join 的表,subJoint 可以看作是一张表
|
||||
List<Table> joinTables = null;
|
||||
if (joinItem instanceof Table) {
|
||||
joinTables = new ArrayList<>();
|
||||
joinTables.add((Table) joinItem);
|
||||
} else if (joinItem instanceof SubJoin) {
|
||||
joinTables = processSubJoin((SubJoin) joinItem);
|
||||
}
|
||||
|
||||
if (joinTables != null) {
|
||||
|
||||
// 如果是隐式内连接
|
||||
if (join.isSimple()) {
|
||||
mainTables.addAll(joinTables);
|
||||
continue;
|
||||
}
|
||||
|
||||
// 当前表是否忽略
|
||||
Table joinTable = joinTables.get(0);
|
||||
|
||||
List<Table> onTables = null;
|
||||
// 如果不要忽略,且是右连接,则记录下当前表
|
||||
if (join.isRight()) {
|
||||
mainTable = joinTable;
|
||||
if (leftTable != null) {
|
||||
onTables = Collections.singletonList(leftTable);
|
||||
}
|
||||
} else if (join.isLeft()) {
|
||||
onTables = Collections.singletonList(joinTable);
|
||||
} else if (join.isInner()) {
|
||||
if (mainTable == null) {
|
||||
onTables = Collections.singletonList(joinTable);
|
||||
} else {
|
||||
onTables = Arrays.asList(mainTable, joinTable);
|
||||
}
|
||||
mainTable = null;
|
||||
}
|
||||
|
||||
mainTables = new ArrayList<>();
|
||||
if (mainTable != null) {
|
||||
mainTables.add(mainTable);
|
||||
}
|
||||
|
||||
// 获取 join 尾缀的 on 表达式列表
|
||||
Collection<Expression> originOnExpressions = join.getOnExpressions();
|
||||
// 正常 join on 表达式只有一个,立刻处理
|
||||
if (originOnExpressions.size() == 1) {
|
||||
processJoin(join);
|
||||
if (originOnExpressions.size() == 1 && onTables != null) {
|
||||
List<Expression> onExpressions = new LinkedList<>();
|
||||
onExpressions.add(builderExpression(originOnExpressions.iterator().next(), onTables));
|
||||
join.setOnExpressions(onExpressions);
|
||||
leftTable = joinTable;
|
||||
continue;
|
||||
}
|
||||
tables.push(fromTable);
|
||||
// 表名压栈,忽略的表压入 null,以便后续不处理
|
||||
onTableDeque.push(onTables);
|
||||
// 尾缀多个 on 表达式的时候统一处理
|
||||
if (originOnExpressions.size() > 1) {
|
||||
Collection<Expression> onExpressions = new LinkedList<>();
|
||||
for (Expression originOnExpression : originOnExpressions) {
|
||||
Table currentTable = tables.poll();
|
||||
onExpressions.add(builderExpression(originOnExpression, currentTable));
|
||||
List<Table> currentTableList = onTableDeque.poll();
|
||||
if (CollectionUtils.isEmpty(currentTableList)) {
|
||||
onExpressions.add(originOnExpression);
|
||||
} else {
|
||||
onExpressions.add(builderExpression(originOnExpression, currentTableList));
|
||||
}
|
||||
}
|
||||
join.setOnExpressions(onExpressions);
|
||||
}
|
||||
leftTable = joinTable;
|
||||
} else {
|
||||
// 处理右边连接的子表达式
|
||||
processFromItem(fromItem);
|
||||
processOtherFromItem(joinItem);
|
||||
leftTable = null;
|
||||
}
|
||||
}
|
||||
|
||||
return mainTables;
|
||||
}
|
||||
|
||||
// ========== 和 TenantLineInnerInterceptor 存在差异的逻辑:关键,实现权限条件的拼接 ==========
|
||||
|
||||
/**
|
||||
* 处理联接语句
|
||||
* 处理条件
|
||||
*
|
||||
* @param currentExpression 当前 where 条件
|
||||
* @param table 单个表
|
||||
*/
|
||||
protected void processJoin(Join join) {
|
||||
if (join.getRightItem() instanceof Table) {
|
||||
Table fromTable = (Table) join.getRightItem();
|
||||
Expression originOnExpression = CollUtil.getFirst(join.getOnExpressions());
|
||||
originOnExpression = builderExpression(originOnExpression, fromTable);
|
||||
join.setOnExpressions(CollUtil.newArrayList(originOnExpression));
|
||||
}
|
||||
protected Expression builderExpression(Expression currentExpression, Table table) {
|
||||
return this.builderExpression(currentExpression, Collections.singletonList(table));
|
||||
}
|
||||
|
||||
/**
|
||||
* 处理条件
|
||||
*
|
||||
* @param currentExpression 当前 where 条件
|
||||
* @param tables 多个表
|
||||
*/
|
||||
protected Expression builderExpression(Expression currentExpression, Table table) {
|
||||
// 获得 Table 对应的数据权限条件
|
||||
Expression equalsTo = buildDataPermissionExpression(table);
|
||||
if (equalsTo == null) { // 如果没条件,则返回 currentExpression 默认
|
||||
protected Expression builderExpression(Expression currentExpression, List<Table> tables) {
|
||||
// 没有表需要处理直接返回
|
||||
if (CollectionUtils.isEmpty(tables)) {
|
||||
return currentExpression;
|
||||
}
|
||||
|
||||
// 表达式为空,则直接返回 equalsTo
|
||||
// 第一步,获得 Table 对应的数据权限条件
|
||||
Expression dataPermissionExpression = null;
|
||||
for (Table table : tables) {
|
||||
// 构建每个表的权限 Expression 条件
|
||||
Expression expression = buildDataPermissionExpression(table);
|
||||
if (expression == null) {
|
||||
continue;
|
||||
}
|
||||
// 合并到 dataPermissionExpression 中
|
||||
dataPermissionExpression = dataPermissionExpression == null ? expression
|
||||
: new AndExpression(dataPermissionExpression, expression);
|
||||
}
|
||||
|
||||
// 第二步,合并多个 Expression 条件
|
||||
if (dataPermissionExpression == null) {
|
||||
return currentExpression;
|
||||
}
|
||||
if (currentExpression == null) {
|
||||
return equalsTo;
|
||||
return dataPermissionExpression;
|
||||
}
|
||||
// 如果表达式为 Or,则需要 (currentExpression) AND equalsTo
|
||||
// ① 如果表达式为 Or,则需要 (currentExpression) AND dataPermissionExpression
|
||||
if (currentExpression instanceof OrExpression) {
|
||||
return new AndExpression(new Parenthesis(currentExpression), equalsTo);
|
||||
return new AndExpression(new Parenthesis(currentExpression), dataPermissionExpression);
|
||||
}
|
||||
// 如果表达式为 And,则直接返回 currentExpression AND equalsTo
|
||||
return new AndExpression(currentExpression, equalsTo);
|
||||
// ② 如果表达式为 And,则直接返回 where AND dataPermissionExpression
|
||||
return new AndExpression(currentExpression, dataPermissionExpression);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -46,7 +46,7 @@ public class DataPermissionDatabaseInterceptorTest2 extends BaseMockitoUnitTest
|
||||
|
||||
@Override
|
||||
public Set<String> getTableNames() {
|
||||
return asSet("entity", "entity1", "entity2", "t1", "t2", // 支持 MyBatis Plus 的单元测试
|
||||
return asSet("entity", "entity1", "entity2", "entity3", "t1", "t2", "sys_dict_item", // 支持 MyBatis Plus 的单元测试
|
||||
"t_user", "t_role"); // 满足自己的单元测试
|
||||
}
|
||||
|
||||
@ -84,30 +84,30 @@ public class DataPermissionDatabaseInterceptorTest2 extends BaseMockitoUnitTest
|
||||
@Test
|
||||
void delete() {
|
||||
assertSql("delete from entity where id = ?",
|
||||
"DELETE FROM entity WHERE id = ? AND tenant_id = 1");
|
||||
"DELETE FROM entity WHERE id = ? AND entity.tenant_id = 1");
|
||||
}
|
||||
|
||||
@Test
|
||||
void update() {
|
||||
assertSql("update entity set name = ? where id = ?",
|
||||
"UPDATE entity SET name = ? WHERE id = ? AND tenant_id = 1");
|
||||
"UPDATE entity SET name = ? WHERE id = ? AND entity.tenant_id = 1");
|
||||
}
|
||||
|
||||
@Test
|
||||
void selectSingle() {
|
||||
// 单表
|
||||
assertSql("select * from entity where id = ?",
|
||||
"SELECT * FROM entity WHERE id = ? AND tenant_id = 1");
|
||||
"SELECT * FROM entity WHERE id = ? AND entity.tenant_id = 1");
|
||||
|
||||
assertSql("select * from entity where id = ? or name = ?",
|
||||
"SELECT * FROM entity WHERE (id = ? OR name = ?) AND tenant_id = 1");
|
||||
"SELECT * FROM entity WHERE (id = ? OR name = ?) AND entity.tenant_id = 1");
|
||||
|
||||
assertSql("SELECT * FROM entity WHERE (id = ? OR name = ?)",
|
||||
"SELECT * FROM entity WHERE (id = ? OR name = ?) AND tenant_id = 1");
|
||||
"SELECT * FROM entity WHERE (id = ? OR name = ?) AND entity.tenant_id = 1");
|
||||
|
||||
/* not */
|
||||
assertSql("SELECT * FROM entity WHERE not (id = ? OR name = ?)",
|
||||
"SELECT * FROM entity WHERE NOT (id = ? OR name = ?) AND tenant_id = 1");
|
||||
"SELECT * FROM entity WHERE NOT (id = ? OR name = ?) AND entity.tenant_id = 1");
|
||||
}
|
||||
|
||||
@Test
|
||||
@ -167,10 +167,12 @@ public class DataPermissionDatabaseInterceptorTest2 extends BaseMockitoUnitTest
|
||||
assertSql("SELECT * FROM entity e WHERE e.id >= (select e1.id from entity1 e1 where e1.id = ?)",
|
||||
"SELECT * FROM entity e WHERE e.id >= (SELECT e1.id FROM entity1 e1 WHERE e1.id = ? AND e1.tenant_id = 1) AND e.tenant_id = 1");
|
||||
|
||||
|
||||
/* <= */
|
||||
assertSql("SELECT * FROM entity e WHERE e.id <= (select e1.id from entity1 e1 where e1.id = ?)",
|
||||
"SELECT * FROM entity e WHERE e.id <= (SELECT e1.id FROM entity1 e1 WHERE e1.id = ? AND e1.tenant_id = 1) AND e.tenant_id = 1");
|
||||
|
||||
|
||||
/* <> */
|
||||
assertSql("SELECT * FROM entity e WHERE e.id <> (select e1.id from entity1 e1 where e1.id = ?)",
|
||||
"SELECT * FROM entity e WHERE e.id <> (SELECT e1.id FROM entity1 e1 WHERE e1.id = ? AND e1.tenant_id = 1) AND e.tenant_id = 1");
|
||||
@ -204,6 +206,14 @@ public class DataPermissionDatabaseInterceptorTest2 extends BaseMockitoUnitTest
|
||||
"SELECT * FROM entity e " +
|
||||
"LEFT JOIN entity1 e1 ON e1.id = e.id AND e1.tenant_id = 1 " +
|
||||
"WHERE (e.id = ? OR e.name = ?) AND e.tenant_id = 1");
|
||||
|
||||
assertSql("SELECT * FROM entity e " +
|
||||
"left join entity1 e1 on e1.id = e.id " +
|
||||
"left join entity2 e2 on e1.id = e2.id",
|
||||
"SELECT * FROM entity e " +
|
||||
"LEFT JOIN entity1 e1 ON e1.id = e.id AND e1.tenant_id = 1 " +
|
||||
"LEFT JOIN entity2 e2 ON e1.id = e2.id AND e2.tenant_id = 1 " +
|
||||
"WHERE e.tenant_id = 1");
|
||||
}
|
||||
|
||||
@Test
|
||||
@ -212,17 +222,125 @@ public class DataPermissionDatabaseInterceptorTest2 extends BaseMockitoUnitTest
|
||||
assertSql("SELECT * FROM entity e " +
|
||||
"right join entity1 e1 on e1.id = e.id",
|
||||
"SELECT * FROM entity e " +
|
||||
"RIGHT JOIN entity1 e1 ON e1.id = e.id AND e1.tenant_id = 1 " +
|
||||
"WHERE e.tenant_id = 1");
|
||||
"RIGHT JOIN entity1 e1 ON e1.id = e.id AND e.tenant_id = 1 " +
|
||||
"WHERE e1.tenant_id = 1");
|
||||
|
||||
assertSql("SELECT * FROM with_as_1 e " +
|
||||
"right join entity1 e1 on e1.id = e.id",
|
||||
"SELECT * FROM with_as_1 e " +
|
||||
"RIGHT JOIN entity1 e1 ON e1.id = e.id " +
|
||||
"WHERE e1.tenant_id = 1");
|
||||
|
||||
assertSql("SELECT * FROM entity e " +
|
||||
"right join entity1 e1 on e1.id = e.id " +
|
||||
"WHERE e.id = ? OR e.name = ?",
|
||||
"SELECT * FROM entity e " +
|
||||
"RIGHT JOIN entity1 e1 ON e1.id = e.id AND e1.tenant_id = 1 " +
|
||||
"WHERE (e.id = ? OR e.name = ?) AND e.tenant_id = 1");
|
||||
"RIGHT JOIN entity1 e1 ON e1.id = e.id AND e.tenant_id = 1 " +
|
||||
"WHERE (e.id = ? OR e.name = ?) AND e1.tenant_id = 1");
|
||||
|
||||
assertSql("SELECT * FROM entity e " +
|
||||
"right join entity1 e1 on e1.id = e.id " +
|
||||
"right join entity2 e2 on e1.id = e2.id ",
|
||||
"SELECT * FROM entity e " +
|
||||
"RIGHT JOIN entity1 e1 ON e1.id = e.id AND e.tenant_id = 1 " +
|
||||
"RIGHT JOIN entity2 e2 ON e1.id = e2.id AND e1.tenant_id = 1 " +
|
||||
"WHERE e2.tenant_id = 1");
|
||||
}
|
||||
|
||||
@Test
|
||||
void selectMixJoin() {
|
||||
assertSql("SELECT * FROM entity e " +
|
||||
"right join entity1 e1 on e1.id = e.id " +
|
||||
"left join entity2 e2 on e1.id = e2.id",
|
||||
"SELECT * FROM entity e " +
|
||||
"RIGHT JOIN entity1 e1 ON e1.id = e.id AND e.tenant_id = 1 " +
|
||||
"LEFT JOIN entity2 e2 ON e1.id = e2.id AND e2.tenant_id = 1 " +
|
||||
"WHERE e1.tenant_id = 1");
|
||||
|
||||
assertSql("SELECT * FROM entity e " +
|
||||
"left join entity1 e1 on e1.id = e.id " +
|
||||
"right join entity2 e2 on e1.id = e2.id",
|
||||
"SELECT * FROM entity e " +
|
||||
"LEFT JOIN entity1 e1 ON e1.id = e.id AND e1.tenant_id = 1 " +
|
||||
"RIGHT JOIN entity2 e2 ON e1.id = e2.id AND e1.tenant_id = 1 " +
|
||||
"WHERE e2.tenant_id = 1");
|
||||
|
||||
assertSql("SELECT * FROM entity e " +
|
||||
"left join entity1 e1 on e1.id = e.id " +
|
||||
"inner join entity2 e2 on e1.id = e2.id",
|
||||
"SELECT * FROM entity e " +
|
||||
"LEFT JOIN entity1 e1 ON e1.id = e.id AND e1.tenant_id = 1 " +
|
||||
"INNER JOIN entity2 e2 ON e1.id = e2.id AND e.tenant_id = 1 AND e2.tenant_id = 1");
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
void selectJoinSubSelect() {
|
||||
assertSql("select * from (select * from entity) e1 " +
|
||||
"left join entity2 e2 on e1.id = e2.id",
|
||||
"SELECT * FROM (SELECT * FROM entity WHERE entity.tenant_id = 1) e1 " +
|
||||
"LEFT JOIN entity2 e2 ON e1.id = e2.id AND e2.tenant_id = 1");
|
||||
|
||||
assertSql("select * from entity1 e1 " +
|
||||
"left join (select * from entity2) e2 " +
|
||||
"on e1.id = e2.id",
|
||||
"SELECT * FROM entity1 e1 " +
|
||||
"LEFT JOIN (SELECT * FROM entity2 WHERE entity2.tenant_id = 1) e2 " +
|
||||
"ON e1.id = e2.id " +
|
||||
"WHERE e1.tenant_id = 1");
|
||||
}
|
||||
|
||||
@Test
|
||||
void selectSubJoin() {
|
||||
|
||||
assertSql("select * FROM " +
|
||||
"(entity1 e1 right JOIN entity2 e2 ON e1.id = e2.id)",
|
||||
"SELECT * FROM " +
|
||||
"(entity1 e1 RIGHT JOIN entity2 e2 ON e1.id = e2.id AND e1.tenant_id = 1) " +
|
||||
"WHERE e2.tenant_id = 1");
|
||||
|
||||
assertSql("select * FROM " +
|
||||
"(entity1 e1 LEFT JOIN entity2 e2 ON e1.id = e2.id)",
|
||||
"SELECT * FROM " +
|
||||
"(entity1 e1 LEFT JOIN entity2 e2 ON e1.id = e2.id AND e2.tenant_id = 1) " +
|
||||
"WHERE e1.tenant_id = 1");
|
||||
|
||||
|
||||
assertSql("select * FROM " +
|
||||
"(entity1 e1 LEFT JOIN entity2 e2 ON e1.id = e2.id) " +
|
||||
"right join entity3 e3 on e1.id = e3.id",
|
||||
"SELECT * FROM " +
|
||||
"(entity1 e1 LEFT JOIN entity2 e2 ON e1.id = e2.id AND e2.tenant_id = 1) " +
|
||||
"RIGHT JOIN entity3 e3 ON e1.id = e3.id AND e1.tenant_id = 1 " +
|
||||
"WHERE e3.tenant_id = 1");
|
||||
|
||||
|
||||
assertSql("select * FROM entity e " +
|
||||
"LEFT JOIN (entity1 e1 right join entity2 e2 ON e1.id = e2.id) " +
|
||||
"on e.id = e2.id",
|
||||
"SELECT * FROM entity e " +
|
||||
"LEFT JOIN (entity1 e1 RIGHT JOIN entity2 e2 ON e1.id = e2.id AND e1.tenant_id = 1) " +
|
||||
"ON e.id = e2.id AND e2.tenant_id = 1 " +
|
||||
"WHERE e.tenant_id = 1");
|
||||
|
||||
assertSql("select * FROM entity e " +
|
||||
"LEFT JOIN (entity1 e1 left join entity2 e2 ON e1.id = e2.id) " +
|
||||
"on e.id = e2.id",
|
||||
"SELECT * FROM entity e " +
|
||||
"LEFT JOIN (entity1 e1 LEFT JOIN entity2 e2 ON e1.id = e2.id AND e2.tenant_id = 1) " +
|
||||
"ON e.id = e2.id AND e1.tenant_id = 1 " +
|
||||
"WHERE e.tenant_id = 1");
|
||||
|
||||
assertSql("select * FROM entity e " +
|
||||
"RIGHT JOIN (entity1 e1 left join entity2 e2 ON e1.id = e2.id) " +
|
||||
"on e.id = e2.id",
|
||||
"SELECT * FROM entity e " +
|
||||
"RIGHT JOIN (entity1 e1 LEFT JOIN entity2 e2 ON e1.id = e2.id AND e2.tenant_id = 1) " +
|
||||
"ON e.id = e2.id AND e.tenant_id = 1 " +
|
||||
"WHERE e1.tenant_id = 1");
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
void selectLeftJoinMultipleTrailingOn() {
|
||||
// 多个 on 尾缀的
|
||||
@ -256,51 +374,97 @@ public class DataPermissionDatabaseInterceptorTest2 extends BaseMockitoUnitTest
|
||||
"inner join entity1 e1 on e1.id = e.id " +
|
||||
"WHERE e.id = ? OR e.name = ?",
|
||||
"SELECT * FROM entity e " +
|
||||
"INNER JOIN entity1 e1 ON e1.id = e.id AND e1.tenant_id = 1 " +
|
||||
"WHERE (e.id = ? OR e.name = ?) AND e.tenant_id = 1");
|
||||
"INNER JOIN entity1 e1 ON e1.id = e.id AND e.tenant_id = 1 AND e1.tenant_id = 1 " +
|
||||
"WHERE e.id = ? OR e.name = ?");
|
||||
|
||||
assertSql("SELECT * FROM entity e " +
|
||||
"inner join entity1 e1 on e1.id = e.id " +
|
||||
"WHERE (e.id = ? OR e.name = ?)",
|
||||
"SELECT * FROM entity e " +
|
||||
"INNER JOIN entity1 e1 ON e1.id = e.id AND e1.tenant_id = 1 " +
|
||||
"WHERE (e.id = ? OR e.name = ?) AND e.tenant_id = 1");
|
||||
"INNER JOIN entity1 e1 ON e1.id = e.id AND e.tenant_id = 1 AND e1.tenant_id = 1 " +
|
||||
"WHERE (e.id = ? OR e.name = ?)");
|
||||
|
||||
// 隐式内连接
|
||||
assertSql("SELECT * FROM entity,entity1 " +
|
||||
"WHERE entity.id = entity1.id",
|
||||
"SELECT * FROM entity, entity1 " +
|
||||
"WHERE entity.id = entity1.id AND entity.tenant_id = 1 AND entity1.tenant_id = 1");
|
||||
|
||||
// 隐式内连接
|
||||
assertSql("SELECT * FROM entity a, with_as_entity1 b " +
|
||||
"WHERE a.id = b.id",
|
||||
"SELECT * FROM entity a, with_as_entity1 b " +
|
||||
"WHERE a.id = b.id AND a.tenant_id = 1");
|
||||
|
||||
assertSql("SELECT * FROM with_as_entity a, with_as_entity1 b " +
|
||||
"WHERE a.id = b.id",
|
||||
"SELECT * FROM with_as_entity a, with_as_entity1 b " +
|
||||
"WHERE a.id = b.id");
|
||||
|
||||
// SubJoin with 隐式内连接
|
||||
assertSql("SELECT * FROM (entity,entity1) " +
|
||||
"WHERE entity.id = entity1.id",
|
||||
"SELECT * FROM (entity, entity1) " +
|
||||
"WHERE entity.id = entity1.id " +
|
||||
"AND entity.tenant_id = 1 AND entity1.tenant_id = 1");
|
||||
|
||||
assertSql("SELECT * FROM ((entity,entity1),entity2) " +
|
||||
"WHERE entity.id = entity1.id and entity.id = entity2.id",
|
||||
"SELECT * FROM ((entity, entity1), entity2) " +
|
||||
"WHERE entity.id = entity1.id AND entity.id = entity2.id " +
|
||||
"AND entity.tenant_id = 1 AND entity1.tenant_id = 1 AND entity2.tenant_id = 1");
|
||||
|
||||
assertSql("SELECT * FROM (entity,(entity1,entity2)) " +
|
||||
"WHERE entity.id = entity1.id and entity.id = entity2.id",
|
||||
"SELECT * FROM (entity, (entity1, entity2)) " +
|
||||
"WHERE entity.id = entity1.id AND entity.id = entity2.id " +
|
||||
"AND entity.tenant_id = 1 AND entity1.tenant_id = 1 AND entity2.tenant_id = 1");
|
||||
|
||||
// 沙雕的括号写法
|
||||
assertSql("SELECT * FROM (((entity,entity1))) " +
|
||||
"WHERE entity.id = entity1.id",
|
||||
"SELECT * FROM (((entity, entity1))) " +
|
||||
"WHERE entity.id = entity1.id " +
|
||||
"AND entity.tenant_id = 1 AND entity1.tenant_id = 1");
|
||||
|
||||
// 垃圾 inner join todo
|
||||
// assertSql("SELECT * FROM entity,entity1 " +
|
||||
// "WHERE entity.id = entity1.id",
|
||||
// "SELECT * FROM entity e " +
|
||||
// "INNER JOIN entity1 e1 ON e1.id = e.id AND e1.tenant_id = 1 " +
|
||||
// "WHERE (e.id = ? OR e.name = ?) AND e.tenant_id = 1");
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
void selectWithAs() {
|
||||
assertSql("with with_as_A as (select * from entity) select * from with_as_A",
|
||||
"WITH with_as_A AS (SELECT * FROM entity WHERE tenant_id = 1) SELECT * FROM with_as_A");
|
||||
"WITH with_as_A AS (SELECT * FROM entity WHERE entity.tenant_id = 1) SELECT * FROM with_as_A");
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
void selectIgnoreTable() {
|
||||
assertSql(" SELECT dict.dict_code, item.item_text AS \"text\", item.item_value AS \"value\" FROM sys_dict_item item INNER JOIN sys_dict dict ON dict.id = item.dict_id WHERE dict.dict_code IN (1, 2, 3) AND item.item_value IN (1, 2, 3)",
|
||||
"SELECT dict.dict_code, item.item_text AS \"text\", item.item_value AS \"value\" FROM sys_dict_item item INNER JOIN sys_dict dict ON dict.id = item.dict_id AND item.tenant_id = 1 WHERE dict.dict_code IN (1, 2, 3) AND item.item_value IN (1, 2, 3)");
|
||||
}
|
||||
|
||||
private void assertSql(String sql, String targetSql) {
|
||||
assertEquals(targetSql, interceptor.parserSingle(sql, null));
|
||||
}
|
||||
|
||||
|
||||
// ========== 额外的测试 ==========
|
||||
|
||||
@Test
|
||||
public void testSelectSingle() {
|
||||
// 单表
|
||||
assertSql("select * from t_user where id = ?",
|
||||
"SELECT * FROM t_user WHERE id = ? AND tenant_id = 1 AND dept_id IN (10, 20)");
|
||||
"SELECT * FROM t_user WHERE id = ? AND t_user.tenant_id = 1 AND t_user.dept_id IN (10, 20)");
|
||||
|
||||
assertSql("select * from t_user where id = ? or name = ?",
|
||||
"SELECT * FROM t_user WHERE (id = ? OR name = ?) AND tenant_id = 1 AND dept_id IN (10, 20)");
|
||||
"SELECT * FROM t_user WHERE (id = ? OR name = ?) AND t_user.tenant_id = 1 AND t_user.dept_id IN (10, 20)");
|
||||
|
||||
assertSql("SELECT * FROM t_user WHERE (id = ? OR name = ?)",
|
||||
"SELECT * FROM t_user WHERE (id = ? OR name = ?) AND tenant_id = 1 AND dept_id IN (10, 20)");
|
||||
"SELECT * FROM t_user WHERE (id = ? OR name = ?) AND t_user.tenant_id = 1 AND t_user.dept_id IN (10, 20)");
|
||||
|
||||
/* not */
|
||||
assertSql("SELECT * FROM t_user WHERE not (id = ? OR name = ?)",
|
||||
"SELECT * FROM t_user WHERE NOT (id = ? OR name = ?) AND tenant_id = 1 AND dept_id IN (10, 20)");
|
||||
"SELECT * FROM t_user WHERE NOT (id = ? OR name = ?) AND t_user.tenant_id = 1 AND t_user.dept_id IN (10, 20)");
|
||||
}
|
||||
|
||||
@Test
|
||||
@ -329,16 +493,16 @@ public class DataPermissionDatabaseInterceptorTest2 extends BaseMockitoUnitTest
|
||||
"right join t_role e1 on e1.id = e.id " +
|
||||
"WHERE e.id = ? OR e.name = ?",
|
||||
"SELECT * FROM t_user e " +
|
||||
"RIGHT JOIN t_role e1 ON e1.id = e.id AND e1.tenant_id = 1 " +
|
||||
"WHERE (e.id = ? OR e.name = ?) AND e.tenant_id = 1 AND e.dept_id IN (10, 20)");
|
||||
"RIGHT JOIN t_role e1 ON e1.id = e.id AND e.tenant_id = 1 AND e.dept_id IN (10, 20) " +
|
||||
"WHERE (e.id = ? OR e.name = ?) AND e1.tenant_id = 1");
|
||||
|
||||
// 条件 e.id = ? OR e.name = ? 带括号
|
||||
assertSql("SELECT * FROM t_user e " +
|
||||
"right join t_role e1 on e1.id = e.id " +
|
||||
"WHERE (e.id = ? OR e.name = ?)",
|
||||
"SELECT * FROM t_user e " +
|
||||
"RIGHT JOIN t_role e1 ON e1.id = e.id AND e1.tenant_id = 1 " +
|
||||
"WHERE (e.id = ? OR e.name = ?) AND e.tenant_id = 1 AND e.dept_id IN (10, 20)");
|
||||
"RIGHT JOIN t_role e1 ON e1.id = e.id AND e.tenant_id = 1 AND e.dept_id IN (10, 20) " +
|
||||
"WHERE (e.id = ? OR e.name = ?) AND e1.tenant_id = 1");
|
||||
}
|
||||
|
||||
@Test
|
||||
@ -348,23 +512,22 @@ public class DataPermissionDatabaseInterceptorTest2 extends BaseMockitoUnitTest
|
||||
"inner join entity1 e1 on e1.id = e.id " +
|
||||
"WHERE e.id = ? OR e.name = ?",
|
||||
"SELECT * FROM t_user e " +
|
||||
"INNER JOIN entity1 e1 ON e1.id = e.id AND e1.tenant_id = 1 " +
|
||||
"WHERE (e.id = ? OR e.name = ?) AND e.tenant_id = 1 AND e.dept_id IN (10, 20)");
|
||||
"INNER JOIN entity1 e1 ON e1.id = e.id AND e.tenant_id = 1 AND e.dept_id IN (10, 20) AND e1.tenant_id = 1 " +
|
||||
"WHERE e.id = ? OR e.name = ?");
|
||||
|
||||
// 条件 e.id = ? OR e.name = ? 带括号
|
||||
assertSql("SELECT * FROM t_user e " +
|
||||
"inner join t_role e1 on e1.id = e.id " +
|
||||
"inner join entity1 e1 on e1.id = e.id " +
|
||||
"WHERE (e.id = ? OR e.name = ?)",
|
||||
"SELECT * FROM t_user e " +
|
||||
"INNER JOIN t_role e1 ON e1.id = e.id AND e1.tenant_id = 1 " +
|
||||
"WHERE (e.id = ? OR e.name = ?) AND e.tenant_id = 1 AND e.dept_id IN (10, 20)");
|
||||
"INNER JOIN entity1 e1 ON e1.id = e.id AND e.tenant_id = 1 AND e.dept_id IN (10, 20) AND e1.tenant_id = 1 " +
|
||||
"WHERE (e.id = ? OR e.name = ?)");
|
||||
|
||||
// 垃圾 inner join todo
|
||||
// assertSql("SELECT * FROM entity,entity1 " +
|
||||
// "WHERE entity.id = entity1.id",
|
||||
// "SELECT * FROM entity e " +
|
||||
// "INNER JOIN entity1 e1 ON e1.id = e.id AND e1.tenant_id = 1 " +
|
||||
// "WHERE (e.id = ? OR e.name = ?) AND e.tenant_id = 1");
|
||||
// 没有 On 的 inner join
|
||||
assertSql("SELECT * FROM entity,entity1 " +
|
||||
"WHERE entity.id = entity1.id",
|
||||
"SELECT * FROM entity, entity1 " +
|
||||
"WHERE entity.id = entity1.id AND entity.tenant_id = 1 AND entity1.tenant_id = 1");
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -27,7 +27,7 @@ public class DictFrameworkUtils {
|
||||
/**
|
||||
* 针对 {@link #getDictDataLabel(String, String)} 的缓存
|
||||
*/
|
||||
private static final LoadingCache<KeyValue<String, String>, DictDataRespDTO> getDictDataCache = CacheUtils.buildAsyncReloadingCache(
|
||||
private static final LoadingCache<KeyValue<String, String>, DictDataRespDTO> GET_DICT_DATA_CACHE = CacheUtils.buildAsyncReloadingCache(
|
||||
Duration.ofMinutes(1L), // 过期时间 1 分钟
|
||||
new CacheLoader<KeyValue<String, String>, DictDataRespDTO>() {
|
||||
|
||||
@ -41,7 +41,7 @@ public class DictFrameworkUtils {
|
||||
/**
|
||||
* 针对 {@link #parseDictDataValue(String, String)} 的缓存
|
||||
*/
|
||||
private static final LoadingCache<KeyValue<String, String>, DictDataRespDTO> parseDictDataCache = CacheUtils.buildAsyncReloadingCache(
|
||||
private static final LoadingCache<KeyValue<String, String>, DictDataRespDTO> PARSE_DICT_DATA_CACHE = CacheUtils.buildAsyncReloadingCache(
|
||||
Duration.ofMinutes(1L), // 过期时间 1 分钟
|
||||
new CacheLoader<KeyValue<String, String>, DictDataRespDTO>() {
|
||||
|
||||
@ -59,12 +59,12 @@ public class DictFrameworkUtils {
|
||||
|
||||
@SneakyThrows
|
||||
public static String getDictDataLabel(String dictType, String value) {
|
||||
return getDictDataCache.get(new KeyValue<>(dictType, value)).getLabel();
|
||||
return GET_DICT_DATA_CACHE.get(new KeyValue<>(dictType, value)).getLabel();
|
||||
}
|
||||
|
||||
@SneakyThrows
|
||||
public static String parseDictDataValue(String dictType, String label) {
|
||||
return parseDictDataCache.get(new KeyValue<>(dictType, label)).getValue();
|
||||
return PARSE_DICT_DATA_CACHE.get(new KeyValue<>(dictType, label)).getValue();
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -52,12 +52,18 @@
|
||||
<dependency>
|
||||
<groupId>com.alipay.sdk</groupId>
|
||||
<artifactId>alipay-sdk-java</artifactId>
|
||||
<version>4.17.9.ALL</version>
|
||||
<version>4.31.72.ALL</version>
|
||||
<exclusions>
|
||||
<exclusion>
|
||||
<groupId>org.bouncycastle</groupId>
|
||||
<artifactId>bcprov-jdk15on</artifactId>
|
||||
</exclusion>
|
||||
</exclusions>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.github.binarywang</groupId>
|
||||
<artifactId>weixin-java-pay</artifactId>
|
||||
<version>4.1.9.B</version>
|
||||
<version>4.3.8.B</version>
|
||||
</dependency>
|
||||
<!-- TODO 芋艿:清理 -->
|
||||
|
||||
|
@ -1,6 +1,5 @@
|
||||
package cn.iocoder.yudao.framework.pay.core.client.impl;
|
||||
|
||||
import cn.hutool.extra.validation.ValidationUtil;
|
||||
import cn.iocoder.yudao.framework.pay.core.client.AbstractPayCodeMapping;
|
||||
import cn.iocoder.yudao.framework.pay.core.client.PayClient;
|
||||
import cn.iocoder.yudao.framework.pay.core.client.PayClientConfig;
|
||||
@ -10,6 +9,8 @@ import cn.iocoder.yudao.framework.pay.core.client.dto.PayRefundUnifiedReqDTO;
|
||||
import cn.iocoder.yudao.framework.pay.core.client.dto.PayRefundUnifiedRespDTO;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
import javax.validation.Validation;
|
||||
|
||||
import static cn.iocoder.yudao.framework.common.util.json.JsonUtils.toJsonString;
|
||||
|
||||
/**
|
||||
@ -79,7 +80,7 @@ public abstract class AbstractPayClient<Config extends PayClientConfig> implemen
|
||||
|
||||
@Override
|
||||
public final PayCommonResult<?> unifiedOrder(PayOrderUnifiedReqDTO reqDTO) {
|
||||
ValidationUtil.validate(reqDTO);
|
||||
Validation.buildDefaultValidatorFactory().getValidator().validate(reqDTO);
|
||||
// 执行短信发送
|
||||
PayCommonResult<?> result;
|
||||
try {
|
||||
|
@ -53,9 +53,8 @@ public class AlipayQrPayClientTest extends BaseMockitoUnitTest {
|
||||
"lrsYhKkVK2OxwM3kFqjoBBY0CZoZCsSQ3LDH5WeZqPArlsS6xa2zqJBuuoKjMrdpELl3eXSjP8K54eDJCbeetCZNKWLL3DPahTPB7LZ" +
|
||||
"ikfYmslb0QUvCgGapD0xkS7eVq70NaL1G57MWABs4tbfWgxike4Daj3EfUrzIVspQxj7w8HEj9WozJPgL88kSJSits0pqD3n5r8HSuseQIDAQAB");
|
||||
|
||||
// TODO @tina:= 前后要有空格哈
|
||||
@InjectMocks
|
||||
AlipayQrPayClient client=new AlipayQrPayClient(10L,config);
|
||||
AlipayQrPayClient client = new AlipayQrPayClient(10L,config);
|
||||
|
||||
@Mock
|
||||
private DefaultAlipayClient defaultAlipayClient;
|
||||
|
@ -35,12 +35,12 @@
|
||||
<dependency>
|
||||
<groupId>com.github.binarywang</groupId>
|
||||
<artifactId>wx-java-mp-spring-boot-starter</artifactId>
|
||||
<version>4.3.4.B</version>
|
||||
<version>4.3.8.B</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.github.binarywang</groupId>
|
||||
<artifactId>wx-java-miniapp-spring-boot-starter</artifactId>
|
||||
<version>4.3.4.B</version>
|
||||
<version>4.3.8.B</version>
|
||||
</dependency>
|
||||
<!-- TODO 芋艿:清理 -->
|
||||
</dependencies>
|
||||
|
39
yudao-framework/yudao-spring-boot-starter-captcha/pom.xml
Normal file
@ -0,0 +1,39 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<parent>
|
||||
<groupId>cn.iocoder.boot</groupId>
|
||||
<artifactId>yudao-framework</artifactId>
|
||||
<version>${revision}</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<artifactId>yudao-spring-boot-starter-captcha</artifactId>
|
||||
<packaging>jar</packaging>
|
||||
|
||||
<name>${project.artifactId}</name>
|
||||
<description>验证码拓展
|
||||
1. 基于 aj-captcha 实现滑块验证码,文档:https://ajcaptcha.beliefteam.cn/captcha-doc/
|
||||
</description>
|
||||
|
||||
<dependencies>
|
||||
<!-- Spring 核心 -->
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- DB 相关 -->
|
||||
<dependency>
|
||||
<groupId>cn.iocoder.boot</groupId>
|
||||
<artifactId>yudao-spring-boot-starter-redis</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- 验证码相关 -->
|
||||
<dependency>
|
||||
<groupId>com.anji-plus</groupId>
|
||||
<artifactId>spring-boot-starter-captcha</artifactId>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
</project>
|
@ -0,0 +1,25 @@
|
||||
package cn.iocoder.yudao.framework.captcha.config;
|
||||
|
||||
import cn.hutool.core.util.ClassUtil;
|
||||
import cn.iocoder.yudao.framework.captcha.core.enums.CaptchaRedisKeyConstants;
|
||||
import cn.iocoder.yudao.framework.captcha.core.service.RedisCaptchaServiceImpl;
|
||||
import com.anji.captcha.service.CaptchaCacheService;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.data.redis.core.StringRedisTemplate;
|
||||
|
||||
@Configuration
|
||||
public class YudaoCaptchaConfiguration {
|
||||
|
||||
static {
|
||||
// 手动加载 Lock4jRedisKeyConstants 类,因为它不会被使用到
|
||||
// 如果不加载,会导致 Redis 监控,看到它的 Redis Key 枚举
|
||||
ClassUtil.loadClass(CaptchaRedisKeyConstants.class.getName());
|
||||
}
|
||||
|
||||
@Bean
|
||||
public CaptchaCacheService captchaCacheService(StringRedisTemplate stringRedisTemplate) {
|
||||
return new RedisCaptchaServiceImpl(stringRedisTemplate);
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,28 @@
|
||||
package cn.iocoder.yudao.framework.captcha.core.enums;
|
||||
|
||||
import cn.iocoder.yudao.framework.redis.core.RedisKeyDefine;
|
||||
import com.anji.captcha.model.vo.PointVO;
|
||||
import org.redisson.api.RLock;
|
||||
|
||||
import java.time.Duration;
|
||||
import java.util.Map;
|
||||
|
||||
import static cn.iocoder.yudao.framework.redis.core.RedisKeyDefine.KeyTypeEnum.HASH;
|
||||
import static cn.iocoder.yudao.framework.redis.core.RedisKeyDefine.KeyTypeEnum.STRING;
|
||||
|
||||
/**
|
||||
* 验证码 Redis Key 枚举类
|
||||
*
|
||||
* @author 芋道源码
|
||||
*/
|
||||
public interface CaptchaRedisKeyConstants {
|
||||
|
||||
RedisKeyDefine AJ_CAPTCHA_REQ_LIMIT = new RedisKeyDefine("验证码的请求限流",
|
||||
"AJ.CAPTCHA.REQ.LIMIT-%s-%s",
|
||||
STRING, Integer.class, Duration.ofSeconds(60)); // 例如说:验证失败 5 次,get 接口锁定
|
||||
|
||||
RedisKeyDefine AJ_CAPTCHA_RUNNING = new RedisKeyDefine("验证码的坐标",
|
||||
"RUNNING:CAPTCHA:%s", // AbstractCaptchaService.REDIS_CAPTCHA_KEY
|
||||
STRING, PointVO.class, Duration.ofSeconds(120)); // {"secretKey":"PP1w2Frr2KEejD2m","x":162,"y":5}
|
||||
|
||||
}
|
@ -0,0 +1,54 @@
|
||||
package cn.iocoder.yudao.framework.captcha.core.service;
|
||||
|
||||
import com.anji.captcha.service.CaptchaCacheService;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.NoArgsConstructor;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.data.redis.core.StringRedisTemplate;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
/**
|
||||
* 基于 Redis 实现验证码的存储
|
||||
*
|
||||
* @author 星语
|
||||
*/
|
||||
@NoArgsConstructor // 保证 aj-captcha 的 SPI 创建
|
||||
@AllArgsConstructor
|
||||
public class RedisCaptchaServiceImpl implements CaptchaCacheService {
|
||||
|
||||
@Resource // 保证 aj-captcha 的 SPI 创建时的注入
|
||||
private StringRedisTemplate stringRedisTemplate;
|
||||
|
||||
@Override
|
||||
public String type() {
|
||||
return "redis";
|
||||
}
|
||||
|
||||
@Override
|
||||
public void set(String key, String value, long expiresInSeconds) {
|
||||
stringRedisTemplate.opsForValue().set(key, value, expiresInSeconds, TimeUnit.SECONDS);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean exists(String key) {
|
||||
return Boolean.TRUE.equals(stringRedisTemplate.hasKey(key));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void delete(String key) {
|
||||
stringRedisTemplate.delete(key);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String get(String key) {
|
||||
return stringRedisTemplate.opsForValue().get(key);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Long increment(String key, long val) {
|
||||
return stringRedisTemplate.opsForValue().increment(key,val);
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,7 @@
|
||||
/**
|
||||
* 验证码拓展
|
||||
* 1. 基于 aj-captcha 实现滑块验证码,文档:https://ajcaptcha.beliefteam.cn/captcha-doc/
|
||||
*
|
||||
* @author 星语
|
||||
*/
|
||||
package cn.iocoder.yudao.framework.captcha;
|
@ -0,0 +1 @@
|
||||
cn.iocoder.yudao.framework.captcha.core.service.RedisCaptchaServiceImpl
|
@ -0,0 +1,2 @@
|
||||
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
|
||||
cn.iocoder.yudao.framework.captcha.config.YudaoCaptchaConfiguration
|
After Width: | Height: | Size: 17 KiB |
After Width: | Height: | Size: 28 KiB |
After Width: | Height: | Size: 25 KiB |
After Width: | Height: | Size: 27 KiB |
After Width: | Height: | Size: 24 KiB |
After Width: | Height: | Size: 19 KiB |
After Width: | Height: | Size: 21 KiB |
After Width: | Height: | Size: 30 KiB |
After Width: | Height: | Size: 26 KiB |
After Width: | Height: | Size: 2.1 KiB |
After Width: | Height: | Size: 1.6 KiB |
After Width: | Height: | Size: 1.6 KiB |
After Width: | Height: | Size: 1.6 KiB |
After Width: | Height: | Size: 1.8 KiB |
After Width: | Height: | Size: 1.8 KiB |
After Width: | Height: | Size: 1.8 KiB |
After Width: | Height: | Size: 1.8 KiB |
After Width: | Height: | Size: 1.8 KiB |
After Width: | Height: | Size: 1.8 KiB |
After Width: | Height: | Size: 1.8 KiB |
After Width: | Height: | Size: 1.6 KiB |
After Width: | Height: | Size: 1.6 KiB |
After Width: | Height: | Size: 2.2 KiB |
After Width: | Height: | Size: 2.2 KiB |
After Width: | Height: | Size: 2.2 KiB |
After Width: | Height: | Size: 24 KiB |
After Width: | Height: | Size: 27 KiB |
After Width: | Height: | Size: 28 KiB |
After Width: | Height: | Size: 23 KiB |
After Width: | Height: | Size: 25 KiB |
After Width: | Height: | Size: 16 KiB |
After Width: | Height: | Size: 23 KiB |
After Width: | Height: | Size: 26 KiB |
After Width: | Height: | Size: 27 KiB |
After Width: | Height: | Size: 29 KiB |
@ -16,11 +16,11 @@ import java.util.Set;
|
||||
*/
|
||||
public class JsonLongSetTypeHandler extends AbstractJsonTypeHandler<Object> {
|
||||
|
||||
private static final TypeReference<Set<Long>> typeReference = new TypeReference<Set<Long>>(){};
|
||||
private static final TypeReference<Set<Long>> TYPE_REFERENCE = new TypeReference<Set<Long>>(){};
|
||||
|
||||
@Override
|
||||
protected Object parse(String json) {
|
||||
return JsonUtils.parseObject(json, typeReference);
|
||||
return JsonUtils.parseObject(json, TYPE_REFERENCE);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -4,6 +4,7 @@ import cn.hutool.core.collection.CollectionUtil;
|
||||
import cn.iocoder.yudao.framework.common.pojo.PageParam;
|
||||
import cn.iocoder.yudao.framework.common.pojo.SortingField;
|
||||
import com.baomidou.mybatisplus.core.metadata.OrderItem;
|
||||
import com.baomidou.mybatisplus.core.toolkit.StringPool;
|
||||
import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor;
|
||||
import com.baomidou.mybatisplus.extension.plugins.inner.InnerInterceptor;
|
||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||
@ -78,7 +79,10 @@ public class MyBatisUtils {
|
||||
* @return Column 对象
|
||||
*/
|
||||
public static Column buildColumn(String tableName, Alias tableAlias, String column) {
|
||||
return new Column(tableAlias != null ? tableAlias.getName() + "." + column : column);
|
||||
if (tableAlias != null) {
|
||||
tableName = tableAlias.getName();
|
||||
}
|
||||
return new Column(tableName + StringPool.DOT + column);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -11,18 +11,18 @@ public class RedisKeyRegistry {
|
||||
/**
|
||||
* Redis RedisKeyDefine 数组
|
||||
*/
|
||||
private static final List<RedisKeyDefine> defines = new ArrayList<>();
|
||||
private static final List<RedisKeyDefine> DEFINES = new ArrayList<>();
|
||||
|
||||
public static void add(RedisKeyDefine define) {
|
||||
defines.add(define);
|
||||
DEFINES.add(define);
|
||||
}
|
||||
|
||||
public static List<RedisKeyDefine> list() {
|
||||
return defines;
|
||||
return DEFINES;
|
||||
}
|
||||
|
||||
public static int size() {
|
||||
return defines.size();
|
||||
return DEFINES.size();
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -81,7 +81,7 @@ public class YudaoWebSecurityConfigurerAdapter extends WebSecurityConfigurerAdap
|
||||
|
||||
/**
|
||||
* 配置 URL 的安全配置
|
||||
*
|
||||
* <p>
|
||||
* anyRequest | 匹配所有请求路径
|
||||
* access | SpringEl表达式结果为true时可以访问
|
||||
* anonymous | 匿名可以访问
|
||||
@ -109,8 +109,8 @@ public class YudaoWebSecurityConfigurerAdapter extends WebSecurityConfigurerAdap
|
||||
.headers().frameOptions().disable().and()
|
||||
// 一堆自定义的 Spring Security 处理器
|
||||
.exceptionHandling().authenticationEntryPoint(authenticationEntryPoint)
|
||||
.accessDeniedHandler(accessDeniedHandler);
|
||||
// 登录、登录暂时不使用 Spring Security 的拓展点,主要考虑一方面拓展多用户、多种登录方式相对复杂,一方面用户的学习成本较高
|
||||
.accessDeniedHandler(accessDeniedHandler);
|
||||
// 登录、登录暂时不使用 Spring Security 的拓展点,主要考虑一方面拓展多用户、多种登录方式相对复杂,一方面用户的学习成本较高
|
||||
|
||||
// 获得 @PermitAll 带来的 URL 列表,免登录
|
||||
Multimap<HttpMethod, String> permitAllUrls = getPermitAllUrlsFromAnnotations();
|
||||
@ -118,23 +118,25 @@ public class YudaoWebSecurityConfigurerAdapter extends WebSecurityConfigurerAdap
|
||||
httpSecurity
|
||||
// ①:全局共享规则
|
||||
.authorizeRequests()
|
||||
// 1.1 静态资源,可匿名访问
|
||||
.antMatchers(HttpMethod.GET, "/*.html", "/**/*.html", "/**/*.css", "/**/*.js").permitAll()
|
||||
// 1.2 设置 @PermitAll 无需认证
|
||||
.antMatchers(HttpMethod.GET, permitAllUrls.get(HttpMethod.GET).toArray(new String[0])).permitAll()
|
||||
.antMatchers(HttpMethod.POST, permitAllUrls.get(HttpMethod.POST).toArray(new String[0])).permitAll()
|
||||
.antMatchers(HttpMethod.PUT, permitAllUrls.get(HttpMethod.PUT).toArray(new String[0])).permitAll()
|
||||
.antMatchers(HttpMethod.DELETE, permitAllUrls.get(HttpMethod.DELETE).toArray(new String[0])).permitAll()
|
||||
// 1.3 基于 yudao.security.permit-all-urls 无需认证
|
||||
.antMatchers(securityProperties.getPermitAllUrls().toArray(new String[0])).permitAll()
|
||||
// 1.4 设置 App API 无需认证
|
||||
.antMatchers(buildAppApi("/**")).permitAll()
|
||||
// 1.1 静态资源,可匿名访问
|
||||
.antMatchers(HttpMethod.GET, "/*.html", "/**/*.html", "/**/*.css", "/**/*.js").permitAll()
|
||||
// 1.2 设置 @PermitAll 无需认证
|
||||
.antMatchers(HttpMethod.GET, permitAllUrls.get(HttpMethod.GET).toArray(new String[0])).permitAll()
|
||||
.antMatchers(HttpMethod.POST, permitAllUrls.get(HttpMethod.POST).toArray(new String[0])).permitAll()
|
||||
.antMatchers(HttpMethod.PUT, permitAllUrls.get(HttpMethod.PUT).toArray(new String[0])).permitAll()
|
||||
.antMatchers(HttpMethod.DELETE, permitAllUrls.get(HttpMethod.DELETE).toArray(new String[0])).permitAll()
|
||||
// 1.3 基于 yudao.security.permit-all-urls 无需认证
|
||||
.antMatchers(securityProperties.getPermitAllUrls().toArray(new String[0])).permitAll()
|
||||
// 1.4 设置 App API 无需认证
|
||||
.antMatchers(buildAppApi("/**")).permitAll()
|
||||
// 1.5 验证码captcha 允许匿名访问
|
||||
.antMatchers("/captcha/get", "/captcha/check").permitAll()
|
||||
// ②:每个项目的自定义规则
|
||||
.and().authorizeRequests(registry -> // 下面,循环设置自定义规则
|
||||
authorizeRequestsCustomizers.forEach(customizer -> customizer.customize(registry)))
|
||||
// ③:兜底规则,必须认证
|
||||
.authorizeRequests()
|
||||
.anyRequest().authenticated()
|
||||
.anyRequest().authenticated()
|
||||
;
|
||||
|
||||
// 添加 Token Filter
|
||||
|
@ -17,19 +17,19 @@ public class TransmittableThreadLocalSecurityContextHolderStrategy implements Se
|
||||
/**
|
||||
* 使用 TransmittableThreadLocal 作为上下文
|
||||
*/
|
||||
private static final ThreadLocal<SecurityContext> contextHolder = new TransmittableThreadLocal<>();
|
||||
private static final ThreadLocal<SecurityContext> CONTEXT_HOLDER = new TransmittableThreadLocal<>();
|
||||
|
||||
@Override
|
||||
public void clearContext() {
|
||||
contextHolder.remove();
|
||||
CONTEXT_HOLDER.remove();
|
||||
}
|
||||
|
||||
@Override
|
||||
public SecurityContext getContext() {
|
||||
SecurityContext ctx = contextHolder.get();
|
||||
SecurityContext ctx = CONTEXT_HOLDER.get();
|
||||
if (ctx == null) {
|
||||
ctx = createEmptyContext();
|
||||
contextHolder.set(ctx);
|
||||
CONTEXT_HOLDER.set(ctx);
|
||||
}
|
||||
return ctx;
|
||||
}
|
||||
@ -37,7 +37,7 @@ public class TransmittableThreadLocalSecurityContextHolderStrategy implements Se
|
||||
@Override
|
||||
public void setContext(SecurityContext context) {
|
||||
Assert.notNull(context, "Only non-null SecurityContext instances are permitted");
|
||||
contextHolder.set(context);
|
||||
CONTEXT_HOLDER.set(context);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -57,7 +57,7 @@ public class BpmMessageServiceImpl implements BpmMessageService {
|
||||
templateParams.put("taskName", reqDTO.getTaskName());
|
||||
templateParams.put("startUserNickname", reqDTO.getStartUserNickname());
|
||||
templateParams.put("detailUrl", getProcessInstanceDetailUrl(reqDTO.getProcessInstanceId()));
|
||||
smsSendApi.sendSingleSmsToAdmin(BpmMessageConvert.INSTANCE.convert(reqDTO.getStartUserId(),
|
||||
smsSendApi.sendSingleSmsToAdmin(BpmMessageConvert.INSTANCE.convert(reqDTO.getAssigneeUserId(),
|
||||
BpmMessageEnum.TASK_ASSIGNED.getSmsTemplateCode(), templateParams));
|
||||
}
|
||||
|
||||
|
@ -154,12 +154,12 @@ public class CodegenServiceImpl implements CodegenService {
|
||||
// 构建 CodegenColumnDO 数组,只同步新增的字段
|
||||
List<CodegenColumnDO> codegenColumns = codegenColumnMapper.selectListByTableId(tableId);
|
||||
Set<String> codegenColumnNames = CollectionUtils.convertSet(codegenColumns, CodegenColumnDO::getColumnName);
|
||||
// 移除已经存在的字段
|
||||
tableFields.removeIf(column -> codegenColumnNames.contains(column.getColumnName()));
|
||||
// 计算需要删除的字段
|
||||
Set<String> tableFieldNames = CollectionUtils.convertSet(tableFields, TableField::getName);
|
||||
Set<Long> deleteColumnIds = codegenColumns.stream().filter(column -> !tableFieldNames.contains(column.getColumnName()))
|
||||
.map(CodegenColumnDO::getId).collect(Collectors.toSet());
|
||||
// 移除已经存在的字段
|
||||
tableFields.removeIf(column -> codegenColumnNames.contains(column.getColumnName()));
|
||||
if (CollUtil.isEmpty(tableFields) && CollUtil.isEmpty(deleteColumnIds)) {
|
||||
throw exception(CODEGEN_SYNC_NONE_CHANGE);
|
||||
}
|
||||
|
@ -31,7 +31,7 @@ public class CodegenBuilder {
|
||||
* 字段名与 {@link CodegenColumnListConditionEnum} 的默认映射
|
||||
* 注意,字段的匹配以后缀的方式
|
||||
*/
|
||||
private static final Map<String, CodegenColumnListConditionEnum> columnListOperationConditionMappings =
|
||||
private static final Map<String, CodegenColumnListConditionEnum> COLUMN_LIST_OPERATION_CONDITION_MAPPINGS =
|
||||
MapUtil.<String, CodegenColumnListConditionEnum>builder()
|
||||
.put("name", CodegenColumnListConditionEnum.LIKE)
|
||||
.put("time", CodegenColumnListConditionEnum.BETWEEN)
|
||||
@ -42,7 +42,7 @@ public class CodegenBuilder {
|
||||
* 字段名与 {@link CodegenColumnHtmlTypeEnum} 的默认映射
|
||||
* 注意,字段的匹配以后缀的方式
|
||||
*/
|
||||
private static final Map<String, CodegenColumnHtmlTypeEnum> columnHtmlTypeMappings =
|
||||
private static final Map<String, CodegenColumnHtmlTypeEnum> COLUMN_HTML_TYPE_MAPPINGS =
|
||||
MapUtil.<String, CodegenColumnHtmlTypeEnum>builder()
|
||||
.put("status", CodegenColumnHtmlTypeEnum.RADIO)
|
||||
.put("sex", CodegenColumnHtmlTypeEnum.RADIO)
|
||||
@ -143,7 +143,7 @@ public class CodegenBuilder {
|
||||
column.setListOperation(!LIST_OPERATION_EXCLUDE_COLUMN.contains(column.getJavaField())
|
||||
&& !column.getPrimaryKey()); // 对于主键,列表过滤不需要传递
|
||||
// 处理 listOperationCondition 字段
|
||||
columnListOperationConditionMappings.entrySet().stream()
|
||||
COLUMN_LIST_OPERATION_CONDITION_MAPPINGS.entrySet().stream()
|
||||
.filter(entry -> StrUtil.endWithIgnoreCase(column.getJavaField(), entry.getKey()))
|
||||
.findFirst().ifPresent(entry -> column.setListOperationCondition(entry.getValue().getCondition()));
|
||||
if (column.getListOperationCondition() == null) {
|
||||
@ -155,7 +155,7 @@ public class CodegenBuilder {
|
||||
|
||||
private void processColumnUI(CodegenColumnDO column) {
|
||||
// 基于后缀进行匹配
|
||||
columnHtmlTypeMappings.entrySet().stream()
|
||||
COLUMN_HTML_TYPE_MAPPINGS.entrySet().stream()
|
||||
.filter(entry -> StrUtil.endWithIgnoreCase(column.getJavaField(), entry.getKey()))
|
||||
.findFirst().ifPresent(entry -> column.setHtmlType(entry.getValue().getType()));
|
||||
// 如果是 Boolean 类型时,设置为 radio 类型.
|
||||
|
@ -96,7 +96,7 @@
|
||||
@pagination="getList"/>
|
||||
|
||||
<!-- 对话框(添加 / 修改) -->
|
||||
<el-dialog :title="title" :visible.sync="open" width="500px" append-to-body>
|
||||
<el-dialog :title="title" :visible.sync="open" width="500px" v-dialogDrag append-to-body>
|
||||
<el-form ref="form" :model="form" :rules="rules" label-width="80px">
|
||||
#foreach($column in $columns)
|
||||
#if ($column.createOperation || $column.updateOperation)
|
||||
|
@ -5,31 +5,31 @@ const request = useAxios()
|
||||
|
||||
#set ($baseURL = "/${table.moduleName}/${simpleClassName_strikeCase}")
|
||||
// 查询${table.classComment}列表
|
||||
export const getPostPageApi = async (params: ${simpleClassName}PageReqVO) => {
|
||||
export const get${simpleClassName}PageApi = async (params: ${simpleClassName}PageReqVO) => {
|
||||
return await request.get({ url: '${baseURL}/page', params })
|
||||
}
|
||||
|
||||
// 查询${table.classComment}详情
|
||||
export const getPostApi = async (id: number) => {
|
||||
export const get${simpleClassName}Api = async (id: number) => {
|
||||
return await request.get({ url: '${baseURL}/get?id=' + id })
|
||||
}
|
||||
|
||||
// 新增${table.classComment}
|
||||
export const createPostApi = async (data: ${simpleClassName}VO) => {
|
||||
export const create${simpleClassName}Api = async (data: ${simpleClassName}VO) => {
|
||||
return await request.post({ url: '${baseURL}/create', data })
|
||||
}
|
||||
|
||||
// 修改${table.classComment}
|
||||
export const updatePostApi = async (data: ${simpleClassName}VO) => {
|
||||
export const update${simpleClassName}Api = async (data: ${simpleClassName}VO) => {
|
||||
return await request.put({ url: '${baseURL}/update', data })
|
||||
}
|
||||
|
||||
// 删除${table.classComment}
|
||||
export const deletePostApi = async (id: number) => {
|
||||
export const delete${simpleClassName}Api = async (id: number) => {
|
||||
return await request.delete({ url: '${baseURL}/delete?id=' + id })
|
||||
}
|
||||
|
||||
// 导出${table.classComment} Excel
|
||||
export const exportPostApi = async (params: ${simpleClassName}ExcelReqVO) => {
|
||||
export const export${simpleClassName}Api = async (params: ${simpleClassName}ExcelReqVO) => {
|
||||
return await request.download({ url: '${baseURL}/export-excel', params })
|
||||
}
|
||||
|
@ -6,9 +6,9 @@
|
||||
import { useTable } from '@/hooks/web/useTable'
|
||||
import { useI18n } from '@/hooks/web/useI18n'
|
||||
import { FormExpose } from '@/components/Form'
|
||||
import type { ${simpleClassName}VO } from '@/api/system/post/types'
|
||||
import { rules, allSchemas } from './post.data'
|
||||
import * as ${simpleClassName}Api from '@/api/system/post'
|
||||
import type { ${simpleClassName}VO } from '@/api/${table.moduleName}/${simpleClassName}/types'
|
||||
import { rules, allSchemas } from './${simpleClassName}.data'
|
||||
import * as ${simpleClassName}Api from '@/api/${table.moduleName}/${simpleClassName}'
|
||||
const { t } = useI18n() // 国际化
|
||||
|
||||
// ========== 列表相关 ==========
|
||||
|
@ -15,17 +15,18 @@
|
||||
<name>${project.artifactId}</name>
|
||||
|
||||
<description>
|
||||
商城大模块,由 product 商品、market 营销、trade 交易等组成
|
||||
商城大模块,由 product 商品、market 营销、trade 交易 coupon等组成
|
||||
</description>
|
||||
<modules>
|
||||
<module>yudao-module-coupon-api</module>
|
||||
<module>yudao-module-coupon-biz</module>
|
||||
<module>yudao-module-market-api</module>
|
||||
<module>yudao-module-market-biz</module>
|
||||
<module>yudao-module-product-api</module>
|
||||
<module>yudao-module-product-biz</module>
|
||||
<module>yudao-module-trade-api</module>
|
||||
<module>yudao-module-trade-biz</module>
|
||||
<module>yudao-module-coupon-api</module>
|
||||
<module>yudao-module-coupon-biz</module>
|
||||
|
||||
</modules>
|
||||
|
||||
</project>
|
||||
|
@ -23,6 +23,13 @@
|
||||
<groupId>cn.iocoder.boot</groupId>
|
||||
<artifactId>yudao-common</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- 参数校验 -->
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-validation</artifactId>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
</project>
|
@ -14,7 +14,8 @@ import lombok.RequiredArgsConstructor;
|
||||
@Getter
|
||||
public enum CouponExpireTimeTypeEnum {
|
||||
|
||||
OPEN(1,"不开启"),CLOSE(0,"开启"),;
|
||||
OPEN(1,"不开启"),
|
||||
CLOSE(0,"开启"),;
|
||||
|
||||
/**
|
||||
* 是否开启过期提醒
|
||||
|
@ -14,7 +14,8 @@ import lombok.RequiredArgsConstructor;
|
||||
@Getter
|
||||
public enum CouponFetchTypeEnum {
|
||||
|
||||
LIMIT(0,"否"),NOT_LIMIT(0,"开启"),;
|
||||
LIMIT(1,"限制"),
|
||||
NOT_LIMIT(0,"不限制"),;
|
||||
|
||||
/**
|
||||
* 是否开启过期提醒
|
||||
|
@ -6,17 +6,16 @@ import lombok.RequiredArgsConstructor;
|
||||
|
||||
|
||||
/**
|
||||
* 优惠券 - 优惠券类型
|
||||
* 优惠券 - 优惠叠加类型
|
||||
*
|
||||
* @author Sin
|
||||
*/
|
||||
@RequiredArgsConstructor
|
||||
@Getter
|
||||
public enum CouponProductTypeEnum {
|
||||
public enum CouponForbidPreferenceEnum {
|
||||
|
||||
PROCESSING(1,"进行中"),
|
||||
END(2,"已结束"),
|
||||
CLOSE(3,"已关闭"),;
|
||||
UN_FORBID(0,"不限制"),
|
||||
FORBID(1,"优惠券仅原价购买商品时可用");
|
||||
|
||||
/**
|
||||
* 优惠券类型
|
@ -0,0 +1,30 @@
|
||||
package cn.iocoder.yudao.module.CouponTemplete.enums;
|
||||
|
||||
|
||||
import lombok.Getter;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
|
||||
|
||||
/**
|
||||
* 优惠券 - 优惠券商品使用类型
|
||||
*
|
||||
* @author Sin
|
||||
*/
|
||||
@RequiredArgsConstructor
|
||||
@Getter
|
||||
public enum CouponGoodsTypeEnum {
|
||||
|
||||
ALL(1,"全部商品可用"),
|
||||
POINT_PRODUCT(2,"指定商品可用"),
|
||||
POINT_PRODUCT_NOT(3,"指定商品不可用"),;
|
||||
|
||||
/**
|
||||
* 优惠券商品使用类型
|
||||
*/
|
||||
private final Integer type;
|
||||
/**
|
||||
* 优惠券商品使用类型名
|
||||
*/
|
||||
private final String name;
|
||||
|
||||
}
|
@ -6,7 +6,7 @@ import lombok.RequiredArgsConstructor;
|
||||
|
||||
|
||||
/**
|
||||
* 优惠券 - 优惠券类型
|
||||
* 优惠券 - 优惠券状态类型
|
||||
*
|
||||
* @author Sin
|
||||
*/
|
||||
@ -14,9 +14,9 @@ import lombok.RequiredArgsConstructor;
|
||||
@Getter
|
||||
public enum CouponStatusTypeEnum {
|
||||
|
||||
ALL(1,"全部商品可用"),
|
||||
POINT_PRODUCT(2,"指定商品可用"),
|
||||
POINT_PRODUCT_NOT(3,"指定商品不可用不能为空"),;
|
||||
PROCESSING(1,"进行中"),
|
||||
END(2,"已结束"),
|
||||
CLOSE(3,"已关闭"),;
|
||||
|
||||
/**
|
||||
* 优惠券类型
|
||||
|
@ -6,7 +6,7 @@ import lombok.RequiredArgsConstructor;
|
||||
|
||||
|
||||
/**
|
||||
* 优惠券 - 优惠券类型
|
||||
* 优惠券使用类型 - 优惠券使用类型类型
|
||||
*
|
||||
* @author Sin
|
||||
*/
|
||||
@ -18,11 +18,11 @@ public enum CouponUseLimitEnum {
|
||||
NO_LIMIT(2,"有门槛"),;
|
||||
|
||||
/**
|
||||
* 优惠券类型
|
||||
* 优惠券使用类型
|
||||
*/
|
||||
private final Integer type;
|
||||
/**
|
||||
* 优惠券类型名
|
||||
* 优惠券使用类型名
|
||||
*/
|
||||
private final String name;
|
||||
|
||||
|
@ -14,7 +14,7 @@ public enum CouponValidityTypeEnum {
|
||||
|
||||
TIME_RANGE_EXPIRTED(1,"时间范围过期"),
|
||||
EXPIRES_AFTER_FIXED_DATE(2,"领取之日固定日期后过期"),
|
||||
EXPIRES_DATE_NEXT_FIEXD_DATE(3,"领取次日固定日期后过期不能为空"),;
|
||||
EXPIRES_DATE_NEXT_FIEXD_DATE(3,"领取次日固定日期后过期"),;
|
||||
|
||||
|
||||
/**
|
||||
|
@ -3,19 +3,18 @@
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<parent>
|
||||
<artifactId>yudao-module-mall</artifactId>
|
||||
<groupId>cn.iocoder.boot</groupId>
|
||||
<artifactId>yudao-module-mall</artifactId>
|
||||
<version>${revision}</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<artifactId>yudao-module-coupon-biz</artifactId>
|
||||
<packaging>jar</packaging>
|
||||
|
||||
<artifactId>yudao-module-coupon-biz</artifactId>
|
||||
|
||||
<name>${project.artifactId}</name>
|
||||
|
||||
<description>
|
||||
trade 模块,主要实现交易相关功能
|
||||
例如:订单、退款、购物车等功能。
|
||||
coupon模块,主要负责优惠券的一些业务,含发布优惠券模板,分发优惠券等
|
||||
</description>
|
||||
|
||||
<dependencies>
|
||||
|
@ -21,7 +21,7 @@ import cn.iocoder.yudao.module.coupon.service.coupon.CouponService;
|
||||
|
||||
@Api(tags = "管理后台 - 优惠券")
|
||||
@RestController
|
||||
@RequestMapping("/coupon/coupon/")
|
||||
@RequestMapping("/coupon/item")
|
||||
@Validated
|
||||
public class CouponController {
|
||||
|
||||
@ -69,7 +69,7 @@ public class CouponController {
|
||||
|
||||
@GetMapping("/list")
|
||||
@ApiOperation("获得优惠券列表")
|
||||
// @ApiImplicitParam(name = "ids", value = "编号列表", required = true, example = "1024,2048", dataTypeClass = List.class)
|
||||
@ApiImplicitParam(name = "ids", value = "编号列表", required = true, example = "1024,2048", dataTypeClass = List.class)
|
||||
@PreAuthorize("@ss.hasPermission('coupon::query')")
|
||||
public CommonResult<List<CouponRespVO>> getList(@RequestParam("ids") Collection<Long> ids) {
|
||||
List<CouponDO> list = couponService.getList(ids);
|
||||
|
@ -68,7 +68,7 @@ public class CouponBaseVO {
|
||||
private Boolean whetherForbidPreference;
|
||||
|
||||
@ApiModelProperty(value = "是否开启过期提醒0-不开启 1-开启", required = true)
|
||||
@NotNull(message = "是否开启过期提醒0-不开启 1-开启不能为空")
|
||||
@NotNull(message = "是否开启过期提醒0-不开启 1-开启")
|
||||
private Boolean whetherExpireNotice;
|
||||
|
||||
@ApiModelProperty(value = "过期前N天提醒", required = true)
|
||||
|
@ -1,81 +0,0 @@
|
||||
package cn.iocoder.yudao.module.coupon.controller.admin.coupontemplete;
|
||||
|
||||
import cn.iocoder.yudao.module.coupon.controller.admin.coupontemplete.vo.*;
|
||||
import cn.iocoder.yudao.module.coupon.convert.CouponTemplete.CouponTempleteConvert;
|
||||
import cn.iocoder.yudao.module.coupon.dal.dataobject.CouponTemplete.CouponTempleteDO;
|
||||
import cn.iocoder.yudao.module.coupon.service.CouponTemplete.CouponTempleteService;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
import javax.annotation.Resource;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
import org.springframework.security.access.prepost.PreAuthorize;
|
||||
import io.swagger.annotations.*;
|
||||
|
||||
import javax.validation.*;
|
||||
import java.util.*;
|
||||
|
||||
import cn.iocoder.yudao.framework.common.pojo.PageResult;
|
||||
import cn.iocoder.yudao.framework.common.pojo.CommonResult;
|
||||
import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
|
||||
|
||||
@Api(tags = "管理后台 - 优惠券模板")
|
||||
@RestController
|
||||
@RequestMapping("/coupon/CouponTemplete/")
|
||||
@Validated
|
||||
public class CouponTempleteController {
|
||||
|
||||
@Resource
|
||||
private CouponTempleteService Service;
|
||||
|
||||
@PostMapping("/create")
|
||||
@ApiOperation("创建优惠券模板")
|
||||
@PreAuthorize("@ss.hasPermission('CouponTemplete::create')")
|
||||
public CommonResult<Long> create(@Valid @RequestBody CouponTempleteCreateReqVO createReqVO) {
|
||||
return success(Service.create(createReqVO));
|
||||
}
|
||||
|
||||
@PutMapping("/update")
|
||||
@ApiOperation("更新优惠券模板")
|
||||
@PreAuthorize("@ss.hasPermission('CouponTemplete::update')")
|
||||
public CommonResult<Boolean> update(@Valid @RequestBody CouponTempleteUpdateReqVO updateReqVO) {
|
||||
Service.update(updateReqVO);
|
||||
return success(true);
|
||||
}
|
||||
|
||||
@DeleteMapping("/delete")
|
||||
@ApiOperation("删除优惠券模板")
|
||||
@ApiImplicitParam(name = "id", value = "编号", required = true, dataTypeClass = Long.class)
|
||||
@PreAuthorize("@ss.hasPermission('CouponTemplete::delete')")
|
||||
public CommonResult<Boolean> delete(@RequestParam("id") Long id) {
|
||||
Service.delete(id);
|
||||
return success(true);
|
||||
}
|
||||
|
||||
@GetMapping("/get")
|
||||
@ApiOperation("获得优惠券模板")
|
||||
// @ApiImplicitParam(name = "id", value = "编号", required = true, example = "1024", dataTypeClass = Long.class)
|
||||
@PreAuthorize("@ss.hasPermission('CouponTemplete::query')")
|
||||
public CommonResult<CouponTempleteRespVO> get(@RequestParam("id") Long id) {
|
||||
CouponTempleteDO couponTempleteDO = Service.get(id);
|
||||
return success(CouponTempleteConvert.INSTANCE.convert(couponTempleteDO));
|
||||
}
|
||||
|
||||
@GetMapping("/list")
|
||||
@ApiOperation("获得优惠券模板列表")
|
||||
// @ApiImplicitParam(name = "ids", value = "编号列表", required = true, example = "1024,2048", dataTypeClass = List.class)
|
||||
@PreAuthorize("@ss.hasPermission('CouponTemplete::query')")
|
||||
public CommonResult<List<CouponTempleteRespVO>> getList(@RequestParam("ids") Collection<Long> ids) {
|
||||
List<CouponTempleteDO> list = Service.getList(ids);
|
||||
return success(CouponTempleteConvert.INSTANCE.convertList(list));
|
||||
}
|
||||
|
||||
@GetMapping("/page")
|
||||
@ApiOperation("获得优惠券模板分页")
|
||||
@PreAuthorize("@ss.hasPermission('CouponTemplete::query')")
|
||||
public CommonResult<PageResult<CouponTempleteRespVO>> getPage(@Valid CouponTempletePageReqVO pageVO) {
|
||||
PageResult<CouponTempleteDO> pageResult = Service.getPage(pageVO);
|
||||
return success(CouponTempleteConvert.INSTANCE.convertPage(pageResult));
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
@ -0,0 +1,81 @@
|
||||
package cn.iocoder.yudao.module.coupon.controller.admin.templete;
|
||||
|
||||
import cn.iocoder.yudao.module.coupon.controller.admin.templete.vo.*;
|
||||
import cn.iocoder.yudao.module.coupon.convert.CouponTemplete.CouponTempleteConvert;
|
||||
import cn.iocoder.yudao.module.coupon.dal.dataobject.CouponTemplete.CouponTempleteDO;
|
||||
import cn.iocoder.yudao.module.coupon.service.CouponTemplete.CouponTempleteService;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
import javax.annotation.Resource;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
import org.springframework.security.access.prepost.PreAuthorize;
|
||||
import io.swagger.annotations.*;
|
||||
|
||||
import javax.validation.*;
|
||||
import java.util.*;
|
||||
|
||||
import cn.iocoder.yudao.framework.common.pojo.PageResult;
|
||||
import cn.iocoder.yudao.framework.common.pojo.CommonResult;
|
||||
import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
|
||||
|
||||
@Api(tags = "管理后台 - 优惠券模板")
|
||||
@RestController
|
||||
@RequestMapping("/coupon/template")
|
||||
@Validated
|
||||
public class CouponTempleteController {
|
||||
|
||||
@Resource
|
||||
private CouponTempleteService couponTempleteServiceService;
|
||||
|
||||
@PostMapping("/create")
|
||||
@ApiOperation("创建优惠券模板")
|
||||
@PreAuthorize("@ss.hasPermission('CouponTemplete::create')")
|
||||
public CommonResult<Long> create(@Valid @RequestBody CouponTempleteCreateReqVO createReqVO) {
|
||||
return success(couponTempleteServiceService.create(createReqVO));
|
||||
}
|
||||
|
||||
// @PutMapping("/update")
|
||||
// @ApiOperation("更新优惠券模板")
|
||||
// @PreAuthorize("@ss.hasPermission('CouponTemplete::update')")
|
||||
// public CommonResult<Boolean> update(@Valid @RequestBody CouponTempleteUpdateReqVO updateReqVO) {
|
||||
// couponTempleteServiceService.update(updateReqVO);
|
||||
// return success(true);
|
||||
// }
|
||||
//
|
||||
// @DeleteMapping("/delete")
|
||||
// @ApiOperation("删除优惠券模板")
|
||||
// @ApiImplicitParam(name = "id", value = "编号", required = true, dataTypeClass = Long.class)
|
||||
// @PreAuthorize("@ss.hasPermission('CouponTemplete::delete')")
|
||||
// public CommonResult<Boolean> delete(@RequestParam("id") Long id) {
|
||||
// couponTempleteServiceService.delete(id);
|
||||
// return success(true);
|
||||
// }
|
||||
//
|
||||
// @GetMapping("/get")
|
||||
// @ApiOperation("获得优惠券模板")
|
||||
// @ApiImplicitParam(name = "id", value = "编号", required = true, example = "1024", dataTypeClass = Long.class)
|
||||
// @PreAuthorize("@ss.hasPermission('CouponTemplete::query')")
|
||||
// public CommonResult<CouponTempleteRespVO> get(@RequestParam("id") Long id) {
|
||||
// CouponTempleteDO couponTempleteDO = couponTempleteServiceService.get(id);
|
||||
// return success(CouponTempleteConvert.INSTANCE.convert(couponTempleteDO));
|
||||
// }
|
||||
//
|
||||
// @GetMapping("/list")
|
||||
// @ApiOperation("获得优惠券模板列表")
|
||||
// @ApiImplicitParam(name = "ids", value = "编号列表", required = true, example = "1024,2048", dataTypeClass = List.class)
|
||||
// @PreAuthorize("@ss.hasPermission('CouponTemplete::query')")
|
||||
// public CommonResult<List<CouponTempleteRespVO>> getList(@RequestParam("ids") Collection<Long> ids) {
|
||||
// List<CouponTempleteDO> list = couponTempleteServiceService.getList(ids);
|
||||
// return success(CouponTempleteConvert.INSTANCE.convertList(list));
|
||||
// }
|
||||
//
|
||||
@GetMapping("/page")
|
||||
@ApiOperation("获得优惠券模板分页")
|
||||
@PreAuthorize("@ss.hasPermission('CouponTemplete::query')")
|
||||
public CommonResult<PageResult<CouponTempleteRespVO>> getPage(@Valid CouponTempletePageReqVO pageVO) {
|
||||
PageResult<CouponTempleteDO> pageResult = couponTempleteServiceService.getPage(pageVO);
|
||||
return success(CouponTempleteConvert.INSTANCE.convertPage(pageResult));
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
@ -1,4 +1,4 @@
|
||||
package cn.iocoder.yudao.module.coupon.controller.admin.coupontemplete.vo;
|
||||
package cn.iocoder.yudao.module.coupon.controller.admin.templete.vo;
|
||||
|
||||
import lombok.*;
|
||||
import java.util.*;
|
||||
@ -34,7 +34,7 @@ public class CouponTempleteBaseVO {
|
||||
|
||||
@ApiModelProperty(value = "适用商品类型1-全部商品可用;2-指定商品可用;3-指定商品不可用", required = true)
|
||||
@NotNull(message = "适用商品类型1-全部商品可用;2-指定商品可用;3-指定商品不可用不能为空")
|
||||
private Boolean goodsType;
|
||||
private Integer goodsType;
|
||||
|
||||
@ApiModelProperty(value = "适用商品id")
|
||||
private String productIds;
|
||||
@ -104,7 +104,7 @@ public class CouponTempleteBaseVO {
|
||||
|
||||
|
||||
@ApiModelProperty(value = "领取是否无限制0-否 1是", required = true)
|
||||
@NotNull(message = "是否无限制0-否 1是 不能为空")
|
||||
@NotNull(message = "是否无限制0-否 1是")
|
||||
private Boolean whetherLimitless;
|
||||
|
||||
@ApiModelProperty(value = "每人最大领取个数", required = true)
|
@ -1,4 +1,4 @@
|
||||
package cn.iocoder.yudao.module.coupon.controller.admin.coupontemplete.vo;
|
||||
package cn.iocoder.yudao.module.coupon.controller.admin.templete.vo;
|
||||
|
||||
import lombok.*;
|
||||
import io.swagger.annotations.*;
|
@ -1,4 +1,4 @@
|
||||
package cn.iocoder.yudao.module.coupon.controller.admin.coupontemplete.vo;
|
||||
package cn.iocoder.yudao.module.coupon.controller.admin.templete.vo;
|
||||
|
||||
import lombok.*;
|
||||
import java.util.*;
|
||||
@ -39,7 +39,7 @@ public class CouponTempleteExcelVO {
|
||||
private Integer usedCount;
|
||||
|
||||
@ExcelProperty("适用商品类型1-全部商品可用;2-指定商品可用;3-指定商品不可用")
|
||||
private Boolean goodsType;
|
||||
private Integer goodsType;
|
||||
|
||||
@ExcelProperty("适用商品id")
|
||||
private String productIds;
|
||||
@ -66,7 +66,7 @@ public class CouponTempleteExcelVO {
|
||||
private BigDecimal maxMoney;
|
||||
|
||||
@ExcelProperty("过期类型1-时间范围过期 2-领取之日固定日期后过期 3-领取次日固定日期后过期")
|
||||
private Boolean validityType;
|
||||
private Integer validityType;
|
||||
|
||||
@ExcelProperty("使用开始日期 过期类型1时必填")
|
||||
private Date startUseTime;
|
@ -1,4 +1,4 @@
|
||||
package cn.iocoder.yudao.module.coupon.controller.admin.coupontemplete.vo;
|
||||
package cn.iocoder.yudao.module.coupon.controller.admin.templete.vo;
|
||||
|
||||
import lombok.*;
|
||||
|
@ -1,4 +1,4 @@
|
||||
package cn.iocoder.yudao.module.coupon.controller.admin.coupontemplete.vo;
|
||||
package cn.iocoder.yudao.module.coupon.controller.admin.templete.vo;
|
||||
|
||||
import lombok.*;
|
||||
|
@ -1,4 +1,4 @@
|
||||
package cn.iocoder.yudao.module.coupon.controller.admin.coupontemplete.vo;
|
||||
package cn.iocoder.yudao.module.coupon.controller.admin.templete.vo;
|
||||
|
||||
import lombok.*;
|
||||
import java.util.*;
|
@ -1,4 +1,4 @@
|
||||
package cn.iocoder.yudao.module.coupon.controller.admin.coupontemplete.vo;
|
||||
package cn.iocoder.yudao.module.coupon.controller.admin.templete.vo;
|
||||
|
||||
import lombok.*;
|
||||
import io.swagger.annotations.*;
|
@ -4,10 +4,10 @@ import java.util.*;
|
||||
|
||||
import cn.iocoder.yudao.framework.common.pojo.PageResult;
|
||||
|
||||
import cn.iocoder.yudao.module.coupon.controller.admin.coupontemplete.vo.CouponTempleteCreateReqVO;
|
||||
import cn.iocoder.yudao.module.coupon.controller.admin.coupontemplete.vo.CouponTempleteExcelVO;
|
||||
import cn.iocoder.yudao.module.coupon.controller.admin.coupontemplete.vo.CouponTempleteRespVO;
|
||||
import cn.iocoder.yudao.module.coupon.controller.admin.coupontemplete.vo.CouponTempleteUpdateReqVO;
|
||||
import cn.iocoder.yudao.module.coupon.controller.admin.templete.vo.CouponTempleteCreateReqVO;
|
||||
import cn.iocoder.yudao.module.coupon.controller.admin.templete.vo.CouponTempleteExcelVO;
|
||||
import cn.iocoder.yudao.module.coupon.controller.admin.templete.vo.CouponTempleteRespVO;
|
||||
import cn.iocoder.yudao.module.coupon.controller.admin.templete.vo.CouponTempleteUpdateReqVO;
|
||||
import cn.iocoder.yudao.module.coupon.dal.dataobject.CouponTemplete.CouponTempleteDO;
|
||||
import org.mapstruct.Mapper;
|
||||
import org.mapstruct.factory.Mappers;
|
||||
|
@ -57,7 +57,7 @@ public class CouponTempleteDO extends BaseDO {
|
||||
/**
|
||||
* 适用商品类型1-全部商品可用;2-指定商品可用;3-指定商品不可用
|
||||
*/
|
||||
private Boolean goodsType;
|
||||
private Integer goodsType;
|
||||
/**
|
||||
* 适用商品id
|
||||
*/
|
||||
@ -93,7 +93,7 @@ public class CouponTempleteDO extends BaseDO {
|
||||
/**
|
||||
* 过期类型1-时间范围过期 2-领取之日固定日期后过期 3-领取次日固定日期后过期
|
||||
*/
|
||||
private Boolean validityType;
|
||||
private Integer validityType;
|
||||
/**
|
||||
* 使用开始日期 过期类型1时必填
|
||||
*/
|
||||
|
@ -5,8 +5,8 @@ import java.util.*;
|
||||
import cn.iocoder.yudao.framework.common.pojo.PageResult;
|
||||
import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX;
|
||||
import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX;
|
||||
import cn.iocoder.yudao.module.coupon.controller.admin.coupontemplete.vo.CouponTempleteExportReqVO;
|
||||
import cn.iocoder.yudao.module.coupon.controller.admin.coupontemplete.vo.CouponTempletePageReqVO;
|
||||
import cn.iocoder.yudao.module.coupon.controller.admin.templete.vo.CouponTempleteExportReqVO;
|
||||
import cn.iocoder.yudao.module.coupon.controller.admin.templete.vo.CouponTempletePageReqVO;
|
||||
import cn.iocoder.yudao.module.coupon.dal.dataobject.CouponTemplete.CouponTempleteDO;
|
||||
import org.apache.ibatis.annotations.Mapper;
|
||||
|
||||
|
@ -0,0 +1,6 @@
|
||||
/**
|
||||
* coupon模块,主要负责麦一些优惠券的额增删
|
||||
*
|
||||
* 1. Controller URL:以 /coumon/ 开头,避免和其它 Module 冲突
|
||||
*/
|
||||
package cn.iocoder.yudao.module.coupon;
|
@ -2,7 +2,7 @@ package cn.iocoder.yudao.module.coupon.service.CouponTemplete;
|
||||
|
||||
import java.util.*;
|
||||
import javax.validation.*;
|
||||
import cn.iocoder.yudao.module.coupon.controller.admin.coupontemplete.vo.*;
|
||||
import cn.iocoder.yudao.module.coupon.controller.admin.templete.vo.*;
|
||||
import cn.iocoder.yudao.framework.common.pojo.PageResult;
|
||||
import cn.iocoder.yudao.module.coupon.dal.dataobject.CouponTemplete.CouponTempleteDO;
|
||||
|
||||
|
@ -2,14 +2,13 @@ package cn.iocoder.yudao.module.coupon.service.CouponTemplete;
|
||||
|
||||
import cn.iocoder.yudao.module.CouponTemplete.enums.CouponTypeEnum;
|
||||
import cn.iocoder.yudao.module.CouponTemplete.enums.CouponValidityTypeEnum;
|
||||
import cn.iocoder.yudao.module.coupon.controller.admin.coupontemplete.vo.CouponTempleteCreateReqVO;
|
||||
import cn.iocoder.yudao.module.coupon.controller.admin.coupontemplete.vo.CouponTempleteExportReqVO;
|
||||
import cn.iocoder.yudao.module.coupon.controller.admin.coupontemplete.vo.CouponTempletePageReqVO;
|
||||
import cn.iocoder.yudao.module.coupon.controller.admin.coupontemplete.vo.CouponTempleteUpdateReqVO;
|
||||
import cn.iocoder.yudao.module.coupon.controller.admin.templete.vo.CouponTempleteCreateReqVO;
|
||||
import cn.iocoder.yudao.module.coupon.controller.admin.templete.vo.CouponTempleteExportReqVO;
|
||||
import cn.iocoder.yudao.module.coupon.controller.admin.templete.vo.CouponTempletePageReqVO;
|
||||
import cn.iocoder.yudao.module.coupon.controller.admin.templete.vo.CouponTempleteUpdateReqVO;
|
||||
import cn.iocoder.yudao.module.coupon.convert.CouponTemplete.CouponTempleteConvert;
|
||||
import cn.iocoder.yudao.module.coupon.dal.dataobject.CouponTemplete.CouponTempleteDO;
|
||||
import cn.iocoder.yudao.module.coupon.dal.mysql.CouponTemplete.CouponTempleteMapper;
|
||||
import cn.iocoder.yudao.module.coupon.service.CouponTemplete.CouponTempleteService;
|
||||
import org.springframework.stereotype.Service;
|
||||
import javax.annotation.Resource;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
@ -41,7 +40,7 @@ public class CouponTempleteServiceImpl implements CouponTempleteService {
|
||||
/* 验证类型、判断必填*/
|
||||
checkCouponType(createReqVO);
|
||||
|
||||
/*todo 验证过期类型、判断必填*/
|
||||
/*验证过期类型、判断必填*/
|
||||
checkValidityType(createReqVO);
|
||||
|
||||
|
||||
|
@ -19,15 +19,10 @@ public class PriceCalculateRespDTO {
|
||||
*/
|
||||
private Order order;
|
||||
|
||||
/**
|
||||
* 商品 SKU 数组
|
||||
*/
|
||||
private List<Item> items;
|
||||
|
||||
/**
|
||||
* 营销活动数组
|
||||
*
|
||||
* 只对应 {@link #items} 商品匹配的活动
|
||||
* 只对应 {@link Order#items} 商品匹配的活动
|
||||
*/
|
||||
private List<Promotion> promotions;
|
||||
|
||||
@ -40,13 +35,13 @@ public class PriceCalculateRespDTO {
|
||||
/**
|
||||
* 商品原价(总),单位:分
|
||||
*
|
||||
* 基于 {@link Item#getTotalOriginalPrice()} 求和
|
||||
* 基于 {@link OrderItem#getTotalOriginalPrice()} 求和
|
||||
*/
|
||||
private Integer skuOriginalPrice;
|
||||
/**
|
||||
* 商品优惠(总),单位:分
|
||||
*
|
||||
* 基于 {@link Item#getTotalPromotionPrice()} 求和
|
||||
* 基于 {@link OrderItem#getTotalPromotionPrice()} 求和
|
||||
*/
|
||||
private Integer skuPromotionPrice;
|
||||
/**
|
||||
@ -69,6 +64,10 @@ public class PriceCalculateRespDTO {
|
||||
*/
|
||||
// * - {@link #couponPrice} // TODO 芋艿:靠营销表记录
|
||||
private Integer payPrice;
|
||||
/**
|
||||
* 商品 SKU 数组
|
||||
*/
|
||||
private List<OrderItem> items;
|
||||
|
||||
// ========== 营销基本信息 ==========
|
||||
/**
|
||||
@ -85,10 +84,15 @@ public class PriceCalculateRespDTO {
|
||||
}
|
||||
|
||||
/**
|
||||
* 商品 SKU
|
||||
* 订单商品 SKU
|
||||
*/
|
||||
@Data
|
||||
public static class Item extends PriceCalculateReqDTO.Item {
|
||||
public static class OrderItem extends PriceCalculateReqDTO.Item {
|
||||
|
||||
/**
|
||||
* 购买数量
|
||||
*/
|
||||
private Integer count;
|
||||
|
||||
/**
|
||||
* 商品原价(单),单位:分
|
||||
@ -140,6 +144,10 @@ public class PriceCalculateRespDTO {
|
||||
* 例如说:营销活动的编号、优惠劵的编号
|
||||
*/
|
||||
private Long id;
|
||||
/**
|
||||
* 营销名字
|
||||
*/
|
||||
private String name;
|
||||
/**
|
||||
* 营销类型
|
||||
*
|
||||
@ -152,10 +160,6 @@ public class PriceCalculateRespDTO {
|
||||
* 枚举 {@link PromotionLevelEnum}
|
||||
*/
|
||||
private Integer level;
|
||||
/**
|
||||
* 匹配的商品 SKU 数组
|
||||
*/
|
||||
private List<Item> items;
|
||||
/**
|
||||
* 计算时的原价(总),单位:分
|
||||
*/
|
||||
@ -164,6 +168,13 @@ public class PriceCalculateRespDTO {
|
||||
* 计算时的优惠(总),单位:分
|
||||
*/
|
||||
private Integer totalPromotionPrice;
|
||||
/**
|
||||
* 匹配的商品 SKU 数组
|
||||
*/
|
||||
private List<PromotionItem> items;
|
||||
|
||||
// ========== 匹配情况 ==========
|
||||
|
||||
/**
|
||||
* 是否满足优惠条件
|
||||
*/
|
||||
@ -176,26 +187,26 @@ public class PriceCalculateRespDTO {
|
||||
*/
|
||||
private String meetTip;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* 营销匹配的商品 SKU
|
||||
*/
|
||||
@Data
|
||||
public static class PromotionItem {
|
||||
|
||||
/**
|
||||
* 匹配的商品 SKU
|
||||
* 商品 SKU 编号
|
||||
*/
|
||||
@Data
|
||||
public static class Item {
|
||||
|
||||
/**
|
||||
* 商品 SKU 编号
|
||||
*/
|
||||
private Long skuId;
|
||||
/**
|
||||
* 计算时的原价(总),单位:分
|
||||
*/
|
||||
private Integer totalOriginalPrice;
|
||||
/**
|
||||
* 计算时的优惠(总),单位:分
|
||||
*/
|
||||
private Integer totalPromotionPrice;
|
||||
|
||||
}
|
||||
private Long skuId;
|
||||
/**
|
||||
* 计算时的原价(总),单位:分
|
||||
*/
|
||||
private Integer totalOriginalPrice;
|
||||
/**
|
||||
* 计算时的优惠(总),单位:分
|
||||
*/
|
||||
private Integer totalPromotionPrice;
|
||||
|
||||
}
|
||||
|
||||
|
@ -24,6 +24,11 @@
|
||||
<artifactId>yudao-module-market-api</artifactId>
|
||||
<version>${revision}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>cn.iocoder.boot</groupId>
|
||||
<artifactId>yudao-module-product-api</artifactId>
|
||||
<version>${revision}</version>
|
||||
</dependency>
|
||||
|
||||
<!-- 业务组件 -->
|
||||
<dependency>
|
||||
|
@ -0,0 +1 @@
|
||||
package cn.iocoder.yudao.module.market.api.discount;
|