Conflicts:
	yudao-ui-admin/yarn.lock
This commit is contained in:
shizhong 2022-09-16 11:05:25 +08:00
commit 3e936f3959
510 changed files with 16884 additions and 6340 deletions

View File

@ -170,28 +170,28 @@ 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 前端](./yudao-ui-admin)
@ -202,16 +202,16 @@ ps核心功能已经实现正在对接微信小程序中...
### [管理后台 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/) | Vue 存储库 替代 vuex5 | 2.0.17 |
| [vue-i18n](https://kazupon.github.io/vue-i18n/zh/introduction.html/) | 国际化 | 9.2.0 |
| [windicss](https://cn.windicss.org/) | 下一代工具优先的 CSS 框架 | 3.5.6 |
| [iconify](https://icon-sets.iconify.design/) | 在线图标库 | 2.2.1 |
| 框架 | 说明 | 版本 |
|----------------------------------------------------------------------|-----------------|--------|
| [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)

7
sql/mysql/update.sql Normal file
View 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');

View File

@ -0,0 +1,85 @@
DROP TABLE IF EXISTS `coupon`;
CREATE TABLE `coupon`
(
`id` bigint NOT NULL AUTO_INCREMENT COMMENT '用户ID',
`type` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '优惠券类型 reward-满减 discount-折扣 random-随机',
`name` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '优惠券名称',
`coupon_type_id` bigint UNSIGNED DEFAULT 0 COMMENT '优惠券类型id',
`coupon_code` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '优惠券编码',
`member_id` bigint UNSIGNED NOT NULL DEFAULT 0 COMMENT '领用人',
`use_order_id` bigint UNSIGNED NOT NULL DEFAULT 0 COMMENT '优惠券使用订单id',
`goods_type` tinyint(1) UNSIGNED NOT NULL DEFAULT 0 COMMENT '适用商品类型1-全部商品可用2-指定商品可用3-指定商品不可用',
`goods_ids` varchar(2000) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '适用商品id',
`at_least` decimal(10, 2) UNSIGNED NOT NULL DEFAULT 0 COMMENT '最小金额',
`money` decimal(10, 2) UNSIGNED NOT NULL DEFAULT 0 COMMENT '面额',
`discount` decimal(10, 2) UNSIGNED NOT NULL DEFAULT 0 COMMENT '1 =< 折扣 <= 9.9 当type为discount时需要添加',
`discount_limit` decimal(10, 2) UNSIGNED NOT NULL DEFAULT 0 COMMENT '最多折扣金额 当type为discount时可选择性添加',
`whether_forbid_preference` tinyint(1) UNSIGNED NOT NULL DEFAULT 0 COMMENT '优惠叠加 0-不限制 1- 优惠券仅原价购买商品时可用',
`whether_expire_notice` tinyint(1) UNSIGNED NOT NULL DEFAULT 0 COMMENT '是否开启过期提醒0-不开启 1-开启',
`expire_notice_fixed_term` int(11) UNSIGNED NOT NULL DEFAULT 0 COMMENT '过期前N天提醒',
`whether_noticed` tinyint(1) UNSIGNED NOT NULL DEFAULT 0 COMMENT '是否已提醒',
`state` tinyint(4) UNSIGNED NOT NULL DEFAULT 0 COMMENT '优惠券状态 1已领用未使用 2已使用 3已过期',
`get_type` tinyint(1) UNSIGNED NOT NULL DEFAULT 0 COMMENT '获取方式1订单2.直接领取3.活动领取 4转赠 5分享获取',
`fetch_time` datetime NOT NULL DEFAULT 0 COMMENT '领取时间',
`use_time` datetime NOT NULL DEFAULT 0 COMMENT '使用时间',
`start_time` datetime NOT NULL DEFAULT 0 COMMENT '可使用的开始时间',
`end_time` datetime NOT NULL DEFAULT 0 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 = 119
CHARACTER SET = utf8mb4
COLLATE = utf8mb4_unicode_ci COMMENT = '优惠券';
DROP TABLE IF EXISTS `coupon_templete`;
CREATE TABLE `coupon_templete`
(
`id` bigint NOT NULL AUTO_INCREMENT COMMENT '用户ID',
`type` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '优惠券类型 reward-满减 discount-折扣 random-随机',
`name` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '优惠券名称',
`coupon_name_remark` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci COMMENT '名称备注',
`image` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci COMMENT '优惠券图片',
`count` int(11) NOT NULL DEFAULT 0 COMMENT '发放数量',
`lead_count` int(11) NOT NULL DEFAULT 0 COMMENT '已领取数量',
`used_count` int(11) UNSIGNED NOT NULL DEFAULT 0 COMMENT '已使用数量',
`goods_type` tinyint(1) UNSIGNED NOT NULL DEFAULT 1 COMMENT '适用商品类型1-全部商品可用2-指定商品可用3-指定商品不可用',
`product_ids` varchar(2000) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci COMMENT '适用商品id',
`has_use_limit` tinyint(1) UNSIGNED NOT NULL DEFAULT 0 COMMENT '使用门槛0-无门槛 1-有门槛',
`at_least` decimal(10, 2) NOT NULL DEFAULT 0 COMMENT '满多少元使用 0代表无限制',
`money` decimal(10, 2) NOT NULL DEFAULT 0 COMMENT '发放面额 当type为reward时需要添加',
`discount` decimal(10, 2) UNSIGNED NOT NULL DEFAULT 0 COMMENT '1 =< 折扣 <= 9.9 当type为discount时需要添加',
`discount_limit` decimal(10, 2) NOT NULL DEFAULT 0 COMMENT '最多折扣金额 当type为discount时可选择性添加',
`min_money` decimal(10, 2) UNSIGNED NOT NULL DEFAULT 0 COMMENT '最低金额 当type为radom时需要添加',
`max_money` decimal(10, 2) UNSIGNED NOT NULL DEFAULT 0 COMMENT '最大金额 当type为radom时需要添加',
`validity_type` tinyint(1) UNSIGNED NOT NULL DEFAULT 0 COMMENT '过期类型1-时间范围过期 2-领取之日固定日期后过期 3-领取次日固定日期后过期',
`start_use_time` datetime COMMENT '使用开始日期 过期类型1时必填',
`end_use_time` datetime COMMENT '使用结束日期 过期类型1时必填',
`fixed_term` int(11) UNSIGNED NOT NULL DEFAULT 0 COMMENT '当validity_type为2或者3时需要添加 领取之日起或者次日N天内有效',
`whether_limitless` tinyint(1) UNSIGNED NOT NULL DEFAULT 0 COMMENT '是否无限制0- 1是',
`max_fetch` int(11) UNSIGNED NOT NULL DEFAULT 0 COMMENT '每人最大领取个数',
`whether_expire_notice` tinyint(1) UNSIGNED NOT NULL DEFAULT 0 COMMENT '是否开启过期提醒0-不开启 1-开启',
`expire_notice_fixed_term` int(11) UNSIGNED NOT NULL DEFAULT 0 COMMENT '过期前N天提醒',
`whether_forbid_preference` tinyint(1) UNSIGNED NOT NULL DEFAULT 0 COMMENT '优惠叠加 0-不限制 1- 优惠券仅原价购买商品时可用',
`whether_show` int(11) UNSIGNED NOT NULL DEFAULT 0 COMMENT '是否显示',
`discount_order_money` decimal(10, 2) UNSIGNED NOT NULL DEFAULT 0 COMMENT '订单的优惠总金额',
`order_money` decimal(10, 2) UNSIGNED NOT NULL DEFAULT 0 COMMENT '用券总成交额',
`whether_forbidden` tinyint(1) UNSIGNED NOT NULL DEFAULT 0 COMMENT '是否禁止发放0- 1-',
`order_goods_num` int(11) UNSIGNED NOT NULL DEFAULT 0 COMMENT '使用优惠券购买的商品数量',
`status` tinyint(11) NOT NULL DEFAULT 0 COMMENT '状态1进行中2已结束-1已关闭',
`end_time` datetime 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 = 119
CHARACTER SET = utf8mb4
COLLATE = utf8mb4_unicode_ci COMMENT = '优惠券模板';

View File

@ -1,7 +1,7 @@
/*
Navicat Premium Data Transfer
Source Server : 127.0.0.1
Source Server : 127.0.0.1 MySQL
Source Server Type : MySQL
Source Server Version : 80026
Source Host : localhost:3306
@ -11,277 +11,305 @@
Target Server Version : 80026
File Encoding : 65001
Date: 05/02/2022 00:50:30
Date: 01/08/2022 23:01:36
*/
SET
FOREIGN_KEY_CHECKS = 0;
SET NAMES utf8mb4;
-- ----------------------------
-- Table structure for product_category
-- ----------------------------
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) NOT NULL COMMENT '分类名称',
`icon` varchar(100) NOT NULL DEFAULT '#' COMMENT '分类图标',
`banner_url` varchar(255) NOT NULL COMMENT '分类图片',
`sort` int DEFAULT '0' COMMENT '分类排序',
`description` varchar(1024) DEFAULT NULL COMMENT '分类描述',
`status` tinyint NOT NULL COMMENT '开启状态',
`creator` varchar(64) DEFAULT '' COMMENT '创建者',
`create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`updater` varchar(64) 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 COMMENT='商品分类';
-- ----------------------------
-- Table structure for product_brand
-- ----------------------------
DROP TABLE IF EXISTS `product_brand`;
CREATE TABLE `product_brand`
(
`id` bigint NOT NULL AUTO_INCREMENT COMMENT '品牌编号',
`category_id` bigint NOT NULL COMMENT '分类编号',
`name` varchar(255) NOT NULL COMMENT '品牌名称',
`banner_url` varchar(255) NOT NULL COMMENT '品牌图片',
`sort` int DEFAULT '0' COMMENT '品牌排序',
`description` varchar(1024) DEFAULT NULL COMMENT '品牌描述',
`status` tinyint NOT NULL COMMENT '状态',
`creator` varchar(64) DEFAULT '' COMMENT '创建者',
`create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`updater` varchar(64) 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 COMMENT='品牌';
-- TODO 父级菜单的 id 处理: 2000 2001
INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `status`)
VALUES (2000, '商城', '', 1, 1, 0, '/mall', 'merchant', NULL, 0);
INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `status`)
VALUES (2001, '商品', '', 1, 1, 2000, 'product', 'dict', NULL, 0);
-- 商品分类 菜单 SQL
INSERT INTO `system_menu`(`name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `status`)
VALUES ('分类管理', '', 2, 0, 2001, 'category', '', 'mall/product/category/index', 0);
-- 按钮父菜单ID
SELECT @parentId := LAST_INSERT_ID();
-- 按钮 SQL
INSERT INTO `system_menu`(`name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `status`)
VALUES ('分类查询', 'product:category:query', 3, 1, @parentId, '', '', '', 0);
INSERT INTO `system_menu`(`name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `status`)
VALUES ('分类创建', 'product:category:create', 3, 2, @parentId, '', '', '', 0);
INSERT INTO `system_menu`(`name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `status`)
VALUES ('分类更新', 'product:category:update', 3, 3, @parentId, '', '', '', 0);
INSERT INTO `system_menu`(`name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `status`)
VALUES ('分类删除', 'product:category:delete', 3, 4, @parentId, '', '', '', 0);
INSERT INTO `system_menu`(`name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `status`)
VALUES ('分类导出', 'product:category:export', 3, 5, @parentId, '', '', '', 0);
-- 品牌管理 菜单 SQL
INSERT INTO `system_menu`(`name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `status`)
VALUES ('品牌管理', '', 2, 1, 2001, 'brand', '', 'mall/product/brand/index', 0);
-- 按钮父菜单ID
SELECT @parentId := LAST_INSERT_ID();
-- 按钮 SQL
INSERT INTO `system_menu`(`name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `status`)
VALUES ('品牌查询', 'product:brand:query', 3, 1, @parentId, '', '', '', 0);
INSERT INTO `system_menu`(`name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `status`)
VALUES ('品牌创建', 'product:brand:create', 3, 2, @parentId, '', '', '', 0);
INSERT INTO `system_menu`(`name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `status`)
VALUES ('品牌更新', 'product:brand:update', 3, 3, @parentId, '', '', '', 0);
INSERT INTO `system_menu`(`name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `status`)
VALUES ('品牌删除', 'product:brand:delete', 3, 4, @parentId, '', '', '', 0);
INSERT INTO `system_menu`(`name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `status`)
VALUES ('品牌导出', 'product:brand:export', 3, 5, @parentId, '', '', '', 0);
SET FOREIGN_KEY_CHECKS = 0;
-- ----------------------------
-- Table structure for market_activity
-- ----------------------------
DROP TABLE IF EXISTS `market_activity`;
CREATE TABLE `market_activity`
(
`id` bigint NOT NULL AUTO_INCREMENT COMMENT '活动编号',
`title` varchar(50) NOT NULL DEFAULT '' COMMENT '活动标题',
`activity_type` tinyint(4) NOT NULL COMMENT '活动类型',
`status` tinyint(4) NOT NULL DEFAULT '-1' COMMENT '活动状态',
`start_time` datetime NOT NULL COMMENT '开始时间',
`end_time` datetime NOT NULL COMMENT '结束时间',
`invalid_time` datetime DEFAULT NULL COMMENT '失效时间',
`delete_time` datetime DEFAULT NULL COMMENT '删除时间',
`time_limited_discount` varchar(2000) DEFAULT NULL COMMENT '限制折扣字符串使用 JSON 序列化成字符串存储',
`full_privilege` varchar(2000) DEFAULT NULL COMMENT '限制折扣字符串使用 JSON 序列化成字符串存储',
`creator` varchar(64) DEFAULT '' COMMENT '创建者',
`create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`updater` varchar(64) 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 DEFAULT CHARSET=utf8mb4 COMMENT='促销活动';
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_unicode_ci COMMENT = '促销活动';
-- ----------------------------
-- Records of market_activity
-- ----------------------------
BEGIN;
COMMIT;
-- 规格菜单 SQL
INSERT INTO system_menu(name, permission, type, sort, parent_id, path, icon, component, status)
VALUES ('规格管理', '', 2, 3, 2001, 'property', '', 'mall/product/property/index', 0);
-- ----------------------------
-- Table structure for market_banner
-- ----------------------------
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_unicode_ci COMMENT = 'Banner管理';
-- 按钮父菜单ID
SELECT @parentId := LAST_INSERT_ID();
-- ----------------------------
-- Records of market_banner
-- ----------------------------
BEGIN;
COMMIT;
-- 按钮 SQL
INSERT INTO system_menu(name, permission, type, sort, parent_id, path, icon, component, status)
VALUES ('规格查询', 'product:property:query', 3, 1, @parentId, '', '', '', 0);
INSERT INTO system_menu(name, permission, type, sort, parent_id, path, icon, component, status)
VALUES ('规格创建', 'product:property:create', 3, 2, @parentId, '', '', '', 0);
INSERT INTO system_menu(name, permission, type, sort, parent_id, path, icon, component, status)
VALUES ('规格更新', 'product:property:update', 3, 3, @parentId, '', '', '', 0);
INSERT INTO system_menu(name, permission, type, sort, parent_id, path, icon, component, status)
VALUES ('规格删除', 'product:property:delete', 3, 4, @parentId, '', '', '', 0);
INSERT INTO system_menu(name, permission, type, sort, parent_id, path, icon, component, status)
VALUES ('规格导出', 'product:property:export', 3, 5, @parentId, '', '', '', 0);
-- ----------------------------
-- Table structure for member_address
-- ----------------------------
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
) ENGINE = InnoDB AUTO_INCREMENT = 21 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_bin COMMENT = '用户收件地址';
-- ----------------------------
-- Records of member_address
-- ----------------------------
BEGIN;
INSERT INTO `member_address` (`id`, `user_id`, `name`, `mobile`, `area_id`, `post_code`, `detail_address`, `defaulted`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (21, 1, 'yunai', '15601691300', 610632, '200000', '芋道源码 233 666 ', b'1', '1', '2022-08-01 22:46:35', '1', '2022-08-01 22:46:35', b'0', 1);
COMMIT;
-- 商品菜单 SQL
INSERT INTO system_menu(name, permission, type, sort, parent_id, path, icon, component, status)
VALUES ('商品管理', '', 2, 2, 2001, 'spu', '', 'mall/product/spu/index', 0);
-- ----------------------------
-- Table structure for product_brand
-- ----------------------------
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
) ENGINE = InnoDB AUTO_INCREMENT = 2 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '商品品牌';
-- 按钮父菜单ID
SELECT @parentId := LAST_INSERT_ID();
-- ----------------------------
-- Records of product_brand
-- ----------------------------
BEGIN;
INSERT INTO `product_brand` (`id`, `name`, `pic_url`, `sort`, `description`, `status`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (1, '苹果', 'http://test.yudao.iocoder.cn/e3726713fa56db5717c78c011762fcc7a251db12735c3581470638b8e1fa17e2.jpeg', 0, '是上市', 0, '1', '2022-07-30 22:12:18', '1', '2022-07-30 22:13:55', b'0', 1);
COMMIT;
-- 按钮 SQL
INSERT INTO system_menu(name, permission, type, sort, parent_id, path, icon, component, status)
VALUES ('商品查询', 'product:spu:query', 3, 1, @parentId, '', '', '', 0);
INSERT INTO system_menu(name, permission, type, sort, parent_id, path, icon, component, status)
VALUES ('商品创建', 'product:spu:create', 3, 2, @parentId, '', '', '', 0);
INSERT INTO system_menu(name, permission, type, sort, parent_id, path, icon, component, status)
VALUES ('商品更新', 'product:spu:update', 3, 3, @parentId, '', '', '', 0);
INSERT INTO system_menu(name, permission, type, sort, parent_id, path, icon, component, status)
VALUES ('商品删除', 'product:spu:delete', 3, 4, @parentId, '', '', '', 0);
INSERT INTO system_menu(name, permission, type, sort, parent_id, path, icon, component, status)
VALUES ('商品导出', 'product:spu:export', 3, 5, @parentId, '', '', '', 0);
-- ----------------------------
-- Table structure for product_category
-- ----------------------------
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
) ENGINE = InnoDB AUTO_INCREMENT = 8 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '商品分类';
-- ----------------------------
-- Records of product_category
-- ----------------------------
BEGIN;
INSERT INTO `product_category` (`id`, `parent_id`, `name`, `pic_url`, `sort`, `description`, `status`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (1, 0, '电脑办公', 'http://test.yudao.iocoder.cn/122d548e1b3cd5dec72fe8075c6977a70f9cc13541a684ab3685f1b5df42f6bd.jpeg', 1, '1234', 0, '1', '2022-07-30 16:36:35', '1', '2022-07-30 20:27:16', b'0', 1), (2, 1, '笔记本', 'http://test.yudao.iocoder.cn/72713ac7b947600a019a18786ed0e6562e8692e253dbd35110a0a85c2469bbec.jpg', 1, '<p>测试一下</p>', 0, '1', '2022-07-30 16:38:09', '1', '2022-07-30 16:38:09', b'0', 1), (3, 1, '游戏本', 'http://test.yudao.iocoder.cn/287c50dd9f5f575f57329a0c57b2095be6d1aeba83867b905fe549f54a296feb.jpg', 2, '<p>测试一下</p>', 0, '1', '2022-07-30 16:39:09', '1', '2022-07-30 20:26:59', b'0', 1), (4, 0, '手机', 'http://test.yudao.iocoder.cn/e1b63900c78dbb661b3e383960cee5cfea7e1dd2fb22cff2e317ff025faaf8b2.jpeg', 2, '<p>123</p>', 0, '1', '2022-07-30 16:40:00', '1', '2022-07-30 16:40:09', b'0', 1), (5, 4, '5G手机', 'http://test.yudao.iocoder.cn/3af6557ac7def6423f046f5b2e920b644793420b466959aaa996a2e19068bbde.jpeg', 1, '<p><br></p>', 0, '1', '2022-07-30 16:43:00', '1', '2022-07-30 16:43:00', b'0', 1), (6, 4, '游戏手机', 'http://test.yudao.iocoder.cn/964fe9ccd1710d64ede261dc36d231918a017641986c15293c367f9f66d94d05.jpeg', 2, NULL, 0, '1', '2022-07-30 16:43:44', '1', '2022-07-30 16:43:44', b'0', 1), (7, 5, '厉害的 5G 手机', 'http://test.yudao.iocoder.cn/b287122f277838e8de368769b96217918605743bc45f3a29bda3cc7359dc66e1.png', 0, '123', 0, '1', '2022-07-30 20:38:09', '1', '2022-07-30 20:38:09', b'0', 1);
COMMIT;
-- 规格名称表
drop table if exists product_property;
create table product_property
(
id bigint NOT NULL AUTO_INCREMENT comment '主键',
name varchar(64) comment '规格名称',
status tinyint comment '状态 0 开启 1 禁用',
create_time datetime default current_timestamp comment '创建时间',
update_time datetime default current_timestamp on update current_timestamp comment '更新时间',
creator varchar(64) comment '创建人',
updater varchar(64) comment '更新',
tenant_id bigint NOT NULL DEFAULT '0' COMMENT '租户编号',
deleted bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除',
primary key (id),
key idx_name ( name (32)) comment '规格名称索引'
) comment '规格名称' character set utf8mb4
collate utf8mb4_general_ci;
-- ----------------------------
-- Table structure for product_property
-- ----------------------------
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 '规格名称索引'
) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci COMMENT = '规格名称';
-- 规格值表
drop table if exists product_property_value;
create table product_property_value
(
id bigint NOT NULL AUTO_INCREMENT COMMENT '主键',
property_id bigint comment '规格键id',
name varchar(128) comment '规格值名字',
status tinyint comment '状态 1 开启 2 禁用',
create_time datetime default current_timestamp comment '创建时间',
update_time datetime default current_timestamp on update current_timestamp comment '更新时间',
creator varchar(64) comment '创建人',
updater varchar(64) comment '更新人',
tenant_id bigint NOT NULL DEFAULT '0' COMMENT '租户编号',
deleted bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除',
primary key (id)
) comment '规格值' character set utf8mb4
collate utf8mb4_general_ci;
-- ----------------------------
-- Records of product_property
-- ----------------------------
BEGIN;
COMMIT;
-- spu
drop table if exists product_spu;
create table product_spu
(
id bigint NOT NULL AUTO_INCREMENT COMMENT '主键',
name varchar(128) comment '商品名称',
sell_point varchar(128) not null comment '卖点',
description text not null comment '描述',
category_id bigint not null comment '分类id',
pic_urls varchar(1024) not null default '' comment '商品主图地址\n *\n * 数组以逗号分隔\n 最多上传15张',
sort int not null default 0 comment '排序字段',
like_count int comment '点赞初始人数',
price int comment '价格 单位使用',
quantity int comment '库存数量',
status bit(1) comment '上下架状态 0 上架开启 1 下架禁用',
create_time datetime default current_timestamp comment '创建时间',
update_time datetime default current_timestamp on update current_timestamp comment '更新时间',
creator varchar(64) comment '创建人',
updater varchar(64) comment '更新人',
tenant_id bigint NOT NULL DEFAULT '0' COMMENT '租户编号',
deleted bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除',
primary key (id)
) comment '商品spu' character set utf8mb4
collate utf8mb4_general_ci;
-- ----------------------------
-- Table structure for product_property_value
-- ----------------------------
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
) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci COMMENT = '规格值';
-- ----------------------------
-- Records of product_property_value
-- ----------------------------
BEGIN;
COMMIT;
-- sku
drop table if exists product_sku;
create table product_sku
(
id bigint NOT NULL AUTO_INCREMENT COMMENT '主键',
spu_id bigint not null comment 'spu编号',
properties varchar(64) not null comment '规格值数组-json格式 [{propertId: , valueId: }, {propertId: , valueId: }]',
price int not null DEFAULT -1 comment '销售价格单位',
original_price int not null DEFAULT -1 comment '原价 单位 ',
cost_price int not null DEFAULT -1 comment '成本价单位 ',
bar_code varchar(64) not null comment '条形码',
pic_url VARCHAR(128) not null comment '图片地址',
status tinyint comment '状态 0-正常 1-禁用',
create_time datetime default current_timestamp comment '创建时间',
update_time datetime default current_timestamp on update current_timestamp comment '更新时间',
creator varchar(64) comment '创建人',
updater varchar(64) comment '更新人',
tenant_id bigint NOT NULL DEFAULT '0' COMMENT '租户编号',
deleted bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除',
primary key (id)
) comment '商品sku' character set utf8mb4
collate utf8mb4_general_ci;
-- ----------------------------
-- Table structure for product_sku
-- ----------------------------
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 '更新人',
`deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除',
PRIMARY KEY (`id`) USING BTREE
) ENGINE=InnoDB COMMENT='商品sku';
-- ----------------------------
-- Records of product_sku
-- ----------------------------
BEGIN;
COMMIT;
-- ----------------------------
-- Table structure for product_spu
-- ----------------------------
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
) ENGINE=InnoDB COMMENT='商品spu';
-- ----------------------------
-- Records of product_spu
-- ----------------------------
BEGIN;
COMMIT;
SET FOREIGN_KEY_CHECKS = 1;
INSERT INTO `ruoyi-vue-pro`.`system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `status`, `visible`, `keep_alive`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2000, '商品中心', '', 1, 60, 0, '/product', 'merchant', NULL, 0, b'1', b'1', '', '2022-07-29 15:53:53', '1', '2022-07-30 22:26:19', b'0');
INSERT INTO `ruoyi-vue-pro`.`system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `status`, `visible`, `keep_alive`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2002, '商品分类', '', 2, 2, 2000, 'category', 'dict', 'mall/product/category/index', 0, b'1', b'1', '', '2022-07-29 15:53:53', '1', '2022-07-30 22:23:37', b'0');
INSERT INTO `ruoyi-vue-pro`.`system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `status`, `visible`, `keep_alive`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2003, '分类查询', 'product:category:query', 3, 1, 2002, '', '', '', 0, b'1', b'1', '', '2022-07-29 15:53:53', '', '2022-07-29 15:53:53', b'0');
INSERT INTO `ruoyi-vue-pro`.`system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `status`, `visible`, `keep_alive`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2004, '分类创建', 'product:category:create', 3, 2, 2002, '', '', '', 0, b'1', b'1', '', '2022-07-29 15:53:53', '', '2022-07-29 15:53:53', b'0');
INSERT INTO `ruoyi-vue-pro`.`system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `status`, `visible`, `keep_alive`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2005, '分类更新', 'product:category:update', 3, 3, 2002, '', '', '', 0, b'1', b'1', '', '2022-07-29 15:53:53', '', '2022-07-29 15:53:53', b'0');
INSERT INTO `ruoyi-vue-pro`.`system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `status`, `visible`, `keep_alive`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2006, '分类删除', 'product:category:delete', 3, 4, 2002, '', '', '', 0, b'1', b'1', '', '2022-07-29 15:53:53', '', '2022-07-29 15:53:53', b'0');
INSERT INTO `ruoyi-vue-pro`.`system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `status`, `visible`, `keep_alive`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2007, '分类导出', 'product:category:export', 3, 5, 2002, '', '', '', 0, b'1', b'1', '', '2022-07-29 15:53:53', '', '2022-07-30 13:52:13', b'1');
INSERT INTO `ruoyi-vue-pro`.`system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `status`, `visible`, `keep_alive`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2008, '商品品牌', '', 2, 1, 2000, 'brand', 'dashboard', 'mall/product/brand/index', 0, b'1', b'1', '', '2022-07-30 13:52:44', '1', '2022-07-30 22:23:43', b'0');
INSERT INTO `ruoyi-vue-pro`.`system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `status`, `visible`, `keep_alive`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2009, '品牌查询', 'product:brand:query', 3, 1, 2008, '', '', '', 0, b'1', b'1', '', '2022-07-30 13:52:44', '', '2022-07-30 13:52:44', b'0');
INSERT INTO `ruoyi-vue-pro`.`system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `status`, `visible`, `keep_alive`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2010, '品牌创建', 'product:brand:create', 3, 2, 2008, '', '', '', 0, b'1', b'1', '', '2022-07-30 13:52:44', '', '2022-07-30 13:52:44', b'0');
INSERT INTO `ruoyi-vue-pro`.`system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `status`, `visible`, `keep_alive`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2011, '品牌更新', 'product:brand:update', 3, 3, 2008, '', '', '', 0, b'1', b'1', '', '2022-07-30 13:52:44', '', '2022-07-30 13:52:44', b'0');
INSERT INTO `ruoyi-vue-pro`.`system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `status`, `visible`, `keep_alive`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2012, '品牌删除', 'product:brand:delete', 3, 4, 2008, '', '', '', 0, b'1', b'1', '', '2022-07-30 13:52:44', '', '2022-07-30 13:52:44', b'0');
INSERT INTO `ruoyi-vue-pro`.`system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `status`, `visible`, `keep_alive`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2013, '品牌导出', 'product:brand:export', 3, 5, 2008, '', '', '', 0, b'1', b'1', '', '2022-07-30 13:52:44', '', '2022-07-30 14:15:00', b'1');
INSERT INTO `ruoyi-vue-pro`.`system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `status`, `visible`, `keep_alive`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2014, '商品管理', '', 2, 0, 2000, 'spu', 'link', 'mall/product/spu/index', 0, b'1', b'1', '', '2022-07-30 14:22:58', '1', '2022-07-30 22:26:35', b'0');
INSERT INTO `ruoyi-vue-pro`.`system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `status`, `visible`, `keep_alive`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2015, '商品查询', 'product:spu:query', 3, 1, 2014, '', '', '', 0, b'1', b'1', '', '2022-07-30 14:22:58', '', '2022-07-30 14:22:58', b'0');
INSERT INTO `ruoyi-vue-pro`.`system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `status`, `visible`, `keep_alive`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2016, '商品创建', 'product:spu:create', 3, 2, 2014, '', '', '', 0, b'1', b'1', '', '2022-07-30 14:22:58', '', '2022-07-30 14:22:58', b'0');
INSERT INTO `ruoyi-vue-pro`.`system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `status`, `visible`, `keep_alive`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2017, '商品更新', 'product:spu:update', 3, 3, 2014, '', '', '', 0, b'1', b'1', '', '2022-07-30 14:22:58', '', '2022-07-30 14:22:58', b'0');
INSERT INTO `ruoyi-vue-pro`.`system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `status`, `visible`, `keep_alive`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2018, '商品删除', 'product:spu:delete', 3, 4, 2014, '', '', '', 0, b'1', b'1', '', '2022-07-30 14:22:58', '', '2022-07-30 14:22:58', b'0');
INSERT INTO `ruoyi-vue-pro`.`system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `status`, `visible`, `keep_alive`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2019, '规格管理', '', 2, 3, 2000, 'property', '', 'mall/product/property/index', 0, b'1', b'1', '', '2022-08-01 14:55:35', '', '2022-08-01 14:55:35', b'0');
INSERT INTO `ruoyi-vue-pro`.`system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `status`, `visible`, `keep_alive`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2020, '规格查询', 'product:property:query', 3, 1, 2019, '', '', '', 0, b'1', b'1', '', '2022-08-01 14:55:35', '', '2022-08-01 14:55:35', b'0');
INSERT INTO `ruoyi-vue-pro`.`system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `status`, `visible`, `keep_alive`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2021, '规格创建', 'product:property:create', 3, 2, 2019, '', '', '', 0, b'1', b'1', '', '2022-08-01 14:55:35', '', '2022-08-01 14:55:35', b'0');
INSERT INTO `ruoyi-vue-pro`.`system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `status`, `visible`, `keep_alive`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2022, '规格更新', 'product:property:update', 3, 3, 2019, '', '', '', 0, b'1', b'1', '', '2022-08-01 14:55:35', '', '2022-08-01 14:55:35', b'0');
INSERT INTO `ruoyi-vue-pro`.`system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `status`, `visible`, `keep_alive`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2023, '规格删除', 'product:property:delete', 3, 4, 2019, '', '', '', 0, b'1', b'1', '', '2022-08-01 14:55:35', '', '2022-08-01 14:55:35', b'0');
INSERT INTO `ruoyi-vue-pro`.`system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `status`, `visible`, `keep_alive`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2024, '规格导出', 'product:property:export', 3, 5, 2019, '', '', '', 0, b'1', b'1', '', '2022-08-01 14:55:35', '', '2022-08-01 14:55:35', b'0');
INSERT INTO `ruoyi-vue-pro`.`system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `status`, `visible`, `keep_alive`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2025, 'Banner管理', '', 2, 1, 2000, 'brand', '', 'mall/market/banner/index', 0, b'1', b'1', '', '2022-08-01 14:56:14', '', '2022-08-01 14:56:14', b'0');
INSERT INTO `ruoyi-vue-pro`.`system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `status`, `visible`, `keep_alive`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2026, 'Banner查询', 'market:banner:query', 3, 1, 2025, '', '', '', 0, b'1', b'1', '', '2022-08-01 14:56:14', '', '2022-08-01 14:56:14', b'0');
INSERT INTO `ruoyi-vue-pro`.`system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `status`, `visible`, `keep_alive`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2027, 'Banner创建', 'market:banner:create', 3, 2, 2025, '', '', '', 0, b'1', b'1', '', '2022-08-01 14:56:14', '', '2022-08-01 14:56:14', b'0');
INSERT INTO `ruoyi-vue-pro`.`system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `status`, `visible`, `keep_alive`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2028, 'Banner更新', 'market:banner:update', 3, 3, 2025, '', '', '', 0, b'1', b'1', '', '2022-08-01 14:56:14', '', '2022-08-01 14:56:14', b'0');
INSERT INTO `ruoyi-vue-pro`.`system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `status`, `visible`, `keep_alive`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2029, 'Banner删除', 'market:banner:delete', 3, 4, 2025, '', '', '', 0, b'1', b'1', '', '2022-08-01 14:56:14', '', '2022-08-01 14:56:14', b'0');
-- Market-Banner管理SQL
drop table if exists market_banner;
CREATE TABLE `market_banner` (
`id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT 'Banner编号',
`title` varchar(64) NOT NULL DEFAULT '' COMMENT 'Banner标题',
`pic_url` varchar(255) NOT NULL COMMENT '图片URL',
`status` tinyint(4) NOT NULL DEFAULT '-1' COMMENT '活动状态',
`url` varchar(255) NOT NULL COMMENT '跳转地址',
`creator` varchar(64) DEFAULT '' COMMENT '创建者',
`create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`updater` varchar(64) 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(20) NOT NULL DEFAULT '0' COMMENT '租户编号',
`sort` tinyint(4) DEFAULT NULL COMMENT '排序',
`memo` varchar(255) DEFAULT NULL COMMENT '描述',
PRIMARY KEY (`id`) USING BTREE
) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8mb4 COMMENT='Banner管理';
-- 菜单 SQL
INSERT INTO `system_menu`(`id`,`name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `status`)
VALUES (2026, 'Banner管理', '', 2, 1, 2000, 'brand', '', 'mall/market/banner/index', 0);
-- 按钮父菜单ID
SELECT @parentId := LAST_INSERT_ID();
-- 按钮 SQL
INSERT INTO `system_menu`(`name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `status`)
VALUES ('Banner查询', 'market:banner:query', 3, 1, @parentId, '', '', '', 0);
INSERT INTO `system_menu`(`name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `status`)
VALUES ('Banner创建', 'market:banner:create', 3, 2, @parentId, '', '', '', 0);
INSERT INTO `system_menu`(`name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `status`)
VALUES ('Banner更新', 'market:banner:update', 3, 3, @parentId, '', '', '', 0);
INSERT INTO `system_menu`(`name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `status`)
VALUES ('Banner删除', 'market:banner:delete', 3, 4, @parentId, '', '', '', 0);

View File

@ -0,0 +1,76 @@
/**todo cancelType 设置默认值 0?*/
CREATE TABLE `trade_order`
(
`id` bigint NOT NULL AUTO_INCREMENT COMMENT '用户ID',
`sn` varchar(32) NOT NULL COMMENT '订单流水号',
`type` int NOT NULL DEFAULT '0' COMMENT '订单类型[0:普通订单 1:秒杀订单 2:拼团订单 3:砍价订单]',
`terminal` int NOT NULL COMMENT '订单来源终端[1:小程序 2:H5 3:iOS 4:安卓]',
`user_id` bigint unsigned NOT NULL COMMENT '用户编号',
`user_ip` varchar(30) NOT NULL DEFAULT '' COMMENT '用户 IP',
`user_remark` varchar(200) DEFAULT NULL COMMENT '用户备注',
`status` int NOT NULL DEFAULT '0' COMMENT '订单状态[0:待付款 1:待发货 2:待收货 3:已完成 4:已关闭]',
`product_count` int NOT NULL COMMENT '购买的商品数量',
`cancel_type` int NOT NULL COMMENT '取消类型[10:超时未支付 20:退款关闭 30:买家取消 40:已通过货到付款交易]',
`remark` varchar(200) DEFAULT NULL COMMENT '商家备注',
`payed` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否已支付[0:未支付 1:已经支付过]',
`finish_time` datetime DEFAULT NULL COMMENT '订单完成时间',
`cancel_time` datetime DEFAULT NULL COMMENT '订单取消时间',
`sku_original_price` int NOT NULL DEFAULT '0' COMMENT '商品原价单位',
`sku_promotion_price` int NOT NULL DEFAULT '0' COMMENT '商品优惠单位',
`order_promotion_price` int NOT NULL DEFAULT '0' COMMENT '订单优惠单位',
`delivery_price` int NOT NULL DEFAULT '0' COMMENT '运费金额单位',
`pay_price` int NOT NULL DEFAULT '0' COMMENT '应付金额单位',
`pay_order_id` int NOT NULL COMMENT '支付订单编号',
`pay_channel` int NOT NULL COMMENT '支付成功的支付渠道',
`delivery_type` int NOT NULL DEFAULT '1' COMMENT '配送方式:[1:快递发货 2:自提]',
`actual_delivery_type` int NOT NULL DEFAULT '1' COMMENT '实际的配送方式:[1:快递发货 2:自提]',
`delivery_templateid` int DEFAULT NULL COMMENT '配置模板的编号',
`express_no` int DEFAULT NULL COMMENT '物流公司单号',
`delivery_status` bit(1) NOT NULL DEFAULT b'0' COMMENT '发货状态[0:未发货 1:已发货]',
`delivery_time` datetime DEFAULT NULL COMMENT '发货时间',
`receive_time` datetime DEFAULT NULL COMMENT '收货时间',
`receiver_name` varchar(20) NOT NULL COMMENT '收件人名称',
`receiver_mobile` varchar(20) NOT NULL COMMENT '收件人手机',
`receiver_area_id` int NOT NULL COMMENT '收件人地区编号',
`receiver_post_code` int DEFAULT NULL COMMENT '收件人邮编',
`receiver_detail_address` varchar(255) NOT NULL COMMENT '收件人详细地址',
`refund_status` int NOT NULL DEFAULT '0' COMMENT '订单状态[0:未退款 1:部分退款 2:全部退款]',
`refund_price` int NOT NULL DEFAULT '0' COMMENT '退款金额单位',
`coupon_id` bigint unsigned NOT NULL COMMENT '优惠劵编号',
`creator` varchar(64) DEFAULT '' COMMENT '创建者',
`create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`updater` varchar(64) DEFAULT '' COMMENT '更新者',
`update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
`deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除',
PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB COMMENT ='交易订单表';
DROP TABLE IF EXISTS `trade_order_item`;
CREATE TABLE `trade_order_item`
(
`id` bigint NOT NULL AUTO_INCREMENT COMMENT '用户ID',
`user_id` bigint unsigned NOT NULL COMMENT '用户编号',
`order_Id` bigint unsigned NOT NULL COMMENT '订单编号',
`spu_id` bigint unsigned NOT NULL COMMENT '商品 SPU 编号',
`sku_id` bigint unsigned NOT NULL COMMENT '商品 SKU 编号',
`properties` json DEFAULT NULL COMMENT '规格值数组JSON 格式',
`name` varchar(128) NOT NULL DEFAULT '' COMMENT '商品名称',
`pic_url` varchar(200) DEFAULT NULL COMMENT '商品图片',
`count` int NOT NULL COMMENT '购买数量',
`commented` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否评论[0:未评论 1:已评论]',
`original_price` int NOT NULL DEFAULT '0' COMMENT '商品原价单位',
`total_original_price` int NOT NULL DEFAULT '0' COMMENT '商品原价单位',
`total_promotion_price` int NOT NULL DEFAULT '0' COMMENT '商品级优惠单位',
`present_price` int NOT NULL DEFAULT '0' COMMENT '最终购买金额单位',
`total_present_price` int NOT NULL DEFAULT '0' COMMENT '最终购买金额单位',
`total_pay_price` int NOT NULL DEFAULT '0' COMMENT '应付金额单位',
`refund_status` int NOT NULL DEFAULT '0' COMMENT '退款状态:[0:未申请退款 1:申请退款 2:等待退款 3:退款成功]',
`refund_total` int NOT NULL DEFAULT '0' COMMENT '退款总金额单位',
`creator` varchar(64) DEFAULT '' COMMENT '创建者',
`create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`updater` varchar(64) DEFAULT '' COMMENT '更新者',
`update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
`deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除',
PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB COMMENT ='交易订单明细表';

View File

@ -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,11 +57,12 @@
<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>
@ -130,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>
@ -452,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>

View File

@ -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>

View File

@ -0,0 +1,39 @@
package cn.iocoder.yudao.framework.common.enums;
import cn.iocoder.yudao.framework.common.core.IntArrayValuable;
import lombok.Getter;
import lombok.RequiredArgsConstructor;
import java.util.Arrays;
/**
* 终端的枚举
*
* @author 芋道源码
*/
@RequiredArgsConstructor
@Getter
public enum TerminalEnum implements IntArrayValuable {
//TODO terminal 重复请参考 '订单来源终端[1:小程序 2:H5 3:iOS 4:安卓]'
MINI_PROGRAM(1, "小程序"),
H5(2, "H5"),
IOS(3, "iOS"),
ANDROID(3, "安卓"),;
public static final int[] ARRAYS = Arrays.stream(values()).mapToInt(TerminalEnum::getTerminal).toArray();
/**
* 终端
*/
private final Integer terminal;
/**
* 终端名
*/
private final String name;
@Override
public int[] array() {
return ARRAYS;
}
}

View File

@ -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) {

View File

@ -173,6 +173,23 @@ public class CollectionUtils {
return valueFunc.apply(t);
}
public static <T, V extends Comparable<? super V>> V getMinValue(List<T> from, Function<T, V> valueFunc) {
if (CollUtil.isEmpty(from)) {
return null;
}
assert from.size() > 0; // 断言避免告警
T t = from.stream().min(Comparator.comparing(valueFunc)).get();
return valueFunc.apply(t);
}
public static <T, V extends Comparable<? super V>> V getSumValue(List<T> from, Function<T, V> valueFunc, BinaryOperator<V> accumulator) {
if (CollUtil.isEmpty(from)) {
return null;
}
assert from.size() > 0; // 断言避免告警
return from.stream().map(valueFunc).reduce(accumulator).get();
}
public static <T> void addIfNotNull(Collection<T> coll, T item) {
if (item == null) {
return;

View File

@ -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) {

View File

@ -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);
}
/**

View File

@ -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");
}
}

View File

@ -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();
}
}

View File

@ -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 芋艿:清理 -->

View File

@ -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 {

View File

@ -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;

View File

@ -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>

View 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>

View File

@ -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);
}
}

View File

@ -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}
}

View File

@ -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);
}
}

View File

@ -0,0 +1,7 @@
/**
* 验证码拓展
* 1. 基于 aj-captcha 实现滑块验证码文档https://ajcaptcha.beliefteam.cn/captcha-doc/
*
* @author 星语
*/
package cn.iocoder.yudao.framework.captcha;

View File

@ -0,0 +1 @@
cn.iocoder.yudao.framework.captcha.core.service.RedisCaptchaServiceImpl

View File

@ -0,0 +1,2 @@
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
cn.iocoder.yudao.framework.captcha.config.YudaoCaptchaConfiguration

Binary file not shown.

After

Width:  |  Height:  |  Size: 17 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 28 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 25 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 27 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 24 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 19 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 21 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 30 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 26 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 24 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 27 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 28 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 23 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 25 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 23 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 26 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 27 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 29 KiB

View File

@ -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

View File

@ -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);
}
}

View File

@ -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();
}
}

View File

@ -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

View File

@ -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

View File

@ -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));
}

View File

@ -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 类型.

View File

@ -15,14 +15,18 @@
<name>${project.artifactId}</name>
<description>
market模块主要实现营销相关功能
例如营销活动、banner广告、优惠券、优惠码等功能。
商城大模块,由 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>
</modules>
</project>

View File

@ -0,0 +1,35 @@
<?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-module-mall</artifactId>
<version>${revision}</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>yudao-module-coupon-api</artifactId>
<packaging>jar</packaging>
<name>${project.artifactId}</name>
<description>
coupon 模块 API暴露给其它模块调用
</description>
<dependencies>
<dependency>
<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>

View File

@ -0,0 +1,29 @@
package cn.iocoder.yudao.module.CouponTemplete.enums;
import lombok.Getter;
import lombok.RequiredArgsConstructor;
/**
* 优惠券 - 是否开启过期提醒
*
* @author Sin
*/
@RequiredArgsConstructor
@Getter
public enum CouponExpireTimeTypeEnum {
OPEN(1,"不开启"),
CLOSE(0,"开启"),;
/**
* 是否开启过期提醒
*/
private final Integer type;
/**
* 是否开启过期提醒
*/
private final String name;
}

View File

@ -0,0 +1,29 @@
package cn.iocoder.yudao.module.CouponTemplete.enums;
import lombok.Getter;
import lombok.RequiredArgsConstructor;
/**
* 优惠券 - 领取是否无限制 0
*
* @author Sin
*/
@RequiredArgsConstructor
@Getter
public enum CouponFetchTypeEnum {
LIMIT(1,"限制"),
NOT_LIMIT(0,"不限制"),;
/**
* 是否开启过期提醒
*/
private final Integer type;
/**
* 是否开启过期提醒
*/
private final String name;
}

View File

@ -0,0 +1,29 @@
package cn.iocoder.yudao.module.CouponTemplete.enums;
import lombok.Getter;
import lombok.RequiredArgsConstructor;
/**
* 优惠券 - 优惠叠加类型
*
* @author Sin
*/
@RequiredArgsConstructor
@Getter
public enum CouponForbidPreferenceEnum {
UN_FORBID(0,"不限制"),
FORBID(1,"优惠券仅原价购买商品时可用");
/**
* 优惠券类型
*/
private final Integer type;
/**
* 优惠券类型名
*/
private final String name;
}

View File

@ -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;
}

View File

@ -0,0 +1,30 @@
package cn.iocoder.yudao.module.CouponTemplete.enums;
import lombok.Getter;
import lombok.RequiredArgsConstructor;
/**
* 优惠券 - 优惠券状态类型
*
* @author Sin
*/
@RequiredArgsConstructor
@Getter
public enum CouponStatusTypeEnum {
PROCESSING(1,"进行中"),
END(2,"已结束"),
CLOSE(3,"已关闭"),;
/**
* 优惠券类型
*/
private final Integer type;
/**
* 优惠券类型名
*/
private final String name;
}

View File

@ -0,0 +1,30 @@
package cn.iocoder.yudao.module.CouponTemplete.enums;
import lombok.Getter;
import lombok.RequiredArgsConstructor;
/**
* 优惠券 - 优惠券类型
*
* @author Sin
*/
@RequiredArgsConstructor
@Getter
public enum CouponTypeEnum {
REWARD(1,"满减"),
DISCOUNT(2,"折扣"),
RANDOW(3,"随机"),;
/**
* 优惠券类型
*/
private final Integer type;
/**
* 优惠券类型名
*/
private final String name;
}

View File

@ -0,0 +1,29 @@
package cn.iocoder.yudao.module.CouponTemplete.enums;
import lombok.Getter;
import lombok.RequiredArgsConstructor;
/**
* 优惠券使用类型 - 优惠券使用类型类型
*
* @author Sin
*/
@RequiredArgsConstructor
@Getter
public enum CouponUseLimitEnum {
HAS_LIMIT(1,"无门槛"),
NO_LIMIT(2,"有门槛"),;
/**
* 优惠券使用类型
*/
private final Integer type;
/**
* 优惠券使用类型名
*/
private final String name;
}

View File

@ -0,0 +1,29 @@
package cn.iocoder.yudao.module.CouponTemplete.enums;
import lombok.Getter;
import lombok.RequiredArgsConstructor;
/**
* 过期类型 - 状态
*
* @author Sin
*/
@RequiredArgsConstructor
@Getter
public enum CouponValidityTypeEnum {
TIME_RANGE_EXPIRTED(1,"时间范围过期"),
EXPIRES_AFTER_FIXED_DATE(2,"领取之日固定日期后过期"),
EXPIRES_DATE_NEXT_FIEXD_DATE(3,"领取次日固定日期后过期"),;
/**
* 状态值
*/
private final Integer status;
/**
* 状态名
*/
private final String name;
}

View File

@ -0,0 +1,27 @@
package cn.iocoder.yudao.module.CouponTemplete.enums;
import cn.iocoder.yudao.framework.common.exception.ErrorCode;
/**
* coupon 优惠券错误码枚举类
*
* coupon 优惠券系统使用 1-010-000-000
*/
public interface ErrorCodeConstants {
// ========== COUPON分类相关 1010001000 ============
ErrorCode COUPON_TEMPLETE_NOT_EXISTS = new ErrorCode(1010001000, "优惠券模板不存在");
ErrorCode MONEY_NOT_NULL = new ErrorCode(1010001001, "当type为reward时需要添加发放面额不能为空");
ErrorCode DISCOUNT_NOT_NULL = new ErrorCode(1010001001, "当type为discount时需要添加折扣不能为空");
ErrorCode DISCOUNT_LIMIT_NOT_NULL = new ErrorCode(1010001001, "当type为discount时可选择性添加最多折扣金额不能为空");
ErrorCode MIN_MAX_NOT_NULL = new ErrorCode(1010001001, "当type为radom时需要添加最低金额");
ErrorCode START_END_TIME_NOT_NULL = new ErrorCode(1010001001, "使用开始日期,使用结束日期不能为空");
ErrorCode FIXED_TERM_NOT_NULL = new ErrorCode(1010001001, "领取之日起或者次日N天内有效不能为空");
// ========== COUPON分类相关 1010002000 ============
ErrorCode COUPON_NOT_EXISTS = new ErrorCode(1010001000, "优惠券模板不存在");
}

View File

@ -0,0 +1,62 @@
<?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-module-mall</artifactId>
<version>${revision}</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<packaging>jar</packaging>
<artifactId>yudao-module-coupon-biz</artifactId>
<name>${project.artifactId}</name>
<description>
coupon模块主要负责优惠券的一些业务含发布优惠券模板分发优惠券等
</description>
<dependencies>
<dependency>
<groupId>cn.iocoder.boot</groupId>
<artifactId>yudao-module-coupon-api</artifactId>
<version>${revision}</version>
</dependency>
<!-- 业务组件 -->
<dependency>
<groupId>cn.iocoder.boot</groupId>
<artifactId>yudao-spring-boot-starter-biz-operatelog</artifactId>
</dependency>
<dependency>
<groupId>cn.iocoder.boot</groupId>
<artifactId>yudao-spring-boot-starter-biz-tenant</artifactId>
</dependency>
<!-- Web 相关 -->
<dependency>
<groupId>cn.iocoder.boot</groupId>
<artifactId>yudao-spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>cn.iocoder.boot</groupId>
<artifactId>yudao-spring-boot-starter-excel</artifactId>
</dependency>
<!-- DB 相关 -->
<dependency>
<groupId>cn.iocoder.boot</groupId>
<artifactId>yudao-spring-boot-starter-mybatis</artifactId>
</dependency>
<!-- Test 测试相关 -->
<dependency>
<groupId>cn.iocoder.boot</groupId>
<artifactId>yudao-spring-boot-starter-test</artifactId>
</dependency>
</dependencies>
</project>

View File

@ -0,0 +1,88 @@
package cn.iocoder.yudao.module.coupon.controller.admin.coupon;
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;
import cn.iocoder.yudao.module.coupon.controller.admin.coupon.vo.*;
import cn.iocoder.yudao.module.coupon.dal.dataobject.coupon.CouponDO;
import cn.iocoder.yudao.module.coupon.convert.coupon.CouponConvert;
import cn.iocoder.yudao.module.coupon.service.coupon.CouponService;
@Api(tags = "管理后台 - 优惠券")
@RestController
@RequestMapping("/coupon/item")
@Validated
public class CouponController {
@Resource
private CouponService couponService;
//todo 用户优惠券
@PostMapping("/create")
@ApiOperation("用户领取优惠券")
@PreAuthorize("@ss.hasPermission('coupon::create')")
public CommonResult<Long> create(@RequestParam("couponTemplateId") Long couponTemplateId) {
return success(couponService.create(couponTemplateId));
}
@PutMapping("/update")
@ApiOperation("更新优惠券")
@PreAuthorize("@ss.hasPermission('coupon::update')")
public CommonResult<Boolean> update(@Valid @RequestBody CouponUpdateReqVO updateReqVO) {
couponService.update(updateReqVO);
return success(true);
}
@DeleteMapping("/delete")
@ApiOperation("删除优惠券")
@ApiImplicitParam(name = "id", value = "编号", required = true, dataTypeClass = Long.class)
@PreAuthorize("@ss.hasPermission('coupon::delete')")
public CommonResult<Boolean> delete(@RequestParam("id") Long id) {
couponService.delete(id);
return success(true);
}
@GetMapping("/get")
@ApiOperation("获得优惠券")
@ApiImplicitParam(name = "id", value = "编号", required = true, example = "1024", dataTypeClass = Long.class)
@PreAuthorize("@ss.hasPermission('coupon::query')")
public CommonResult<CouponRespVO> get(@RequestParam("id") Long id) {
CouponDO couponDO = couponService.get(id);
return success(CouponConvert.INSTANCE.convert(couponDO));
}
@GetMapping("/list")
@ApiOperation("获得优惠券列表")
@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);
return success(CouponConvert.INSTANCE.convertList(list));
}
@GetMapping("/page")
@ApiOperation("获得优惠券分页")
@PreAuthorize("@ss.hasPermission('coupon::query')")
public CommonResult<PageResult<CouponRespVO>> getPage(@Valid CouponPageReqVO pageVO) {
PageResult<CouponDO> pageResult = couponService.getPage(pageVO);
return success(CouponConvert.INSTANCE.convertPage(pageResult));
}
}

View File

@ -0,0 +1,110 @@
package cn.iocoder.yudao.module.coupon.controller.admin.coupon.vo;
import lombok.*;
import java.util.*;
import java.math.BigDecimal;
import io.swagger.annotations.*;
import javax.validation.constraints.*;
import org.springframework.format.annotation.DateTimeFormat;
import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND;
/**
* 优惠券 Base VO提供给添加修改详细的子 VO 使用
* 如果子 VO 存在差异的字段请不要添加到这里影响 Swagger 文档生成
*/
@Data
public class CouponBaseVO {
@ApiModelProperty(value = "优惠券类型 reward-满减 discount-折扣 random-随机", required = true)
@NotNull(message = "优惠券类型 reward-满减 discount-折扣 random-随机不能为空")
private String type;
@ApiModelProperty(value = "优惠券名称", required = true)
@NotNull(message = "优惠券名称不能为空")
private String name;
@ApiModelProperty(value = "优惠券类型id")
private Long couponTypeId;
@ApiModelProperty(value = "优惠券编码", required = true)
@NotNull(message = "优惠券编码不能为空")
private String couponCode;
@ApiModelProperty(value = "领用人", required = true)
@NotNull(message = "领用人不能为空")
private Long memberId;
@ApiModelProperty(value = "优惠券使用订单id", required = true)
@NotNull(message = "优惠券使用订单id不能为空")
private Long useOrderId;
@ApiModelProperty(value = "适用商品类型1-全部商品可用2-指定商品可用3-指定商品不可用", required = true)
@NotNull(message = "适用商品类型1-全部商品可用2-指定商品可用3-指定商品不可用不能为空")
private Boolean goodsType;
@ApiModelProperty(value = "适用商品id", required = true)
@NotNull(message = "适用商品id不能为空")
private String goodsIds;
@ApiModelProperty(value = "最小金额", required = true)
@NotNull(message = "最小金额不能为空")
private BigDecimal atLeast;
@ApiModelProperty(value = "面额", required = true)
@NotNull(message = "面额不能为空")
private BigDecimal money;
@ApiModelProperty(value = "1 =< 折扣 <= 9.9 当type为discount时需要添加", required = true)
@NotNull(message = "1 =< 折扣 <= 9.9 当type为discount时需要添加不能为空")
private BigDecimal discount;
@ApiModelProperty(value = "最多折扣金额 当type为discount时可选择性添加", required = true)
@NotNull(message = "最多折扣金额 当type为discount时可选择性添加不能为空")
private BigDecimal discountLimit;
@ApiModelProperty(value = "优惠叠加 0-不限制 1- 优惠券仅原价购买商品时可用", required = true)
@NotNull(message = "优惠叠加 0-不限制 1- 优惠券仅原价购买商品时可用不能为空")
private Boolean whetherForbidPreference;
@ApiModelProperty(value = "是否开启过期提醒0-不开启 1-开启", required = true)
@NotNull(message = "是否开启过期提醒0-不开启 1-开启")
private Boolean whetherExpireNotice;
@ApiModelProperty(value = "过期前N天提醒", required = true)
@NotNull(message = "过期前N天提醒不能为空")
private Integer expireNoticeFixedTerm;
@ApiModelProperty(value = "是否已提醒", required = true)
@NotNull(message = "是否已提醒不能为空")
private Boolean whetherNoticed;
@ApiModelProperty(value = "优惠券状态 1已领用未使用 2已使用 3已过期", required = true)
@NotNull(message = "优惠券状态 1已领用未使用 2已使用 3已过期不能为空")
private Integer state;
@ApiModelProperty(value = "获取方式1订单2.直接领取3.活动领取 4转赠 5分享获取", required = true)
@NotNull(message = "获取方式1订单2.直接领取3.活动领取 4转赠 5分享获取不能为空")
private Boolean getType;
@ApiModelProperty(value = "领取时间", required = true)
@NotNull(message = "领取时间不能为空")
@DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
private Date fetchTime;
@ApiModelProperty(value = "使用时间", required = true)
@NotNull(message = "使用时间不能为空")
@DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
private Date useTime;
@ApiModelProperty(value = "可使用的开始时间", required = true)
@NotNull(message = "可使用的开始时间不能为空")
@DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
private Date startTime;
@ApiModelProperty(value = "有效期结束时间", required = true)
@NotNull(message = "有效期结束时间不能为空")
@DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
private Date endTime;
}

View File

@ -1,14 +1,14 @@
package cn.iocoder.yudao.module.product.controller.admin.sku.vo;
package cn.iocoder.yudao.module.coupon.controller.admin.coupon.vo;
import lombok.*;
import java.util.*;
import io.swagger.annotations.*;
import javax.validation.constraints.*;
@ApiModel("管理后台 - 商品sku创建 Request VO")
@ApiModel("管理后台 - 优惠券创建 Request VO")
@Data
@EqualsAndHashCode(callSuper = true)
@ToString(callSuper = true)
public class ProductSkuCreateReqVO extends ProductSkuBaseVO {
public class CouponCreateReqVO extends CouponBaseVO {
}

View File

@ -0,0 +1,90 @@
package cn.iocoder.yudao.module.coupon.controller.admin.coupon.vo;
import lombok.*;
import java.util.*;
import java.math.BigDecimal;
import io.swagger.annotations.*;
import com.alibaba.excel.annotation.ExcelProperty;
/**
* 优惠券 Excel VO
*
* @author wxr
*/
@Data
public class CouponExcelVO {
@ExcelProperty("用户ID")
private Long id;
@ExcelProperty("优惠券类型 reward-满减 discount-折扣 random-随机")
private String type;
@ExcelProperty("优惠券名称")
private String name;
@ExcelProperty("优惠券类型id")
private Long couponTypeId;
@ExcelProperty("优惠券编码")
private String couponCode;
@ExcelProperty("领用人")
private Long memberId;
@ExcelProperty("优惠券使用订单id")
private Long useOrderId;
@ExcelProperty("适用商品类型1-全部商品可用2-指定商品可用3-指定商品不可用")
private Boolean goodsType;
@ExcelProperty("适用商品id")
private String goodsIds;
@ExcelProperty("最小金额")
private BigDecimal atLeast;
@ExcelProperty("面额")
private BigDecimal money;
@ExcelProperty("1 =< 折扣 <= 9.9 当type为discount时需要添加")
private BigDecimal discount;
@ExcelProperty("最多折扣金额 当type为discount时可选择性添加")
private BigDecimal discountLimit;
@ExcelProperty("优惠叠加 0-不限制 1- 优惠券仅原价购买商品时可用")
private Boolean whetherForbidPreference;
@ExcelProperty("是否开启过期提醒0-不开启 1-开启")
private Boolean whetherExpireNotice;
@ExcelProperty("过期前N天提醒")
private Integer expireNoticeFixedTerm;
@ExcelProperty("是否已提醒")
private Boolean whetherNoticed;
@ExcelProperty("优惠券状态 1已领用未使用 2已使用 3已过期")
private Integer state;
@ExcelProperty("获取方式1订单2.直接领取3.活动领取 4转赠 5分享获取")
private Boolean getType;
@ExcelProperty("领取时间")
private Date fetchTime;
@ExcelProperty("使用时间")
private Date useTime;
@ExcelProperty("可使用的开始时间")
private Date startTime;
@ExcelProperty("有效期结束时间")
private Date endTime;
@ExcelProperty("创建时间")
private Date createTime;
}

View File

@ -0,0 +1,91 @@
package cn.iocoder.yudao.module.coupon.controller.admin.coupon.vo;
import lombok.*;
import java.math.BigDecimal;
import java.util.*;
import io.swagger.annotations.*;
import cn.iocoder.yudao.framework.common.pojo.PageParam;
import org.springframework.format.annotation.DateTimeFormat;
import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND;
@ApiModel(value = "管理后台 - 优惠券 Excel 导出 Request VO", description = "参数和 CouponPageReqVO 是一致的")
@Data
public class CouponExportReqVO {
@ApiModelProperty(value = "优惠券类型 reward-满减 discount-折扣 random-随机")
private String type;
@ApiModelProperty(value = "优惠券名称")
private String name;
@ApiModelProperty(value = "优惠券类型id")
private Long couponTypeId;
@ApiModelProperty(value = "优惠券编码")
private String couponCode;
@ApiModelProperty(value = "领用人")
private Long memberId;
@ApiModelProperty(value = "优惠券使用订单id")
private Long useOrderId;
@ApiModelProperty(value = "适用商品类型1-全部商品可用2-指定商品可用3-指定商品不可用")
private Boolean goodsType;
@ApiModelProperty(value = "适用商品id")
private String goodsIds;
@ApiModelProperty(value = "最小金额")
private BigDecimal atLeast;
@ApiModelProperty(value = "面额")
private BigDecimal money;
@ApiModelProperty(value = "1 =< 折扣 <= 9.9 当type为discount时需要添加")
private BigDecimal discount;
@ApiModelProperty(value = "最多折扣金额 当type为discount时可选择性添加")
private BigDecimal discountLimit;
@ApiModelProperty(value = "优惠叠加 0-不限制 1- 优惠券仅原价购买商品时可用")
private Boolean whetherForbidPreference;
@ApiModelProperty(value = "是否开启过期提醒0-不开启 1-开启")
private Boolean whetherExpireNotice;
@ApiModelProperty(value = "过期前N天提醒")
private Integer expireNoticeFixedTerm;
@ApiModelProperty(value = "是否已提醒")
private Boolean whetherNoticed;
@ApiModelProperty(value = "优惠券状态 1已领用未使用 2已使用 3已过期")
private Integer state;
@ApiModelProperty(value = "获取方式1订单2.直接领取3.活动领取 4转赠 5分享获取")
private Boolean getType;
@ApiModelProperty(value = "领取时间")
@DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
private Date[] fetchTime;
@ApiModelProperty(value = "使用时间")
@DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
private Date[] useTime;
@ApiModelProperty(value = "可使用的开始时间")
@DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
private Date[] startTime;
@ApiModelProperty(value = "有效期结束时间")
@DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
private Date[] endTime;
@ApiModelProperty(value = "创建时间")
@DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
private Date[] createTime;
}

View File

@ -0,0 +1,93 @@
package cn.iocoder.yudao.module.coupon.controller.admin.coupon.vo;
import lombok.*;
import java.math.BigDecimal;
import java.util.*;
import io.swagger.annotations.*;
import cn.iocoder.yudao.framework.common.pojo.PageParam;
import org.springframework.format.annotation.DateTimeFormat;
import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND;
@ApiModel("管理后台 - 优惠券分页 Request VO")
@Data
@EqualsAndHashCode(callSuper = true)
@ToString(callSuper = true)
public class CouponPageReqVO extends PageParam {
@ApiModelProperty(value = "优惠券类型 reward-满减 discount-折扣 random-随机")
private String type;
@ApiModelProperty(value = "优惠券名称")
private String name;
@ApiModelProperty(value = "优惠券类型id")
private Long couponTypeId;
@ApiModelProperty(value = "优惠券编码")
private String couponCode;
@ApiModelProperty(value = "领用人")
private Long memberId;
@ApiModelProperty(value = "优惠券使用订单id")
private Long useOrderId;
@ApiModelProperty(value = "适用商品类型1-全部商品可用2-指定商品可用3-指定商品不可用")
private Boolean goodsType;
@ApiModelProperty(value = "适用商品id")
private String goodsIds;
@ApiModelProperty(value = "最小金额")
private BigDecimal atLeast;
@ApiModelProperty(value = "面额")
private BigDecimal money;
@ApiModelProperty(value = "1 =< 折扣 <= 9.9 当type为discount时需要添加")
private BigDecimal discount;
@ApiModelProperty(value = "最多折扣金额 当type为discount时可选择性添加")
private BigDecimal discountLimit;
@ApiModelProperty(value = "优惠叠加 0-不限制 1- 优惠券仅原价购买商品时可用")
private Boolean whetherForbidPreference;
@ApiModelProperty(value = "是否开启过期提醒0-不开启 1-开启")
private Boolean whetherExpireNotice;
@ApiModelProperty(value = "过期前N天提醒")
private Integer expireNoticeFixedTerm;
@ApiModelProperty(value = "是否已提醒")
private Boolean whetherNoticed;
@ApiModelProperty(value = "优惠券状态 1已领用未使用 2已使用 3已过期")
private Integer state;
@ApiModelProperty(value = "获取方式1订单2.直接领取3.活动领取 4转赠 5分享获取")
private Boolean getType;
@ApiModelProperty(value = "领取时间")
@DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
private Date[] fetchTime;
@ApiModelProperty(value = "使用时间")
@DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
private Date[] useTime;
@ApiModelProperty(value = "可使用的开始时间")
@DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
private Date[] startTime;
@ApiModelProperty(value = "有效期结束时间")
@DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
private Date[] endTime;
@ApiModelProperty(value = "创建时间")
@DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
private Date[] createTime;
}

View File

@ -1,16 +1,16 @@
package cn.iocoder.yudao.module.market.controller.admin.activity.vo;
package cn.iocoder.yudao.module.coupon.controller.admin.coupon.vo;
import lombok.*;
import java.util.*;
import io.swagger.annotations.*;
@ApiModel("管理后台 - 促销活动 Response VO")
@ApiModel("管理后台 - 优惠券 Response VO")
@Data
@EqualsAndHashCode(callSuper = true)
@ToString(callSuper = true)
public class ActivityRespVO extends ActivityBaseVO {
public class CouponRespVO extends CouponBaseVO {
@ApiModelProperty(value = "活动编号", required = true)
@ApiModelProperty(value = "用户ID", required = true)
private Long id;
@ApiModelProperty(value = "创建时间", required = true)

View File

@ -0,0 +1,18 @@
package cn.iocoder.yudao.module.coupon.controller.admin.coupon.vo;
import lombok.*;
import java.util.*;
import io.swagger.annotations.*;
import javax.validation.constraints.*;
@ApiModel("管理后台 - 优惠券更新 Request VO")
@Data
@EqualsAndHashCode(callSuper = true)
@ToString(callSuper = true)
public class CouponUpdateReqVO extends CouponBaseVO {
@ApiModelProperty(value = "用户ID", required = true)
@NotNull(message = "用户ID不能为空")
private Long id;
}

View File

@ -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));
}
}

View File

@ -0,0 +1,172 @@
package cn.iocoder.yudao.module.coupon.controller.admin.templete.vo;
import lombok.*;
import java.util.*;
import java.math.BigDecimal;
import io.swagger.annotations.*;
import javax.validation.constraints.*;
import org.springframework.format.annotation.DateTimeFormat;
import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND;
/**
* 优惠券模板 Base VO提供给添加修改详细的子 VO 使用
* 如果子 VO 存在差异的字段请不要添加到这里影响 Swagger 文档生成
*/
@Data
public class CouponTempleteBaseVO {
//基本信息
@ApiModelProperty(value = "优惠券名称", required = true)
@NotNull(message = "优惠券名称不能为空")
private String name;
@ApiModelProperty(value = "名称备注")
private String couponNameRemark;
@ApiModelProperty(value = "优惠券图片")
private String image;
/* ============判断适用商品——开始============= */
@ApiModelProperty(value = "适用商品类型1-全部商品可用2-指定商品可用3-指定商品不可用", required = true)
@NotNull(message = "适用商品类型1-全部商品可用2-指定商品可用3-指定商品不可用不能为空")
private Integer goodsType;
@ApiModelProperty(value = "适用商品id")
private String productIds;
@ApiModelProperty(value = "使用门槛0-无门槛 1-有门槛", required = true)
@NotNull(message = "使用门槛0-无门槛 1-有门槛不能为空")
private Boolean hasUseLimit;
@ApiModelProperty(value = "满多少元使用 0代表无限制", required = true)
@NotNull(message = "满多少元使用 0代表无限制不能为空")
private BigDecimal atLeast;
/* ============折扣类型——开始============= */
@ApiModelProperty(value = "优惠券类型 reward-满减 discount-折扣 random-随机", required = true)
@NotNull(message = "优惠券类型 reward-满减 discount-折扣 random-随机不能为空")
private String type;
@ApiModelProperty(value = "发放面额 当type为reward时需要添加")
@NotNull(message = "发放面额 当type为reward时需要添加不能为空")
private BigDecimal money;
@ApiModelProperty(value = "1 =< 折扣 <= 9.9 当type为discount时需要添加")
@NotNull(message = "1 =< 折扣 <= 9.9 当type为discount时需要添加不能为空")
private BigDecimal discount;
@ApiModelProperty(value = "最多折扣金额 当type为discount时可选择性添加")
@NotNull(message = "最多折扣金额 当type为discount时可选择性添加不能为空")
private BigDecimal discountLimit;
@ApiModelProperty(value = "最低金额 当type为radom时需要添加", required = true)
@NotNull(message = "最低金额 当type为radom时需要添加不能为空")
private BigDecimal minMoney;
@ApiModelProperty(value = "最大金额 当type为radom时需要添加", required = true)
@NotNull(message = "最大金额 当type为radom时需要添加不能为空")
private BigDecimal maxMoney;
/* ============折扣类型——结束============= */
/* ============过期类型——开始============= */
@ApiModelProperty(value = "过期类型1-时间范围过期 2-领取之日固定日期后过期 3-领取次日固定日期后过期", required = true)
@NotNull(message = "过期类型1-时间范围过期 2-领取之日固定日期后过期 3-领取次日固定日期后过期 不能为空")
private Integer validityType;
@ApiModelProperty(value = "使用开始日期 过期类型1时必填")
@DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
private Date startUseTime;
@ApiModelProperty(value = "使用结束日期 过期类型1时必填")
@DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
private Date endUseTime;
@ApiModelProperty(value = "当validity_type为2或者3时需要添加 领取之日起或者次日N天内有效")
@NotNull(message = "当validity_type为2或者3时需要添加 领取之日起或者次日N天内有效不能为空")
private Integer fixedTerm;
@ApiModelProperty(value = "有效日期结束时间")
@DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
private Date endTime;
/* ============过期类型——结束============= */
@ApiModelProperty(value = "领取是否无限制0-否 1是", required = true)
@NotNull(message = "是否无限制0-否 1是")
private Boolean whetherLimitless;
@ApiModelProperty(value = "每人最大领取个数", required = true)
@NotNull(message = "每人最大领取个数不能为空")
private Integer maxFetch;
@ApiModelProperty(value = "是否开启过期提醒 0-不开启 1-开启", required = true)
@NotNull(message = "是否开启过期提醒0-不开启 1-开启不能为空")
private Boolean whetherExpireNotice;
@ApiModelProperty(value = "过期前N天提醒", required = true)
@NotNull(message = "过期前N天提醒不能为空")
private Integer expireNoticeFixedTerm;
@ApiModelProperty(value = "优惠叠加 0-不限制 1- 优惠券仅原价购买商品时可用", required = true)
@NotNull(message = "优惠叠加 0-不限制 1- 优惠券仅原价购买商品时可用不能为空")
private Boolean whetherForbidPreference;
@ApiModelProperty(value = "是否显示", required = true)
@NotNull(message = "是否显示不能为空")
private Integer whetherShow;
@ApiModelProperty(value = "是否禁止发放0-否 1-是", required = true)
@NotNull(message = "是否禁止发放0-否 1-是不能为空")
private Boolean whetherForbidden;
/* ============汇总计算——开始============= */
@ApiModelProperty(value = "使用优惠券购买的商品数量", required = true)
@NotNull(message = "使用优惠券购买的商品数量不能为空")
private Integer orderGoodsNum;
@ApiModelProperty(value = "订单的优惠总金额", required = true)
@NotNull(message = "订单的优惠总金额不能为空")
private BigDecimal discountOrderMoney;
@ApiModelProperty(value = "用券总成交额", required = true)
@NotNull(message = "用券总成交额不能为空")
private BigDecimal orderMoney;
@ApiModelProperty(value = "发放数量", required = true)
@NotNull(message = "发放数量不能为空")
private Integer count;
@ApiModelProperty(value = "已领取数量", required = true)
@NotNull(message = "已领取数量不能为空")
private Integer leadCount;
@ApiModelProperty(value = "已使用数量", required = true)
@NotNull(message = "已使用数量不能为空")
private Integer usedCount;
/* ============汇总计算——结束============= */
@ApiModelProperty(value = "状态1进行中2已结束3已关闭", required = true)
@NotNull(message = "状态1进行中2已结束-1已关闭不能为空")
private Integer status;
}

View File

@ -0,0 +1,12 @@
package cn.iocoder.yudao.module.coupon.controller.admin.templete.vo;
import lombok.*;
import io.swagger.annotations.*;
@ApiModel("管理后台 - 优惠券模板创建 Request VO")
@Data
@EqualsAndHashCode(callSuper = true)
@ToString(callSuper = true)
public class CouponTempleteCreateReqVO extends CouponTempleteBaseVO {
}

View File

@ -0,0 +1,119 @@
package cn.iocoder.yudao.module.coupon.controller.admin.templete.vo;
import lombok.*;
import java.util.*;
import java.math.BigDecimal;
import com.alibaba.excel.annotation.ExcelProperty;
/**
* 优惠券模板 Excel VO
*
* @author wxr
*/
@Data
public class CouponTempleteExcelVO {
@ExcelProperty("用户ID")
private Long id;
@ExcelProperty("优惠券类型 reward-满减 discount-折扣 random-随机")
private String type;
@ExcelProperty("优惠券名称")
private String name;
@ExcelProperty("名称备注")
private String couponNameRemark;
@ExcelProperty("优惠券图片")
private String image;
@ExcelProperty("发放数量")
private Integer count;
@ExcelProperty("已领取数量")
private Integer leadCount;
@ExcelProperty("已使用数量")
private Integer usedCount;
@ExcelProperty("适用商品类型1-全部商品可用2-指定商品可用3-指定商品不可用")
private Integer goodsType;
@ExcelProperty("适用商品id")
private String productIds;
@ExcelProperty("使用门槛0-无门槛 1-有门槛")
private Boolean hasUseLimit;
@ExcelProperty("满多少元使用 0代表无限制")
private BigDecimal atLeast;
@ExcelProperty("发放面额 当type为reward时需要添加")
private BigDecimal money;
@ExcelProperty("1 =< 折扣 <= 9.9 当type为discount时需要添加")
private BigDecimal discount;
@ExcelProperty("最多折扣金额 当type为discount时可选择性添加")
private BigDecimal discountLimit;
@ExcelProperty("最低金额 当type为radom时需要添加")
private BigDecimal minMoney;
@ExcelProperty("最大金额 当type为radom时需要添加")
private BigDecimal maxMoney;
@ExcelProperty("过期类型1-时间范围过期 2-领取之日固定日期后过期 3-领取次日固定日期后过期")
private Integer validityType;
@ExcelProperty("使用开始日期 过期类型1时必填")
private Date startUseTime;
@ExcelProperty("使用结束日期 过期类型1时必填")
private Date endUseTime;
@ExcelProperty("当validity_type为2或者3时需要添加 领取之日起或者次日N天内有效")
private Integer fixedTerm;
@ExcelProperty("是否无限制0-否 1是")
private Boolean whetherLimitless;
@ExcelProperty("每人最大领取个数")
private Integer maxFetch;
@ExcelProperty("是否开启过期提醒0-不开启 1-开启")
private Boolean whetherExpireNotice;
@ExcelProperty("过期前N天提醒")
private Integer expireNoticeFixedTerm;
@ExcelProperty("优惠叠加 0-不限制 1- 优惠券仅原价购买商品时可用")
private Boolean whetherForbidPreference;
@ExcelProperty("是否显示")
private Integer whetherShow;
@ExcelProperty("订单的优惠总金额")
private BigDecimal discountOrderMoney;
@ExcelProperty("用券总成交额")
private BigDecimal orderMoney;
@ExcelProperty("是否禁止发放0-否 1-是")
private Boolean whetherForbidden;
@ExcelProperty("使用优惠券购买的商品数量")
private Integer orderGoodsNum;
@ExcelProperty("状态1进行中2已结束-1已关闭")
private Integer status;
@ExcelProperty("有效日期结束时间")
private Date endTime;
@ExcelProperty("创建时间")
private Date createTime;
}

View File

@ -0,0 +1,119 @@
package cn.iocoder.yudao.module.coupon.controller.admin.templete.vo;
import lombok.*;
import java.math.BigDecimal;
import java.util.*;
import io.swagger.annotations.*;
import org.springframework.format.annotation.DateTimeFormat;
import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND;
@ApiModel(value = "管理后台 - 优惠券模板 Excel 导出 Request VO", description = "参数和 CouponTempletePageReqVO 是一致的")
@Data
public class CouponTempleteExportReqVO {
@ApiModelProperty(value = "优惠券类型 reward-满减 discount-折扣 random-随机")
private String type;
@ApiModelProperty(value = "优惠券名称")
private String name;
@ApiModelProperty(value = "名称备注")
private String couponNameRemark;
@ApiModelProperty(value = "优惠券图片")
private String image;
@ApiModelProperty(value = "发放数量")
private Integer count;
@ApiModelProperty(value = "已领取数量")
private Integer leadCount;
@ApiModelProperty(value = "已使用数量")
private Integer usedCount;
@ApiModelProperty(value = "适用商品类型1-全部商品可用2-指定商品可用3-指定商品不可用")
private Boolean goodsType;
@ApiModelProperty(value = "适用商品id")
private String productIds;
@ApiModelProperty(value = "使用门槛0-无门槛 1-有门槛")
private Boolean hasUseLimit;
@ApiModelProperty(value = "满多少元使用 0代表无限制")
private BigDecimal atLeast;
@ApiModelProperty(value = "发放面额 当type为reward时需要添加")
private BigDecimal money;
@ApiModelProperty(value = "1 =< 折扣 <= 9.9 当type为discount时需要添加")
private BigDecimal discount;
@ApiModelProperty(value = "最多折扣金额 当type为discount时可选择性添加")
private BigDecimal discountLimit;
@ApiModelProperty(value = "最低金额 当type为radom时需要添加")
private BigDecimal minMoney;
@ApiModelProperty(value = "最大金额 当type为radom时需要添加")
private BigDecimal maxMoney;
@ApiModelProperty(value = "过期类型1-时间范围过期 2-领取之日固定日期后过期 3-领取次日固定日期后过期")
private Boolean validityType;
@ApiModelProperty(value = "使用开始日期 过期类型1时必填")
@DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
private Date[] startUseTime;
@ApiModelProperty(value = "使用结束日期 过期类型1时必填")
@DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
private Date[] endUseTime;
@ApiModelProperty(value = "当validity_type为2或者3时需要添加 领取之日起或者次日N天内有效")
private Integer fixedTerm;
@ApiModelProperty(value = "是否无限制0-否 1是")
private Boolean whetherLimitless;
@ApiModelProperty(value = "每人最大领取个数")
private Integer maxFetch;
@ApiModelProperty(value = "是否开启过期提醒0-不开启 1-开启")
private Boolean whetherExpireNotice;
@ApiModelProperty(value = "过期前N天提醒")
private Integer expireNoticeFixedTerm;
@ApiModelProperty(value = "优惠叠加 0-不限制 1- 优惠券仅原价购买商品时可用")
private Boolean whetherForbidPreference;
@ApiModelProperty(value = "是否显示")
private Integer whetherShow;
@ApiModelProperty(value = "订单的优惠总金额")
private BigDecimal discountOrderMoney;
@ApiModelProperty(value = "用券总成交额")
private BigDecimal orderMoney;
@ApiModelProperty(value = "是否禁止发放0-否 1-是")
private Boolean whetherForbidden;
@ApiModelProperty(value = "使用优惠券购买的商品数量")
private Integer orderGoodsNum;
@ApiModelProperty(value = "状态1进行中2已结束-1已关闭")
private Integer status;
@ApiModelProperty(value = "有效日期结束时间")
@DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
private Date[] endTime;
@ApiModelProperty(value = "创建时间")
@DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
private Date[] createTime;
}

View File

@ -0,0 +1,122 @@
package cn.iocoder.yudao.module.coupon.controller.admin.templete.vo;
import lombok.*;
import java.math.BigDecimal;
import java.util.*;
import io.swagger.annotations.*;
import cn.iocoder.yudao.framework.common.pojo.PageParam;
import org.springframework.format.annotation.DateTimeFormat;
import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND;
@ApiModel("管理后台 - 优惠券模板分页 Request VO")
@Data
@EqualsAndHashCode(callSuper = true)
@ToString(callSuper = true)
public class CouponTempletePageReqVO extends PageParam {
@ApiModelProperty(value = "优惠券类型 reward-满减 discount-折扣 random-随机")
private String type;
@ApiModelProperty(value = "优惠券名称")
private String name;
@ApiModelProperty(value = "名称备注")
private String couponNameRemark;
@ApiModelProperty(value = "优惠券图片")
private String image;
@ApiModelProperty(value = "发放数量")
private Integer count;
@ApiModelProperty(value = "已领取数量")
private Integer leadCount;
@ApiModelProperty(value = "已使用数量")
private Integer usedCount;
@ApiModelProperty(value = "适用商品类型1-全部商品可用2-指定商品可用3-指定商品不可用")
private Boolean goodsType;
@ApiModelProperty(value = "适用商品id")
private String productIds;
@ApiModelProperty(value = "使用门槛0-无门槛 1-有门槛")
private Boolean hasUseLimit;
@ApiModelProperty(value = "满多少元使用 0代表无限制")
private BigDecimal atLeast;
@ApiModelProperty(value = "发放面额 当type为reward时需要添加")
private BigDecimal money;
@ApiModelProperty(value = "1 =< 折扣 <= 9.9 当type为discount时需要添加")
private BigDecimal discount;
@ApiModelProperty(value = "最多折扣金额 当type为discount时可选择性添加")
private BigDecimal discountLimit;
@ApiModelProperty(value = "最低金额 当type为radom时需要添加")
private BigDecimal minMoney;
@ApiModelProperty(value = "最大金额 当type为radom时需要添加")
private BigDecimal maxMoney;
@ApiModelProperty(value = "过期类型1-时间范围过期 2-领取之日固定日期后过期 3-领取次日固定日期后过期")
private Boolean validityType;
@ApiModelProperty(value = "使用开始日期 过期类型1时必填")
@DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
private Date[] startUseTime;
@ApiModelProperty(value = "使用结束日期 过期类型1时必填")
@DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
private Date[] endUseTime;
@ApiModelProperty(value = "当validity_type为2或者3时需要添加 领取之日起或者次日N天内有效")
private Integer fixedTerm;
@ApiModelProperty(value = "是否无限制0-否 1是")
private Boolean whetherLimitless;
@ApiModelProperty(value = "每人最大领取个数")
private Integer maxFetch;
@ApiModelProperty(value = "是否开启过期提醒0-不开启 1-开启")
private Boolean whetherExpireNotice;
@ApiModelProperty(value = "过期前N天提醒")
private Integer expireNoticeFixedTerm;
@ApiModelProperty(value = "优惠叠加 0-不限制 1- 优惠券仅原价购买商品时可用")
private Boolean whetherForbidPreference;
@ApiModelProperty(value = "是否显示")
private Integer whetherShow;
@ApiModelProperty(value = "订单的优惠总金额")
private BigDecimal discountOrderMoney;
@ApiModelProperty(value = "用券总成交额")
private BigDecimal orderMoney;
@ApiModelProperty(value = "是否禁止发放0-否 1-是")
private Boolean whetherForbidden;
@ApiModelProperty(value = "使用优惠券购买的商品数量")
private Integer orderGoodsNum;
@ApiModelProperty(value = "状态1进行中2已结束-1已关闭")
private Integer status;
@ApiModelProperty(value = "有效日期结束时间")
@DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
private Date[] endTime;
@ApiModelProperty(value = "创建时间")
@DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
private Date[] createTime;
}

View File

@ -0,0 +1,19 @@
package cn.iocoder.yudao.module.coupon.controller.admin.templete.vo;
import lombok.*;
import java.util.*;
import io.swagger.annotations.*;
@ApiModel("管理后台 - 优惠券模板 Response VO")
@Data
@EqualsAndHashCode(callSuper = true)
@ToString(callSuper = true)
public class CouponTempleteRespVO extends CouponTempleteBaseVO {
@ApiModelProperty(value = "用户ID", required = true)
private Long id;
@ApiModelProperty(value = "创建时间", required = true)
private Date createTime;
}

View File

@ -0,0 +1,17 @@
package cn.iocoder.yudao.module.coupon.controller.admin.templete.vo;
import lombok.*;
import io.swagger.annotations.*;
import javax.validation.constraints.*;
@ApiModel("管理后台 - 优惠券模板更新 Request VO")
@Data
@EqualsAndHashCode(callSuper = true)
@ToString(callSuper = true)
public class CouponTempleteUpdateReqVO extends CouponTempleteBaseVO {
@ApiModelProperty(value = "用户ID", required = true)
@NotNull(message = "用户ID不能为空")
private Long id;
}

View File

@ -0,0 +1,38 @@
package cn.iocoder.yudao.module.coupon.convert.CouponTemplete;
import java.util.*;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
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;
/**
* 优惠券模板 Convert
*
* @author wxr
*/
@Mapper
public interface CouponTempleteConvert {
CouponTempleteConvert INSTANCE = Mappers.getMapper(CouponTempleteConvert.class);
CouponTempleteDO convert(CouponTempleteCreateReqVO bean);
CouponTempleteDO convert(CouponTempleteUpdateReqVO bean);
CouponTempleteRespVO convert(CouponTempleteDO bean);
List<CouponTempleteRespVO> convertList(List<CouponTempleteDO> list);
PageResult<CouponTempleteRespVO> convertPage(PageResult<CouponTempleteDO> page);
List<CouponTempleteExcelVO> convertList02(List<CouponTempleteDO> list);
}

View File

@ -0,0 +1,34 @@
package cn.iocoder.yudao.module.coupon.convert.coupon;
import java.util.*;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import org.mapstruct.Mapper;
import org.mapstruct.factory.Mappers;
import cn.iocoder.yudao.module.coupon.controller.admin.coupon.vo.*;
import cn.iocoder.yudao.module.coupon.dal.dataobject.coupon.CouponDO;
/**
* 优惠券 Convert
*
* @author wxr
*/
@Mapper
public interface CouponConvert {
CouponConvert INSTANCE = Mappers.getMapper(CouponConvert.class);
CouponDO convert(CouponCreateReqVO bean);
CouponDO convert(CouponUpdateReqVO bean);
CouponRespVO convert(CouponDO bean);
List<CouponRespVO> convertList(List<CouponDO> list);
PageResult<CouponRespVO> convertPage(PageResult<CouponDO> page);
List<CouponExcelVO> convertList02(List<CouponDO> list);
}

View File

@ -0,0 +1,158 @@
package cn.iocoder.yudao.module.coupon.dal.dataobject.CouponTemplete;
import lombok.*;
import java.util.*;
import java.math.BigDecimal;
import com.baomidou.mybatisplus.annotation.*;
import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
/**
* 优惠券模板 DO
*
* @author wxr
*/
@TableName("coupon_templete")
@KeySequence("coupon_templete_seq") // 用于 OraclePostgreSQLKingbaseDB2H2 数据库的主键自增如果是 MySQL 等数据库可不写
@Data
@EqualsAndHashCode(callSuper = true)
@ToString(callSuper = true)
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class CouponTempleteDO extends BaseDO {
/**
* 用户ID
*/
@TableId
private Long id;
/**
* 优惠券类型 reward-满减 discount-折扣 random-随机
*/
private String type;
/**
* 优惠券名称
*/
private String name;
/**
* 名称备注
*/
private String couponNameRemark;
/**
* 优惠券图片
*/
private String image;
/**
* 发放数量
*/
private Integer count;
/**
* 已领取数量
*/
private Integer leadCount;
/**
* 已使用数量
*/
private Integer usedCount;
/**
* 适用商品类型1-全部商品可用2-指定商品可用3-指定商品不可用
*/
private Integer goodsType;
/**
* 适用商品id
*/
private String productIds;
/**
* 使用门槛0-无门槛 1-有门槛
*/
private Boolean hasUseLimit;
/**
* 满多少元使用 0代表无限制
*/
private BigDecimal atLeast;
/**
* 发放面额 当type为reward时需要添加
*/
private BigDecimal money;
/**
* 1 =< 折扣 <= 9.9 当type为discount时需要添加
*/
private BigDecimal discount;
/**
* 最多折扣金额 当type为discount时可选择性添加
*/
private BigDecimal discountLimit;
/**
* 最低金额 当type为radom时需要添加
*/
private BigDecimal minMoney;
/**
* 最大金额 当type为radom时需要添加
*/
private BigDecimal maxMoney;
/**
* 过期类型1-时间范围过期 2-领取之日固定日期后过期 3-领取次日固定日期后过期
*/
private Integer validityType;
/**
* 使用开始日期 过期类型1时必填
*/
private Date startUseTime;
/**
* 使用结束日期 过期类型1时必填
*/
private Date endUseTime;
/**
* 当validity_type为2或者3时需要添加 领取之日起或者次日N天内有效
*/
private Integer fixedTerm;
/**
* 是否无限制0- 1是
*/
private Boolean whetherLimitless;
/**
* 每人最大领取个数
*/
private Integer maxFetch;
/**
* 是否开启过期提醒0-不开启 1-开启
*/
private Boolean whetherExpireNotice;
/**
* 过期前N天提醒
*/
private Integer expireNoticeFixedTerm;
/**
* 优惠叠加 0-不限制 1- 优惠券仅原价购买商品时可用
*/
private Boolean whetherForbidPreference;
/**
* 是否显示
*/
private Integer whetherShow;
/**
* 订单的优惠总金额
*/
private BigDecimal discountOrderMoney;
/**
* 用券总成交额
*/
private BigDecimal orderMoney;
/**
* 是否禁止发放0- 1-
*/
private Boolean whetherForbidden;
/**
* 使用优惠券购买的商品数量
*/
private Integer orderGoodsNum;
/**
* 状态1进行中2已结束-1已关闭
*/
private Integer status;
/**
* 有效日期结束时间
*/
private Date endTime;
}

View File

@ -0,0 +1,118 @@
package cn.iocoder.yudao.module.coupon.dal.dataobject.coupon;
import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
import lombok.*;
import java.util.*;
import java.math.BigDecimal;
import com.baomidou.mybatisplus.annotation.*;
/**
* 优惠券 DO
*
* @author wxr
*/
@TableName("coupon")
@KeySequence("coupon_seq") // 用于 OraclePostgreSQLKingbaseDB2H2 数据库的主键自增如果是 MySQL 等数据库可不写
@Data
@EqualsAndHashCode(callSuper = true)
@ToString(callSuper = true)
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class CouponDO extends BaseDO {
/**
* 用户ID
*/
@TableId
private Long id;
/**
* 优惠券类型 reward-满减 discount-折扣 random-随机
*/
private String type;
/**
* 优惠券名称
*/
private String name;
/**
* 优惠券类型id
*/
private Long couponTypeId;
/**
* 优惠券编码
*/
private String couponCode;
/**
* 领用人
*/
private Long memberId;
/**
* 优惠券使用订单id
*/
private Long useOrderId;
/**
* 适用商品类型1-全部商品可用2-指定商品可用3-指定商品不可用
*/
private Boolean goodsType;
/**
* 适用商品id
*/
private String goodsIds;
/**
* 最小金额
*/
private BigDecimal atLeast;
/**
* 面额
*/
private BigDecimal money;
/**
* 1 =< 折扣 <= 9.9 当type为discount时需要添加
*/
private BigDecimal discount;
/**
* 最多折扣金额 当type为discount时可选择性添加
*/
private BigDecimal discountLimit;
/**
* 优惠叠加 0-不限制 1- 优惠券仅原价购买商品时可用
*/
private Boolean whetherForbidPreference;
/**
* 是否开启过期提醒0-不开启 1-开启
*/
private Boolean whetherExpireNotice;
/**
* 过期前N天提醒
*/
private Integer expireNoticeFixedTerm;
/**
* 是否已提醒
*/
private Boolean whetherNoticed;
/**
* 优惠券状态 1已领用未使用 2已使用 3已过期
*/
private Integer state;
/**
* 获取方式1订单2.直接领取3.活动领取 4转赠 5分享获取
*/
private Boolean getType;
/**
* 领取时间
*/
private Date fetchTime;
/**
* 使用时间
*/
private Date useTime;
/**
* 可使用的开始时间
*/
private Date startTime;
/**
* 有效期结束时间
*/
private Date endTime;
}

View File

@ -0,0 +1,98 @@
package cn.iocoder.yudao.module.coupon.dal.mysql.CouponTemplete;
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.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;
/**
* 优惠券模板 Mapper
*
* @author wxr
*/
@Mapper
public interface CouponTempleteMapper extends BaseMapperX<CouponTempleteDO> {
default PageResult<CouponTempleteDO> selectPage(CouponTempletePageReqVO reqVO) {
return selectPage(reqVO, new LambdaQueryWrapperX<CouponTempleteDO>()
.eqIfPresent(CouponTempleteDO::getType, reqVO.getType())
.likeIfPresent(CouponTempleteDO::getName, reqVO.getName())
.eqIfPresent(CouponTempleteDO::getCouponNameRemark, reqVO.getCouponNameRemark())
.eqIfPresent(CouponTempleteDO::getImage, reqVO.getImage())
.eqIfPresent(CouponTempleteDO::getCount, reqVO.getCount())
.eqIfPresent(CouponTempleteDO::getLeadCount, reqVO.getLeadCount())
.eqIfPresent(CouponTempleteDO::getUsedCount, reqVO.getUsedCount())
.eqIfPresent(CouponTempleteDO::getGoodsType, reqVO.getGoodsType())
.eqIfPresent(CouponTempleteDO::getProductIds, reqVO.getProductIds())
.eqIfPresent(CouponTempleteDO::getHasUseLimit, reqVO.getHasUseLimit())
.eqIfPresent(CouponTempleteDO::getAtLeast, reqVO.getAtLeast())
.eqIfPresent(CouponTempleteDO::getMoney, reqVO.getMoney())
.eqIfPresent(CouponTempleteDO::getDiscount, reqVO.getDiscount())
.eqIfPresent(CouponTempleteDO::getDiscountLimit, reqVO.getDiscountLimit())
.eqIfPresent(CouponTempleteDO::getMinMoney, reqVO.getMinMoney())
.eqIfPresent(CouponTempleteDO::getMaxMoney, reqVO.getMaxMoney())
.eqIfPresent(CouponTempleteDO::getValidityType, reqVO.getValidityType())
.betweenIfPresent(CouponTempleteDO::getStartUseTime, reqVO.getStartUseTime())
.betweenIfPresent(CouponTempleteDO::getEndUseTime, reqVO.getEndUseTime())
.eqIfPresent(CouponTempleteDO::getFixedTerm, reqVO.getFixedTerm())
.eqIfPresent(CouponTempleteDO::getWhetherLimitless, reqVO.getWhetherLimitless())
.eqIfPresent(CouponTempleteDO::getMaxFetch, reqVO.getMaxFetch())
.eqIfPresent(CouponTempleteDO::getWhetherExpireNotice, reqVO.getWhetherExpireNotice())
.eqIfPresent(CouponTempleteDO::getExpireNoticeFixedTerm, reqVO.getExpireNoticeFixedTerm())
.eqIfPresent(CouponTempleteDO::getWhetherForbidPreference, reqVO.getWhetherForbidPreference())
.eqIfPresent(CouponTempleteDO::getWhetherShow, reqVO.getWhetherShow())
.eqIfPresent(CouponTempleteDO::getDiscountOrderMoney, reqVO.getDiscountOrderMoney())
.eqIfPresent(CouponTempleteDO::getOrderMoney, reqVO.getOrderMoney())
.eqIfPresent(CouponTempleteDO::getWhetherForbidden, reqVO.getWhetherForbidden())
.eqIfPresent(CouponTempleteDO::getOrderGoodsNum, reqVO.getOrderGoodsNum())
.eqIfPresent(CouponTempleteDO::getStatus, reqVO.getStatus())
.betweenIfPresent(CouponTempleteDO::getEndTime, reqVO.getEndTime())
.betweenIfPresent(CouponTempleteDO::getCreateTime, reqVO.getCreateTime())
.orderByDesc(CouponTempleteDO::getId));
}
default List<CouponTempleteDO> selectList(CouponTempleteExportReqVO reqVO) {
return selectList(new LambdaQueryWrapperX<CouponTempleteDO>()
.eqIfPresent(CouponTempleteDO::getType, reqVO.getType())
.likeIfPresent(CouponTempleteDO::getName, reqVO.getName())
.eqIfPresent(CouponTempleteDO::getCouponNameRemark, reqVO.getCouponNameRemark())
.eqIfPresent(CouponTempleteDO::getImage, reqVO.getImage())
.eqIfPresent(CouponTempleteDO::getCount, reqVO.getCount())
.eqIfPresent(CouponTempleteDO::getLeadCount, reqVO.getLeadCount())
.eqIfPresent(CouponTempleteDO::getUsedCount, reqVO.getUsedCount())
.eqIfPresent(CouponTempleteDO::getGoodsType, reqVO.getGoodsType())
.eqIfPresent(CouponTempleteDO::getProductIds, reqVO.getProductIds())
.eqIfPresent(CouponTempleteDO::getHasUseLimit, reqVO.getHasUseLimit())
.eqIfPresent(CouponTempleteDO::getAtLeast, reqVO.getAtLeast())
.eqIfPresent(CouponTempleteDO::getMoney, reqVO.getMoney())
.eqIfPresent(CouponTempleteDO::getDiscount, reqVO.getDiscount())
.eqIfPresent(CouponTempleteDO::getDiscountLimit, reqVO.getDiscountLimit())
.eqIfPresent(CouponTempleteDO::getMinMoney, reqVO.getMinMoney())
.eqIfPresent(CouponTempleteDO::getMaxMoney, reqVO.getMaxMoney())
.eqIfPresent(CouponTempleteDO::getValidityType, reqVO.getValidityType())
.betweenIfPresent(CouponTempleteDO::getStartUseTime, reqVO.getStartUseTime())
.betweenIfPresent(CouponTempleteDO::getEndUseTime, reqVO.getEndUseTime())
.eqIfPresent(CouponTempleteDO::getFixedTerm, reqVO.getFixedTerm())
.eqIfPresent(CouponTempleteDO::getWhetherLimitless, reqVO.getWhetherLimitless())
.eqIfPresent(CouponTempleteDO::getMaxFetch, reqVO.getMaxFetch())
.eqIfPresent(CouponTempleteDO::getWhetherExpireNotice, reqVO.getWhetherExpireNotice())
.eqIfPresent(CouponTempleteDO::getExpireNoticeFixedTerm, reqVO.getExpireNoticeFixedTerm())
.eqIfPresent(CouponTempleteDO::getWhetherForbidPreference, reqVO.getWhetherForbidPreference())
.eqIfPresent(CouponTempleteDO::getWhetherShow, reqVO.getWhetherShow())
.eqIfPresent(CouponTempleteDO::getDiscountOrderMoney, reqVO.getDiscountOrderMoney())
.eqIfPresent(CouponTempleteDO::getOrderMoney, reqVO.getOrderMoney())
.eqIfPresent(CouponTempleteDO::getWhetherForbidden, reqVO.getWhetherForbidden())
.eqIfPresent(CouponTempleteDO::getOrderGoodsNum, reqVO.getOrderGoodsNum())
.eqIfPresent(CouponTempleteDO::getStatus, reqVO.getStatus())
.betweenIfPresent(CouponTempleteDO::getEndTime, reqVO.getEndTime())
.betweenIfPresent(CouponTempleteDO::getCreateTime, reqVO.getCreateTime())
.orderByDesc(CouponTempleteDO::getId));
}
}

Some files were not shown because too many files have changed in this diff Show More