!578 同步商城实现:会员列表、会员积分、会员签到、会员标签

Merge pull request !578 from 芋道源码/feature/mall_product
This commit is contained in:
芋道源码 2023-08-20 11:50:58 +00:00 committed by Gitee
commit 3124948175
No known key found for this signature in database
GPG Key ID: 173E9B9CA92EEF8F
267 changed files with 5680 additions and 3624 deletions

View File

@ -16,11 +16,11 @@
<module>yudao-module-member</module> <module>yudao-module-member</module>
<module>yudao-module-system</module> <module>yudao-module-system</module>
<module>yudao-module-infra</module> <module>yudao-module-infra</module>
<!-- <module>yudao-module-pay</module>--> <module>yudao-module-pay</module>
<!-- <module>yudao-module-bpm</module>--> <!-- <module>yudao-module-bpm</module>-->
<!-- <module>yudao-module-report</module>--> <!-- <module>yudao-module-report</module>-->
<!-- <module>yudao-module-mp</module>--> <!-- <module>yudao-module-mp</module>-->
<!-- <module>yudao-module-mall</module>--> <module>yudao-module-mall</module>
<!-- 示例项目 --> <!-- 示例项目 -->
<module>yudao-example</module> <module>yudao-example</module>
</modules> </modules>

View File

@ -1637,18 +1637,18 @@ INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_i
INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2209, '秒杀活动', '', 2, 3, 2030, 'seckill', 'ep:place', '', '', 0, b'1', b'1', b'1', '1', '2023-06-24 17:39:13', '1', '2023-06-24 18:55:15', b'0'); INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2209, '秒杀活动', '', 2, 3, 2030, 'seckill', 'ep:place', '', '', 0, b'1', b'1', b'1', '1', '2023-06-24 17:39:13', '1', '2023-06-24 18:55:15', b'0');
INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2262, '会员中心', '', 1, 55, 0, '/member', 'date-range', NULL, NULL, 0, b'1', b'1', b'1', '1', '2023-06-10 00:42:03', '1', '2023-06-28 22:52:34', b'0'); INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2262, '会员中心', '', 1, 55, 0, '/member', 'date-range', NULL, NULL, 0, b'1', b'1', b'1', '1', '2023-06-10 00:42:03', '1', '2023-06-28 22:52:34', b'0');
INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2275, '积分配置', '', 2, 0, 2299, 'config', '', 'member/point/config/index', 'PointConfig', 0, b'1', b'1', b'1', '', '2023-06-10 02:07:44', '1', '2023-06-27 22:50:59', b'0'); INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2275, '积分配置', '', 2, 0, 2299, 'config', '', 'member/point/config/index', 'PointConfig', 0, b'1', b'1', b'1', '', '2023-06-10 02:07:44', '1', '2023-06-27 22:50:59', b'0');
INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2276, '积分设置查询', 'point:config:query', 3, 1, 2275, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2023-06-10 02:07:44', '', '2023-06-10 02:07:44', b'0'); INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2276, '积分设置查询', 'member:point:config:get', 3, 1, 2275, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2023-06-10 02:07:44', '', '2023-06-10 02:07:44', b'0');
INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2277, '积分设置创建', 'point:config:save', 3, 2, 2275, '', '', '', '', 0, b'1', b'1', b'1', '', '2023-06-10 02:07:44', '1', '2023-06-27 20:32:31', b'0'); INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2277, '积分设置创建', 'member:point:config:save', 3, 2, 2275, '', '', '', '', 0, b'1', b'1', b'1', '', '2023-06-10 02:07:44', '1', '2023-06-27 20:32:31', b'0');
INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2281, '签到配置', '', 2, 2, 2300, 'sign-in-config', '', 'member/signin/config/index', 'SignInConfig', 0, b'1', b'1', b'1', '', '2023-06-10 03:26:12', '1', '2023-07-02 15:04:15', b'0'); INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2281, '签到配置', '', 2, 2, 2300, 'sign-in-config', '', 'member/signin/config/index', 'SignInConfig', 0, b'1', b'1', b'1', '', '2023-06-10 03:26:12', '1', '2023-07-02 15:04:15', b'0');
INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2282, '积分签到规则查询', 'point:sign-in-config:query', 3, 1, 2281, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2023-06-10 03:26:12', '', '2023-06-10 03:26:12', b'0'); INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2282, '签到规则查询', 'member:point:sign-in-config:query', 3, 1, 2281, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2023-06-10 03:26:12', '', '2023-06-10 03:26:12', b'0');
INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2283, '积分签到规则创建', 'point:sign-in-config:create', 3, 2, 2281, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2023-06-10 03:26:12', '', '2023-06-10 03:26:12', b'0'); INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2283, '签到规则创建', 'member:point:sign-in-config:create', 3, 2, 2281, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2023-06-10 03:26:12', '', '2023-06-10 03:26:12', b'0');
INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2284, '积分签到规则更新', 'point:sign-in-config:update', 3, 3, 2281, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2023-06-10 03:26:12', '', '2023-06-10 03:26:12', b'0'); INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2284, '签到规则更新', 'member:point:sign-in-config:update', 3, 3, 2281, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2023-06-10 03:26:12', '', '2023-06-10 03:26:12', b'0');
INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2285, '积分签到规则删除', 'point:sign-in-config:delete', 3, 4, 2281, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2023-06-10 03:26:12', '', '2023-06-10 03:26:12', b'0'); INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2285, '签到规则删除', 'member:point:sign-in-config:delete', 3, 4, 2281, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2023-06-10 03:26:12', '', '2023-06-10 03:26:12', b'0');
INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2286, '签到规则获取', 'member:point:sign-in-config:get', 3, 5, 2281, '', '', '', '', 0, b'1', b'1', b'1', '', '2023-06-10 03:26:12', '1', '2023-08-19 09:48:32', b'0');
INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2287, '积分记录', '', 2, 1, 2299, 'record', '', 'member/point/record/index', 'PointRecord', 0, b'1', b'1', b'1', '', '2023-06-10 04:18:50', '1', '2023-06-27 22:51:07', b'0'); INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2287, '积分记录', '', 2, 1, 2299, 'record', '', 'member/point/record/index', 'PointRecord', 0, b'1', b'1', b'1', '', '2023-06-10 04:18:50', '1', '2023-06-27 22:51:07', b'0');
INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2288, '用户积分记录查询', 'point:record:query', 3, 1, 2287, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2023-06-10 04:18:50', '', '2023-06-10 04:18:50', b'0'); INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2288, '用户积分记录查询', 'member:point:record:query', 3, 1, 2287, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2023-06-10 04:18:50', '', '2023-06-10 04:18:50', b'0');
INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2293, '签到记录', '', 2, 3, 2300, 'sign-in-record', '', 'member/signin/record/index', 'SignInRecord', 0, b'1', b'1', b'1', '', '2023-06-10 04:48:22', '1', '2023-07-02 15:04:10', b'0'); INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2293, '签到记录', '', 2, 3, 2300, 'sign-in-record', '', 'member/signin/record/index', 'SignInRecord', 0, b'1', b'1', b'1', '', '2023-06-10 04:48:22', '1', '2023-07-02 15:04:10', b'0');
INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2294, '用户签到积分查询', 'point:sign-in-record:query', 3, 1, 2293, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2023-06-10 04:48:22', '', '2023-06-10 04:48:22', b'0'); INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2294, '签到记录查询', 'member:point:sign-in-record:query', 3, 1, 2293, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2023-06-10 04:48:22', '', '2023-06-10 04:48:22', b'0');
INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2297, '用户签到积分删除', 'point:sign-in-record:delete', 3, 4, 2293, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2023-06-10 04:48:22', '', '2023-06-10 04:48:22', b'0');
INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2299, '会员积分', '', 1, 1, 2262, 'point', '', '', '', 0, b'1', b'1', b'1', '1', '2023-06-27 22:48:51', '1', '2023-06-27 22:48:51', b'0'); INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2299, '会员积分', '', 1, 1, 2262, 'point', '', '', '', 0, b'1', b'1', b'1', '1', '2023-06-27 22:48:51', '1', '2023-06-27 22:48:51', b'0');
INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2300, '会员签到', '', 1, 2, 2262, 'signin', '', '', '', 0, b'1', b'1', b'1', '1', '2023-06-27 22:49:53', '1', '2023-06-27 22:49:53', b'0'); INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2300, '会员签到', '', 1, 2, 2262, 'signin', '', '', '', 0, b'1', b'1', b'1', '1', '2023-06-27 22:49:53', '1', '2023-06-27 22:49:53', b'0');
INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2301, '回调通知', '', 2, 4, 1117, 'notify', 'example', 'pay/notify/index', 'PayNotify', 0, b'1', b'1', b'1', '', '2023-07-20 04:41:32', '1', '2023-07-20 13:45:08', b'0'); INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2301, '回调通知', '', 2, 4, 1117, 'notify', 'example', 'pay/notify/index', 'PayNotify', 0, b'1', b'1', b'1', '', '2023-07-20 04:41:32', '1', '2023-07-20 13:45:08', b'0');

View File

@ -133,6 +133,11 @@
<artifactId>transmittable-thread-local</artifactId> <artifactId>transmittable-thread-local</artifactId>
</dependency> </dependency>
<!-- Test 测试相关 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
</dependency>
</dependencies> </dependencies>
</project> </project>

View File

@ -5,12 +5,11 @@ import cn.hutool.core.collection.CollectionUtil;
import com.google.common.collect.ImmutableMap; import com.google.common.collect.ImmutableMap;
import java.util.*; import java.util.*;
import java.util.function.BinaryOperator; import java.util.function.*;
import java.util.function.Function;
import java.util.function.Predicate;
import java.util.function.Supplier;
import java.util.stream.Collectors; import java.util.stream.Collectors;
import static java.util.Arrays.asList;
/** /**
* Collection 工具类 * Collection 工具类
* *
@ -19,13 +18,17 @@ import java.util.stream.Collectors;
public class CollectionUtils { public class CollectionUtils {
public static boolean containsAny(Object source, Object... targets) { public static boolean containsAny(Object source, Object... targets) {
return Arrays.asList(targets).contains(source); return asList(targets).contains(source);
} }
public static boolean isAnyEmpty(Collection<?>... collections) { public static boolean isAnyEmpty(Collection<?>... collections) {
return Arrays.stream(collections).anyMatch(CollectionUtil::isEmpty); return Arrays.stream(collections).anyMatch(CollectionUtil::isEmpty);
} }
public static <T> boolean anyMatch(Collection<T> from, Predicate<T> predicate) {
return from.stream().anyMatch(predicate);
}
public static <T> List<T> filterList(Collection<T> from, Predicate<T> predicate) { public static <T> List<T> filterList(Collection<T> from, Predicate<T> predicate) {
if (CollUtil.isEmpty(from)) { if (CollUtil.isEmpty(from)) {
return new ArrayList<>(); return new ArrayList<>();
@ -149,6 +152,46 @@ public class CollectionUtils {
return builder.build(); return builder.build();
} }
/**
* 对比老新两个列表找出新增修改删除的数据
*
* @param oldList 老列表
* @param newList 新列表
* @param sameFunc 对比函数返回 true 表示相同返回 false 表示不同
* 注意same 是通过每个元素的标识判断它们是不是同一个数据
* @return [新增列表修改列表删除列表]
*/
public static <T> List<List<T>> diffList(Collection<T> oldList, Collection<T> newList,
BiFunction<T, T, Boolean> sameFunc) {
List<T> createList = new LinkedList<>(newList); // 默认都认为是新增的后续会进行移除
List<T> updateList = new ArrayList<>();
List<T> deleteList = new ArrayList<>();
// 通过以 oldList 为主遍历找出 updateList deleteList
for (T oldObj : oldList) {
// 1. 寻找是否有匹配的
T foundObj = null;
for (Iterator<T> iterator = createList.iterator(); iterator.hasNext(); ) {
T newObj = iterator.next();
// 1.1 不匹配则直接跳过
if (!sameFunc.apply(oldObj, newObj)) {
continue;
}
// 1.2 匹配则移除并结束寻找
iterator.remove();
foundObj = newObj;
break;
}
// 2. 匹配添加到 updateList不匹配则添加到 deleteList
if (foundObj != null) {
updateList.add(foundObj);
} else {
deleteList.add(oldObj);
}
}
return asList(createList, updateList, deleteList);
}
public static boolean containsAny(Collection<?> source, Collection<?> candidates) { public static boolean containsAny(Collection<?> source, Collection<?> candidates) {
return org.springframework.util.CollectionUtils.containsAny(source, candidates); return org.springframework.util.CollectionUtils.containsAny(source, candidates);
} }

View File

@ -23,6 +23,8 @@ public class DateUtils {
*/ */
public static final long SECOND_MILLIS = 1000; public static final long SECOND_MILLIS = 1000;
public static final String FORMAT_YEAR_MONTH_DAY = "yyyy-MM-dd";
public static final String FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND = "yyyy-MM-dd HH:mm:ss"; public static final String FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND = "yyyy-MM-dd HH:mm:ss";
public static final String FORMAT_HOUR_MINUTE_SECOND = "HH:mm:ss"; public static final String FORMAT_HOUR_MINUTE_SECOND = "HH:mm:ss";

View File

@ -3,6 +3,7 @@ package cn.iocoder.yudao.framework.common.util.date;
import cn.hutool.core.date.LocalDateTimeUtil; import cn.hutool.core.date.LocalDateTimeUtil;
import java.time.Duration; import java.time.Duration;
import java.time.LocalDate;
import java.time.LocalDateTime; import java.time.LocalDateTime;
import java.time.LocalTime; import java.time.LocalTime;
@ -62,23 +63,18 @@ public class LocalDateTimeUtils {
} }
/** /**
* 检查时间重叠 不包含日期 * 判断时间段是否重叠
* *
* @param startTime1 需要校验的开始时间 * @param startTime1 开始 time1
* @param endTime1 需要校验的结束时间 * @param endTime1 结束 time1
* @param startTime2 校验所需的开始时间 * @param startTime2 开始 time2
* @param endTime2 校验所需的结束时间 * @param endTime2 结束 time2
* @return 是否重叠 * @return 重叠true 不重叠false
*/ */
// TODO @puhui999LocalDateTimeUtil.isOverlap() 是不是可以满足呀 public static boolean isOverlap(LocalTime startTime1, LocalTime endTime1, LocalTime startTime2, LocalTime endTime2) {
public static boolean checkTimeOverlap(LocalTime startTime1, LocalTime endTime1, LocalTime startTime2, LocalTime endTime2) { LocalDate nowDate = LocalDate.now();
// 判断时间是否重叠 return LocalDateTimeUtil.isOverlap(LocalDateTime.of(nowDate, startTime1), LocalDateTime.of(nowDate, endTime1),
// 开始时间在已配置时段的结束时间之前 结束时间在已配置时段的开始时间之后 [] LocalDateTime.of(nowDate, startTime2), LocalDateTime.of(nowDate, endTime2));
return startTime1.isBefore(endTime2) && endTime1.isAfter(startTime2)
// 开始时间在已配置时段的开始时间之前 结束时间在已配置时段的开始时间之后 (] ()
|| startTime1.isBefore(startTime2) && endTime1.isAfter(startTime2)
// 开始时间在已配置时段的结束时间之前 结束时间在已配值时段的结束时间之后 [) ()
|| startTime1.isBefore(endTime2) && endTime1.isAfter(endTime2);
} }
} }

View File

@ -0,0 +1,64 @@
package cn.iocoder.yudao.framework.common.util.collection;
import lombok.AllArgsConstructor;
import lombok.Data;
import org.junit.jupiter.api.Test;
import java.util.Arrays;
import java.util.Collection;
import java.util.List;
import java.util.function.BiFunction;
import static org.junit.jupiter.api.Assertions.assertEquals;
/**
* {@link CollectionUtils} 的单元测试
*/
public class CollectionUtilsTest {
@Data
@AllArgsConstructor
private static class Dog {
private Integer id;
private String name;
private String code;
}
@Test
public void testDiffList() {
// 准备参数
Collection<Dog> oldList = Arrays.asList(
new Dog(1, "花花", "hh"),
new Dog(2, "旺财", "wc")
);
Collection<Dog> newList = Arrays.asList(
new Dog(null, "花花2", "hh"),
new Dog(null, "小白", "xb")
);
BiFunction<Dog, Dog, Boolean> sameFunc = (oldObj, newObj) -> {
boolean same = oldObj.getCode().equals(newObj.getCode());
// 如果相等的情况下需要设置下 id后续好更新
if (same) {
newObj.setId(oldObj.getId());
}
return same;
};
// 调用
List<List<Dog>> result = CollectionUtils.diffList(oldList, newList, sameFunc);
// 断言
assertEquals(result.size(), 3);
// 断言 create
assertEquals(result.get(0).size(), 1);
assertEquals(result.get(0).get(0), new Dog(null, "小白", "xb"));
// 断言 update
assertEquals(result.get(1).size(), 1);
assertEquals(result.get(1).get(0), new Dog(1, "花花2", "hh"));
// 断言 delete
assertEquals(result.get(2).size(), 1);
assertEquals(result.get(2).get(0), new Dog(2, "旺财", "wc"));
}
}

View File

@ -148,7 +148,7 @@ public abstract class AbstractAlipayPayClient extends AbstractPayClient<AlipayPa
// 2.1 执行请求 // 2.1 执行请求
AlipayTradeRefundResponse response = client.execute(request); AlipayTradeRefundResponse response = client.execute(request);
if (!response.isSuccess()) { if (!response.isSuccess()) {
return PayRefundRespDTO.failureOf(reqDTO.getOutRefundNo(), response); return PayRefundRespDTO.failureOf(response.getSubCode(), response.getSubMsg(), reqDTO.getOutRefundNo(), response);
} }
// 2.2 创建返回结果 // 2.2 创建返回结果
// 支付宝只要退款调用返回 success就认为退款成功不需要回调具体可见 parseNotify 方法的说明 // 支付宝只要退款调用返回 success就认为退款成功不需要回调具体可见 parseNotify 方法的说明

View File

@ -1,99 +1,294 @@
package cn.iocoder.yudao.framework.pay.core.client.impl.alipay; package cn.iocoder.yudao.framework.pay.core.client.impl.alipay;
import cn.hutool.core.date.LocalDateTimeUtil;
import cn.hutool.core.util.RandomUtil;
import cn.hutool.core.util.ReflectUtil; import cn.hutool.core.util.ReflectUtil;
import cn.iocoder.yudao.framework.common.exception.ServiceException;
import cn.iocoder.yudao.framework.common.exception.enums.GlobalErrorCodeConstants;
import cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil;
import cn.iocoder.yudao.framework.pay.core.client.dto.order.PayOrderRespDTO;
import cn.iocoder.yudao.framework.pay.core.client.dto.order.PayOrderUnifiedReqDTO; import cn.iocoder.yudao.framework.pay.core.client.dto.order.PayOrderUnifiedReqDTO;
import cn.iocoder.yudao.framework.pay.core.client.dto.refund.PayRefundRespDTO;
import cn.iocoder.yudao.framework.pay.core.client.dto.refund.PayRefundUnifiedReqDTO;
import cn.iocoder.yudao.framework.pay.core.client.exception.PayException;
import cn.iocoder.yudao.framework.pay.core.enums.order.PayOrderDisplayModeEnum;
import cn.iocoder.yudao.framework.pay.core.enums.refund.PayRefundStatusRespEnum;
import cn.iocoder.yudao.framework.test.core.ut.BaseMockitoUnitTest; import cn.iocoder.yudao.framework.test.core.ut.BaseMockitoUnitTest;
import com.alipay.api.AlipayApiException; import com.alipay.api.AlipayApiException;
import com.alipay.api.DefaultAlipayClient; import com.alipay.api.DefaultAlipayClient;
import com.alipay.api.domain.AlipayTradeRefundModel;
import com.alipay.api.request.AlipayTradePrecreateRequest; import com.alipay.api.request.AlipayTradePrecreateRequest;
import com.alipay.api.request.AlipayTradeRefundRequest;
import com.alipay.api.response.AlipayTradePrecreateResponse; import com.alipay.api.response.AlipayTradePrecreateResponse;
import org.junit.jupiter.api.Disabled; import com.alipay.api.response.AlipayTradeRefundResponse;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
import org.mockito.ArgumentMatcher; import org.mockito.ArgumentMatcher;
import org.mockito.InjectMocks; import org.mockito.InjectMocks;
import org.mockito.Mock; import org.mockito.Mock;
import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.randomPojo; import javax.validation.ConstraintViolationException;
import static org.junit.jupiter.api.Assertions.assertEquals; import java.util.Date;
import static org.junit.jupiter.api.Assertions.assertNotSame;
import static cn.iocoder.yudao.framework.pay.core.client.impl.alipay.AlipayPayClientConfig.MODE_PUBLIC_KEY;
import static cn.iocoder.yudao.framework.pay.core.enums.order.PayOrderStatusRespEnum.CLOSED;
import static cn.iocoder.yudao.framework.pay.core.enums.order.PayOrderStatusRespEnum.WAITING;
import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.*;
import static org.junit.jupiter.api.Assertions.*;
import static org.mockito.ArgumentMatchers.argThat; import static org.mockito.ArgumentMatchers.argThat;
import static org.mockito.Mockito.when; import static org.mockito.Mockito.when;
/**
* {@link AlipayQrPayClient} 单元测试
*
* @author jason
*/
public class AlipayQrPayClientTest extends BaseMockitoUnitTest { public class AlipayQrPayClientTest extends BaseMockitoUnitTest {
private static final String SERVER_URL_SANDBOX = "https://openapi.alipaydev.com/gateway.do"; private final AlipayPayClientConfig config = randomPojo(AlipayPayClientConfig.class, t -> {
t.setServerUrl(randomURL());
private final AlipayPayClientConfig config = new AlipayPayClientConfig() t.setMode(MODE_PUBLIC_KEY);
.setAppId("2021000118634035") t.setSignType(AlipayPayClientConfig.SIGN_TYPE_DEFAULT);
.setServerUrl(SERVER_URL_SANDBOX) t.setAppCertContent("");
.setSignType(AlipayPayClientConfig.SIGN_TYPE_DEFAULT) t.setAlipayPublicCertContent("");
// TODO @tinakey 可以随机就好简洁一点哈 t.setRootCertContent("");
.setPrivateKey("MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQCHsEV1cDupwJ" + });
"v890x84qbppUtRIfhaKSwSVN0thCcsDCaAsGR5MZslDkO8NCT9V4r2SVXjyY7eJUZlZd1M0C8T" +
"01Tg4UOx5LUbic0O3A1uJMy6V1n9IyYwbAW3AEZhBd5bSbPgrqvmv3NeWSTQT6Anxnllf+2iDH" +
"6zyA2fPl7cYyQtbZoDJQFGqr4F+cGh2R6akzRKNoBkAeMYwoY6es2lX8sJxCVPWUmxNUoL3tScw" +
"lSpd7Bxw0q9c/X01jMwuQ0+Va358zgFiGERTE6yD01eu40OBDXOYO3z++y+TAYHlQQ2toMO63tr" +
"epo88X3xV3R44/1DH+k2pAm2IF5ixiLrAgMBAAECggEAPx3SoXcseaD7rmcGcE0p4SMfbsUDdk" +
"USmBBbtfF0GzwnqNLkWa+mgE0rWt9SmXngTQH97vByAYmLPl1s3G82ht1V7Sk7yQMe74lhFllr" +
"8eEyTjeVx3dTK1EEM4TwN+936DTXdFsr4TELJEcJJdD0KaxcCcfBLRDs2wnitEFZ9N+GoZybVmY8w" +
"0e0MI7PLObUZ2l0X4RurQnfG9ZxjXjC7PkeMVv7cGGylpNFi3BbvkRhdhLPDC2E6wqnr9e7zk+hiENi" +
"vAezXrtxtwKovzCtnWJ1r0IO14Rh47H509Ic0wFnj+o5YyUL4LdmpL7yaaH6fM7zcSLFjNZPHvZCKPw" +
"YcQKBgQDQFho98QvnL8ex4v6cry4VitGpjSXm1qP3vmMQk4rTsn8iPWtcxPjqGEqOQJjdi4Mi0VZKQO" +
"LFwlH0kl95wNrD/isJ4O1yeYfX7YAXApzHqYNINzM79HemO3Yx1qLMW3okRFJ9pPRzbQ9qkTpsaegsm" +
"yX316zOBhzGRYjKbutTYwKBgQCm7phr9XdFW5Vh+XR90mVs483nrLmMiDKg7YKxSLJ8amiDjzPejCn7i9" +
"5Hah08P+2MIZLIPbh2VLacczR6ltRRzN5bg5etFuqSgfkuHyxpoDmpjbe08+Q2h8JBYqcC5Nhv1AKU4iOU" +
"hVLHo/FBAQliMcGc/J3eiYTFC7EsNx382QKBgClb20doe7cttgFTXswBvaUmfFm45kmla924B7SpvrQpDD" +
"/f+VDtDZRp05fGmxuduSjYdtA3aVtpLiTwWu22OUUvZZqHDGruYOO4Hvdz23mL5b4ayqImCwoNU4bAZIc9v1" +
"8p/UNf3/55NNE3oGcf/bev9rH2OjCQ4nM+Ktwhg8CFAoGACSgvbkShzUkv0ZcIf9ppu+ZnJh1AdGgINvGwaJ" +
"8vQ0nm/8h8NOoFZ4oNoGc+wU5Ubops7dUM6FjPR5e+OjdJ4E7Xp7d5O4J1TaIZlCEbo5OpdhaTDDcQvrkFu+Z4e" +
"N0qzj+YAKjDAOOrXc4tbr5q0FsgXscwtcNfaBuzFVTUrUkCgYEAwzPnMNhWG3zOWLUs2QFA2GP4Y+J8cpUYfj6p" +
"bKKzeLwyG9qBwF1NJpN8m+q9q7V9P2LY+9Lp9e1mGsGeqt5HMEA3P6vIpcqLJLqE/4PBLLRzfccTcmqb1m71+erx" +
"TRhHBRkGS+I7dZEb3olQfnS1Y1tpMBxiwYwR3LW4oXuJwj8=")
.setAlipayPublicKey("MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAnq90KnF4dTnlzzmxpujbI05OYqi5WxAS6cL0" +
"gnZFv2gK51HExF8v/BaP7P979PhFMgWTqmOOI+Dtno5s+yD09XTY1WkshbLk6i4g2Xlr8fyW9ODnkU88RI2w9UdPhQU4cPPwBN" +
"lrsYhKkVK2OxwM3kFqjoBBY0CZoZCsSQ3LDH5WeZqPArlsS6xa2zqJBuuoKjMrdpELl3eXSjP8K54eDJCbeetCZNKWLL3DPahTPB7LZ" +
"ikfYmslb0QUvCgGapD0xkS7eVq70NaL1G57MWABs4tbfWgxike4Daj3EfUrzIVspQxj7w8HEj9WozJPgL88kSJSits0pqD3n5r8HSuseQIDAQAB");
@InjectMocks @InjectMocks
AlipayQrPayClient client = new AlipayQrPayClient(10L,config); AlipayQrPayClient client = new AlipayQrPayClient(randomLongId(), config);
@Mock @Mock
private DefaultAlipayClient defaultAlipayClient; private DefaultAlipayClient defaultAlipayClient;
@Test @Test
public void testDoInit(){ public void test_do_init() {
client.doInit(); client.doInit();
assertNotSame(defaultAlipayClient, ReflectUtil.getFieldValue(client, "defaultAlipayClient")); assertNotSame(defaultAlipayClient, ReflectUtil.getFieldValue(client, "defaultAlipayClient"));
} }
@Test @Test
@Disabled // TODO 芋艿临时禁用 @DisplayName("支付包扫描支付下单成功")
public void create() throws AlipayApiException { public void test_unified_order_success() throws AlipayApiException {
// TODO @tina参数可以尽量随机一点使用随机方法这样的好处是避免对固定参数的依赖导致可能仅仅满足固定参数的结果 // 准备返回对象
// 这里设置可以直接随机整个对象 String notifyUrl = randomURL();
Long shopOrderId = System.currentTimeMillis(); String qrCode = randomString();
PayOrderUnifiedReqDTO reqDTO=new PayOrderUnifiedReqDTO(); AlipayTradePrecreateResponse response = randomPojo(AlipayTradePrecreateResponse.class, o -> {
reqDTO.setOutTradeNo(String.valueOf(System.currentTimeMillis())); o.setQrCode(qrCode);
reqDTO.setPrice(1); o.setSubCode("");
reqDTO.setBody("内容:" + shopOrderId); });
reqDTO.setSubject("标题:"+shopOrderId); // mock
String notify="http://niubi.natapp1.cc/api/pay/order/notify"; when(defaultAlipayClient.execute(argThat((ArgumentMatcher<AlipayTradePrecreateRequest>) request -> {
reqDTO.setNotifyUrl(notify); assertEquals(notifyUrl, request.getNotifyUrl());
AlipayTradePrecreateResponse response=randomPojo(AlipayTradePrecreateResponse.class,o->o.setQrCode("success"));
when(defaultAlipayClient.execute(argThat((ArgumentMatcher<AlipayTradePrecreateRequest>) request ->{
assertEquals(notify,request.getNotifyUrl());
return true; return true;
}))).thenReturn(response); }))).thenReturn(response);
// 准备请求参数
String outTradeNo = randomString();
PayOrderUnifiedReqDTO reqDTO = buildOrderUnifiedReqDTO(notifyUrl, outTradeNo);
PayOrderRespDTO resp = client.unifiedOrder(reqDTO);
// 断言
assertEquals(WAITING.getStatus(), resp.getStatus());
assertEquals(PayOrderDisplayModeEnum.QR_CODE.getMode(), resp.getDisplayMode());
assertEquals(outTradeNo, resp.getOutTradeNo());
assertEquals(qrCode, resp.getDisplayContent());
assertSame(response, resp.getRawData());
}
// PayCommonResult<PayOrderUnifiedRespDTO> result = client.doUnifiedOrder(reqDTO); @Test
// // 断言 @DisplayName("支付包扫描支付,渠道返回失败")
// assertEquals(response.getCode(), result.getApiCode()); public void test_unified_order_channel_failed() throws AlipayApiException {
// assertEquals(response.getMsg(), result.getApiMsg()); String notifyUrl = randomURL();
// // TODO @tina这个断言木有过 String subCode = randomString();
// assertEquals(GlobalErrorCodeConstants.SUCCESS.getCode(), result.getCode()); String subMsg = randomString();
// assertEquals(GlobalErrorCodeConstants.SUCCESS.getMsg(), result.getMsg()); AlipayTradePrecreateResponse response = randomPojo(AlipayTradePrecreateResponse.class, o -> {
o.setSubCode(subCode);
o.setSubMsg(subMsg);
});
// mock
when(defaultAlipayClient.execute(argThat((ArgumentMatcher<AlipayTradePrecreateRequest>) request -> {
assertEquals(notifyUrl, request.getNotifyUrl());
return true;
}))).thenReturn(response);
// 准备请求参数
String outTradeNo = randomString();
PayOrderUnifiedReqDTO reqDTO = buildOrderUnifiedReqDTO(notifyUrl, outTradeNo);
PayOrderRespDTO resp = client.unifiedOrder(reqDTO);
// 断言
assertEquals(CLOSED.getStatus(), resp.getStatus());
assertEquals(subCode, resp.getChannelErrorCode());
assertEquals(subMsg, resp.getChannelErrorMsg());
assertSame(response, resp.getRawData());
}
@Test
@DisplayName("支付包扫描支付,抛出系统异常")
public void test_unified_order_throw_pay_exception() throws AlipayApiException {
// 准备请求参数
String outTradeNo = randomString();
String notifyUrl = randomURL();
// mock
when(defaultAlipayClient.execute(argThat((ArgumentMatcher<AlipayTradePrecreateRequest>) request -> {
assertEquals(notifyUrl, request.getNotifyUrl());
return true;
}))).thenThrow(new RuntimeException("系统异常"));
// 准备请求参数
PayOrderUnifiedReqDTO reqDTO = buildOrderUnifiedReqDTO(notifyUrl, outTradeNo);
// 断言
assertThrows(PayException.class, () -> client.unifiedOrder(reqDTO));
}
@Test
@DisplayName("支付包扫描支付,抛出业务异常")
public void test_unified_order_throw_service_exception() throws AlipayApiException {
// 准备请求参数
String outTradeNo = randomString();
String notifyUrl = randomURL();
// mock
when(defaultAlipayClient.execute(argThat((ArgumentMatcher<AlipayTradePrecreateRequest>) request -> {
assertEquals(notifyUrl, request.getNotifyUrl());
return true;
}))).thenThrow(ServiceExceptionUtil.exception(GlobalErrorCodeConstants.INTERNAL_SERVER_ERROR));
// 准备请求参数
PayOrderUnifiedReqDTO reqDTO = buildOrderUnifiedReqDTO(notifyUrl, outTradeNo);
// 断言
assertThrows(ServiceException.class, () -> client.unifiedOrder(reqDTO));
}
@Test
@DisplayName("支付包扫描支付,参数校验不通过")
public void test_unified_order_param_validate() {
// 准备请求参数
String outTradeNo = randomString();
String notifyUrl = randomURL();
PayOrderUnifiedReqDTO reqDTO = randomPojo(PayOrderUnifiedReqDTO.class, o -> {
o.setOutTradeNo(outTradeNo);
o.setNotifyUrl(notifyUrl);
});
// 断言
assertThrows(ConstraintViolationException.class, () -> client.unifiedOrder(reqDTO));
}
private PayOrderUnifiedReqDTO buildOrderUnifiedReqDTO(String notifyUrl, String outTradeNo) {
return randomPojo(PayOrderUnifiedReqDTO.class, o -> {
o.setOutTradeNo(outTradeNo);
o.setNotifyUrl(notifyUrl);
o.setSubject(RandomUtil.randomString(32));
o.setBody(RandomUtil.randomString(32));
});
}
@Test
@DisplayName("支付包扫描退款成功")
public void test_unified_refund_success() throws AlipayApiException {
// 准备返回对象
String notifyUrl = randomURL();
Date refundTime = randomDate();
String outRefundNo = randomString();
String outTradeNo = randomString();
Integer refundAmount = randomInteger();
AlipayTradeRefundResponse response = randomPojo(AlipayTradeRefundResponse.class, o -> {
o.setSubCode("");
o.setGmtRefundPay(refundTime);
});
// mock
when(defaultAlipayClient.execute(argThat((ArgumentMatcher<AlipayTradeRefundRequest>) request -> {
assertInstanceOf(AlipayTradeRefundModel.class, request.getBizModel());
AlipayTradeRefundModel bizModel = (AlipayTradeRefundModel) request.getBizModel();
assertEquals(outRefundNo, bizModel.getOutRequestNo());
assertEquals(outTradeNo, bizModel.getOutTradeNo());
assertEquals(String.valueOf(refundAmount / 100.0), bizModel.getRefundAmount());
return true;
}))).thenReturn(response);
// 准备请求参数
PayRefundUnifiedReqDTO refundReqDTO = randomPojo(PayRefundUnifiedReqDTO.class, o -> {
o.setOutRefundNo(outRefundNo);
o.setOutTradeNo(outTradeNo);
o.setNotifyUrl(notifyUrl);
o.setRefundPrice(refundAmount);
});
PayRefundRespDTO resp = client.unifiedRefund(refundReqDTO);
// 断言
assertEquals(PayRefundStatusRespEnum.SUCCESS.getStatus(), resp.getStatus());
assertNull(resp.getChannelRefundNo());
assertEquals(LocalDateTimeUtil.of(refundTime), resp.getSuccessTime());
assertEquals(outRefundNo, resp.getOutRefundNo());
assertSame(response, resp.getRawData());
}
@Test
@DisplayName("支付包扫描退款,渠道返回失败")
public void test_unified_refund_channel_failed() throws AlipayApiException {
// 准备返回对象
String notifyUrl = randomURL();
String subCode = randomString();
String subMsg = randomString();
AlipayTradeRefundResponse response = randomPojo(AlipayTradeRefundResponse.class, o -> {
o.setSubCode(subCode);
o.setSubMsg(subMsg);
});
// mock
when(defaultAlipayClient.execute(argThat((ArgumentMatcher<AlipayTradeRefundRequest>) request -> {
assertInstanceOf(AlipayTradeRefundModel.class, request.getBizModel());
return true;
}))).thenReturn(response);
// 准备请求参数
String outRefundNo = randomString();
String outTradeNo = randomString();
PayRefundUnifiedReqDTO refundReqDTO = randomPojo(PayRefundUnifiedReqDTO.class, o -> {
o.setOutRefundNo(outRefundNo);
o.setOutTradeNo(outTradeNo);
o.setNotifyUrl(notifyUrl);
});
PayRefundRespDTO resp = client.unifiedRefund(refundReqDTO);
// 断言
assertEquals(PayRefundStatusRespEnum.FAILURE.getStatus(), resp.getStatus());
assertNull(resp.getChannelRefundNo());
assertEquals(subCode, resp.getChannelErrorCode());
assertEquals(subMsg, resp.getChannelErrorMsg());
assertNull(resp.getSuccessTime());
assertEquals(outRefundNo, resp.getOutRefundNo());
assertSame(response, resp.getRawData());
}
@Test
@DisplayName("支付包扫描退款,参数校验不通过")
public void test_unified_refund_param_validate() {
// 准备请求参数
String notifyUrl = randomURL();
PayRefundUnifiedReqDTO refundReqDTO = randomPojo(PayRefundUnifiedReqDTO.class, o -> {
o.setOutTradeNo("");
o.setNotifyUrl(notifyUrl);
});
// 断言
assertThrows(ConstraintViolationException.class, () -> client.unifiedRefund(refundReqDTO));
}
@Test
@DisplayName("支付包扫描退款,抛出业务异常")
public void test_unified_refund_throw_service_exception() throws AlipayApiException {
// mock
when(defaultAlipayClient.execute(argThat((ArgumentMatcher<AlipayTradeRefundRequest>) request -> true)))
.thenThrow(ServiceExceptionUtil.exception(GlobalErrorCodeConstants.INTERNAL_SERVER_ERROR));
// 准备请求参数
String notifyUrl = randomURL();
PayRefundUnifiedReqDTO refundReqDTO = randomPojo(PayRefundUnifiedReqDTO.class, o -> {
o.setNotifyUrl(notifyUrl);
});
// 断言
assertThrows(ServiceException.class, () -> client.unifiedRefund(refundReqDTO));
}
@Test
@DisplayName("支付包扫描退款,抛出系统异常")
public void test_unified_refund_throw_pay_exception() throws AlipayApiException {
// mock
when(defaultAlipayClient.execute(argThat((ArgumentMatcher<AlipayTradeRefundRequest>) request -> true)))
.thenThrow(new RuntimeException("系统异常"));
// 准备请求参数
String notifyUrl = randomURL();
PayRefundUnifiedReqDTO refundReqDTO = randomPojo(PayRefundUnifiedReqDTO.class, o -> {
o.setNotifyUrl(notifyUrl);
});
// 断言
assertThrows(PayException.class, () -> client.unifiedRefund(refundReqDTO));
} }
} }

View File

@ -44,6 +44,12 @@ public interface BaseMapperX<T> extends BaseMapper<T> {
return selectOne(new LambdaQueryWrapper<T>().eq(field1, value1).eq(field2, value2)); return selectOne(new LambdaQueryWrapper<T>().eq(field1, value1).eq(field2, value2));
} }
default T selectOne(SFunction<T, ?> field1, Object value1, SFunction<T, ?> field2, Object value2,
SFunction<T, ?> field3, Object value3) {
return selectOne(new LambdaQueryWrapper<T>().eq(field1, value1).eq(field2, value2)
.eq(field3, value3));
}
default Long selectCount() { default Long selectCount() {
return selectCount(new QueryWrapper<T>()); return selectCount(new QueryWrapper<T>());
} }

View File

@ -1,7 +1,6 @@
package cn.iocoder.yudao.framework.jackson.core.databind; package cn.iocoder.yudao.framework.jackson.core.databind;
import com.fasterxml.jackson.core.JsonParser; import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.DeserializationContext; import com.fasterxml.jackson.databind.DeserializationContext;
import com.fasterxml.jackson.databind.JsonDeserializer; import com.fasterxml.jackson.databind.JsonDeserializer;
@ -20,7 +19,7 @@ public class LocalDateTimeDeserializer extends JsonDeserializer<LocalDateTime> {
public static final LocalDateTimeDeserializer INSTANCE = new LocalDateTimeDeserializer(); public static final LocalDateTimeDeserializer INSTANCE = new LocalDateTimeDeserializer();
@Override @Override
public LocalDateTime deserialize(JsonParser p, DeserializationContext ctxt) throws IOException, JsonProcessingException { public LocalDateTime deserialize(JsonParser p, DeserializationContext ctxt) throws IOException {
return LocalDateTime.ofInstant(Instant.ofEpochMilli(p.getValueAsLong()), ZoneId.systemDefault()); return LocalDateTime.ofInstant(Instant.ofEpochMilli(p.getValueAsLong()), ZoneId.systemDefault());
} }
} }

View File

@ -1,21 +0,0 @@
package cn.iocoder.yudao.framework.jackson.core.databind;
import com.fasterxml.jackson.datatype.jsr310.deser.LocalTimeDeserializer;
import com.fasterxml.jackson.datatype.jsr310.ser.LocalTimeSerializer;
import java.time.ZoneId;
import java.time.format.DateTimeFormatter;
import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_HOUR_MINUTE_SECOND;
public class LocalTimeJson {
public static final LocalTimeSerializer SERIALIZER = new LocalTimeSerializer(DateTimeFormatter
.ofPattern(FORMAT_HOUR_MINUTE_SECOND)
.withZone(ZoneId.systemDefault()));
public static final LocalTimeDeserializer DESERIALIZABLE = new LocalTimeDeserializer(DateTimeFormatter
.ofPattern(FORMAT_HOUR_MINUTE_SECOND)
.withZone(ZoneId.systemDefault()));
}

View File

@ -0,0 +1,38 @@
package cn.iocoder.yudao.module.infra.controller.app.file;
import cn.hutool.core.io.IoUtil;
import cn.iocoder.yudao.framework.common.pojo.CommonResult;
import cn.iocoder.yudao.module.infra.controller.app.file.vo.AppFileUploadReqVO;
import cn.iocoder.yudao.module.infra.service.file.FileService;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.extern.slf4j.Slf4j;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;
import javax.annotation.Resource;
import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
@Tag(name = "用户 App - 文件存储")
@RestController
@RequestMapping("/infra/file")
@Validated
@Slf4j
public class AppFileController {
@Resource
private FileService fileService;
@PostMapping("/upload")
@Operation(summary = "上传文件")
public CommonResult<String> uploadFile(AppFileUploadReqVO uploadReqVO) throws Exception {
MultipartFile file = uploadReqVO.getFile();
String path = uploadReqVO.getPath();
return success(fileService.createFile(file.getOriginalFilename(), path, IoUtil.readBytes(file.getInputStream())));
}
}

View File

@ -0,0 +1,20 @@
package cn.iocoder.yudao.module.infra.controller.app.file.vo;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import org.springframework.web.multipart.MultipartFile;
import javax.validation.constraints.NotNull;
@Schema(description = "用户 App - 上传文件 Request VO")
@Data
public class AppFileUploadReqVO {
@Schema(description = "文件附件", requiredMode = Schema.RequiredMode.REQUIRED)
@NotNull(message = "文件附件不能为空")
private MultipartFile file;
@Schema(description = "文件附件", example = "yudaoyuanma.png")
private String path;
}

View File

@ -120,7 +120,6 @@
<!-- 列表 --> <!-- 列表 -->
<ContentWrap> <ContentWrap>
<el-table v-loading="loading" :data="list" :stripe="true" :show-overflow-tooltip="true"> <el-table v-loading="loading" :data="list" :stripe="true" :show-overflow-tooltip="true">
<el-table-column label="序号" type="index" width="70px" />
#foreach($column in $columns) #foreach($column in $columns)
#if ($column.listOperationResult) #if ($column.listOperationResult)
#set ($dictType=$column.dictType) #set ($dictType=$column.dictType)
@ -142,7 +141,7 @@
</template> </template>
</el-table-column> </el-table-column>
#else #else
<el-table-column label="${comment}" align="center" prop="${javaField}" width="150px"/> <el-table-column label="${comment}" align="center" prop="${javaField}" width="150px" />
#end #end
#end #end
#end #end
@ -180,7 +179,7 @@
<${simpleClassName}Form ref="formRef" @success="getList" /> <${simpleClassName}Form ref="formRef" @success="getList" />
</template> </template>
<script setup lang="ts" name="${table.className}"> <script setup lang="ts">
#if ($dictMethods.size() > 0) #if ($dictMethods.size() > 0)
import { DICT_TYPE#foreach ($dictMethod in $dictMethods), ${dictMethod}#end } from '@/utils/dict' import { DICT_TYPE#foreach ($dictMethod in $dictMethods), ${dictMethod}#end } from '@/utils/dict'
#end #end
@ -193,6 +192,9 @@ import { dateFormatter } from '@/utils/formatTime'
import download from '@/utils/download' import download from '@/utils/download'
import * as ${simpleClassName}Api from '@/api/${table.moduleName}/${classNameVar}' import * as ${simpleClassName}Api from '@/api/${table.moduleName}/${classNameVar}'
import ${simpleClassName}Form from './${simpleClassName}Form.vue' import ${simpleClassName}Form from './${simpleClassName}Form.vue'
defineOptions({ name: '${table.className}' })
const message = useMessage() // 消息弹窗 const message = useMessage() // 消息弹窗
const { t } = useI18n() // 国际化 const { t } = useI18n() // 国际化

View File

@ -21,4 +21,11 @@ public interface ProductSpuApi {
*/ */
List<ProductSpuRespDTO> getSpuList(Collection<Long> ids); List<ProductSpuRespDTO> getSpuList(Collection<Long> ids);
/**
* 获得 SPU
*
* @return SPU
*/
ProductSpuRespDTO getSpu(Long id);
} }

View File

@ -5,6 +5,8 @@ import cn.iocoder.yudao.module.product.api.spu.dto.ProductSpuRespDTO;
import cn.iocoder.yudao.module.product.convert.spu.ProductSpuConvert; import cn.iocoder.yudao.module.product.convert.spu.ProductSpuConvert;
import cn.iocoder.yudao.module.product.dal.dataobject.spu.ProductSpuDO; import cn.iocoder.yudao.module.product.dal.dataobject.spu.ProductSpuDO;
import cn.iocoder.yudao.module.product.dal.mysql.spu.ProductSpuMapper; import cn.iocoder.yudao.module.product.dal.mysql.spu.ProductSpuMapper;
import cn.iocoder.yudao.module.product.service.sku.ProductSkuService;
import cn.iocoder.yudao.module.product.service.spu.ProductSpuService;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import org.springframework.validation.annotation.Validated; import org.springframework.validation.annotation.Validated;
@ -24,15 +26,19 @@ import java.util.List;
public class ProductSpuApiImpl implements ProductSpuApi { public class ProductSpuApiImpl implements ProductSpuApi {
@Resource @Resource
private ProductSpuMapper productSpuMapper; private ProductSpuService spuService;
@Override @Override
public List<ProductSpuRespDTO> getSpuList(Collection<Long> spuIds) { public List<ProductSpuRespDTO> getSpuList(Collection<Long> ids) {
if (CollectionUtil.isEmpty(spuIds)) { if (CollectionUtil.isEmpty(ids)) {
return Collections.emptyList(); return Collections.emptyList();
} }
List<ProductSpuDO> productSpuDOList = productSpuMapper.selectBatchIds(spuIds); return ProductSpuConvert.INSTANCE.convertList2(spuService.getSpuList(ids));
return ProductSpuConvert.INSTANCE.convertList2(productSpuDOList); }
@Override
public ProductSpuRespDTO getSpu(Long id) {
return ProductSpuConvert.INSTANCE.convert02(spuService.getSpu(id));
} }
} }

View File

@ -3,16 +3,13 @@ package cn.iocoder.yudao.module.product.controller.app.comment;
import cn.hutool.core.collection.CollUtil; import cn.hutool.core.collection.CollUtil;
import cn.iocoder.yudao.framework.common.pojo.CommonResult; import cn.iocoder.yudao.framework.common.pojo.CommonResult;
import cn.iocoder.yudao.framework.common.pojo.PageResult; import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils;
import cn.iocoder.yudao.module.product.controller.app.comment.vo.AppCommentPageReqVO; import cn.iocoder.yudao.module.product.controller.app.comment.vo.AppCommentPageReqVO;
import cn.iocoder.yudao.module.product.controller.app.comment.vo.AppCommentStatisticsRespVO; import cn.iocoder.yudao.module.product.controller.app.comment.vo.AppCommentStatisticsRespVO;
import cn.iocoder.yudao.module.product.controller.app.comment.vo.AppProductCommentRespVO; import cn.iocoder.yudao.module.product.controller.app.comment.vo.AppProductCommentRespVO;
import cn.iocoder.yudao.module.product.convert.comment.ProductCommentConvert; import cn.iocoder.yudao.module.product.convert.comment.ProductCommentConvert;
import cn.iocoder.yudao.module.product.dal.dataobject.comment.ProductCommentDO; import cn.iocoder.yudao.module.product.dal.dataobject.comment.ProductCommentDO;
import cn.iocoder.yudao.module.product.dal.dataobject.sku.ProductSkuDO;
import cn.iocoder.yudao.module.product.service.comment.ProductCommentService; import cn.iocoder.yudao.module.product.service.comment.ProductCommentService;
import cn.iocoder.yudao.module.product.service.sku.ProductSkuService; import cn.iocoder.yudao.module.product.service.sku.ProductSkuService;
import com.google.common.collect.Maps;
import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter; import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.Parameters; import io.swagger.v3.oas.annotations.Parameters;
@ -27,10 +24,10 @@ import org.springframework.web.bind.annotation.RestController;
import javax.annotation.Resource; import javax.annotation.Resource;
import javax.validation.Valid; import javax.validation.Valid;
import java.util.List; import java.util.List;
import java.util.Map;
import java.util.Set; import java.util.Set;
import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet;
@Tag(name = "用户 APP - 商品评价") @Tag(name = "用户 APP - 商品评价")
@RestController @RestController
@ -60,16 +57,17 @@ public class AppProductCommentController {
@GetMapping("/page") @GetMapping("/page")
@Operation(summary = "获得商品评价分页") @Operation(summary = "获得商品评价分页")
public CommonResult<PageResult<AppProductCommentRespVO>> getCommentPage(@Valid AppCommentPageReqVO pageVO) { public CommonResult<PageResult<AppProductCommentRespVO>> getCommentPage(@Valid AppCommentPageReqVO pageVO) {
// TODO @puhui999写到 convert 可以更简洁哈 // 查询评论分页
PageResult<ProductCommentDO> commentDOPage = productCommentService.getCommentPage(pageVO, Boolean.TRUE); PageResult<ProductCommentDO> commentPageResult = productCommentService.getCommentPage(pageVO, Boolean.TRUE);
Set<Long> skuIds = CollectionUtils.convertSet(commentDOPage.getList(), ProductCommentDO::getSkuId); if (CollUtil.isEmpty(commentPageResult.getList())) {
List<ProductSkuDO> skuList = productSkuService.getSkuList(skuIds); return success(PageResult.empty(commentPageResult.getTotal()));
Map<Long, ProductSkuDO> skuDOMap = Maps.newLinkedHashMapWithExpectedSize(skuIds.size());
if (CollUtil.isNotEmpty(skuList)) {
skuDOMap.putAll(CollectionUtils.convertMap(skuList, ProductSkuDO::getId, c -> c));
} }
PageResult<AppProductCommentRespVO> page = ProductCommentConvert.INSTANCE.convertPage02(commentDOPage, skuDOMap);
return success(page); // 拼接返回
Set<Long> skuIds = convertSet(commentPageResult.getList(), ProductCommentDO::getSkuId);
PageResult<AppProductCommentRespVO> commentVOPageResult = ProductCommentConvert.INSTANCE.convertPage02(
commentPageResult, productSkuService.getSkuList(skuIds));
return success(commentVOPageResult);
} }
// TODO 芋艿需要搞下 // TODO 芋艿需要搞下

View File

@ -20,7 +20,6 @@ import org.springframework.web.bind.annotation.*;
import javax.annotation.Resource; import javax.annotation.Resource;
import javax.validation.Valid; import javax.validation.Valid;
import java.util.List; import java.util.List;
import java.util.Objects;
import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertList; import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertList;
@ -84,8 +83,15 @@ public class AppFavoriteController {
@Operation(summary = "检查是否收藏过商品") @Operation(summary = "检查是否收藏过商品")
@PreAuthenticated @PreAuthenticated
public CommonResult<Boolean> isFavoriteExists(AppFavoriteReqVO reqVO) { public CommonResult<Boolean> isFavoriteExists(AppFavoriteReqVO reqVO) {
ProductFavoriteDO favoriteDO = productFavoriteService.getFavorite(getLoginUserId(), reqVO.getSpuId()); ProductFavoriteDO favorite = productFavoriteService.getFavorite(getLoginUserId(), reqVO.getSpuId());
return success(Objects.nonNull(favoriteDO)); return success(favorite != null);
}
@GetMapping(value = "/get-count")
@Operation(summary = "获得商品收藏数量")
@PreAuthenticated
public CommonResult<Long> getFavoriteCount() {
return success(productFavoriteService.getFavoriteCount(getLoginUserId()));
} }
} }

View File

@ -2,6 +2,7 @@ package cn.iocoder.yudao.module.product.convert.comment;
import cn.hutool.core.util.ObjectUtil; import cn.hutool.core.util.ObjectUtil;
import cn.iocoder.yudao.framework.common.pojo.PageResult; import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils;
import cn.iocoder.yudao.framework.common.util.collection.MapUtils; import cn.iocoder.yudao.framework.common.util.collection.MapUtils;
import cn.iocoder.yudao.module.member.api.user.dto.MemberUserRespDTO; import cn.iocoder.yudao.module.member.api.user.dto.MemberUserRespDTO;
import cn.iocoder.yudao.module.product.api.comment.dto.ProductCommentCreateReqDTO; import cn.iocoder.yudao.module.product.api.comment.dto.ProductCommentCreateReqDTO;
@ -37,6 +38,7 @@ public interface ProductCommentConvert {
@Mapping(target = "scores", expression = "java(calculateOverallScore(goodCount, mediocreCount, negativeCount))") @Mapping(target = "scores", expression = "java(calculateOverallScore(goodCount, mediocreCount, negativeCount))")
AppCommentStatisticsRespVO convert(Long goodCount, Long mediocreCount, Long negativeCount); AppCommentStatisticsRespVO convert(Long goodCount, Long mediocreCount, Long negativeCount);
@Named("calculateOverallScore") @Named("calculateOverallScore")
default double calculateOverallScore(long goodCount, long mediocreCount, long negativeCount) { default double calculateOverallScore(long goodCount, long mediocreCount, long negativeCount) {
return (goodCount * 5 + mediocreCount * 3 + negativeCount) / (double) (goodCount + mediocreCount + negativeCount); return (goodCount * 5 + mediocreCount * 3 + negativeCount) / (double) (goodCount + mediocreCount + negativeCount);
@ -49,18 +51,21 @@ public interface ProductCommentConvert {
PageResult<AppProductCommentRespVO> convertPage01(PageResult<ProductCommentDO> pageResult); PageResult<AppProductCommentRespVO> convertPage01(PageResult<ProductCommentDO> pageResult);
default PageResult<AppProductCommentRespVO> convertPage02(PageResult<ProductCommentDO> pageResult, default PageResult<AppProductCommentRespVO> convertPage02(PageResult<ProductCommentDO> pageResult,
Map<Long, ProductSkuDO> skuMap) { List<ProductSkuDO> skuList) {
Map<Long, ProductSkuDO> skuMap = CollectionUtils.convertMap(skuList, ProductSkuDO::getId);
PageResult<AppProductCommentRespVO> page = convertPage01(pageResult); PageResult<AppProductCommentRespVO> page = convertPage01(pageResult);
page.getList().forEach(item -> { page.getList().forEach(item -> {
// 判断用户是否选择匿名 // 判断用户是否选择匿名
if (ObjectUtil.equal(item.getAnonymous(), true)) { if (ObjectUtil.equal(item.getAnonymous(), true)) {
item.setUserNickname(ProductCommentDO.NICKNAME_ANONYMOUS); item.setUserNickname(ProductCommentDO.NICKNAME_ANONYMOUS);
} }
// 设置 SKU 规格值
MapUtils.findAndThen(skuMap, item.getSkuId(), MapUtils.findAndThen(skuMap, item.getSkuId(),
sku -> item.setSkuProperties(convertList01(sku.getProperties()))); sku -> item.setSkuProperties(convertList01(sku.getProperties())));
}); });
return page; return page;
} }
List<AppProductPropertyValueDetailRespVO> convertList01(List<ProductSkuDO.Property> properties); List<AppProductPropertyValueDetailRespVO> convertList01(List<ProductSkuDO.Property> properties);
/** /**

View File

@ -1,6 +1,7 @@
package cn.iocoder.yudao.module.product.convert.spu; package cn.iocoder.yudao.module.product.convert.spu;
import cn.iocoder.yudao.framework.common.pojo.PageResult; import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils;
import cn.iocoder.yudao.framework.dict.core.util.DictFrameworkUtils; import cn.iocoder.yudao.framework.dict.core.util.DictFrameworkUtils;
import cn.iocoder.yudao.module.product.api.spu.dto.ProductSpuRespDTO; import cn.iocoder.yudao.module.product.api.spu.dto.ProductSpuRespDTO;
import cn.iocoder.yudao.module.product.controller.admin.spu.vo.*; import cn.iocoder.yudao.module.product.controller.admin.spu.vo.*;
@ -63,6 +64,8 @@ public interface ProductSpuConvert {
ProductSpuDetailRespVO convert03(ProductSpuDO spu); ProductSpuDetailRespVO convert03(ProductSpuDO spu);
ProductSpuRespDTO convert02(ProductSpuDO bean);
// ========== 用户 App 相关 ========== // ========== 用户 App 相关 ==========
PageResult<AppProductSpuPageRespVO> convertPageForGetSpuPage(PageResult<ProductSpuDO> page); PageResult<AppProductSpuPageRespVO> convertPageForGetSpuPage(PageResult<ProductSpuDO> page);
@ -81,6 +84,7 @@ public interface ProductSpuConvert {
} }
return voList; return voList;
} }
@Named("convertListForGetSpuList0") @Named("convertListForGetSpuList0")
List<AppProductSpuPageRespVO> convertListForGetSpuList0(List<ProductSpuDO> list); List<AppProductSpuPageRespVO> convertListForGetSpuList0(List<ProductSpuDO> list);
@ -110,15 +114,9 @@ public interface ProductSpuConvert {
} }
default List<ProductSpuDetailRespVO> convertForSpuDetailRespListVO(List<ProductSpuDO> spus, List<ProductSkuDO> skus) { default List<ProductSpuDetailRespVO> convertForSpuDetailRespListVO(List<ProductSpuDO> spus, List<ProductSkuDO> skus) {
List<ProductSpuDetailRespVO> vos = new ArrayList<>(spus.size());
Map<Long, List<ProductSkuDO>> skuMultiMap = convertMultiMap(skus, ProductSkuDO::getSpuId); Map<Long, List<ProductSkuDO>> skuMultiMap = convertMultiMap(skus, ProductSkuDO::getSpuId);
// TODO @puhui999可以直接使用 CollUtils.convertList return CollectionUtils.convertList(spus, spu -> convert03(spu)
spus.forEach(spu -> { .setSkus(ProductSkuConvert.INSTANCE.convertList(skuMultiMap.get(spu.getId()))));
ProductSpuDetailRespVO detailRespVO = convert03(spu);
detailRespVO.setSkus(ProductSkuConvert.INSTANCE.convertList(skuMultiMap.get(spu.getId())));
vos.add(detailRespVO);
});
return vos;
} }
} }

View File

@ -26,18 +26,19 @@ public interface ProductCommentMapper extends BaseMapperX<ProductCommentDO> {
} }
static void appendTabQuery(LambdaQueryWrapperX<ProductCommentDO> queryWrapper, Integer type) { static void appendTabQuery(LambdaQueryWrapperX<ProductCommentDO> queryWrapper, Integer type) {
// TODO @puhui999是不是不用 apply 直接用 mybatis 的方法就好啦 LambdaQueryWrapperX<ProductCommentDO> queryWrapperX = new LambdaQueryWrapperX<>();
// 构建好评查询语句好评计算 总评 >= 4 // 构建好评查询语句好评计算 总评 >= 4
if (ObjectUtil.equal(type, AppCommentPageReqVO.GOOD_COMMENT)) { if (ObjectUtil.equal(type, AppCommentPageReqVO.GOOD_COMMENT)) {
queryWrapper.apply("scores >= 4"); queryWrapperX.ge(ProductCommentDO::getScores, 4);
} }
// 构建中评查询语句中评计算 总评 >= 3 总评 < 4 // 构建中评查询语句中评计算 总评 >= 3 总评 < 4
if (ObjectUtil.equal(type, AppCommentPageReqVO.MEDIOCRE_COMMENT)) { if (ObjectUtil.equal(type, AppCommentPageReqVO.MEDIOCRE_COMMENT)) {
queryWrapper.apply("scores >=3 and scores < 4"); queryWrapperX.ge(ProductCommentDO::getScores, 3);
queryWrapperX.lt(ProductCommentDO::getScores, 4);
} }
// 构建差评查询语句差评计算 总评 < 3 // 构建差评查询语句差评计算 总评 < 3
if (ObjectUtil.equal(type, AppCommentPageReqVO.NEGATIVE_COMMENT)) { if (ObjectUtil.equal(type, AppCommentPageReqVO.NEGATIVE_COMMENT)) {
queryWrapper.apply("scores < 3"); queryWrapperX.lt(ProductCommentDO::getScores, 3);
} }
} }

View File

@ -21,4 +21,8 @@ public interface ProductFavoriteMapper extends BaseMapperX<ProductFavoriteDO> {
.orderByDesc(ProductFavoriteDO::getId)); .orderByDesc(ProductFavoriteDO::getId));
} }
default Long selectCountByUserId(Long userId) {
return selectCount(ProductFavoriteDO::getUserId, userId);
}
} }

View File

@ -16,7 +16,7 @@ public interface ProductFavoriteService {
/** /**
* 创建商品收藏 * 创建商品收藏
* *
* @param userId 用户 id * @param userId 用户编号
* @param spuId SPU 编号 * @param spuId SPU 编号
*/ */
Long createFavorite(Long userId, Long spuId); Long createFavorite(Long userId, Long spuId);
@ -24,7 +24,7 @@ public interface ProductFavoriteService {
/** /**
* 取消商品收藏 * 取消商品收藏
* *
* @param userId 用户 id * @param userId 用户编号
* @param spuId SPU 编号 * @param spuId SPU 编号
*/ */
void deleteFavorite(Long userId, Long spuId); void deleteFavorite(Long userId, Long spuId);
@ -32,7 +32,7 @@ public interface ProductFavoriteService {
/** /**
* 分页查询用户收藏列表 * 分页查询用户收藏列表
* *
* @param userId 用户 id * @param userId 用户编号
* @param reqVO 请求 vo * @param reqVO 请求 vo
*/ */
PageResult<ProductFavoriteDO> getFavoritePage(Long userId, @Valid AppFavoritePageReqVO reqVO); PageResult<ProductFavoriteDO> getFavoritePage(Long userId, @Valid AppFavoritePageReqVO reqVO);
@ -40,9 +40,17 @@ public interface ProductFavoriteService {
/** /**
* 获取收藏过商品 * 获取收藏过商品
* *
* @param userId 用户id * @param userId 用户编号
* @param spuId SPU 编号 * @param spuId SPU 编号
*/ */
ProductFavoriteDO getFavorite(Long userId, Long spuId); ProductFavoriteDO getFavorite(Long userId, Long spuId);
/**
* 获取用户收藏数量
*
* @param userId 用户编号
* @return 数量
*/
Long getFavoriteCount(Long userId);
} }

View File

@ -10,7 +10,6 @@ import org.springframework.validation.annotation.Validated;
import javax.annotation.Resource; import javax.annotation.Resource;
import javax.validation.Valid; import javax.validation.Valid;
import java.util.Objects;
import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
import static cn.iocoder.yudao.module.product.enums.ErrorCodeConstants.FAVORITE_EXISTS; import static cn.iocoder.yudao.module.product.enums.ErrorCodeConstants.FAVORITE_EXISTS;
@ -31,7 +30,7 @@ public class ProductFavoriteServiceImpl implements ProductFavoriteService {
@Override @Override
public Long createFavorite(Long userId, Long spuId) { public Long createFavorite(Long userId, Long spuId) {
ProductFavoriteDO favorite = productFavoriteMapper.selectByUserIdAndSpuId(userId, spuId); ProductFavoriteDO favorite = productFavoriteMapper.selectByUserIdAndSpuId(userId, spuId);
if (Objects.nonNull(favorite)) { if (favorite != null) {
throw exception(FAVORITE_EXISTS); throw exception(FAVORITE_EXISTS);
} }
@ -43,7 +42,7 @@ public class ProductFavoriteServiceImpl implements ProductFavoriteService {
@Override @Override
public void deleteFavorite(Long userId, Long spuId) { public void deleteFavorite(Long userId, Long spuId) {
ProductFavoriteDO favorite = productFavoriteMapper.selectByUserIdAndSpuId(userId, spuId); ProductFavoriteDO favorite = productFavoriteMapper.selectByUserIdAndSpuId(userId, spuId);
if (Objects.isNull(favorite)) { if (favorite == null) {
throw exception(FAVORITE_NOT_EXISTS); throw exception(FAVORITE_NOT_EXISTS);
} }
@ -60,4 +59,9 @@ public class ProductFavoriteServiceImpl implements ProductFavoriteService {
return productFavoriteMapper.selectByUserIdAndSpuId(userId, spuId); return productFavoriteMapper.selectByUserIdAndSpuId(userId, spuId);
} }
@Override
public Long getFavoriteCount(Long userId) {
return productFavoriteMapper.selectCountByUserId(userId);
}
} }

View File

@ -0,0 +1,32 @@
package cn.iocoder.yudao.module.promotion.api.bargain;
import cn.iocoder.yudao.module.promotion.api.bargain.dto.BargainRecordCreateReqDTO;
import javax.validation.Valid;
// TODO @芋艿后面也再撸撸这几个接口
/**
* 砍价记录 API 接口
*
* @author HUIHUI
*/
public interface BargainRecordApi {
/**
* 创建砍价记录
*
* @param reqDTO 请求 DTO
*/
void createBargainRecord(@Valid BargainRecordCreateReqDTO reqDTO);
/**
* 查询砍价是否成功
*
* @param userId 用户编号
* @param orderId 订单编号
* @return 砍价是否成功
*/
boolean isBargainRecordSuccess(Long userId, Long orderId);
}

View File

@ -0,0 +1,81 @@
package cn.iocoder.yudao.module.promotion.api.bargain.dto;
import lombok.Data;
import javax.validation.constraints.NotEmpty;
import javax.validation.constraints.NotNull;
// TODO @芋艿这块要在看看
/**
* 砍价记录的创建 Request DTO
*
* @author HUIHUI
*/
@Data
public class BargainRecordCreateReqDTO {
/**
* 砍价活动编号
*/
@NotNull(message = "砍价活动编号不能为空")
private Long activityId;
/**
* spu 编号
*/
@NotNull(message = "spu 编号不能为空")
private Long spuId;
/**
* sku 编号
*/
@NotNull(message = "sku 编号不能为空")
private Long skuId;
/**
* 用户编号
*/
@NotNull(message = "用户编号不能为空")
private Long userId;
/**
* 订单编号
*/
@NotNull(message = "订单编号不能为空")
private Long orderId;
// TODO @puhui999spuNamepicUrl 之类字段不用传递
/**
* 商品名字
*/
@NotEmpty(message = "商品名字不能为空")
private String spuName;
/**
* 商品图片
*/
@NotEmpty(message = "商品图片不能为空")
private String picUrl;
/**
* 砍价商品单价
*/
@NotNull(message = "砍价底价不能为空")
private Integer bargainPrice;
/**
* 商品原价单位分
*/
@NotNull(message = "商品原价不能为空")
private Integer price;
// TODO @puhui999nicknameavatar 不用传递去查询
/**
* 用户昵称
*/
@NotEmpty(message = "用户昵称不能为空")
private String nickname;
/**
* 用户头像
*/
@NotEmpty(message = "用户头像不能为空")
private String avatar;
/**
* 开团状态进行中 砍价成功 砍价失败
*/
@NotNull(message = "开团状态不能为空")
private Integer status;
}

View File

@ -1,49 +0,0 @@
package cn.iocoder.yudao.module.promotion.api.combination;
import cn.iocoder.yudao.module.promotion.api.combination.dto.CombinationRecordReqDTO;
import javax.validation.Valid;
// TODO @puhui999:CombinationRecordApi 分成活动记录哈
// TODO @芋艿后面也再撸撸这几个接口
/**
* 拼团活动 API 接口
*
* @author HUIHUI
*/
public interface CombinationApi {
/**
* 创建开团记录
*
* @param reqDTO 请求 DTO
*/
void createRecord(@Valid CombinationRecordReqDTO reqDTO);
/**
* 获取开团记录状态
*
* @param userId 用户编号
* @param orderId 订单编号
*/
boolean validateRecordStatusIsSuccess(Long userId, Long orderId);
/**
* 更新开团记录状态
*
* @param userId 用户编号
* @param orderId 订单编号
* @param status 状态值
*/
void updateRecordStatus(Long userId, Long orderId, Integer status);
/**
* 更新开团记录状态和开始时间
*
* @param userId 用户编号
* @param orderId 订单编号
* @param status 状态值
*/
void updateRecordStatusAndStartTime(Long userId, Long orderId, Integer status);
}

View File

@ -0,0 +1,63 @@
package cn.iocoder.yudao.module.promotion.api.combination;
import cn.iocoder.yudao.module.promotion.api.combination.dto.CombinationRecordCreateReqDTO;
import cn.iocoder.yudao.module.promotion.api.combination.dto.CombinationRecordRespDTO;
import cn.iocoder.yudao.module.promotion.api.combination.dto.CombinationRecordUpdateStatusReqDTO;
import javax.validation.Valid;
import java.util.List;
// TODO @芋艿后面也再撸撸这几个接口
/**
* 拼团记录 API 接口
*
* @author HUIHUI
*/
public interface CombinationRecordApi {
/**
* 创建开团记录
*
* @param reqDTO 请求 DTO
*/
void createCombinationRecord(@Valid CombinationRecordCreateReqDTO reqDTO);
/**
* 查询拼团记录是否成功
*
* @param userId 用户编号
* @param orderId 订单编号
* @return 拼团是否成功
*/
boolean isCombinationRecordSuccess(Long userId, Long orderId);
/**
* 获取拼团记录
*
* @param userId 用户编号
* @param activityId 活动编号
* @return 拼团记录列表
*/
List<CombinationRecordRespDTO> getRecordListByUserIdAndActivityId(Long userId, Long activityId);
/**
* 验证组合限制数
* 校验是否满足限购要求
*
* @param count 本次购买数量
* @param sumCount 已购买数量合计
* @param activityId 活动编号
*/
void validateCombinationLimitCount(Long activityId, Integer count, Integer sumCount);
// TODO @puhui999是不是搞成具体的方法拼团成功拼团失败这种方法
/**
* 更新开团记录状态
*
* @param reqDTO 请求 DTO
*/
void updateCombinationRecordStatus(CombinationRecordUpdateStatusReqDTO reqDTO);
}

View File

@ -5,14 +5,14 @@ import lombok.Data;
import javax.validation.constraints.NotEmpty; import javax.validation.constraints.NotEmpty;
import javax.validation.constraints.NotNull; import javax.validation.constraints.NotNull;
// TODO @puhui999CombinationRecordCreateReqDTO这样更容易知道是创建噢 // TODO @芋艿这块要在看看
/** /**
* 拼团记录 Request DTO * 拼团记录的创建 Request DTO
* *
* @author HUIHUI * @author HUIHUI
*/ */
@Data @Data
public class CombinationRecordReqDTO { public class CombinationRecordCreateReqDTO {
/** /**
* 拼团活动编号 * 拼团活动编号
@ -70,7 +70,7 @@ public class CombinationRecordReqDTO {
@NotEmpty(message = "用户头像不能为空") @NotEmpty(message = "用户头像不能为空")
private String avatar; private String avatar;
/** /**
* 开团状态正在开团 拼团成功 拼团失败 TODO 等待支付 * 开团状态正在开团 拼团成功 拼团失败
*/ */
@NotNull(message = "开团状态不能为空") @NotNull(message = "开团状态不能为空")
private Integer status; private Integer status;

View File

@ -0,0 +1,41 @@
package cn.iocoder.yudao.module.promotion.api.combination.dto;
import cn.iocoder.yudao.module.promotion.enums.combination.CombinationRecordStatusEnum;
import lombok.Data;
/**
* 拼团记录 Response DTO
*
* @author HUIHUI
*/
@Data
public class CombinationRecordRespDTO {
/**
* 拼团活动编号
*/
private Long activityId;
/**
* SPU 编号
*/
private Long spuId;
/**
* SKU 编号
*/
private Long skuId;
/**
* 用户编号
*/
private Long userId;
/**
* 订单编号
*/
private Long orderId;
/**
* 开团状态
*
* 枚举 {@link CombinationRecordStatusEnum}
*/
private Integer status;
}

View File

@ -0,0 +1,39 @@
package cn.iocoder.yudao.module.promotion.api.combination.dto;
import lombok.Data;
import javax.validation.constraints.NotNull;
import java.time.LocalDateTime;
/**
* 拼团记录的更新状态 Request DTO
*
* @author HUIHUI
*/
@Data
public class CombinationRecordUpdateStatusReqDTO {
/**
* 用户编号
*/
@NotNull(message = "用户编号不能为空")
private Long userId;
/**
* 订单编号
*/
@NotNull(message = "订单编号不能为空")
private Long orderId;
/**
* 开团状态正在开团 拼团成功 拼团失败
*/
@NotNull(message = "开团状态不能为空")
private Integer status;
/**
* 团开始时间
*/
private LocalDateTime startTime;
}

View File

@ -50,14 +50,11 @@ public interface ErrorCodeConstants {
ErrorCode SECKILL_ACTIVITY_UPDATE_FAIL_STATUS_CLOSED = new ErrorCode(1013008003, "秒杀活动已关闭,不能修改"); ErrorCode SECKILL_ACTIVITY_UPDATE_FAIL_STATUS_CLOSED = new ErrorCode(1013008003, "秒杀活动已关闭,不能修改");
ErrorCode SECKILL_ACTIVITY_DELETE_FAIL_STATUS_NOT_CLOSED_OR_END = new ErrorCode(1013008004, "秒杀活动未关闭或未结束,不能删除"); ErrorCode SECKILL_ACTIVITY_DELETE_FAIL_STATUS_NOT_CLOSED_OR_END = new ErrorCode(1013008004, "秒杀活动未关闭或未结束,不能删除");
ErrorCode SECKILL_ACTIVITY_CLOSE_FAIL_STATUS_CLOSED = new ErrorCode(1013008005, "秒杀活动已关闭,不能重复关闭"); ErrorCode SECKILL_ACTIVITY_CLOSE_FAIL_STATUS_CLOSED = new ErrorCode(1013008005, "秒杀活动已关闭,不能重复关闭");
ErrorCode SECKILL_ACTIVITY_CLOSE_FAIL_STATUS_END = new ErrorCode(1013008006, "秒杀活动已结束,不能关闭");
// ========== 秒杀时段 1013009000 ========== // ========== 秒杀时段 1013009000 ==========
ErrorCode SECKILL_TIME_NOT_EXISTS = new ErrorCode(1013009000, "秒杀时段不存在"); ErrorCode SECKILL_CONFIG_NOT_EXISTS = new ErrorCode(1013009000, "秒杀时段不存在");
ErrorCode SECKILL_TIME_CONFLICTS = new ErrorCode(1013009001, "秒杀时段冲突"); ErrorCode SECKILL_CONFIG_TIME_CONFLICTS = new ErrorCode(1013009001, "秒杀时段冲突");
ErrorCode SECKILL_TIME_EQUAL = new ErrorCode(1013009002, "秒杀时段开始时间和结束时间不能相等"); ErrorCode SECKILL_CONFIG_DISABLE = new ErrorCode(1013009004, "秒杀时段已关闭");
ErrorCode SECKILL_START_TIME_BEFORE_END_TIME = new ErrorCode(1013009003, "秒杀时段开始时间不能在结束时间之后");
ErrorCode SECKILL_TIME_DISABLE = new ErrorCode(1013009004, "秒杀时段已关闭");
// ========== 拼团活动 1013010000 ========== // ========== 拼团活动 1013010000 ==========
ErrorCode COMBINATION_ACTIVITY_NOT_EXISTS = new ErrorCode(1013010000, "拼团活动不存在"); ErrorCode COMBINATION_ACTIVITY_NOT_EXISTS = new ErrorCode(1013010000, "拼团活动不存在");
@ -66,4 +63,25 @@ public interface ErrorCodeConstants {
ErrorCode COMBINATION_ACTIVITY_DELETE_FAIL_STATUS_NOT_CLOSED_OR_END = new ErrorCode(1013010003, "拼团活动未关闭或未结束,不能删除"); ErrorCode COMBINATION_ACTIVITY_DELETE_FAIL_STATUS_NOT_CLOSED_OR_END = new ErrorCode(1013010003, "拼团活动未关闭或未结束,不能删除");
ErrorCode COMBINATION_RECORD_NOT_EXISTS = new ErrorCode(1013010004, "拼团不存在"); ErrorCode COMBINATION_RECORD_NOT_EXISTS = new ErrorCode(1013010004, "拼团不存在");
// ========== 拼团记录 1013011000 ==========
ErrorCode COMBINATION_RECORD_EXISTS = new ErrorCode(1013011000, "拼团失败,已参与过该拼团");
ErrorCode COMBINATION_RECORD_HEAD_NOT_EXISTS = new ErrorCode(1013011001, "拼团失败,父拼团不存在");
ErrorCode COMBINATION_RECORD_USER_FULL = new ErrorCode(1013011002, "拼团失败,拼团人数已满");
ErrorCode COMBINATION_RECORD_FAILED_HAVE_JOINED = new ErrorCode(1013011003, "拼团失败,已参与其它拼团");
ErrorCode COMBINATION_RECORD_FAILED_TIME_END = new ErrorCode(1013011004, "拼团失败,活动已经结束");
ErrorCode COMBINATION_RECORD_FAILED_SINGLE_LIMIT_COUNT_EXCEED = new ErrorCode(1013011005, "拼团失败,单次限购超出");
ErrorCode COMBINATION_RECORD_FAILED_TOTAL_LIMIT_COUNT_EXCEED = new ErrorCode(1013011006, "拼团失败,单次限购超出");
// ========== 砍价活动 1013012000 ==========
ErrorCode BARGAIN_ACTIVITY_NOT_EXISTS = new ErrorCode(1013012000, "砍价活动不存在");
ErrorCode BARGAIN_ACTIVITY_SPU_CONFLICTS = new ErrorCode(1013012001, "存在商品参加了其它砍价活动");
ErrorCode BARGAIN_ACTIVITY_STATUS_DISABLE = new ErrorCode(1013012002, "砍价活动已关闭不能修改");
ErrorCode BARGAIN_ACTIVITY_DELETE_FAIL_STATUS_NOT_CLOSED_OR_END = new ErrorCode(1013012003, "砍价活动未关闭或未结束,不能删除");
// ========== 砍价记录 1013013000 ==========
ErrorCode BARGAIN_RECORD_NOT_EXISTS = new ErrorCode(1013013000, "砍价记录不存在");
ErrorCode BARGAIN_RECORD_EXISTS = new ErrorCode(1013013001, "砍价失败,已参与过该砍价");
ErrorCode BARGAIN_RECORD_HEAD_NOT_EXISTS = new ErrorCode(1013013002, "砍价失败,父砍价不存在");
ErrorCode BARGAIN_RECORD_USER_FULL = new ErrorCode(1013013003, "砍价失败,砍价人数已满");
} }

View File

@ -1,5 +1,6 @@
package cn.iocoder.yudao.module.promotion.enums.combination; package cn.iocoder.yudao.module.promotion.enums.combination;
import cn.hutool.core.util.ObjectUtil;
import cn.iocoder.yudao.framework.common.core.IntArrayValuable; import cn.iocoder.yudao.framework.common.core.IntArrayValuable;
import lombok.AllArgsConstructor; import lombok.AllArgsConstructor;
import lombok.Getter; import lombok.Getter;
@ -15,10 +16,9 @@ import java.util.Arrays;
@Getter @Getter
public enum CombinationRecordStatusEnum implements IntArrayValuable { public enum CombinationRecordStatusEnum implements IntArrayValuable {
WAITING(0, "未付款"), IN_PROGRESS(0, "进行中"),
IN_PROGRESS(1, "进行中"), SUCCESS(1, "拼团成功"),
SUCCESS(2, "拼团成功"), FAILED(2, "拼团失败");
FAILED(3, "拼团失败");
public static final int[] ARRAYS = Arrays.stream(values()).mapToInt(CombinationRecordStatusEnum::getStatus).toArray(); public static final int[] ARRAYS = Arrays.stream(values()).mapToInt(CombinationRecordStatusEnum::getStatus).toArray();
@ -36,4 +36,8 @@ public enum CombinationRecordStatusEnum implements IntArrayValuable {
return ARRAYS; return ARRAYS;
} }
public static boolean isSuccess(Integer status) {
return ObjectUtil.equal(status, SUCCESS.getStatus());
}
} }

View File

@ -1,5 +1,6 @@
package cn.iocoder.yudao.module.promotion.enums.decorate; package cn.iocoder.yudao.module.promotion.enums.decorate;
import lombok.AllArgsConstructor;
import lombok.Getter; import lombok.Getter;
/** /**
@ -8,11 +9,44 @@ import lombok.Getter;
* @author jason * @author jason
*/ */
@Getter @Getter
@AllArgsConstructor
@SuppressWarnings("JavadocLinkAsPlainText")
public enum DecorateComponentEnum { public enum DecorateComponentEnum {
NAV_MENU("nav-menu", "导航菜单"), /**
ROLLING_BANNER("rolling-banner", "滚动横幅广告"), * 格式[{
PRODUCT_CATEGORY("product-category", "商品分类"); * "name": "标题"
* "picUrl": "https://www.iocoder.cn/xxx.png",
* "url": "/pages/users/index"
* }]
*
* 最多 10
*/
MENU("menu", "菜单"),
/**
* 格式[{
* "name": "标题"
* "url": "/pages/users/index"
* }]
*/
ROLLING_NEWS("scrolling-news", "滚动新闻"),
/**
* 格式[{
* "picUrl": "https://www.iocoder.cn/xxx.png",
* "url": "/pages/users/index"
* }]
*/
SLIDE_SHOW("slide-show", "轮播图"),
/**
* 格式[{
* "name": "标题"
* "type": "类型", // besthotnewbenefitgood
* "tag": "标签" // 例如说多买多省
* }]
*
* 最多 4
*/
PRODUCT_RECOMMEND("product-recommend", "商品推荐");
/** /**
* 页面组件代码 * 页面组件代码
@ -24,9 +58,4 @@ public enum DecorateComponentEnum {
*/ */
private final String desc; private final String desc;
DecorateComponentEnum(String code, String desc) {
this.code = code;
this.desc = desc;
}
} }

View File

@ -15,14 +15,17 @@ import java.util.Arrays;
@Getter @Getter
public enum DecoratePageEnum implements IntArrayValuable { public enum DecoratePageEnum implements IntArrayValuable {
INDEX(1, "首页"); INDEX(1, "首页"),
MY(2, "个人中心"),
;
private static final int[] ARRAYS = Arrays.stream(values()).mapToInt(DecoratePageEnum::getId).toArray(); private static final int[] ARRAYS = Arrays.stream(values()).mapToInt(DecoratePageEnum::getPage).toArray();
/** /**
* 页面 id * 页面编号
*/ */
private final Integer id; private final Integer page;
/** /**
* 页面名称 * 页面名称
*/ */

View File

@ -0,0 +1,24 @@
package cn.iocoder.yudao.module.promotion.api.bargain;
import cn.iocoder.yudao.module.promotion.api.bargain.dto.BargainRecordCreateReqDTO;
import org.springframework.stereotype.Service;
/**
* 砍价活动 API 实现类 TODO @puhui999
*
* @author HUIHUI
*/
@Service
public class BargainRecordApiImpl implements BargainRecordApi {
@Override
public void createBargainRecord(BargainRecordCreateReqDTO reqDTO) {
}
@Override
public boolean isBargainRecordSuccess(Long userId, Long orderId) {
return false;
}
}

View File

@ -1,42 +0,0 @@
package cn.iocoder.yudao.module.promotion.api.combination;
import cn.iocoder.yudao.module.promotion.api.combination.dto.CombinationRecordReqDTO;
import cn.iocoder.yudao.module.promotion.service.combination.CombinationActivityService;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
import java.time.LocalDateTime;
/**
* 拼团活动 API 实现类
*
* @author HUIHUI
*/
@Service
public class CombinationApiImpl implements CombinationApi {
@Resource
private CombinationActivityService activityService;
@Override
public void createRecord(CombinationRecordReqDTO reqDTO) {
activityService.createRecord(reqDTO);
}
@Override
public boolean validateRecordStatusIsSuccess(Long userId, Long orderId) {
return activityService.validateRecordStatusIsSuccess(userId, orderId);
}
@Override
public void updateRecordStatus(Long userId, Long orderId, Integer status) {
activityService.updateRecordStatusByUserIdAndOrderId(userId, orderId, status);
}
@Override
public void updateRecordStatusAndStartTime(Long userId, Long orderId, Integer status) {
activityService.updateRecordStatusAndStartTimeByUserIdAndOrderId(userId, orderId, status, LocalDateTime.now());
}
}

View File

@ -0,0 +1,54 @@
package cn.iocoder.yudao.module.promotion.api.combination;
import cn.iocoder.yudao.module.promotion.api.combination.dto.CombinationRecordCreateReqDTO;
import cn.iocoder.yudao.module.promotion.api.combination.dto.CombinationRecordRespDTO;
import cn.iocoder.yudao.module.promotion.api.combination.dto.CombinationRecordUpdateStatusReqDTO;
import cn.iocoder.yudao.module.promotion.convert.combination.CombinationActivityConvert;
import cn.iocoder.yudao.module.promotion.enums.combination.CombinationRecordStatusEnum;
import cn.iocoder.yudao.module.promotion.service.combination.CombinationRecordService;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
import java.util.List;
/**
* 拼团活动 API 实现类
*
* @author HUIHUI
*/
@Service
public class CombinationRecordApiImpl implements CombinationRecordApi {
@Resource
private CombinationRecordService recordService;
@Override
public void createCombinationRecord(CombinationRecordCreateReqDTO reqDTO) {
recordService.createCombinationRecord(reqDTO);
}
@Override
public boolean isCombinationRecordSuccess(Long userId, Long orderId) {
return CombinationRecordStatusEnum.isSuccess(recordService.getCombinationRecord(userId, orderId).getStatus());
}
@Override
public List<CombinationRecordRespDTO> getRecordListByUserIdAndActivityId(Long userId, Long activityId) {
return CombinationActivityConvert.INSTANCE.convert(recordService.getRecordListByUserIdAndActivityId(userId, activityId));
}
@Override
public void validateCombinationLimitCount(Long activityId, Integer count, Integer sumCount) {
recordService.validateCombinationLimitCount(activityId, count, sumCount);
}
@Override
public void updateCombinationRecordStatus(CombinationRecordUpdateStatusReqDTO reqDTO) {
if (null == reqDTO.getStartTime()) {
recordService.updateCombinationRecordStatusByUserIdAndOrderId(reqDTO);
} else {
recordService.updateCombinationRecordStatusAndStartTimeByUserIdAndOrderId(reqDTO);
}
}
}

View File

@ -0,0 +1,79 @@
package cn.iocoder.yudao.module.promotion.controller.admin.bargain;
import cn.hutool.core.collection.CollUtil;
import cn.iocoder.yudao.framework.common.pojo.CommonResult;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.module.promotion.controller.admin.bargain.vo.BargainActivityCreateReqVO;
import cn.iocoder.yudao.module.promotion.controller.admin.bargain.vo.BargainActivityPageReqVO;
import cn.iocoder.yudao.module.promotion.controller.admin.bargain.vo.BargainActivityRespVO;
import cn.iocoder.yudao.module.promotion.controller.admin.bargain.vo.BargainActivityUpdateReqVO;
import cn.iocoder.yudao.module.promotion.convert.bargain.BargainActivityConvert;
import cn.iocoder.yudao.module.promotion.dal.dataobject.bargain.BargainActivityDO;
import cn.iocoder.yudao.module.promotion.service.bargain.BargainActivityService;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.tags.Tag;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import javax.annotation.Resource;
import javax.validation.Valid;
import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
@Tag(name = "管理后台 - 砍价活动")
@RestController
@RequestMapping("/promotion/bargain-activity")
@Validated
public class BargainActivityController {
@Resource
private BargainActivityService activityService;
@PostMapping("/create")
@Operation(summary = "创建砍价活动")
@PreAuthorize("@ss.hasPermission('promotion:bargain-activity:create')")
public CommonResult<Long> createBargainActivity(@Valid @RequestBody BargainActivityCreateReqVO createReqVO) {
return success(activityService.createBargainActivity(createReqVO));
}
@PutMapping("/update")
@Operation(summary = "更新砍价活动")
@PreAuthorize("@ss.hasPermission('promotion:bargain-activity:update')")
public CommonResult<Boolean> updateBargainActivity(@Valid @RequestBody BargainActivityUpdateReqVO updateReqVO) {
activityService.updateBargainActivity(updateReqVO);
return success(true);
}
@DeleteMapping("/delete")
@Operation(summary = "删除砍价活动")
@Parameter(name = "id", description = "编号", required = true)
@PreAuthorize("@ss.hasPermission('promotion:bargain-activity:delete')")
public CommonResult<Boolean> deleteBargainActivity(@RequestParam("id") Long id) {
activityService.deleteBargainActivity(id);
return success(true);
}
@GetMapping("/get")
@Operation(summary = "获得砍价活动")
@Parameter(name = "id", description = "编号", required = true, example = "1024")
@PreAuthorize("@ss.hasPermission('promotion:bargain-activity:query')")
public CommonResult<BargainActivityRespVO> getBargainActivity(@RequestParam("id") Long id) {
return success(BargainActivityConvert.INSTANCE.convert(activityService.getBargainActivity(id)));
}
@GetMapping("/page")
@Operation(summary = "获得砍价活动分页")
@PreAuthorize("@ss.hasPermission('promotion:bargain-activity:query')")
public CommonResult<PageResult<BargainActivityRespVO>> getBargainActivityPage(
@Valid BargainActivityPageReqVO pageVO) {
// 查询砍价活动
PageResult<BargainActivityDO> pageResult = activityService.getBargainActivityPage(pageVO);
if (CollUtil.isEmpty(pageResult.getList())) {
return success(PageResult.empty(pageResult.getTotal()));
}
return success(BargainActivityConvert.INSTANCE.convertPage(activityService.getBargainActivityPage(pageVO)));
}
}

View File

@ -0,0 +1,75 @@
package cn.iocoder.yudao.module.promotion.controller.admin.bargain.vo;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import org.springframework.format.annotation.DateTimeFormat;
import javax.validation.constraints.NotNull;
import java.time.LocalDateTime;
import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND;
/**
* 砍价活动 Base VO提供给添加修改详细的子 VO 使用
* 如果子 VO 存在差异的字段请不要添加到这里影响 Swagger 文档生成
*
* @author HUIHUI
*/
@Data
public class BargainActivityBaseVO {
@Schema(description = "砍价活动名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "越拼越省钱")
@NotNull(message = "砍价名称不能为空")
private String name;
@Schema(description = "商品 SPU 编号", example = "1")
@NotNull(message = "砍价商品不能为空")
private Long spuId;
@Schema(description = "商品 skuId", requiredMode = Schema.RequiredMode.REQUIRED, example = "23")
@NotNull(message = "商品 skuId 不能为空")
private Long skuId;
@Schema(description = "砍价起始价格", requiredMode = Schema.RequiredMode.REQUIRED, example = "23")
@NotNull(message = "砍价起始价格不能为空")
private Integer bargainFirstPrice;
@Schema(description = "砍价底价", requiredMode = Schema.RequiredMode.REQUIRED, example = "23")
@NotNull(message = "砍价底价不能为空")
private Integer bargainPrice;
@Schema(description = "活动库存", requiredMode = Schema.RequiredMode.REQUIRED, example = "23")
@NotNull(message = "活动库存不能为空")
private Integer stock;
@Schema(description = "总限购数量", requiredMode = Schema.RequiredMode.REQUIRED, example = "16218")
@NotNull(message = "总限购数量不能为空")
private Integer totalLimitCount;
@Schema(description = "活动开始时间", requiredMode = Schema.RequiredMode.REQUIRED, example = "[2022-07-01 23:59:59]")
@NotNull(message = "活动开始时间不能为空")
@DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
private LocalDateTime startTime;
@Schema(description = "活动结束时间", requiredMode = Schema.RequiredMode.REQUIRED, example = "[2022-07-01 23:59:59]")
@NotNull(message = "活动结束时间不能为空")
@DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
private LocalDateTime endTime;
@Schema(description = "砍价人数", requiredMode = Schema.RequiredMode.REQUIRED, example = "25222")
@NotNull(message = "砍价人数不能为空")
private Integer userSize;
@Schema(description = "最大帮砍次数", requiredMode = Schema.RequiredMode.REQUIRED, example = "25222")
@NotNull(message = "最大帮砍次数不能为空")
private Integer bargainCount;
@Schema(description = "用户每次砍价的最小金额", requiredMode = Schema.RequiredMode.REQUIRED, example = "25222")
@NotNull(message = "用户每次砍价的最小金额不能为空")
private Integer randomMinPrice;
@Schema(description = "用户每次砍价的最大金额", requiredMode = Schema.RequiredMode.REQUIRED, example = "25222")
@NotNull(message = "用户每次砍价的最大金额不能为空")
private Integer randomMaxPrice;
}

View File

@ -0,0 +1,14 @@
package cn.iocoder.yudao.module.promotion.controller.admin.bargain.vo;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.ToString;
@Schema(description = "管理后台 - 砍价活动创建 Request VO")
@Data
@EqualsAndHashCode(callSuper = true)
@ToString(callSuper = true)
public class BargainActivityCreateReqVO extends BargainActivityBaseVO {
}

View File

@ -0,0 +1,21 @@
package cn.iocoder.yudao.module.promotion.controller.admin.bargain.vo;
import cn.iocoder.yudao.framework.common.pojo.PageParam;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.ToString;
@Schema(description = "管理后台 - 砍价活动分页 Request VO")
@Data
@EqualsAndHashCode(callSuper = true)
@ToString(callSuper = true)
public class BargainActivityPageReqVO extends PageParam {
@Schema(description = "砍价名称", example = "赵六")
private String name;
@Schema(description = "活动状态", example = "0")
private Integer status;
}

View File

@ -0,0 +1,35 @@
package cn.iocoder.yudao.module.promotion.controller.admin.bargain.vo;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.ToString;
import javax.validation.constraints.NotNull;
import java.time.LocalDateTime;
@Schema(description = "管理后台 - 砍价活动 Response VO")
@Data
@EqualsAndHashCode(callSuper = true)
@ToString(callSuper = true)
public class BargainActivityRespVO extends BargainActivityBaseVO {
@Schema(description = "商品名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "618大促")
private String spuName;
@Schema(description = "商品主图", requiredMode = Schema.RequiredMode.REQUIRED, example = "https://www.iocoder.cn/xx.png")
private String picUrl;
@Schema(description = "活动编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "22901")
private Long id;
@Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED, example = "2022-07-01 23:59:59")
private LocalDateTime createTime;
@Schema(description = "砍价成功数量", requiredMode = Schema.RequiredMode.REQUIRED, example = "999")
private Integer successCount;
@Schema(description = "活动状态", requiredMode = Schema.RequiredMode.REQUIRED, example = "0")
@NotNull(message = "活动状态不能为空")
private Integer status;
}

View File

@ -0,0 +1,20 @@
package cn.iocoder.yudao.module.promotion.controller.admin.bargain.vo;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.ToString;
import javax.validation.constraints.NotNull;
@Schema(description = "管理后台 - 砍价活动更新 Request VO")
@Data
@EqualsAndHashCode(callSuper = true)
@ToString(callSuper = true)
public class BargainActivityUpdateReqVO extends BargainActivityBaseVO {
@Schema(description = "活动编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "22901")
@NotNull(message = "活动编号不能为空")
private Long id;
}

View File

@ -1,16 +1,17 @@
package cn.iocoder.yudao.module.promotion.controller.admin.combination; package cn.iocoder.yudao.module.promotion.controller.admin.combination;
import cn.hutool.core.collection.CollUtil;
import cn.iocoder.yudao.framework.common.pojo.CommonResult; import cn.iocoder.yudao.framework.common.pojo.CommonResult;
import cn.iocoder.yudao.framework.common.pojo.PageResult; import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils;
import cn.iocoder.yudao.framework.excel.core.util.ExcelUtils;
import cn.iocoder.yudao.framework.operatelog.core.annotations.OperateLog;
import cn.iocoder.yudao.module.product.api.spu.ProductSpuApi; import cn.iocoder.yudao.module.product.api.spu.ProductSpuApi;
import cn.iocoder.yudao.module.product.api.spu.dto.ProductSpuRespDTO; import cn.iocoder.yudao.module.product.api.spu.dto.ProductSpuRespDTO;
import cn.iocoder.yudao.module.promotion.controller.admin.combination.vo.activity.*; import cn.iocoder.yudao.module.promotion.controller.admin.combination.vo.activity.CombinationActivityCreateReqVO;
import cn.iocoder.yudao.module.promotion.controller.admin.combination.vo.activity.CombinationActivityPageReqVO;
import cn.iocoder.yudao.module.promotion.controller.admin.combination.vo.activity.CombinationActivityRespVO;
import cn.iocoder.yudao.module.promotion.controller.admin.combination.vo.activity.CombinationActivityUpdateReqVO;
import cn.iocoder.yudao.module.promotion.convert.combination.CombinationActivityConvert; import cn.iocoder.yudao.module.promotion.convert.combination.CombinationActivityConvert;
import cn.iocoder.yudao.module.promotion.dal.dataobject.combination.combinationactivity.CombinationActivityDO; import cn.iocoder.yudao.module.promotion.dal.dataobject.combination.CombinationActivityDO;
import cn.iocoder.yudao.module.promotion.dal.dataobject.combination.combinationactivity.CombinationProductDO; import cn.iocoder.yudao.module.promotion.dal.dataobject.combination.CombinationProductDO;
import cn.iocoder.yudao.module.promotion.service.combination.CombinationActivityService; import cn.iocoder.yudao.module.promotion.service.combination.CombinationActivityService;
import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter; import io.swagger.v3.oas.annotations.Parameter;
@ -20,16 +21,12 @@ import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*; import org.springframework.web.bind.annotation.*;
import javax.annotation.Resource; import javax.annotation.Resource;
import javax.servlet.http.HttpServletResponse;
import javax.validation.Valid; import javax.validation.Valid;
import java.io.IOException;
import java.util.Collection;
import java.util.List; import java.util.List;
import java.util.Set;
import static cn.hutool.core.collection.CollectionUtil.newArrayList; import static cn.hutool.core.collection.CollectionUtil.newArrayList;
import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
import static cn.iocoder.yudao.framework.operatelog.core.enums.OperateTypeEnum.EXPORT; import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet;
@Tag(name = "管理后台 - 拼团活动") @Tag(name = "管理后台 - 拼团活动")
@RestController @RestController
@ -39,8 +36,9 @@ public class CombinationActivityController {
@Resource @Resource
private CombinationActivityService combinationActivityService; private CombinationActivityService combinationActivityService;
@Resource @Resource
private ProductSpuApi spuApi; private ProductSpuApi productSpuApi;
@PostMapping("/create") @PostMapping("/create")
@Operation(summary = "创建拼团活动") @Operation(summary = "创建拼团活动")
@ -72,43 +70,27 @@ public class CombinationActivityController {
@PreAuthorize("@ss.hasPermission('promotion:combination-activity:query')") @PreAuthorize("@ss.hasPermission('promotion:combination-activity:query')")
public CommonResult<CombinationActivityRespVO> getCombinationActivity(@RequestParam("id") Long id) { public CommonResult<CombinationActivityRespVO> getCombinationActivity(@RequestParam("id") Long id) {
CombinationActivityDO activity = combinationActivityService.getCombinationActivity(id); CombinationActivityDO activity = combinationActivityService.getCombinationActivity(id);
List<CombinationProductDO> products = combinationActivityService.getProductsByActivityIds(newArrayList(id)); List<CombinationProductDO> products = combinationActivityService.getCombinationProductsByActivityIds(newArrayList(id));
return success(CombinationActivityConvert.INSTANCE.convert(activity, products)); return success(CombinationActivityConvert.INSTANCE.convert(activity, products));
} }
@GetMapping("/list")
@Operation(summary = "获得拼团活动列表")
@Parameter(name = "ids", description = "编号列表", required = true, example = "1024,2048")
@PreAuthorize("@ss.hasPermission('promotion:combination-activity:query')")
public CommonResult<List<CombinationActivityRespVO>> getCombinationActivityList(@RequestParam("ids") Collection<Long> ids) {
List<CombinationActivityDO> list = combinationActivityService.getCombinationActivityList(ids);
return success(CombinationActivityConvert.INSTANCE.convertList(list));
}
@GetMapping("/page") @GetMapping("/page")
@Operation(summary = "获得拼团活动分页") @Operation(summary = "获得拼团活动分页")
@PreAuthorize("@ss.hasPermission('promotion:combination-activity:query')") @PreAuthorize("@ss.hasPermission('promotion:combination-activity:query')")
public CommonResult<PageResult<CombinationActivityRespVO>> getCombinationActivityPage( public CommonResult<PageResult<CombinationActivityRespVO>> getCombinationActivityPage(
@Valid CombinationActivityPageReqVO pageVO) { @Valid CombinationActivityPageReqVO pageVO) {
// 查询拼团活动
PageResult<CombinationActivityDO> pageResult = combinationActivityService.getCombinationActivityPage(pageVO); PageResult<CombinationActivityDO> pageResult = combinationActivityService.getCombinationActivityPage(pageVO);
// TODO @puhui999可以不一定 aIds直接批量查询结果出来下面也是类似 if (CollUtil.isEmpty(pageResult.getList())) {
Set<Long> aIds = CollectionUtils.convertSet(pageResult.getList(), CombinationActivityDO::getId); return success(PageResult.empty(pageResult.getTotal()));
List<CombinationProductDO> products = combinationActivityService.getProductsByActivityIds(aIds); }
Set<Long> spuIds = CollectionUtils.convertSet(pageResult.getList(), CombinationActivityDO::getSpuId);
List<ProductSpuRespDTO> spus = spuApi.getSpuList(spuIds); // 拼接数据
List<CombinationProductDO> products = combinationActivityService.getCombinationProductsByActivityIds(
convertSet(pageResult.getList(), CombinationActivityDO::getId));
List<ProductSpuRespDTO> spus = productSpuApi.getSpuList(
convertSet(pageResult.getList(), CombinationActivityDO::getSpuId));
return success(CombinationActivityConvert.INSTANCE.convertPage(pageResult, products, spus)); return success(CombinationActivityConvert.INSTANCE.convertPage(pageResult, products, spus));
} }
@GetMapping("/export-excel")
@Operation(summary = "导出拼团活动 Excel")
@PreAuthorize("@ss.hasPermission('promotion:combination-activity:export')")
@OperateLog(type = EXPORT)
public void exportCombinationActivityExcel(@Valid CombinationActivityExportReqVO exportReqVO,
HttpServletResponse response) throws IOException {
List<CombinationActivityDO> list = combinationActivityService.getCombinationActivityList(exportReqVO);
// 导出 Excel
List<CombinationActivityExcelVO> datas = CombinationActivityConvert.INSTANCE.convertList02(list);
ExcelUtils.write(response, "拼团活动.xls", "数据", CombinationActivityExcelVO.class, datas);
}
} }

View File

@ -12,6 +12,8 @@ import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_
/** /**
* 拼团活动 Base VO提供给添加修改详细的子 VO 使用 * 拼团活动 Base VO提供给添加修改详细的子 VO 使用
* 如果子 VO 存在差异的字段请不要添加到这里影响 Swagger 文档生成 * 如果子 VO 存在差异的字段请不要添加到这里影响 Swagger 文档生成
*
* @author HUIHUI
*/ */
@Data @Data
public class CombinationActivityBaseVO { public class CombinationActivityBaseVO {
@ -20,7 +22,7 @@ public class CombinationActivityBaseVO {
@NotNull(message = "拼团名称不能为空") @NotNull(message = "拼团名称不能为空")
private String name; private String name;
@Schema(description = "商品 SPU 编号,关联 ProductSpuDO 的 id", example = "[1,2,3]") @Schema(description = "商品 SPU 编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
@NotNull(message = "拼团商品不能为空") @NotNull(message = "拼团商品不能为空")
private Long spuId; private Long spuId;
@ -32,17 +34,21 @@ public class CombinationActivityBaseVO {
@NotNull(message = "单次限购数量不能为空") @NotNull(message = "单次限购数量不能为空")
private Integer singleLimitCount; private Integer singleLimitCount;
// TODO @puhui999是不是弄成 2 个字段会好点哈开始结束 @Schema(description = "活动时间", requiredMode = Schema.RequiredMode.REQUIRED, example = "[2022-07-01 23:59:59]")
@Schema(description = "活动时间", requiredMode = Schema.RequiredMode.REQUIRED, example = "[2022-07-01 00:00:00,2022-07-01 23:59:59]")
@NotNull(message = "活动时间不能为空") @NotNull(message = "活动时间不能为空")
@DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
private LocalDateTime[] activityTime; private LocalDateTime startTime;
@Schema(description = "活动时间", requiredMode = Schema.RequiredMode.REQUIRED, example = "[2022-07-01 23:59:59]")
@NotNull(message = "活动时间不能为空")
@DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
private LocalDateTime endTime;
@Schema(description = "开团人数", requiredMode = Schema.RequiredMode.REQUIRED, example = "25222") @Schema(description = "开团人数", requiredMode = Schema.RequiredMode.REQUIRED, example = "25222")
@NotNull(message = "开团人数不能为空") @NotNull(message = "开团人数不能为空")
private Integer userSize; private Integer userSize;
@Schema(description = "限制时长(小时)", requiredMode = Schema.RequiredMode.REQUIRED) @Schema(description = "限制时长(小时)", requiredMode = Schema.RequiredMode.REQUIRED, example = "2")
@NotNull(message = "限制时长不能为空") @NotNull(message = "限制时长不能为空")
private Integer limitDuration; private Integer limitDuration;

View File

@ -1,6 +1,6 @@
package cn.iocoder.yudao.module.promotion.controller.admin.combination.vo.activity; package cn.iocoder.yudao.module.promotion.controller.admin.combination.vo.activity;
import cn.iocoder.yudao.module.promotion.controller.admin.combination.vo.product.CombinationProductCreateReqVO; import cn.iocoder.yudao.module.promotion.controller.admin.combination.vo.product.CombinationProductBaseVO;
import io.swagger.v3.oas.annotations.media.Schema; import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data; import lombok.Data;
import lombok.EqualsAndHashCode; import lombok.EqualsAndHashCode;
@ -17,6 +17,6 @@ public class CombinationActivityCreateReqVO extends CombinationActivityBaseVO {
@Schema(description = "拼团商品", requiredMode = Schema.RequiredMode.REQUIRED) @Schema(description = "拼团商品", requiredMode = Schema.RequiredMode.REQUIRED)
@Valid @Valid
private List<CombinationProductCreateReqVO> products; private List<CombinationProductBaseVO> products;
} }

View File

@ -1,65 +0,0 @@
package cn.iocoder.yudao.module.promotion.controller.admin.combination.vo.activity;
import cn.iocoder.yudao.framework.excel.core.annotations.DictFormat;
import cn.iocoder.yudao.framework.excel.core.convert.DictConvert;
import com.alibaba.excel.annotation.ExcelProperty;
import lombok.Data;
import java.time.LocalDateTime;
// TODO @puhui999如无必要导出都可以删除哈
/**
* 拼团活动 Excel VO
*
* @author HUIHUI
*/
@Data
public class CombinationActivityExcelVO {
@ExcelProperty("活动编号")
private Long id;
@ExcelProperty("拼团名称")
private String name;
@ExcelProperty("商品 SPU 编号关联 ProductSpuDO 的 id")
private Long spuId;
@ExcelProperty("总限购数量")
private Integer totalLimitCount;
@ExcelProperty("单次限购数量")
private Integer singleLimitCount;
@ExcelProperty("开始时间")
private LocalDateTime startTime;
@ExcelProperty("结束时间")
private LocalDateTime endTime;
@ExcelProperty("开团人数")
private Integer userSize;
@ExcelProperty("开团组数")
private Integer totalNum;
@ExcelProperty("成团组数")
private Integer successNum;
@ExcelProperty("参与人数")
private Integer orderUserCount;
@ExcelProperty("虚拟成团")
private Integer virtualGroup;
@ExcelProperty(value = "活动状态0开启 1关闭", converter = DictConvert.class)
@DictFormat("common_status") // TODO 代码优化建议设置到对应的 XXXDictTypeConstants 枚举类中
private Integer status;
@ExcelProperty("限制时长(小时)")
private Integer limitDuration;
@ExcelProperty("创建时间")
private LocalDateTime createTime;
}

View File

@ -1,61 +0,0 @@
package cn.iocoder.yudao.module.promotion.controller.admin.combination.vo.activity;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import org.springframework.format.annotation.DateTimeFormat;
import java.time.LocalDateTime;
import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND;
// TODO @puhui999如无必要导出都可以删除哈
@Schema(description = "管理后台 - 拼团活动 Excel 导出 Request VO参数和 CombinationActivityPageReqVO 是一致的")
@Data
public class CombinationActivityExportReqVO {
@Schema(description = "拼团名称", example = "赵六")
private String name;
@Schema(description = "商品 SPU 编号关联 ProductSpuDO 的 id", example = "14016")
private Long spuId;
@Schema(description = "总限购数量", example = "16218")
private Integer totalLimitCount;
@Schema(description = "单次限购数量", example = "28265")
private Integer singleLimitCount;
@Schema(description = "开始时间")
@DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
private LocalDateTime[] startTime;
@Schema(description = "结束时间")
@DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
private LocalDateTime[] endTime;
@Schema(description = "开团人数")
private Integer userSize;
@Schema(description = "开团组数")
private Integer totalNum;
@Schema(description = "成团组数")
private Integer successNum;
@Schema(description = "参与人数", example = "25222")
private Integer orderUserCount;
@Schema(description = "虚拟成团")
private Integer virtualGroup;
@Schema(description = "活动状态0开启 1关闭", example = "0")
private Integer status;
@Schema(description = "限制时长(小时)")
private Integer limitDuration;
@Schema(description = "创建时间")
@DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
private LocalDateTime[] createTime;
}

View File

@ -5,11 +5,6 @@ import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data; import lombok.Data;
import lombok.EqualsAndHashCode; import lombok.EqualsAndHashCode;
import lombok.ToString; import lombok.ToString;
import org.springframework.format.annotation.DateTimeFormat;
import java.time.LocalDateTime;
import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND;
@Schema(description = "管理后台 - 拼团活动分页 Request VO") @Schema(description = "管理后台 - 拼团活动分页 Request VO")
@Data @Data
@ -20,46 +15,8 @@ public class CombinationActivityPageReqVO extends PageParam {
@Schema(description = "拼团名称", example = "赵六") @Schema(description = "拼团名称", example = "赵六")
private String name; private String name;
@Schema(description = "商品 SPU 编号关联 ProductSpuDO 的 id", example = "14016")
private Long spuId;
@Schema(description = "总限购数量", example = "16218")
private Integer totalLimitCount;
@Schema(description = "单次限购数量", example = "28265")
private Integer singleLimitCount;
@Schema(description = "开始时间")
@DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
private LocalDateTime[] startTime;
@Schema(description = "结束时间")
@DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
private LocalDateTime[] endTime;
@Schema(description = "开团人数")
private Integer userSize;
@Schema(description = "开团组数")
private Integer totalNum;
@Schema(description = "成团组数")
private Integer successNum;
@Schema(description = "参与人数", example = "25222")
private Integer orderUserCount;
@Schema(description = "虚拟成团")
private Integer virtualGroup;
@Schema(description = "活动状态0开启 1关闭", example = "0") @Schema(description = "活动状态0开启 1关闭", example = "0")
private Integer status; private Integer status;
@Schema(description = "限制时长(小时)")
private Integer limitDuration;
@Schema(description = "创建时间")
@DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
private LocalDateTime[] createTime;
} }

View File

@ -17,40 +17,34 @@ import java.util.List;
@ToString(callSuper = true) @ToString(callSuper = true)
public class CombinationActivityRespVO extends CombinationActivityBaseVO { public class CombinationActivityRespVO extends CombinationActivityBaseVO {
@Schema(description = "商品名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "618大促") @Schema(description = "活动编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "22901")
private Long id;
@Schema(description = "商品名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "618 大促")
private String spuName; private String spuName;
@Schema(description = "商品主图", requiredMode = Schema.RequiredMode.REQUIRED, example = "https://www.iocoder.cn/xx.png") @Schema(description = "商品主图", requiredMode = Schema.RequiredMode.REQUIRED, example = "https://www.iocoder.cn/xx.png")
private String picUrl; private String picUrl;
@Schema(description = "活动编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "22901")
private Long id;
@Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED) @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED)
private LocalDateTime createTime; private LocalDateTime createTime;
@Schema(description = "开团人数", requiredMode = Schema.RequiredMode.REQUIRED) @Schema(description = "开团人数", requiredMode = Schema.RequiredMode.REQUIRED, example = "666")
@NotNull(message = "开团人数不能为空")
private Integer userSize; private Integer userSize;
@Schema(description = "开团组数", requiredMode = Schema.RequiredMode.REQUIRED) @Schema(description = "开团组数", requiredMode = Schema.RequiredMode.REQUIRED, example = "33")
@NotNull(message = "开团组数不能为空") private Integer totalCount;
private Integer totalNum;
@Schema(description = "成团组数", requiredMode = Schema.RequiredMode.REQUIRED) @Schema(description = "成团组数", requiredMode = Schema.RequiredMode.REQUIRED, example = "20")
@NotNull(message = "成团组数不能为空") private Integer successCount;
private Integer successNum;
@Schema(description = "虚拟成团", requiredMode = Schema.RequiredMode.REQUIRED) @Schema(description = "虚拟成团", requiredMode = Schema.RequiredMode.REQUIRED, example = "10")
@NotNull(message = "虚拟成团不能为空")
private Integer virtualGroup; private Integer virtualGroup;
@Schema(description = "活动状态", requiredMode = Schema.RequiredMode.REQUIRED, example = "0") @Schema(description = "活动状态", requiredMode = Schema.RequiredMode.REQUIRED, example = "0")
@NotNull(message = "活动状态不能为空")
private Integer status; private Integer status;
@Schema(description = "拼团商品", requiredMode = Schema.RequiredMode.REQUIRED) @Schema(description = "拼团商品", requiredMode = Schema.RequiredMode.REQUIRED)
@Valid
private List<CombinationProductRespVO> products; private List<CombinationProductRespVO> products;
} }

View File

@ -1,6 +1,6 @@
package cn.iocoder.yudao.module.promotion.controller.admin.combination.vo.activity; package cn.iocoder.yudao.module.promotion.controller.admin.combination.vo.activity;
import cn.iocoder.yudao.module.promotion.controller.admin.combination.vo.product.CombinationProductUpdateReqVO; import cn.iocoder.yudao.module.promotion.controller.admin.combination.vo.product.CombinationProductBaseVO;
import io.swagger.v3.oas.annotations.media.Schema; import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data; import lombok.Data;
import lombok.EqualsAndHashCode; import lombok.EqualsAndHashCode;
@ -22,6 +22,6 @@ public class CombinationActivityUpdateReqVO extends CombinationActivityBaseVO {
@Schema(description = "拼团商品", requiredMode = Schema.RequiredMode.REQUIRED) @Schema(description = "拼团商品", requiredMode = Schema.RequiredMode.REQUIRED)
@Valid @Valid
private List<CombinationProductUpdateReqVO> products; private List<CombinationProductBaseVO> products;
} }

View File

@ -21,7 +21,7 @@ public class CombinationProductBaseVO {
private Long skuId; private Long skuId;
@Schema(description = "拼团价格,单位分", requiredMode = Schema.RequiredMode.REQUIRED, example = "27682") @Schema(description = "拼团价格,单位分", requiredMode = Schema.RequiredMode.REQUIRED, example = "27682")
@NotNull(message = "拼团价格,单位分不能为空") @NotNull(message = "拼团价格不能为空")
private Integer activePrice; private Integer combinationPrice;
} }

View File

@ -1,14 +0,0 @@
package cn.iocoder.yudao.module.promotion.controller.admin.combination.vo.product;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.ToString;
@Schema(description = "管理后台 - 拼团商品创建 Request VO")
@Data
@EqualsAndHashCode(callSuper = true)
@ToString(callSuper = true)
public class CombinationProductCreateReqVO extends CombinationProductBaseVO {
}

View File

@ -1,44 +0,0 @@
package cn.iocoder.yudao.module.promotion.controller.admin.combination.vo.product;
import com.alibaba.excel.annotation.ExcelProperty;
import lombok.Data;
import java.time.LocalDateTime;
// TODO @puhui999可以考虑删除 excel 导出哈
/**
* 拼团商品 Excel VO
*
* @author HUIHUI
*/
@Data
public class CombinationProductExcelVO {
@ExcelProperty("编号")
private Long id;
@ExcelProperty("拼团活动编号")
private Long activityId;
@ExcelProperty("商品 SPU 编号")
private Long spuId;
@ExcelProperty("商品 SKU 编号")
private Long skuId;
@ExcelProperty("拼团商品状态")
private Integer activityStatus;
@ExcelProperty("活动开始时间点")
private LocalDateTime activityStartTime;
@ExcelProperty("活动结束时间点")
private LocalDateTime activityEndTime;
@ExcelProperty("拼团价格,单位分")
private Integer activePrice;
@ExcelProperty("创建时间")
private LocalDateTime createTime;
}

View File

@ -1,43 +0,0 @@
package cn.iocoder.yudao.module.promotion.controller.admin.combination.vo.product;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import org.springframework.format.annotation.DateTimeFormat;
import java.time.LocalDateTime;
import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND;
// TODO @puhui999可以考虑删除 excel 导出哈
@Schema(description = "管理后台 - 拼团商品 Excel 导出 Request VO参数和 CombinationProductPageReqVO 是一致的")
@Data
public class CombinationProductExportReqVO {
@Schema(description = "拼团活动编号", example = "6829")
private Long activityId;
@Schema(description = "商品 SPU 编号", example = "18731")
private Long spuId;
@Schema(description = "商品 SKU 编号", example = "31675")
private Long skuId;
@Schema(description = "拼团商品状态", example = "2")
private Integer activityStatus;
@Schema(description = "活动开始时间点")
@DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
private LocalDateTime[] activityStartTime;
@Schema(description = "活动结束时间点")
@DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
private LocalDateTime[] activityEndTime;
@Schema(description = "拼团价格,单位分", example = "27682")
private Integer activePrice;
@Schema(description = "创建时间")
@DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
private LocalDateTime[] createTime;
}

View File

@ -1,14 +0,0 @@
package cn.iocoder.yudao.module.promotion.controller.admin.combination.vo.product;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.ToString;
@Schema(description = "管理后台 - 拼团商品更新 Request VO")
@Data
@EqualsAndHashCode(callSuper = true)
@ToString(callSuper = true)
public class CombinationProductUpdateReqVO extends CombinationProductBaseVO {
}

View File

@ -0,0 +1,18 @@
### /promotion/decorate/save 保存页面装修组件
POST {{baseUrl}}/promotion/decorate/save
Content-Type: application/json
Authorization: Bearer {{token}}
tenant-id: {{adminTenentId}}
{
"page": 1,
"code": "slide-show",
"status": 0,
"value": "null"
}
### /promotion/decorate/list 获取指定页面的组件列表
GET {{baseUrl}}/promotion/decorate/list?page=1
Content-Type: application/json
Authorization: Bearer {{token}}
tenant-id: {{adminTenentId}}

View File

@ -2,45 +2,49 @@ package cn.iocoder.yudao.module.promotion.controller.admin.decorate;
import cn.iocoder.yudao.framework.common.pojo.CommonResult; import cn.iocoder.yudao.framework.common.pojo.CommonResult;
import cn.iocoder.yudao.framework.common.validation.InEnum; import cn.iocoder.yudao.framework.common.validation.InEnum;
import cn.iocoder.yudao.module.promotion.controller.admin.decorate.vo.DecorateComponentSaveReqVO;
import cn.iocoder.yudao.module.promotion.controller.admin.decorate.vo.DecorateComponentRespVO; import cn.iocoder.yudao.module.promotion.controller.admin.decorate.vo.DecorateComponentRespVO;
import cn.iocoder.yudao.module.promotion.controller.admin.decorate.vo.DecorateComponentSaveReqVO;
import cn.iocoder.yudao.module.promotion.convert.decorate.DecorateComponentConvert;
import cn.iocoder.yudao.module.promotion.enums.decorate.DecoratePageEnum; import cn.iocoder.yudao.module.promotion.enums.decorate.DecoratePageEnum;
import cn.iocoder.yudao.module.promotion.service.decorate.DecorateComponentService; import cn.iocoder.yudao.module.promotion.service.decorate.DecorateComponentService;
import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter; import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.tags.Tag; import io.swagger.v3.oas.annotations.tags.Tag;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.validation.annotation.Validated; import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*; import org.springframework.web.bind.annotation.*;
import javax.annotation.Resource; import javax.annotation.Resource;
import javax.validation.Valid; import javax.validation.Valid;
import java.util.List;
import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
import static cn.iocoder.yudao.module.promotion.convert.decorate.DecorateComponentConvert.INSTANCE;
@Tag(name = "管理后台 - 店铺页面装修") @Tag(name = "管理后台 - 店铺页面装修")
@RestController @RestController
@RequestMapping("/promotion/decorate") @RequestMapping("/promotion/decorate")
@Validated @Validated
public class DecorateComponentController { public class DecorateComponentController {
@Resource @Resource
private DecorateComponentService decorateComponentService; private DecorateComponentService decorateComponentService;
@PostMapping("/page-save") @PostMapping("/save")
@Operation(summary = "保存页面装修") @Operation(summary = "保存页面装修组件")
// TODO 加权限 @PreAuthorize("@ss.hasPermission('promotion:decorate:save')")
public CommonResult<Boolean> savePageComponents(@Valid @RequestBody DecorateComponentSaveReqVO reqVO) { public CommonResult<Boolean> saveDecorateComponent(@Valid @RequestBody DecorateComponentSaveReqVO reqVO) {
decorateComponentService.savePageComponents(reqVO); decorateComponentService.saveDecorateComponent(reqVO);
return success(true); return success(true);
} }
@GetMapping("/get-page-components") @GetMapping("/list")
@Operation(summary = "获取装修页面组件") @Operation(summary = "获取指定页面的组件列表")
@Parameter(name = "pageId", description = "页面 id", required = true) @Parameter(name = "page", description = "页面 id", required = true)
// TODO 加权限 @PreAuthorize("@ss.hasPermission('promotion:decorate:query')")
public CommonResult<DecorateComponentRespVO> getPageComponents( public CommonResult<List<DecorateComponentRespVO>> getDecorateComponentListByPage(
@RequestParam("pageId") @InEnum(DecoratePageEnum.class) Integer pageId) { @RequestParam("page") @InEnum(DecoratePageEnum.class) Integer page) {
return success(INSTANCE.convert2(pageId, decorateComponentService.getPageComponents(pageId))); return success(DecorateComponentConvert.INSTANCE.convertList02(
decorateComponentService.getDecorateComponentListByPage(page, null)));
} }
} }

View File

@ -3,31 +3,17 @@ package cn.iocoder.yudao.module.promotion.controller.admin.decorate.vo;
import io.swagger.v3.oas.annotations.media.Schema; import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data; import lombok.Data;
import java.util.List;
@Schema(description = "管理后台 - 页面装修 Resp VO") @Schema(description = "管理后台 - 页面装修 Resp VO")
@Data @Data
public class DecorateComponentRespVO { public class DecorateComponentRespVO {
@Schema(description = "页面 id ", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") @Schema(description = "组件编码", requiredMode = Schema.RequiredMode.REQUIRED, example = "nav-menu")
private Integer pageId; private String code;
@Schema(description = "页面组件", requiredMode = Schema.RequiredMode.REQUIRED, example = "TODO") @Schema(description = "组件的内容配置项", requiredMode = Schema.RequiredMode.NOT_REQUIRED, example = "TODO")
private List<ComponentRespVO> components; private String value;
@Schema(description = "管理后台 - 页面组件 Resp VO") @Schema(description = "状态", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
@Data private Integer status;
public static class ComponentRespVO {
@Schema(description = "组件编码", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
private Long id;
@Schema(description = "组件编码", requiredMode = Schema.RequiredMode.REQUIRED, example = "nav-menu")
private String code;
@Schema(description = "组件的内容配置项", requiredMode = Schema.RequiredMode.NOT_REQUIRED, example = "TODO")
private String value;
}
} }

View File

@ -5,10 +5,8 @@ import cn.iocoder.yudao.module.promotion.enums.decorate.DecoratePageEnum;
import io.swagger.v3.oas.annotations.media.Schema; import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data; import lombok.Data;
import javax.validation.Valid;
import javax.validation.constraints.NotEmpty; import javax.validation.constraints.NotEmpty;
import javax.validation.constraints.NotNull; import javax.validation.constraints.NotNull;
import java.util.List;
@Schema(description = "管理后台 - 页面装修的保存 Request VO ") @Schema(description = "管理后台 - 页面装修的保存 Request VO ")
@Data @Data
@ -17,28 +15,17 @@ public class DecorateComponentSaveReqVO {
@Schema(description = "页面 id ", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") @Schema(description = "页面 id ", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
@NotNull(message = "页面 id 不能为空") @NotNull(message = "页面 id 不能为空")
@InEnum(DecoratePageEnum.class) @InEnum(DecoratePageEnum.class)
private Integer pageId; private Integer page;
@Schema(description = "页面组件列表", requiredMode = Schema.RequiredMode.REQUIRED, example = "TODO") @Schema(description = "组件编码", requiredMode = Schema.RequiredMode.REQUIRED, example = "nav-menu")
@NotEmpty(message = "页面组件列表不能为空") @NotEmpty(message = "组件编码不能为空")
@Valid private String code;
private List<ComponentReqVO> components;
@Schema(description = "管理后台 - 页面装修组件 Request VO") @Schema(description = "组件对应值, json 字符串, 含内容配置,具体数据", requiredMode = Schema.RequiredMode.REQUIRED)
@Data @NotEmpty(message = "组件值为空")
public static class ComponentReqVO { private String value;
@Schema(description = "组件编码", example = "1") @Schema(description = "状态", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
private Long id; private Integer status;
@Schema(description = "组件编码", requiredMode = Schema.RequiredMode.REQUIRED, example = "nav-menu")
@NotEmpty(message = "组件编码不能为空")
private String code;
@Schema(description = "组件对应值, json 字符串, 含内容配置,具体数据", requiredMode = Schema.RequiredMode.REQUIRED, example = "TODO")
@NotEmpty(message = "组件值为空")
private String value;
}
} }

View File

@ -1,15 +1,15 @@
package cn.iocoder.yudao.module.promotion.controller.admin.seckill; package cn.iocoder.yudao.module.promotion.controller.admin.seckill;
import cn.hutool.core.collection.CollUtil;
import cn.iocoder.yudao.framework.common.pojo.CommonResult; import cn.iocoder.yudao.framework.common.pojo.CommonResult;
import cn.iocoder.yudao.framework.common.pojo.PageResult; import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils;
import cn.iocoder.yudao.module.product.api.spu.ProductSpuApi; import cn.iocoder.yudao.module.product.api.spu.ProductSpuApi;
import cn.iocoder.yudao.module.product.api.spu.dto.ProductSpuRespDTO; import cn.iocoder.yudao.module.product.api.spu.dto.ProductSpuRespDTO;
import cn.iocoder.yudao.module.promotion.controller.admin.seckill.vo.activity.*; import cn.iocoder.yudao.module.promotion.controller.admin.seckill.vo.activity.*;
import cn.iocoder.yudao.module.promotion.convert.seckill.seckillactivity.SeckillActivityConvert; import cn.iocoder.yudao.module.promotion.convert.seckill.seckillactivity.SeckillActivityConvert;
import cn.iocoder.yudao.module.promotion.dal.dataobject.seckill.seckillactivity.SeckillActivityDO; import cn.iocoder.yudao.module.promotion.dal.dataobject.seckill.seckillactivity.SeckillActivityDO;
import cn.iocoder.yudao.module.promotion.dal.dataobject.seckill.seckillactivity.SeckillProductDO; import cn.iocoder.yudao.module.promotion.dal.dataobject.seckill.seckillactivity.SeckillProductDO;
import cn.iocoder.yudao.module.promotion.service.seckill.seckillactivity.SeckillActivityService; import cn.iocoder.yudao.module.promotion.service.seckill.SeckillActivityService;
import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter; import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.tags.Tag; import io.swagger.v3.oas.annotations.tags.Tag;
@ -19,11 +19,10 @@ import org.springframework.web.bind.annotation.*;
import javax.annotation.Resource; import javax.annotation.Resource;
import javax.validation.Valid; import javax.validation.Valid;
import java.util.Collection;
import java.util.List; import java.util.List;
import java.util.Set;
import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet;
@Tag(name = "管理后台 - 秒杀活动") @Tag(name = "管理后台 - 秒杀活动")
@RestController @RestController
@ -34,7 +33,7 @@ public class SeckillActivityController {
@Resource @Resource
private SeckillActivityService seckillActivityService; private SeckillActivityService seckillActivityService;
@Resource @Resource
private ProductSpuApi spuApi; private ProductSpuApi productSpuApi;
@PostMapping("/create") @PostMapping("/create")
@Operation(summary = "创建秒杀活动") @Operation(summary = "创建秒杀活动")
@ -74,30 +73,27 @@ public class SeckillActivityController {
@Parameter(name = "id", description = "编号", required = true, example = "1024") @Parameter(name = "id", description = "编号", required = true, example = "1024")
@PreAuthorize("@ss.hasPermission('promotion:seckill-activity:query')") @PreAuthorize("@ss.hasPermission('promotion:seckill-activity:query')")
public CommonResult<SeckillActivityDetailRespVO> getSeckillActivity(@RequestParam("id") Long id) { public CommonResult<SeckillActivityDetailRespVO> getSeckillActivity(@RequestParam("id") Long id) {
SeckillActivityDO seckillActivity = seckillActivityService.getSeckillActivity(id); SeckillActivityDO activity = seckillActivityService.getSeckillActivity(id);
List<SeckillProductDO> seckillProducts = seckillActivityService.getSeckillProductListByActivityId(id); List<SeckillProductDO> products = seckillActivityService.getSeckillProductListByActivityId(id);
return success(SeckillActivityConvert.INSTANCE.convert(seckillActivity, seckillProducts)); return success(SeckillActivityConvert.INSTANCE.convert(activity, products));
}
@GetMapping("/list")
@Operation(summary = "获得秒杀活动列表")
@Parameter(name = "ids", description = "编号列表", required = true, example = "1024,2048")
@PreAuthorize("@ss.hasPermission('promotion:seckill-activity:query')")
public CommonResult<List<SeckillActivityRespVO>> getSeckillActivityList(@RequestParam("ids") Collection<Long> ids) {
List<SeckillActivityDO> list = seckillActivityService.getSeckillActivityList(ids);
return success(SeckillActivityConvert.INSTANCE.convertList(list));
} }
@GetMapping("/page") @GetMapping("/page")
@Operation(summary = "获得秒杀活动分页") @Operation(summary = "获得秒杀活动分页")
@PreAuthorize("@ss.hasPermission('promotion:seckill-activity:query')") @PreAuthorize("@ss.hasPermission('promotion:seckill-activity:query')")
public CommonResult<PageResult<SeckillActivityRespVO>> getSeckillActivityPage(@Valid SeckillActivityPageReqVO pageVO) { public CommonResult<PageResult<SeckillActivityRespVO>> getSeckillActivityPage(@Valid SeckillActivityPageReqVO pageVO) {
// 查询活动列表
PageResult<SeckillActivityDO> pageResult = seckillActivityService.getSeckillActivityPage(pageVO); PageResult<SeckillActivityDO> pageResult = seckillActivityService.getSeckillActivityPage(pageVO);
Set<Long> aIds = CollectionUtils.convertSet(pageResult.getList(), SeckillActivityDO::getId); if (CollUtil.isEmpty(pageResult.getList())) {
List<SeckillProductDO> seckillProducts = seckillActivityService.getSeckillProductListByActivityId(aIds); return success(PageResult.empty(pageResult.getTotal()));
Set<Long> spuIds = CollectionUtils.convertSet(pageResult.getList(), SeckillActivityDO::getSpuId); }
List<ProductSpuRespDTO> spuList = spuApi.getSpuList(spuIds);
return success(SeckillActivityConvert.INSTANCE.convertPage(pageResult, seckillProducts, spuList)); // 拼接数据
List<SeckillProductDO> products = seckillActivityService.getSeckillProductListByActivityId(
convertSet(pageResult.getList(), SeckillActivityDO::getId));
List<ProductSpuRespDTO> spuList = productSpuApi.getSpuList(
convertSet(pageResult.getList(), SeckillActivityDO::getSpuId));
return success(SeckillActivityConvert.INSTANCE.convertPage(pageResult, products, spuList));
} }
} }

View File

@ -1,11 +1,12 @@
package cn.iocoder.yudao.module.promotion.controller.admin.seckill; package cn.iocoder.yudao.module.promotion.controller.admin.seckill;
import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
import cn.iocoder.yudao.framework.common.pojo.CommonResult; import cn.iocoder.yudao.framework.common.pojo.CommonResult;
import cn.iocoder.yudao.framework.common.pojo.PageResult; import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.module.promotion.controller.admin.seckill.vo.config.*; import cn.iocoder.yudao.module.promotion.controller.admin.seckill.vo.config.*;
import cn.iocoder.yudao.module.promotion.convert.seckill.seckillconfig.SeckillConfigConvert; import cn.iocoder.yudao.module.promotion.convert.seckill.seckillconfig.SeckillConfigConvert;
import cn.iocoder.yudao.module.promotion.dal.dataobject.seckill.seckillconfig.SeckillConfigDO; import cn.iocoder.yudao.module.promotion.dal.dataobject.seckill.seckillconfig.SeckillConfigDO;
import cn.iocoder.yudao.module.promotion.service.seckill.seckillconfig.SeckillConfigService; import cn.iocoder.yudao.module.promotion.service.seckill.SeckillConfigService;
import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter; import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.tags.Tag; import io.swagger.v3.oas.annotations.tags.Tag;
@ -80,7 +81,7 @@ public class SeckillConfigController {
@GetMapping("/list-all-simple") @GetMapping("/list-all-simple")
@Operation(summary = "获得所有开启状态的秒杀时段精简列表", description = "主要用于前端的下拉选项") @Operation(summary = "获得所有开启状态的秒杀时段精简列表", description = "主要用于前端的下拉选项")
public CommonResult<List<SeckillConfigSimpleRespVO>> getListAllSimple() { public CommonResult<List<SeckillConfigSimpleRespVO>> getListAllSimple() {
List<SeckillConfigDO> list = seckillConfigService.getListAllSimple(); List<SeckillConfigDO> list = seckillConfigService.getSeckillConfigListByStatus(CommonStatusEnum.ENABLE.getStatus());
return success(SeckillConfigConvert.INSTANCE.convertList1(list)); return success(SeckillConfigConvert.INSTANCE.convertList1(list));
} }
@ -91,4 +92,5 @@ public class SeckillConfigController {
PageResult<SeckillConfigDO> pageResult = seckillConfigService.getSeckillConfigPage(pageVO); PageResult<SeckillConfigDO> pageResult = seckillConfigService.getSeckillConfigPage(pageVO);
return success(SeckillConfigConvert.INSTANCE.convertPage(pageResult)); return success(SeckillConfigConvert.INSTANCE.convertPage(pageResult));
} }
} }

View File

@ -20,7 +20,7 @@ import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_
@Data @Data
public class SeckillActivityBaseVO { public class SeckillActivityBaseVO {
@Schema(description = "秒杀活动商品id", requiredMode = Schema.RequiredMode.REQUIRED, example = "[121,1212]") @Schema(description = "秒杀活动商品 id", requiredMode = Schema.RequiredMode.REQUIRED, example = "[121,1212]")
@NotNull(message = "秒杀活动商品不能为空") @NotNull(message = "秒杀活动商品不能为空")
private Long spuId; private Long spuId;

View File

@ -1,7 +1,7 @@
package cn.iocoder.yudao.module.promotion.controller.admin.seckill.vo.activity; package cn.iocoder.yudao.module.promotion.controller.admin.seckill.vo.activity;
import cn.iocoder.yudao.module.promotion.controller.admin.seckill.vo.product.SeckillProductCreateReqVO; import cn.iocoder.yudao.module.promotion.controller.admin.seckill.vo.product.SeckillProductBaseVO;
import io.swagger.v3.oas.annotations.media.Schema; import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data; import lombok.Data;
import lombok.EqualsAndHashCode; import lombok.EqualsAndHashCode;
@ -16,6 +16,6 @@ import java.util.List;
public class SeckillActivityCreateReqVO extends SeckillActivityBaseVO { public class SeckillActivityCreateReqVO extends SeckillActivityBaseVO {
@Schema(description = "秒杀商品", requiredMode = Schema.RequiredMode.REQUIRED) @Schema(description = "秒杀商品", requiredMode = Schema.RequiredMode.REQUIRED)
private List<SeckillProductCreateReqVO> products; private List<SeckillProductBaseVO> products;
} }

View File

@ -21,28 +21,28 @@ public class SeckillActivityRespVO extends SeckillActivityBaseVO {
@Schema(description = "商品主图", requiredMode = Schema.RequiredMode.REQUIRED, example = "https://www.iocoder.cn/xx.png") @Schema(description = "商品主图", requiredMode = Schema.RequiredMode.REQUIRED, example = "https://www.iocoder.cn/xx.png")
private String picUrl; private String picUrl;
@Schema(description = "秒杀活动id", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") @Schema(description = "秒杀活动 id", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
private Long id; private Long id;
@Schema(description = "秒杀商品", requiredMode = Schema.RequiredMode.REQUIRED) @Schema(description = "秒杀商品", requiredMode = Schema.RequiredMode.REQUIRED)
private List<SeckillProductRespVO> products; private List<SeckillProductRespVO> products;
@Schema(description = "活动状态 开启0 禁用1", requiredMode = Schema.RequiredMode.REQUIRED, example = "0") @Schema(description = "活动状态", requiredMode = Schema.RequiredMode.REQUIRED, example = "0")
private Integer status; private Integer status;
@Schema(description = "订单实付金额,单位:分", requiredMode = Schema.RequiredMode.REQUIRED, example = "22354") @Schema(description = "订单实付金额,单位:分", requiredMode = Schema.RequiredMode.REQUIRED, example = "22354")
private Integer totalPrice; private Integer totalPrice;
@Schema(description = "秒杀库存", example = "10") @Schema(description = "秒杀库存", requiredMode = Schema.RequiredMode.REQUIRED, example = "10")
private Integer stock; private Integer stock;
@Schema(description = "秒杀总库存", example = "20") @Schema(description = "秒杀总库存", requiredMode = Schema.RequiredMode.REQUIRED, example = "20")
private Integer totalStock; private Integer totalStock;
@Schema(description = "新增订单数", example = "20") @Schema(description = "新增订单数", requiredMode = Schema.RequiredMode.REQUIRED, example = "20")
private Integer orderCount; private Integer orderCount;
@Schema(description = "付款人数", example = "20") @Schema(description = "付款人数", requiredMode = Schema.RequiredMode.REQUIRED, example = "20")
private Integer userCount; private Integer userCount;
@Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED) @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED)

View File

@ -1,6 +1,6 @@
package cn.iocoder.yudao.module.promotion.controller.admin.seckill.vo.activity; package cn.iocoder.yudao.module.promotion.controller.admin.seckill.vo.activity;
import cn.iocoder.yudao.module.promotion.controller.admin.seckill.vo.product.SeckillProductUpdateReqVO; import cn.iocoder.yudao.module.promotion.controller.admin.seckill.vo.product.SeckillProductBaseVO;
import io.swagger.v3.oas.annotations.media.Schema; import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data; import lombok.Data;
import lombok.EqualsAndHashCode; import lombok.EqualsAndHashCode;
@ -18,6 +18,6 @@ public class SeckillActivityUpdateReqVO extends SeckillActivityBaseVO {
private Long id; private Long id;
@Schema(description = "秒杀商品", requiredMode = Schema.RequiredMode.REQUIRED) @Schema(description = "秒杀商品", requiredMode = Schema.RequiredMode.REQUIRED)
private List<SeckillProductUpdateReqVO> products; private List<SeckillProductBaseVO> products;
} }

View File

@ -22,7 +22,7 @@ public class SeckillProductBaseVO {
@NotNull(message = "秒杀金额,单位:分不能为空") @NotNull(message = "秒杀金额,单位:分不能为空")
private Integer seckillPrice; private Integer seckillPrice;
@Schema(description = "秒杀库存", requiredMode = Schema.RequiredMode.REQUIRED) @Schema(description = "秒杀库存", requiredMode = Schema.RequiredMode.REQUIRED, example = "100")
@NotNull(message = "秒杀库存不能为空") @NotNull(message = "秒杀库存不能为空")
private Integer stock; private Integer stock;

View File

@ -1,13 +0,0 @@
package cn.iocoder.yudao.module.promotion.controller.admin.seckill.vo.product;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.ToString;
@Schema(description = "管理后台 - 秒杀参与商品创建 Request VO")
@Data
@EqualsAndHashCode(callSuper = true)
@ToString(callSuper = true)
public class SeckillProductCreateReqVO extends SeckillProductBaseVO {
}

View File

@ -1,14 +0,0 @@
package cn.iocoder.yudao.module.promotion.controller.admin.seckill.vo.product;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.ToString;
@Schema(description = "管理后台 - 秒杀参与商品更新 Request VO")
@Data
@EqualsAndHashCode(callSuper = true)
@ToString(callSuper = true)
public class SeckillProductUpdateReqVO extends SeckillProductBaseVO {
}

View File

@ -2,22 +2,26 @@ package cn.iocoder.yudao.module.promotion.controller.app.coupon;
import cn.iocoder.yudao.framework.common.pojo.CommonResult; import cn.iocoder.yudao.framework.common.pojo.CommonResult;
import cn.iocoder.yudao.framework.common.pojo.PageResult; import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.security.core.annotations.PreAuthenticated;
import cn.iocoder.yudao.module.promotion.controller.app.coupon.vo.coupon.AppCouponMatchReqVO; import cn.iocoder.yudao.module.promotion.controller.app.coupon.vo.coupon.AppCouponMatchReqVO;
import cn.iocoder.yudao.module.promotion.controller.app.coupon.vo.coupon.AppCouponMatchRespVO; import cn.iocoder.yudao.module.promotion.controller.app.coupon.vo.coupon.AppCouponMatchRespVO;
import cn.iocoder.yudao.module.promotion.controller.app.coupon.vo.coupon.AppCouponPageReqVO; import cn.iocoder.yudao.module.promotion.controller.app.coupon.vo.coupon.AppCouponPageReqVO;
import cn.iocoder.yudao.module.promotion.controller.app.coupon.vo.coupon.AppCouponRespVO; import cn.iocoder.yudao.module.promotion.controller.app.coupon.vo.coupon.AppCouponRespVO;
import cn.iocoder.yudao.module.promotion.controller.app.coupon.vo.template.AppCouponTemplatePageReqVO; import cn.iocoder.yudao.module.promotion.controller.app.coupon.vo.template.AppCouponTemplatePageReqVO;
import cn.iocoder.yudao.module.promotion.service.coupon.CouponService;
import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag; import io.swagger.v3.oas.annotations.tags.Tag;
import org.springframework.validation.annotation.Validated; import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*; import org.springframework.web.bind.annotation.*;
import javax.annotation.Resource;
import java.time.LocalDateTime; import java.time.LocalDateTime;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.Random; import java.util.Random;
import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
import static cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils.getLoginUserId;
@Tag(name = "用户 App - 优惠劵") @Tag(name = "用户 App - 优惠劵")
@RestController @RestController
@ -25,6 +29,9 @@ import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
@Validated @Validated
public class AppCouponController { public class AppCouponController {
@Resource
private CouponService couponService;
// TODO 芋艿待实现 // TODO 芋艿待实现
@PostMapping("/take") @PostMapping("/take")
@Operation(summary = "领取优惠劵") @Operation(summary = "领取优惠劵")
@ -93,4 +100,11 @@ public class AppCouponController {
return success(new PageResult<>(list, 20L)); return success(new PageResult<>(list, 20L));
} }
@GetMapping(value = "/get-unused-count")
@Operation(summary = "获得未使用的优惠劵数量")
@PreAuthenticated
public CommonResult<Long> getUnusedCouponCount() {
return success(couponService.getUnusedCouponCount(getLoginUserId()));
}
} }

View File

@ -1,8 +1,10 @@
package cn.iocoder.yudao.module.promotion.controller.app.decorate; package cn.iocoder.yudao.module.promotion.controller.app.decorate;
import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
import cn.iocoder.yudao.framework.common.pojo.CommonResult; import cn.iocoder.yudao.framework.common.pojo.CommonResult;
import cn.iocoder.yudao.framework.common.validation.InEnum; import cn.iocoder.yudao.framework.common.validation.InEnum;
import cn.iocoder.yudao.module.promotion.controller.app.decorate.vo.AppDecorateComponentRespVO; import cn.iocoder.yudao.module.promotion.controller.app.decorate.vo.AppDecorateComponentRespVO;
import cn.iocoder.yudao.module.promotion.convert.decorate.DecorateComponentConvert;
import cn.iocoder.yudao.module.promotion.enums.decorate.DecoratePageEnum; import cn.iocoder.yudao.module.promotion.enums.decorate.DecoratePageEnum;
import cn.iocoder.yudao.module.promotion.service.decorate.DecorateComponentService; import cn.iocoder.yudao.module.promotion.service.decorate.DecorateComponentService;
import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.Operation;
@ -15,9 +17,9 @@ import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController; import org.springframework.web.bind.annotation.RestController;
import javax.annotation.Resource; import javax.annotation.Resource;
import java.util.List;
import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
import static cn.iocoder.yudao.module.promotion.convert.decorate.DecorateComponentConvert.INSTANCE;
@Tag(name = "用户 APP - 店铺装修") @Tag(name = "用户 APP - 店铺装修")
@RestController @RestController
@ -28,12 +30,13 @@ public class AppDecorateController {
@Resource @Resource
private DecorateComponentService decorateComponentService; private DecorateComponentService decorateComponentService;
@GetMapping("/get-page-components") @GetMapping("/list")
@Operation(summary = "获取装修页面组件") @Operation(summary = "获取指定页面的组件列表")
@Parameter(name = "pageId", description = "页面 id", required = true) @Parameter(name = "page", description = "页面编号", required = true)
public CommonResult<AppDecorateComponentRespVO> getPageComponents( public CommonResult<List<AppDecorateComponentRespVO>> getDecorateComponentListByPage(
@RequestParam("pageId") @InEnum(DecoratePageEnum.class) Integer pageId) { @RequestParam("page") @InEnum(DecoratePageEnum.class) Integer page) {
return success(INSTANCE.appConvert(pageId, decorateComponentService.getPageComponents(pageId))); return success(DecorateComponentConvert.INSTANCE.convertList(
decorateComponentService.getDecorateComponentListByPage(page, CommonStatusEnum.ENABLE.getStatus())));
} }
} }

View File

@ -3,28 +3,14 @@ package cn.iocoder.yudao.module.promotion.controller.app.decorate.vo;
import io.swagger.v3.oas.annotations.media.Schema; import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data; import lombok.Data;
import java.util.List; @Schema(description = "用户 App - 页面组件 Resp VO")
@Schema(description = "用户 App - 页面装修 Resp VO")
@Data @Data
public class AppDecorateComponentRespVO { public class AppDecorateComponentRespVO {
@Schema(description = "页面 id ", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") @Schema(description = "组件编码", requiredMode = Schema.RequiredMode.REQUIRED, example = "nav-menu")
private Integer pageId; private String code;
@Schema(description = "页面组件", requiredMode = Schema.RequiredMode.REQUIRED, example = "TODO") @Schema(description = "组件的内容配置项", requiredMode = Schema.RequiredMode.NOT_REQUIRED, example = "TODO")
private List<AppComponentRespVO> components; private String value;
@Schema(description = "用户 App - 页面组件 Resp VO")
@Data
public static class AppComponentRespVO {
@Schema(description = "组件编码", requiredMode = Schema.RequiredMode.REQUIRED, example = "nav-menu")
private String code;
@Schema(description = "组件的内容配置项", requiredMode = Schema.RequiredMode.NOT_REQUIRED, example = "TODO")
private String value;
}
} }

View File

@ -0,0 +1,33 @@
package cn.iocoder.yudao.module.promotion.convert.bargain;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.module.promotion.controller.admin.bargain.vo.BargainActivityBaseVO;
import cn.iocoder.yudao.module.promotion.controller.admin.bargain.vo.BargainActivityRespVO;
import cn.iocoder.yudao.module.promotion.controller.admin.bargain.vo.BargainActivityUpdateReqVO;
import cn.iocoder.yudao.module.promotion.dal.dataobject.bargain.BargainActivityDO;
import org.mapstruct.Mapper;
import org.mapstruct.factory.Mappers;
import java.util.List;
/**
* 拼团活动 Convert
*
* @author HUIHUI
*/
@Mapper
public interface BargainActivityConvert {
BargainActivityConvert INSTANCE = Mappers.getMapper(BargainActivityConvert.class);
BargainActivityDO convert(BargainActivityBaseVO bean);
BargainActivityDO convert(BargainActivityUpdateReqVO bean);
BargainActivityRespVO convert(BargainActivityDO bean);
List<BargainActivityRespVO> convertList(List<BargainActivityDO> list);
PageResult<BargainActivityRespVO> convertPage(PageResult<BargainActivityDO> page);
}

View File

@ -1,27 +1,24 @@
package cn.iocoder.yudao.module.promotion.convert.combination; package cn.iocoder.yudao.module.promotion.convert.combination;
import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
import cn.iocoder.yudao.framework.common.pojo.PageResult; import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils;
import cn.iocoder.yudao.framework.common.util.collection.MapUtils;
import cn.iocoder.yudao.module.product.api.spu.dto.ProductSpuRespDTO; import cn.iocoder.yudao.module.product.api.spu.dto.ProductSpuRespDTO;
import cn.iocoder.yudao.module.promotion.api.combination.dto.CombinationRecordReqDTO; import cn.iocoder.yudao.module.promotion.api.combination.dto.CombinationRecordCreateReqDTO;
import cn.iocoder.yudao.module.promotion.api.combination.dto.CombinationRecordRespDTO;
import cn.iocoder.yudao.module.promotion.controller.admin.combination.vo.activity.CombinationActivityCreateReqVO; import cn.iocoder.yudao.module.promotion.controller.admin.combination.vo.activity.CombinationActivityCreateReqVO;
import cn.iocoder.yudao.module.promotion.controller.admin.combination.vo.activity.CombinationActivityExcelVO;
import cn.iocoder.yudao.module.promotion.controller.admin.combination.vo.activity.CombinationActivityRespVO; import cn.iocoder.yudao.module.promotion.controller.admin.combination.vo.activity.CombinationActivityRespVO;
import cn.iocoder.yudao.module.promotion.controller.admin.combination.vo.activity.CombinationActivityUpdateReqVO; import cn.iocoder.yudao.module.promotion.controller.admin.combination.vo.activity.CombinationActivityUpdateReqVO;
import cn.iocoder.yudao.module.promotion.controller.admin.combination.vo.product.CombinationProductBaseVO; import cn.iocoder.yudao.module.promotion.controller.admin.combination.vo.product.CombinationProductBaseVO;
import cn.iocoder.yudao.module.promotion.controller.admin.combination.vo.product.CombinationProductRespVO; import cn.iocoder.yudao.module.promotion.controller.admin.combination.vo.product.CombinationProductRespVO;
import cn.iocoder.yudao.module.promotion.controller.admin.combination.vo.product.CombinationProductUpdateReqVO; import cn.iocoder.yudao.module.promotion.dal.dataobject.combination.CombinationActivityDO;
import cn.iocoder.yudao.module.promotion.dal.dataobject.combination.combinationactivity.CombinationActivityDO; import cn.iocoder.yudao.module.promotion.dal.dataobject.combination.CombinationProductDO;
import cn.iocoder.yudao.module.promotion.dal.dataobject.combination.combinationactivity.CombinationProductDO; import cn.iocoder.yudao.module.promotion.dal.dataobject.combination.CombinationRecordDO;
import cn.iocoder.yudao.module.promotion.dal.dataobject.combination.combinationactivity.CombinationRecordDO;
import org.mapstruct.Mapper; import org.mapstruct.Mapper;
import org.mapstruct.Mapping; import org.mapstruct.Mapping;
import org.mapstruct.Mappings; import org.mapstruct.Mappings;
import org.mapstruct.Named;
import org.mapstruct.factory.Mappers; import org.mapstruct.factory.Mappers;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
@ -37,38 +34,16 @@ public interface CombinationActivityConvert {
CombinationActivityConvert INSTANCE = Mappers.getMapper(CombinationActivityConvert.class); CombinationActivityConvert INSTANCE = Mappers.getMapper(CombinationActivityConvert.class);
@Mappings({
@Mapping(target = "startTime", expression = "java(bean.getActivityTime()[0])"),
@Mapping(target = "endTime", expression = "java(bean.getActivityTime()[1])")
})
CombinationActivityDO convert(CombinationActivityCreateReqVO bean); CombinationActivityDO convert(CombinationActivityCreateReqVO bean);
@Mappings({
@Mapping(target = "startTime", expression = "java(bean.getActivityTime()[0])"),
@Mapping(target = "endTime", expression = "java(bean.getActivityTime()[1])")
})
CombinationActivityDO convert(CombinationActivityUpdateReqVO bean); CombinationActivityDO convert(CombinationActivityUpdateReqVO bean);
@Named("mergeTime")
default LocalDateTime[] mergeTime(LocalDateTime startTime, LocalDateTime endTime) {
// TODO 有点怪第一次这样写 hh
LocalDateTime[] localDateTime = new LocalDateTime[2];
localDateTime[0] = startTime;
localDateTime[1] = endTime;
return localDateTime;
}
@Mappings({
@Mapping(target = "activityTime", expression = "java(mergeTime(bean.getStartTime(),bean.getEndTime()))")
})
CombinationActivityRespVO convert(CombinationActivityDO bean); CombinationActivityRespVO convert(CombinationActivityDO bean);
CombinationProductRespVO convert(CombinationProductDO bean); CombinationProductRespVO convert(CombinationProductDO bean);
default CombinationActivityRespVO convert(CombinationActivityDO bean, List<CombinationProductDO> productDOs) { default CombinationActivityRespVO convert(CombinationActivityDO activity, List<CombinationProductDO> products) {
CombinationActivityRespVO respVO = convert(bean); return convert(activity).setProducts(convertList2(products));
respVO.setProducts(convertList2(productDOs));
return respVO;
} }
List<CombinationActivityRespVO> convertList(List<CombinationActivityDO> list); List<CombinationActivityRespVO> convertList(List<CombinationActivityDO> list);
@ -78,13 +53,13 @@ public interface CombinationActivityConvert {
default PageResult<CombinationActivityRespVO> convertPage(PageResult<CombinationActivityDO> page, default PageResult<CombinationActivityRespVO> convertPage(PageResult<CombinationActivityDO> page,
List<CombinationProductDO> productList, List<CombinationProductDO> productList,
List<ProductSpuRespDTO> spuList) { List<ProductSpuRespDTO> spuList) {
// TODO @puhui999c -> c 可以去掉哈 Map<Long, ProductSpuRespDTO> spuMap = convertMap(spuList, ProductSpuRespDTO::getId);
Map<Long, ProductSpuRespDTO> spuMap = convertMap(spuList, ProductSpuRespDTO::getId, c -> c);
PageResult<CombinationActivityRespVO> pageResult = convertPage(page); PageResult<CombinationActivityRespVO> pageResult = convertPage(page);
pageResult.getList().forEach(item -> { pageResult.getList().forEach(item -> {
// TODO @puhui999最好 MapUtils.findAndThen万一没找到呢啊哈哈 MapUtils.findAndThen(spuMap, item.getSpuId(), spu -> {
item.setSpuName(spuMap.get(item.getSpuId()).getName()); item.setSpuName(spu.getName());
item.setPicUrl(spuMap.get(item.getSpuId()).getPicUrl()); item.setPicUrl(spu.getPicUrl());
});
item.setProducts(convertList2(productList)); item.setProducts(convertList2(productList));
}); });
return pageResult; return pageResult;
@ -92,47 +67,31 @@ public interface CombinationActivityConvert {
List<CombinationProductRespVO> convertList2(List<CombinationProductDO> productDOs); List<CombinationProductRespVO> convertList2(List<CombinationProductDO> productDOs);
List<CombinationActivityExcelVO> convertList02(List<CombinationActivityDO> list);
@Mappings({ @Mappings({
@Mapping(target = "id", ignore = true), @Mapping(target = "id", ignore = true),
@Mapping(target = "activityId", source = "activityDO.id"), @Mapping(target = "activityId", source = "activity.id"),
@Mapping(target = "spuId", source = "activityDO.spuId"), @Mapping(target = "spuId", source = "activity.spuId"),
@Mapping(target = "skuId", source = "vo.skuId"), @Mapping(target = "skuId", source = "product.skuId"),
@Mapping(target = "activePrice", source = "vo.activePrice"), @Mapping(target = "combinationPrice", source = "product.combinationPrice"),
@Mapping(target = "activityStartTime", source = "activityDO.startTime"), @Mapping(target = "activityStartTime", source = "activity.startTime"),
@Mapping(target = "activityEndTime", source = "activityDO.endTime") @Mapping(target = "activityEndTime", source = "activity.endTime")
}) })
CombinationProductDO convert(CombinationActivityDO activityDO, CombinationProductBaseVO vo); CombinationProductDO convert(CombinationActivityDO activity, CombinationProductBaseVO product);
default List<CombinationProductDO> convertList(CombinationActivityDO activityDO, List<? extends CombinationProductBaseVO> products) { default List<CombinationProductDO> convertList(List<? extends CombinationProductBaseVO> products, CombinationActivityDO activity) {
List<CombinationProductDO> list = new ArrayList<>(); return CollectionUtils.convertList(products, item -> convert(activity, item).setActivityStatus(activity.getStatus()));
products.forEach(sku -> {
CombinationProductDO productDO = convert(activityDO, sku);
// TODO 状态设置
productDO.setActivityStatus(CommonStatusEnum.ENABLE.getStatus());
list.add(productDO);
});
return list;
} }
// TODO @puhui999这个方法的参数调整成 productDOsvosactivityDO因为 productDOs 是主角 default List<CombinationProductDO> convertList(List<CombinationProductBaseVO> updateProductVOs,
// 然后这个方法感觉不是为了 convert而是为了补全 List<CombinationProductDO> products, CombinationActivityDO activity) {
default List<CombinationProductDO> convertList1(CombinationActivityDO activityDO, Map<Long, Long> productMap = convertMap(products, CombinationProductDO::getSkuId, CombinationProductDO::getId);
List<CombinationProductUpdateReqVO> vos, return CollectionUtils.convertList(updateProductVOs, updateProductVO -> convert(activity, updateProductVO)
List<CombinationProductDO> productDOs) { .setId(productMap.get(updateProductVO.getSkuId()))
Map<Long, Long> longMap = convertMap(productDOs, CombinationProductDO::getSkuId, CombinationProductDO::getId); .setActivityStatus(activity.getStatus()));
List<CombinationProductDO> list = new ArrayList<>();
vos.forEach(sku -> {
CombinationProductDO productDO = convert(activityDO, sku);
productDO.setId(longMap.get(sku.getSkuId()));
// TODO @puhui999是是不是用 activityDO 的状态
productDO.setActivityStatus(CommonStatusEnum.ENABLE.getStatus());
list.add(productDO);
});
return list;
} }
CombinationRecordDO convert(CombinationRecordReqDTO reqDTO); CombinationRecordDO convert(CombinationRecordCreateReqDTO reqDTO);
List<CombinationRecordRespDTO> convert(List<CombinationRecordDO> bean);
} }

View File

@ -1,8 +1,7 @@
package cn.iocoder.yudao.module.promotion.convert.decorate; package cn.iocoder.yudao.module.promotion.convert.decorate;
import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils;
import cn.iocoder.yudao.module.promotion.controller.admin.decorate.vo.DecorateComponentSaveReqVO;
import cn.iocoder.yudao.module.promotion.controller.admin.decorate.vo.DecorateComponentRespVO; import cn.iocoder.yudao.module.promotion.controller.admin.decorate.vo.DecorateComponentRespVO;
import cn.iocoder.yudao.module.promotion.controller.admin.decorate.vo.DecorateComponentSaveReqVO;
import cn.iocoder.yudao.module.promotion.controller.app.decorate.vo.AppDecorateComponentRespVO; import cn.iocoder.yudao.module.promotion.controller.app.decorate.vo.AppDecorateComponentRespVO;
import cn.iocoder.yudao.module.promotion.dal.dataobject.decorate.DecorateComponentDO; import cn.iocoder.yudao.module.promotion.dal.dataobject.decorate.DecorateComponentDO;
import org.mapstruct.Mapper; import org.mapstruct.Mapper;
@ -10,33 +9,15 @@ import org.mapstruct.factory.Mappers;
import java.util.List; import java.util.List;
import static cn.iocoder.yudao.module.promotion.controller.admin.decorate.vo.DecorateComponentRespVO.*;
import static cn.iocoder.yudao.module.promotion.controller.app.decorate.vo.AppDecorateComponentRespVO.*;
@Mapper @Mapper
public interface DecorateComponentConvert { public interface DecorateComponentConvert {
DecorateComponentConvert INSTANCE = Mappers.getMapper(DecorateComponentConvert.class); DecorateComponentConvert INSTANCE = Mappers.getMapper(DecorateComponentConvert.class);
default List<DecorateComponentDO> convertList(Integer pageId, List<DecorateComponentSaveReqVO.ComponentReqVO> components) { List<DecorateComponentRespVO> convertList02(List<DecorateComponentDO> list);
return CollectionUtils.convertList(components, c -> convert(pageId, c));
}
default DecorateComponentRespVO convert2(Integer pageId, List<DecorateComponentDO> list) { DecorateComponentDO convert(DecorateComponentSaveReqVO bean);
List<ComponentRespVO> components = CollectionUtils.convertList(list, this::convert3);
return new DecorateComponentRespVO().setPageId(pageId).setComponents(components);
}
DecorateComponentDO convert(Integer pageId, DecorateComponentSaveReqVO.ComponentReqVO reqVO); List<AppDecorateComponentRespVO> convertList(List<DecorateComponentDO> list);
ComponentRespVO convert3(DecorateComponentDO componentDO);
// ========== App convert ==========
default AppDecorateComponentRespVO appConvert(Integer pageId, List<DecorateComponentDO> list) {
List<AppComponentRespVO> components = CollectionUtils.convertList(list, this::appConvert2);
return new AppDecorateComponentRespVO().setPageId(pageId).setComponents(components);
}
AppComponentRespVO appConvert2(DecorateComponentDO bean);
} }

View File

@ -1,8 +1,8 @@
package cn.iocoder.yudao.module.promotion.convert.seckill.seckillactivity; package cn.iocoder.yudao.module.promotion.convert.seckill.seckillactivity;
import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
import cn.iocoder.yudao.framework.common.pojo.PageResult; import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils; import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils;
import cn.iocoder.yudao.framework.common.util.collection.MapUtils;
import cn.iocoder.yudao.module.product.api.spu.dto.ProductSpuRespDTO; import cn.iocoder.yudao.module.product.api.spu.dto.ProductSpuRespDTO;
import cn.iocoder.yudao.module.promotion.controller.admin.seckill.vo.activity.SeckillActivityCreateReqVO; import cn.iocoder.yudao.module.promotion.controller.admin.seckill.vo.activity.SeckillActivityCreateReqVO;
import cn.iocoder.yudao.module.promotion.controller.admin.seckill.vo.activity.SeckillActivityDetailRespVO; import cn.iocoder.yudao.module.promotion.controller.admin.seckill.vo.activity.SeckillActivityDetailRespVO;
@ -10,7 +10,6 @@ import cn.iocoder.yudao.module.promotion.controller.admin.seckill.vo.activity.Se
import cn.iocoder.yudao.module.promotion.controller.admin.seckill.vo.activity.SeckillActivityUpdateReqVO; import cn.iocoder.yudao.module.promotion.controller.admin.seckill.vo.activity.SeckillActivityUpdateReqVO;
import cn.iocoder.yudao.module.promotion.controller.admin.seckill.vo.product.SeckillProductBaseVO; import cn.iocoder.yudao.module.promotion.controller.admin.seckill.vo.product.SeckillProductBaseVO;
import cn.iocoder.yudao.module.promotion.controller.admin.seckill.vo.product.SeckillProductRespVO; import cn.iocoder.yudao.module.promotion.controller.admin.seckill.vo.product.SeckillProductRespVO;
import cn.iocoder.yudao.module.promotion.controller.admin.seckill.vo.product.SeckillProductUpdateReqVO;
import cn.iocoder.yudao.module.promotion.dal.dataobject.seckill.seckillactivity.SeckillActivityDO; import cn.iocoder.yudao.module.promotion.dal.dataobject.seckill.seckillactivity.SeckillActivityDO;
import cn.iocoder.yudao.module.promotion.dal.dataobject.seckill.seckillactivity.SeckillProductDO; import cn.iocoder.yudao.module.promotion.dal.dataobject.seckill.seckillactivity.SeckillProductDO;
import org.mapstruct.Mapper; import org.mapstruct.Mapper;
@ -18,7 +17,6 @@ import org.mapstruct.Mapping;
import org.mapstruct.Mappings; import org.mapstruct.Mappings;
import org.mapstruct.factory.Mappers; import org.mapstruct.factory.Mappers;
import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
@ -42,61 +40,43 @@ public interface SeckillActivityConvert {
PageResult<SeckillActivityRespVO> convertPage(PageResult<SeckillActivityDO> page); PageResult<SeckillActivityRespVO> convertPage(PageResult<SeckillActivityDO> page);
default PageResult<SeckillActivityRespVO> convertPage(PageResult<SeckillActivityDO> page, List<SeckillProductDO> seckillProducts, List<ProductSpuRespDTO> spuList) { default PageResult<SeckillActivityRespVO> convertPage(PageResult<SeckillActivityDO> page,
Map<Long, ProductSpuRespDTO> spuMap = CollectionUtils.convertMap(spuList, ProductSpuRespDTO::getId, c -> c); List<SeckillProductDO> seckillProducts,
List<ProductSpuRespDTO> spuList) {
PageResult<SeckillActivityRespVO> pageResult = convertPage(page); PageResult<SeckillActivityRespVO> pageResult = convertPage(page);
// 拼接商品
Map<Long, ProductSpuRespDTO> spuMap = CollectionUtils.convertMap(spuList, ProductSpuRespDTO::getId);
pageResult.getList().forEach(item -> { pageResult.getList().forEach(item -> {
item.setSpuName(spuMap.get(item.getSpuId()).getName());
item.setPicUrl(spuMap.get(item.getSpuId()).getPicUrl());
item.setProducts(convertList2(seckillProducts)); item.setProducts(convertList2(seckillProducts));
MapUtils.findAndThen(spuMap, item.getSpuId(),
spu -> item.setSpuName(spu.getName()).setPicUrl(spu.getPicUrl()));
}); });
return pageResult; return pageResult;
} }
SeckillActivityDetailRespVO convert1(SeckillActivityDO seckillActivity); SeckillActivityDetailRespVO convert1(SeckillActivityDO activity);
default SeckillActivityDetailRespVO convert(SeckillActivityDO seckillActivity, List<SeckillProductDO> seckillProducts) { default SeckillActivityDetailRespVO convert(SeckillActivityDO activity, List<SeckillProductDO> products) {
SeckillActivityDetailRespVO respVO = convert1(seckillActivity); return convert1(activity).setProducts(convertList2(products));
respVO.setProducts(convertList2(seckillProducts));
return respVO;
} }
@Mappings({ @Mappings({
@Mapping(target = "id", ignore = true), @Mapping(target = "id", ignore = true),
@Mapping(target = "activityId", source = "activityDO.id"), @Mapping(target = "activityId", source = "activity.id"),
@Mapping(target = "configIds", source = "activityDO.configIds"), @Mapping(target = "configIds", source = "activity.configIds"),
@Mapping(target = "spuId", source = "activityDO.spuId"), @Mapping(target = "spuId", source = "activity.spuId"),
@Mapping(target = "skuId", source = "vo.skuId"), @Mapping(target = "skuId", source = "product.skuId"),
@Mapping(target = "seckillPrice", source = "vo.seckillPrice"), @Mapping(target = "seckillPrice", source = "product.seckillPrice"),
@Mapping(target = "stock", source = "vo.stock"), @Mapping(target = "stock", source = "product.stock"),
@Mapping(target = "activityStartTime", source = "activityDO.startTime"), @Mapping(target = "activityStartTime", source = "activity.startTime"),
@Mapping(target = "activityEndTime", source = "activityDO.endTime") @Mapping(target = "activityEndTime", source = "activity.endTime")
}) })
SeckillProductDO convert(SeckillActivityDO activityDO, SeckillProductBaseVO vo); SeckillProductDO convert(SeckillActivityDO activity, SeckillProductBaseVO product);
default List<SeckillProductDO> convertList(SeckillActivityDO activityDO, List<? extends SeckillProductBaseVO> products) { default List<SeckillProductDO> convertList(List<? extends SeckillProductBaseVO> products, SeckillActivityDO activity) {
List<SeckillProductDO> list = new ArrayList<>(); return CollectionUtils.convertList(products, item -> convert(activity, item).setActivityStatus(activity.getStatus()));
products.forEach(sku -> {
SeckillProductDO productDO = convert(activityDO, sku);
productDO.setActivityStatus(CommonStatusEnum.ENABLE.getStatus());
list.add(productDO);
});
return list;
} }
// TODO @puhui999同拼团那个 convert 想通的情况哈 List<SeckillProductRespVO> convertList2(List<SeckillProductDO> list);
default List<SeckillProductDO> convertList1(SeckillActivityDO activityDO, List<SeckillProductUpdateReqVO> vos, List<SeckillProductDO> productDOs) {
Map<Long, Long> longMap = CollectionUtils.convertMap(productDOs, SeckillProductDO::getSkuId, SeckillProductDO::getId);
List<SeckillProductDO> list = new ArrayList<>();
vos.forEach(sku -> {
SeckillProductDO productDO = convert(activityDO, sku);
productDO.setId(longMap.get(sku.getSkuId()));
productDO.setActivityStatus(CommonStatusEnum.ENABLE.getStatus());
list.add(productDO);
});
return list;
}
List<SeckillProductRespVO> convertList2(List<SeckillProductDO> productDOs);
} }

View File

@ -0,0 +1,101 @@
package cn.iocoder.yudao.module.promotion.dal.dataobject.bargain;
import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
import com.baomidou.mybatisplus.annotation.KeySequence;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.*;
import java.time.LocalDateTime;
/**
* 砍价活动 DO
*
* @author HUIHUI
*/
@TableName("promotion_bargain_activity")
@KeySequence("promotion_bargain_activity_seq") // 用于 OraclePostgreSQLKingbaseDB2H2 数据库的主键自增如果是 MySQL 等数据库可不写
@Data
@EqualsAndHashCode(callSuper = true)
@ToString(callSuper = true)
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class BargainActivityDO extends BaseDO {
/**
* 砍价活动编号
*/
@TableId
private Long id;
/**
* 砍价活动名称
*/
private String name;
/**
* 活动开始时间
*/
private LocalDateTime startTime;
/**
* 活动结束时间
*/
private LocalDateTime endTime;
/**
* 活动状态
*
* 枚举 {@link CommonStatusEnum}
*/
private Integer status;
/**
* 商品 SPU 编号
*/
private Long spuId;
/**
* 商品 SKU 编号
*/
private Long skuId;
/**
* 砍价起始价格单位分
*/
private Integer bargainFirstPrice;
/**
* 砍价底价单位
*/
private Integer bargainPrice;
/**
* 砍价活动库存
*/
private Integer stock;
/**
* 达到该人数才能砍到低价
*/
private Integer userSize;
/**
* 最大帮砍次数
*/
private Integer bargainCount;
/**
* 总限购数量
*/
private Integer totalLimitCount;
/**
* 用户每次砍价的最小金额单位
*/
private Integer randomMinPrice;
/**
* 用户每次砍价的最大金额单位
*/
private Integer randomMaxPrice;
/**
* 砍价成功数量
*/
private Integer successCount;
}

View File

@ -0,0 +1,50 @@
package cn.iocoder.yudao.module.promotion.dal.dataobject.bargain;
import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
import com.baomidou.mybatisplus.annotation.KeySequence;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.*;
/**
* 砍价助力 DO TODO 芋艿表结构
*
* @author HUIHUI
*/
@TableName("promotion_bargain_assist")
@KeySequence("promotion_bargain_assist_seq") // 用于 OraclePostgreSQLKingbaseDB2H2 数据库的主键自增如果是 MySQL 等数据库可不写
@Data
@EqualsAndHashCode(callSuper = true)
@ToString(callSuper = true)
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class BargainAssistDO extends BaseDO {
/**
* 编号
*/
@TableId
private Long id;
/**
* 砍价活动编号
*/
private Long activityId;
/**
* 砍价记录编号
*/
private Long recordId;
/**
* 用户编号
*/
private Long userId;
/**
* 减少价格单位分
*/
private Integer reducePrice;
}

View File

@ -0,0 +1,87 @@
package cn.iocoder.yudao.module.promotion.dal.dataobject.bargain;
import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
import com.baomidou.mybatisplus.annotation.KeySequence;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.*;
import java.time.LocalDateTime;
/**
* 砍价记录 DO TODO
*
* @author HUIHUI
*/
@TableName("promotion_bargain_record")
@KeySequence("promotion_bargain_record_seq") // 用于 OraclePostgreSQLKingbaseDB2H2 数据库的主键自增如果是 MySQL 等数据库可不写
@Data
@EqualsAndHashCode(callSuper = true)
@ToString(callSuper = true)
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class BargainRecordDO extends BaseDO {
/**
* 编号
*/
@TableId
private Long id;
/**
* 砍价活动编号
*/
private Long activityId;
/**
* 用户编号
*/
private Long userId;
/**
* 商品 SPU 编号
*/
private Long spuId;
/**
* 商品 SKU 编号
*/
private Long skuId;
/**
* 砍价底价单位分
*/
private Integer bargainPrice;
/**
* 商品原价单位分
*/
private Integer price;
/**
* 应付金额单位分
*/
private Integer payPrice;
/**
* 状态1 - 砍价中2- 砍价成功3 - 砍价失败
*/
private Integer status;
/**
* 订单编号
*/
private Long orderId;
/**
* 结束时间
*/
private LocalDateTime endTime;
/**
* 过期时间
*/
private Data expireTime;
}

View File

@ -1,4 +1,4 @@
package cn.iocoder.yudao.module.promotion.dal.dataobject.combination.combinationactivity; package cn.iocoder.yudao.module.promotion.dal.dataobject.combination;
import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
@ -9,7 +9,6 @@ import lombok.*;
import java.time.LocalDateTime; import java.time.LocalDateTime;
// TODO @puhui999是不是应该在 combination
/** /**
* 拼团活动 DO * 拼团活动 DO
* *
@ -63,11 +62,11 @@ public class CombinationActivityDO extends BaseDO {
/** /**
* 开团组数 * 开团组数
*/ */
private Integer totalNum; private Integer totalCount;
/** /**
* 成团组数 * 成团组数
*/ */
private Integer successNum; private Integer successCount;
/** /**
* 参与人数 * 参与人数
*/ */
@ -77,7 +76,7 @@ public class CombinationActivityDO extends BaseDO {
*/ */
private Integer virtualGroup; private Integer virtualGroup;
/** /**
* 活动状态0开启 1关闭 * 活动状态
* *
* 枚举 {@link CommonStatusEnum} * 枚举 {@link CommonStatusEnum}
*/ */

View File

@ -1,4 +1,4 @@
package cn.iocoder.yudao.module.promotion.dal.dataobject.combination.combinationactivity; package cn.iocoder.yudao.module.promotion.dal.dataobject.combination;
import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
import com.baomidou.mybatisplus.annotation.KeySequence; import com.baomidou.mybatisplus.annotation.KeySequence;
@ -40,21 +40,28 @@ public class CombinationProductDO extends BaseDO {
* 商品 SKU 编号 * 商品 SKU 编号
*/ */
private Long skuId; private Long skuId;
/**
* 拼团价格单位分
*/
private Integer combinationPrice;
/** /**
* 拼团商品状态 * 拼团商品状态
*
* 关联 {@link CombinationActivityDO#getStatus()}
*/ */
private Integer activityStatus; private Integer activityStatus;
/** /**
* 活动开始时间点 * 活动开始时间点
*
* 冗余 {@link CombinationActivityDO#getStartTime()}
*/ */
private LocalDateTime activityStartTime; private LocalDateTime activityStartTime;
/** /**
* 活动结束时间点 * 活动结束时间点
*
* 冗余 {@link CombinationActivityDO#getEndTime()}
*/ */
private LocalDateTime activityEndTime; private LocalDateTime activityEndTime;
/**
* 拼团价格单位分
*/
private Integer activePrice;
} }

View File

@ -1,4 +1,4 @@
package cn.iocoder.yudao.module.promotion.dal.dataobject.combination.combinationactivity; package cn.iocoder.yudao.module.promotion.dal.dataobject.combination;
import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
import cn.iocoder.yudao.module.promotion.enums.combination.CombinationRecordStatusEnum; import cn.iocoder.yudao.module.promotion.enums.combination.CombinationRecordStatusEnum;
@ -12,6 +12,9 @@ import java.time.LocalDateTime;
/** /**
* 拼团记录 DO * 拼团记录 DO
* *
* 1. 用户参与拼团时会创建一条记录
* 2. 团长的拼团记录和参团人的拼团记录通过 {@link #headId} 关联
*
* @author HUIHUI * @author HUIHUI
*/ */
@TableName("promotion_combination_record") @TableName("promotion_combination_record")
@ -49,7 +52,7 @@ public class CombinationRecordDO extends BaseDO {
/** /**
* 团长编号 * 团长编号
* *
* 关联 {@link CombinationRecordDO#getUserId()} * 关联 {@link CombinationRecordDO#getId()}
*/ */
private Long headId; private Long headId;
/** /**

View File

@ -26,13 +26,14 @@ public class DecorateComponentDO extends BaseDO {
/** /**
* 所属页面 id * 所属页面 id
* 枚举 {@link DecoratePageEnum#getId()} *
* 枚举 {@link DecoratePageEnum#getPage()}
*/ */
private Integer pageId; private Integer page;
/** /**
* 组件编码 * 组件编码
* 枚举 {@link DecorateComponentEnum#getCode()} * 枚举 {@link DecorateComponentEnum#getCode()}
*/ */
private String code; private String code;
@ -47,4 +48,5 @@ public class DecorateComponentDO extends BaseDO {
* 枚举 {@link CommonStatusEnum} * 枚举 {@link CommonStatusEnum}
*/ */
private Integer status; private Integer status;
} }

View File

@ -0,0 +1,31 @@
package cn.iocoder.yudao.module.promotion.dal.mysql.bargain;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX;
import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX;
import cn.iocoder.yudao.module.promotion.controller.admin.bargain.vo.BargainActivityPageReqVO;
import cn.iocoder.yudao.module.promotion.dal.dataobject.bargain.BargainActivityDO;
import org.apache.ibatis.annotations.Mapper;
import java.util.List;
/**
* 砍价活动 Mapper
*
* @author HUIHUI
*/
@Mapper
public interface BargainActivityMapper extends BaseMapperX<BargainActivityDO> {
default PageResult<BargainActivityDO> selectPage(BargainActivityPageReqVO reqVO) {
return selectPage(reqVO, new LambdaQueryWrapperX<BargainActivityDO>()
.likeIfPresent(BargainActivityDO::getName, reqVO.getName())
.eqIfPresent(BargainActivityDO::getStatus, reqVO.getStatus())
.orderByDesc(BargainActivityDO::getId));
}
default List<BargainActivityDO> selectListByStatus(Integer status) {
return selectList(BargainActivityDO::getStatus, status);
}
}

View File

@ -0,0 +1,15 @@
package cn.iocoder.yudao.module.promotion.dal.mysql.bargain;
import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX;
import cn.iocoder.yudao.module.promotion.dal.dataobject.bargain.BargainRecordDO;
import org.apache.ibatis.annotations.Mapper;
/**
* 砍价记录 Mapper
*
* @author HUIHUI
*/
@Mapper
public interface BargainRecordMapper extends BaseMapperX<BargainRecordDO> {
}

View File

@ -1,16 +1,14 @@
package cn.iocoder.yudao.module.promotion.dal.mysql.combination.combinationactivity; package cn.iocoder.yudao.module.promotion.dal.mysql.combination;
import cn.iocoder.yudao.framework.common.pojo.PageResult; import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX;
import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX; import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX;
import cn.iocoder.yudao.module.promotion.controller.admin.combination.vo.activity.CombinationActivityExportReqVO;
import cn.iocoder.yudao.module.promotion.controller.admin.combination.vo.activity.CombinationActivityPageReqVO; import cn.iocoder.yudao.module.promotion.controller.admin.combination.vo.activity.CombinationActivityPageReqVO;
import cn.iocoder.yudao.module.promotion.dal.dataobject.combination.combinationactivity.CombinationActivityDO; import cn.iocoder.yudao.module.promotion.dal.dataobject.combination.CombinationActivityDO;
import org.apache.ibatis.annotations.Mapper; import org.apache.ibatis.annotations.Mapper;
import java.util.List; import java.util.List;
// TODO @puhui999是不是应该在 combination
/** /**
* 拼团活动 Mapper * 拼团活动 Mapper
* *
@ -21,12 +19,6 @@ public interface CombinationActivityMapper extends BaseMapperX<CombinationActivi
default PageResult<CombinationActivityDO> selectPage(CombinationActivityPageReqVO reqVO) { default PageResult<CombinationActivityDO> selectPage(CombinationActivityPageReqVO reqVO) {
return selectPage(reqVO, new LambdaQueryWrapperX<CombinationActivityDO>() return selectPage(reqVO, new LambdaQueryWrapperX<CombinationActivityDO>()
.likeIfPresent(CombinationActivityDO::getName, reqVO.getName())
.orderByDesc(CombinationActivityDO::getId));
}
default List<CombinationActivityDO> selectList(CombinationActivityExportReqVO reqVO) {
return selectList(new LambdaQueryWrapperX<CombinationActivityDO>()
.likeIfPresent(CombinationActivityDO::getName, reqVO.getName()) .likeIfPresent(CombinationActivityDO::getName, reqVO.getName())
.eqIfPresent(CombinationActivityDO::getStatus, reqVO.getStatus()) .eqIfPresent(CombinationActivityDO::getStatus, reqVO.getStatus())
.orderByDesc(CombinationActivityDO::getId)); .orderByDesc(CombinationActivityDO::getId));

View File

@ -1,11 +1,10 @@
package cn.iocoder.yudao.module.promotion.dal.mysql.combination.combinationactivity; package cn.iocoder.yudao.module.promotion.dal.mysql.combination;
import cn.iocoder.yudao.framework.common.pojo.PageResult; import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX;
import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX; import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX;
import cn.iocoder.yudao.module.promotion.controller.admin.combination.vo.product.CombinationProductExportReqVO;
import cn.iocoder.yudao.module.promotion.controller.admin.combination.vo.product.CombinationProductPageReqVO; import cn.iocoder.yudao.module.promotion.controller.admin.combination.vo.product.CombinationProductPageReqVO;
import cn.iocoder.yudao.module.promotion.dal.dataobject.combination.combinationactivity.CombinationProductDO; import cn.iocoder.yudao.module.promotion.dal.dataobject.combination.CombinationProductDO;
import org.apache.ibatis.annotations.Mapper; import org.apache.ibatis.annotations.Mapper;
import java.util.Collection; import java.util.Collection;
@ -27,20 +26,7 @@ public interface CombinationProductMapper extends BaseMapperX<CombinationProduct
.eqIfPresent(CombinationProductDO::getActivityStatus, reqVO.getActivityStatus()) .eqIfPresent(CombinationProductDO::getActivityStatus, reqVO.getActivityStatus())
.betweenIfPresent(CombinationProductDO::getActivityStartTime, reqVO.getActivityStartTime()) .betweenIfPresent(CombinationProductDO::getActivityStartTime, reqVO.getActivityStartTime())
.betweenIfPresent(CombinationProductDO::getActivityEndTime, reqVO.getActivityEndTime()) .betweenIfPresent(CombinationProductDO::getActivityEndTime, reqVO.getActivityEndTime())
.eqIfPresent(CombinationProductDO::getActivePrice, reqVO.getActivePrice()) .eqIfPresent(CombinationProductDO::getCombinationPrice, reqVO.getActivePrice())
.betweenIfPresent(CombinationProductDO::getCreateTime, reqVO.getCreateTime())
.orderByDesc(CombinationProductDO::getId));
}
default List<CombinationProductDO> selectList(CombinationProductExportReqVO reqVO) {
return selectList(new LambdaQueryWrapperX<CombinationProductDO>()
.eqIfPresent(CombinationProductDO::getActivityId, reqVO.getActivityId())
.eqIfPresent(CombinationProductDO::getSpuId, reqVO.getSpuId())
.eqIfPresent(CombinationProductDO::getSkuId, reqVO.getSkuId())
.eqIfPresent(CombinationProductDO::getActivityStatus, reqVO.getActivityStatus())
.betweenIfPresent(CombinationProductDO::getActivityStartTime, reqVO.getActivityStartTime())
.betweenIfPresent(CombinationProductDO::getActivityEndTime, reqVO.getActivityEndTime())
.eqIfPresent(CombinationProductDO::getActivePrice, reqVO.getActivePrice())
.betweenIfPresent(CombinationProductDO::getCreateTime, reqVO.getCreateTime()) .betweenIfPresent(CombinationProductDO::getCreateTime, reqVO.getCreateTime())
.orderByDesc(CombinationProductDO::getId)); .orderByDesc(CombinationProductDO::getId));
} }

View File

@ -0,0 +1,62 @@
package cn.iocoder.yudao.module.promotion.dal.mysql.combination;
import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX;
import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX;
import cn.iocoder.yudao.module.promotion.dal.dataobject.combination.CombinationRecordDO;
import org.apache.ibatis.annotations.Mapper;
import java.util.List;
/**
* 拼团记录 Mapper
*
* @author HUIHUI
*/
@Mapper
public interface CombinationRecordMapper extends BaseMapperX<CombinationRecordDO> {
default CombinationRecordDO selectByUserIdAndOrderId(Long userId, Long orderId) {
return selectOne(CombinationRecordDO::getUserId, userId,
CombinationRecordDO::getOrderId, orderId);
}
default List<CombinationRecordDO> selectListByUserIdAndStatus(Long userId, Integer status) {
return selectList(new LambdaQueryWrapperX<CombinationRecordDO>()
.eq(CombinationRecordDO::getUserId, userId)
.eq(CombinationRecordDO::getStatus, status));
}
/**
* 查询拼团记录
*
* @param headId 团长编号
* @return 拼团记录
*/
default CombinationRecordDO selectOneByHeadId(Long headId, Integer status) {
return selectOne(new LambdaQueryWrapperX<CombinationRecordDO>()
.eq(CombinationRecordDO::getId, headId)
.eq(CombinationRecordDO::getStatus, status));
}
default List<CombinationRecordDO> selectListByHeadIdAndStatus(Long headId, Integer status) {
return selectList(new LambdaQueryWrapperX<CombinationRecordDO>()
.eq(CombinationRecordDO::getHeadId, headId)
.eq(CombinationRecordDO::getStatus, status));
}
default List<CombinationRecordDO> selectListByStatus(Integer status) {
return selectList(CombinationRecordDO::getStatus, status);
}
/**
* 查询拼团记录
*
* @param userId 用户 id
* @param activityId 活动 id
* @return 拼团记录
*/
default List<CombinationRecordDO> selectListByUserIdAndActivityId(Long userId, Long activityId) {
return selectList(new LambdaQueryWrapperX<CombinationRecordDO>()
.eq(CombinationRecordDO::getUserId, userId)
.eq(CombinationRecordDO::getActivityId, activityId));
}
}

View File

@ -1,33 +0,0 @@
package cn.iocoder.yudao.module.promotion.dal.mysql.combination.combinationactivity;
import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX;
import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX;
import cn.iocoder.yudao.module.promotion.dal.dataobject.combination.combinationactivity.CombinationRecordDO;
import org.apache.ibatis.annotations.Mapper;
import java.util.List;
/**
* 拼团记录 Mapper
*
* @author HUIHUI
*/
@Mapper
public interface CombinationRecordMapper extends BaseMapperX<CombinationRecordDO> {
default CombinationRecordDO selectRecord(Long userId, Long orderId) {
return selectOne(CombinationRecordDO::getUserId, userId,
CombinationRecordDO::getOrderId, orderId);
}
default List<CombinationRecordDO> selectListByHeadIdAndStatus(Long headId, Integer status) {
return selectList(new LambdaQueryWrapperX<CombinationRecordDO>()
.eq(CombinationRecordDO::getHeadId, headId)
.eq(CombinationRecordDO::getStatus, status));
}
default List<CombinationRecordDO> selectListByStatus(Integer status) {
return selectList(CombinationRecordDO::getStatus, status);
}
}

View File

@ -49,4 +49,10 @@ public interface CouponMapper extends BaseMapperX<CouponDO> {
.eq(CouponDO::getId, id).eq(CouponDO::getStatus, status)); .eq(CouponDO::getId, id).eq(CouponDO::getStatus, status));
} }
default Long selectCountByUserIdAndStatus(Long userId, Integer status) {
return selectCount(new LambdaQueryWrapperX<CouponDO>()
.eq(CouponDO::getUserId, userId)
.eq(CouponDO::getStatus, status));
}
} }

View File

@ -1,7 +1,8 @@
package cn.iocoder.yudao.module.promotion.dal.mysql.decorate; package cn.iocoder.yudao.module.promotion.dal.mysql.decorate;
import cn.iocoder.yudao.module.promotion.dal.dataobject.decorate.DecorateComponentDO;
import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX;
import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX;
import cn.iocoder.yudao.module.promotion.dal.dataobject.decorate.DecorateComponentDO;
import org.apache.ibatis.annotations.Mapper; import org.apache.ibatis.annotations.Mapper;
import java.util.List; import java.util.List;
@ -9,8 +10,15 @@ import java.util.List;
@Mapper @Mapper
public interface DecorateComponentMapper extends BaseMapperX<DecorateComponentDO> { public interface DecorateComponentMapper extends BaseMapperX<DecorateComponentDO> {
default List<DecorateComponentDO> selectByPage(Integer pageId){ default List<DecorateComponentDO> selectListByPageAndStatus(Integer page, Integer status) {
return selectList(DecorateComponentDO::getPageId, pageId); return selectList(new LambdaQueryWrapperX<DecorateComponentDO>()
.eq(DecorateComponentDO::getPage, page)
.eqIfPresent(DecorateComponentDO::getStatus, status));
}
default DecorateComponentDO selectByPageAndCode(Integer page, String code) {
return selectOne(DecorateComponentDO::getPage, page,
DecorateComponentDO::getCode, code);
} }
} }

View File

@ -1,9 +1,7 @@
package cn.iocoder.yudao.module.promotion.dal.mysql.seckill.seckillactivity; package cn.iocoder.yudao.module.promotion.dal.mysql.seckill.seckillactivity;
import cn.hutool.core.collection.CollUtil;
import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX;
import cn.iocoder.yudao.module.promotion.dal.dataobject.seckill.seckillactivity.SeckillProductDO; import cn.iocoder.yudao.module.promotion.dal.dataobject.seckill.seckillactivity.SeckillProductDO;
import com.baomidou.mybatisplus.extension.conditions.update.LambdaUpdateChainWrapper;
import org.apache.ibatis.annotations.Mapper; import org.apache.ibatis.annotations.Mapper;
import java.util.Collection; import java.util.Collection;
@ -25,15 +23,4 @@ public interface SeckillProductMapper extends BaseMapperX<SeckillProductDO> {
return selectList(SeckillProductDO::getActivityId, ids); return selectList(SeckillProductDO::getActivityId, ids);
} }
default List<SeckillProductDO> selectListBySkuIds(Collection<Long> skuIds) {
return selectList(SeckillProductDO::getSkuId, skuIds);
}
default void updateTimeIdsByActivityId(Long id, List<Long> timeIds) {
new LambdaUpdateChainWrapper<>(this)
.set(SeckillProductDO::getConfigIds, CollUtil.join(timeIds, ","))
.eq(SeckillProductDO::getActivityId, id)
.update();
}
} }

View File

@ -0,0 +1,57 @@
package cn.iocoder.yudao.module.promotion.service.bargain;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.module.promotion.controller.admin.bargain.vo.BargainActivityCreateReqVO;
import cn.iocoder.yudao.module.promotion.controller.admin.bargain.vo.BargainActivityPageReqVO;
import cn.iocoder.yudao.module.promotion.controller.admin.bargain.vo.BargainActivityUpdateReqVO;
import cn.iocoder.yudao.module.promotion.dal.dataobject.bargain.BargainActivityDO;
import javax.validation.Valid;
/**
* 砍价活动 Service 接口
*
* @author HUIHUI
*/
public interface BargainActivityService {
/**
* 创建砍价活动
*
* @param createReqVO 创建信息
* @return 编号
*/
Long createBargainActivity(@Valid BargainActivityCreateReqVO createReqVO);
/**
* 更新砍价活动
*
* @param updateReqVO 更新信息
*/
void updateBargainActivity(@Valid BargainActivityUpdateReqVO updateReqVO);
/**
* 删除砍价活动
*
* @param id 编号
*/
void deleteBargainActivity(Long id);
/**
* 获得砍价活动
*
* @param id 编号
* @return 砍价活动
*/
BargainActivityDO getBargainActivity(Long id);
/**
* 获得砍价活动分页
*
* @param pageReqVO 分页查询
* @return 砍价活动分页
*/
PageResult<BargainActivityDO> getBargainActivityPage(BargainActivityPageReqVO pageReqVO);
}

View File

@ -0,0 +1,124 @@
package cn.iocoder.yudao.module.promotion.service.bargain;
import cn.hutool.core.util.ObjectUtil;
import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.module.product.api.sku.ProductSkuApi;
import cn.iocoder.yudao.module.product.api.sku.dto.ProductSkuRespDTO;
import cn.iocoder.yudao.module.promotion.controller.admin.bargain.vo.BargainActivityCreateReqVO;
import cn.iocoder.yudao.module.promotion.controller.admin.bargain.vo.BargainActivityPageReqVO;
import cn.iocoder.yudao.module.promotion.controller.admin.bargain.vo.BargainActivityUpdateReqVO;
import cn.iocoder.yudao.module.promotion.convert.bargain.BargainActivityConvert;
import cn.iocoder.yudao.module.promotion.dal.dataobject.bargain.BargainActivityDO;
import cn.iocoder.yudao.module.promotion.dal.mysql.bargain.BargainActivityMapper;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.validation.annotation.Validated;
import javax.annotation.Resource;
import java.util.List;
import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.anyMatch;
import static cn.iocoder.yudao.module.product.enums.ErrorCodeConstants.SKU_NOT_EXISTS;
import static cn.iocoder.yudao.module.promotion.enums.ErrorCodeConstants.*;
/**
* 砍价活动 Service 实现类
*
* @author HUIHUI
*/
@Service
@Validated
public class BargainActivityServiceImpl implements BargainActivityService {
@Resource
private BargainActivityMapper bargainActivityMapper;
@Resource
private ProductSkuApi productSkuApi;
@Override
public Long createBargainActivity(BargainActivityCreateReqVO createReqVO) {
// 校验商品 SPU 是否存在是否参加的别的活动
validateBargainConflict(createReqVO.getSpuId(), null);
// 校验商品 sku 是否存在
validateSku(createReqVO.getSkuId());
// 插入砍价活动
BargainActivityDO activityDO = BargainActivityConvert.INSTANCE.convert(createReqVO)
.setStatus(CommonStatusEnum.ENABLE.getStatus()).setSuccessCount(0);
bargainActivityMapper.insert(activityDO);
return activityDO.getId();
}
@Override
public void updateBargainActivity(BargainActivityUpdateReqVO updateReqVO) {
// 校验存在
BargainActivityDO activityDO = validateBargainActivityExists(updateReqVO.getId());
// 校验状态
if (ObjectUtil.equal(activityDO.getStatus(), CommonStatusEnum.DISABLE.getStatus())) {
throw exception(BARGAIN_ACTIVITY_STATUS_DISABLE);
}
// 校验商品冲突
validateBargainConflict(updateReqVO.getSpuId(), updateReqVO.getId());
// 校验商品 sku 是否存在
validateSku(updateReqVO.getSkuId());
// 更新
BargainActivityDO updateObj = BargainActivityConvert.INSTANCE.convert(updateReqVO);
bargainActivityMapper.updateById(updateObj);
}
private void validateBargainConflict(Long spuId, Long activityId) {
// 查询所有开启的砍价活动
List<BargainActivityDO> activityList = bargainActivityMapper.selectListByStatus(CommonStatusEnum.ENABLE.getStatus());
if (activityId != null) { // 更新时排除自己
activityList.removeIf(item -> ObjectUtil.equal(item.getId(), activityId));
}
// 校验商品 spu 是否参加了其它活动
if (anyMatch(activityList, activity -> ObjectUtil.equal(activity.getSpuId(), spuId))) {
throw exception(BARGAIN_ACTIVITY_SPU_CONFLICTS);
}
}
private void validateSku(Long skuId) {
ProductSkuRespDTO sku = productSkuApi.getSku(skuId);
if (sku == null) {
throw exception(SKU_NOT_EXISTS);
}
}
@Override
@Transactional(rollbackFor = Exception.class)
public void deleteBargainActivity(Long id) {
// 校验存在
BargainActivityDO activityDO = validateBargainActivityExists(id);
// 校验状态
if (ObjectUtil.equal(activityDO.getStatus(), CommonStatusEnum.ENABLE.getStatus())) {
throw exception(BARGAIN_ACTIVITY_DELETE_FAIL_STATUS_NOT_CLOSED_OR_END);
}
// 删除
bargainActivityMapper.deleteById(id);
}
private BargainActivityDO validateBargainActivityExists(Long id) {
BargainActivityDO activityDO = bargainActivityMapper.selectById(id);
if (activityDO == null) {
throw exception(BARGAIN_ACTIVITY_NOT_EXISTS);
}
return activityDO;
}
@Override
public BargainActivityDO getBargainActivity(Long id) {
return bargainActivityMapper.selectById(id);
}
@Override
public PageResult<BargainActivityDO> getBargainActivityPage(BargainActivityPageReqVO pageReqVO) {
return bargainActivityMapper.selectPage(pageReqVO);
}
}

View File

@ -0,0 +1,13 @@
package cn.iocoder.yudao.module.promotion.service.bargain;
/**
* 砍价记录 service 接口
*
* @author HUIHUI
*/
public interface BargainRecordService {
// TODO
}

View File

@ -0,0 +1,14 @@
package cn.iocoder.yudao.module.promotion.service.bargain;
import org.springframework.stereotype.Service;
import org.springframework.validation.annotation.Validated;
/**
* 砍价记录 Service 实现类
*
* @author HUIHUI
*/
@Service
@Validated
public class BargainRecordServiceImpl implements BargainRecordService {
}

View File

@ -1,16 +1,13 @@
package cn.iocoder.yudao.module.promotion.service.combination; package cn.iocoder.yudao.module.promotion.service.combination;
import cn.iocoder.yudao.framework.common.pojo.PageResult; import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.module.promotion.api.combination.dto.CombinationRecordReqDTO;
import cn.iocoder.yudao.module.promotion.controller.admin.combination.vo.activity.CombinationActivityCreateReqVO; import cn.iocoder.yudao.module.promotion.controller.admin.combination.vo.activity.CombinationActivityCreateReqVO;
import cn.iocoder.yudao.module.promotion.controller.admin.combination.vo.activity.CombinationActivityExportReqVO;
import cn.iocoder.yudao.module.promotion.controller.admin.combination.vo.activity.CombinationActivityPageReqVO; import cn.iocoder.yudao.module.promotion.controller.admin.combination.vo.activity.CombinationActivityPageReqVO;
import cn.iocoder.yudao.module.promotion.controller.admin.combination.vo.activity.CombinationActivityUpdateReqVO; import cn.iocoder.yudao.module.promotion.controller.admin.combination.vo.activity.CombinationActivityUpdateReqVO;
import cn.iocoder.yudao.module.promotion.dal.dataobject.combination.combinationactivity.CombinationActivityDO; import cn.iocoder.yudao.module.promotion.dal.dataobject.combination.CombinationActivityDO;
import cn.iocoder.yudao.module.promotion.dal.dataobject.combination.combinationactivity.CombinationProductDO; import cn.iocoder.yudao.module.promotion.dal.dataobject.combination.CombinationProductDO;
import javax.validation.Valid; import javax.validation.Valid;
import java.time.LocalDateTime;
import java.util.Collection; import java.util.Collection;
import java.util.List; import java.util.List;
@ -43,6 +40,14 @@ public interface CombinationActivityService {
*/ */
void deleteCombinationActivity(Long id); void deleteCombinationActivity(Long id);
/**
* 校验拼团活动是否存在
*
* @param id 编号
* @return 拼团活动
*/
CombinationActivityDO validateCombinationActivityExists(Long id);
/** /**
* 获得拼团活动 * 获得拼团活动
* *
@ -51,14 +56,6 @@ public interface CombinationActivityService {
*/ */
CombinationActivityDO getCombinationActivity(Long id); CombinationActivityDO getCombinationActivity(Long id);
/**
* 获得拼团活动列表
*
* @param ids 编号
* @return 拼团活动列表
*/
List<CombinationActivityDO> getCombinationActivityList(Collection<Long> ids);
/** /**
* 获得拼团活动分页 * 获得拼团活动分页
* *
@ -67,57 +64,12 @@ public interface CombinationActivityService {
*/ */
PageResult<CombinationActivityDO> getCombinationActivityPage(CombinationActivityPageReqVO pageReqVO); PageResult<CombinationActivityDO> getCombinationActivityPage(CombinationActivityPageReqVO pageReqVO);
/**
* 获得拼团活动列表, 用于 Excel 导出
*
* @param exportReqVO 查询条件
* @return 拼团活动列表
*/
List<CombinationActivityDO> getCombinationActivityList(CombinationActivityExportReqVO exportReqVO);
/** /**
* 获得拼团活动商品列表 * 获得拼团活动商品列表
* *
* @param ids 拼团活动 ids * @param activityIds 拼团活动 ids
* @return 拼团活动的商品列表 * @return 拼团活动的商品列表
*/ */
List<CombinationProductDO> getProductsByActivityIds(Collection<Long> ids); List<CombinationProductDO> getCombinationProductsByActivityIds(Collection<Long> activityIds);
// TODO @puhui999拆一个 CombinationRecordService 方法名可以简洁成 updateRecordStatusByOrderIdservice 方法可以稍微简单一点如果是 update 方法
/**
* 更新拼团状态
*
* @param userId 用户编号
* @param orderId 订单编号
* @param status 状态
*/
void updateRecordStatusByUserIdAndOrderId(Long userId, Long orderId, Integer status);
/**
* 更新拼团状态和开始时间
*
* @param userId 用户编号
* @param orderId 订单编号
* @param status 状态
* @param startTime 开始时间
*/
void updateRecordStatusAndStartTimeByUserIdAndOrderId(Long userId, Long orderId, Integer status, LocalDateTime startTime);
// TODO @puhui999拆一个 CombinationRecordService
/**
* 创建拼团记录
*
* @param reqDTO 创建信息
*/
void createRecord(CombinationRecordReqDTO reqDTO);
/**
* 获得拼团状态
*
* @param userId 用户编号
* @param orderId 订单编号
* @return 拼团状态
*/
boolean validateRecordStatusIsSuccess(Long userId, Long orderId);
} }

View File

@ -1,7 +1,6 @@
package cn.iocoder.yudao.module.promotion.service.combination; package cn.iocoder.yudao.module.promotion.service.combination;
import cn.hutool.core.collection.CollUtil; import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.ObjectUtil; import cn.hutool.core.util.ObjectUtil;
import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
import cn.iocoder.yudao.framework.common.pojo.PageResult; import cn.iocoder.yudao.framework.common.pojo.PageResult;
@ -10,35 +9,31 @@ import cn.iocoder.yudao.module.product.api.sku.ProductSkuApi;
import cn.iocoder.yudao.module.product.api.sku.dto.ProductSkuRespDTO; import cn.iocoder.yudao.module.product.api.sku.dto.ProductSkuRespDTO;
import cn.iocoder.yudao.module.product.api.spu.ProductSpuApi; import cn.iocoder.yudao.module.product.api.spu.ProductSpuApi;
import cn.iocoder.yudao.module.product.api.spu.dto.ProductSpuRespDTO; import cn.iocoder.yudao.module.product.api.spu.dto.ProductSpuRespDTO;
import cn.iocoder.yudao.module.promotion.api.combination.dto.CombinationRecordReqDTO;
import cn.iocoder.yudao.module.promotion.controller.admin.combination.vo.activity.CombinationActivityCreateReqVO; import cn.iocoder.yudao.module.promotion.controller.admin.combination.vo.activity.CombinationActivityCreateReqVO;
import cn.iocoder.yudao.module.promotion.controller.admin.combination.vo.activity.CombinationActivityExportReqVO;
import cn.iocoder.yudao.module.promotion.controller.admin.combination.vo.activity.CombinationActivityPageReqVO; import cn.iocoder.yudao.module.promotion.controller.admin.combination.vo.activity.CombinationActivityPageReqVO;
import cn.iocoder.yudao.module.promotion.controller.admin.combination.vo.activity.CombinationActivityUpdateReqVO; import cn.iocoder.yudao.module.promotion.controller.admin.combination.vo.activity.CombinationActivityUpdateReqVO;
import cn.iocoder.yudao.module.promotion.controller.admin.combination.vo.product.CombinationProductCreateReqVO; import cn.iocoder.yudao.module.promotion.controller.admin.combination.vo.product.CombinationProductBaseVO;
import cn.iocoder.yudao.module.promotion.controller.admin.combination.vo.product.CombinationProductUpdateReqVO;
import cn.iocoder.yudao.module.promotion.convert.combination.CombinationActivityConvert; import cn.iocoder.yudao.module.promotion.convert.combination.CombinationActivityConvert;
import cn.iocoder.yudao.module.promotion.dal.dataobject.combination.combinationactivity.CombinationActivityDO; import cn.iocoder.yudao.module.promotion.dal.dataobject.combination.CombinationActivityDO;
import cn.iocoder.yudao.module.promotion.dal.dataobject.combination.combinationactivity.CombinationProductDO; import cn.iocoder.yudao.module.promotion.dal.dataobject.combination.CombinationProductDO;
import cn.iocoder.yudao.module.promotion.dal.dataobject.combination.combinationactivity.CombinationRecordDO; import cn.iocoder.yudao.module.promotion.dal.mysql.combination.CombinationActivityMapper;
import cn.iocoder.yudao.module.promotion.dal.mysql.combination.combinationactivity.CombinationActivityMapper; import cn.iocoder.yudao.module.promotion.dal.mysql.combination.CombinationProductMapper;
import cn.iocoder.yudao.module.promotion.dal.mysql.combination.combinationactivity.CombinationProductMapper;
import cn.iocoder.yudao.module.promotion.dal.mysql.combination.combinationactivity.CombinationRecordMapper;
import cn.iocoder.yudao.module.promotion.enums.combination.CombinationRecordStatusEnum;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional; import org.springframework.transaction.annotation.Transactional;
import org.springframework.validation.annotation.Validated; import org.springframework.validation.annotation.Validated;
import javax.annotation.Resource; import javax.annotation.Resource;
import java.time.LocalDateTime;
import java.util.Collection; import java.util.Collection;
import java.util.List; import java.util.List;
import java.util.Set; import java.util.Map;
import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertMap;
import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.filterList;
import static cn.iocoder.yudao.module.product.enums.ErrorCodeConstants.SKU_NOT_EXISTS;
import static cn.iocoder.yudao.module.product.enums.ErrorCodeConstants.SPU_NOT_EXISTS; import static cn.iocoder.yudao.module.product.enums.ErrorCodeConstants.SPU_NOT_EXISTS;
import static cn.iocoder.yudao.module.promotion.enums.ErrorCodeConstants.*; import static cn.iocoder.yudao.module.promotion.enums.ErrorCodeConstants.*;
import static cn.iocoder.yudao.module.promotion.util.PromotionUtils.validateProductSkuExistence; import static java.util.Collections.singletonList;
/** /**
* 拼团活动 Service 实现类 * 拼团活动 Service 实现类
@ -52,61 +47,77 @@ public class CombinationActivityServiceImpl implements CombinationActivityServic
@Resource @Resource
private CombinationActivityMapper combinationActivityMapper; private CombinationActivityMapper combinationActivityMapper;
@Resource @Resource
private CombinationRecordMapper recordMapper;
@Resource
private CombinationProductMapper combinationProductMapper; private CombinationProductMapper combinationProductMapper;
@Resource @Resource
private ProductSpuApi productSpuApi; private ProductSpuApi productSpuApi;
@Resource @Resource
private ProductSkuApi productSkuApi; private ProductSkuApi productSkuApi;
@Override @Override
@Transactional(rollbackFor = Exception.class)
public Long createCombinationActivity(CombinationActivityCreateReqVO createReqVO) { public Long createCombinationActivity(CombinationActivityCreateReqVO createReqVO) {
// 校验商品 SPU 是否存在是否参加的别的活动 // 校验商品 SPU 是否存在是否参加的别的活动
validateProductCombinationConflict(createReqVO.getSpuId(), null); validateProductConflict(createReqVO.getSpuId(), null);
// 获取所选 spu下的所有 sku // 校验商品是否存在
List<ProductSkuRespDTO> skus = productSkuApi.getSkuListBySpuId(CollectionUtil.newArrayList(createReqVO.getSpuId())); validateProductExists(createReqVO.getSpuId(), createReqVO.getProducts());
// 校验商品 sku 是否存在
validateProductSkuExistence(skus, createReqVO.getProducts(), CombinationProductCreateReqVO::getSkuId);
// TODO 艿艿 有个小问题现在有活动时间和限制时长活动时间的结束时间早于设置的限制时间怎么算状态比如
// 活动时间 2023-08-05 15:00:00 - 2023-08-05 15:20:00 限制时长 2小时那么活动时间结束就结束还是加时到满两小时
// 插入拼团活动 // 插入拼团活动
CombinationActivityDO activityDO = CombinationActivityConvert.INSTANCE.convert(createReqVO); CombinationActivityDO activity = CombinationActivityConvert.INSTANCE.convert(createReqVO)
// TODO 营销相关属性初始化 .setStatus(CommonStatusEnum.ENABLE.getStatus())
activityDO.setTotalNum(0); .setTotalCount(0).setSuccessCount(0).setOrderUserCount(0).setVirtualGroup(0);
activityDO.setSuccessNum(0); combinationActivityMapper.insert(activity);
activityDO.setOrderUserCount(0);
activityDO.setVirtualGroup(0);
activityDO.setStatus(CommonStatusEnum.ENABLE.getStatus());
combinationActivityMapper.insert(activityDO);
// 插入商品 // 插入商品
List<CombinationProductDO> productDOs = CombinationActivityConvert.INSTANCE.convertList(activityDO, createReqVO.getProducts()); List<CombinationProductDO> products = CombinationActivityConvert.INSTANCE.convertList(createReqVO.getProducts(), activity);
combinationProductMapper.insertBatch(productDOs); combinationProductMapper.insertBatch(products);
// 返回 // 返回
return activityDO.getId(); return activity.getId();
} }
private void validateProductCombinationConflict(Long spuId, Long activityId) { /**
// 校验商品 spu 是否存在 * 校验拼团商品参与的活动是否存在冲突
List<ProductSpuRespDTO> spuList = productSpuApi.getSpuList(CollUtil.newArrayList(spuId)); *
if (CollUtil.isEmpty(spuList)) { * @param spuId 商品 SPU 编号
throw exception(SPU_NOT_EXISTS); * @param activityId 拼团活动编号
} */
private void validateProductConflict(Long spuId, Long activityId) {
// 查询所有开启的拼团活动 // 查询所有开启的拼团活动
List<CombinationActivityDO> activityDOs = combinationActivityMapper.selectListByStatus(CommonStatusEnum.ENABLE.getStatus()); List<CombinationActivityDO> activityList = combinationActivityMapper.selectListByStatus(CommonStatusEnum.ENABLE.getStatus());
// 更新时排除自己 if (activityId != null) { // 时排除自己
if (activityId != null) { activityList.removeIf(item -> ObjectUtil.equal(item.getId(), activityId));
activityDOs.removeIf(item -> ObjectUtil.equal(item.getId(), activityId));
} }
// 过滤出所有 spuIds 有交集的活动 // 查找是否有其它活动选择了该产品
List<CombinationActivityDO> doList = CollectionUtils.convertList(activityDOs, c -> c, s -> ObjectUtil.equal(s.getId(), spuId)); List<CombinationActivityDO> matchActivityList = filterList(activityList, activity -> ObjectUtil.equal(activity.getId(), spuId));
if (CollUtil.isNotEmpty(doList)) { if (CollUtil.isNotEmpty(matchActivityList)) {
throw exception(COMBINATION_ACTIVITY_SPU_CONFLICTS); throw exception(COMBINATION_ACTIVITY_SPU_CONFLICTS);
} }
} }
/**
* 校验拼团商品是否都存在
*
* @param spuId 商品 SPU 编号
* @param products 秒杀商品
*/
private void validateProductExists(Long spuId, List<CombinationProductBaseVO> products) {
// 1. 校验商品 spu 是否存在
ProductSpuRespDTO spu = productSpuApi.getSpu(spuId);
if (spu == null) {
throw exception(SPU_NOT_EXISTS);
}
// 2. 校验商品 sku 都存在
Map<Long, ProductSkuRespDTO> skuMap = convertMap(productSkuApi.getSkuListBySpuId(singletonList(spuId)),
ProductSkuRespDTO::getId);
products.forEach(product -> {
if (!skuMap.containsKey(product.getSkuId())) {
throw exception(SKU_NOT_EXISTS);
}
});
}
@Override @Override
@Transactional(rollbackFor = Exception.class)
public void updateCombinationActivity(CombinationActivityUpdateReqVO updateReqVO) { public void updateCombinationActivity(CombinationActivityUpdateReqVO updateReqVO) {
// 校验存在 // 校验存在
CombinationActivityDO activityDO = validateCombinationActivityExists(updateReqVO.getId()); CombinationActivityDO activityDO = validateCombinationActivityExists(updateReqVO.getId());
@ -115,13 +126,11 @@ public class CombinationActivityServiceImpl implements CombinationActivityServic
throw exception(COMBINATION_ACTIVITY_STATUS_DISABLE); throw exception(COMBINATION_ACTIVITY_STATUS_DISABLE);
} }
// 校验商品冲突 // 校验商品冲突
validateProductCombinationConflict(updateReqVO.getSpuId(), updateReqVO.getId()); validateProductConflict(updateReqVO.getSpuId(), updateReqVO.getId());
// 获取所选 spu下的所有 sku // 校验商品是否存在
List<ProductSkuRespDTO> skus = productSkuApi.getSkuListBySpuId(CollectionUtil.newArrayList(updateReqVO.getSpuId())); validateProductExists(updateReqVO.getSpuId(), updateReqVO.getProducts());
// 校验商品 sku 是否存在
validateProductSkuExistence(skus, updateReqVO.getProducts(), CombinationProductUpdateReqVO::getSkuId);
// 更新 // 更新活动
CombinationActivityDO updateObj = CombinationActivityConvert.INSTANCE.convert(updateReqVO); CombinationActivityDO updateObj = CombinationActivityConvert.INSTANCE.convert(updateReqVO);
combinationActivityMapper.updateById(updateObj); combinationActivityMapper.updateById(updateObj);
// 更新商品 // 更新商品
@ -129,40 +138,37 @@ public class CombinationActivityServiceImpl implements CombinationActivityServic
} }
/** /**
* 更新秒杀商品 * 更新拼团商品
* TODO 更新商品要不要封装成通用方法
* *
* @param updateObj DO * @param activity 拼团活动
* @param products 商品配置 * @param products 该活动的最新商品配置
*/ */
private void updateCombinationProduct(CombinationActivityDO updateObj, List<CombinationProductUpdateReqVO> products) { private void updateCombinationProduct(CombinationActivityDO activity, List<CombinationProductBaseVO> products) {
List<CombinationProductDO> combinationProductDOs = combinationProductMapper.selectListByActivityIds(CollUtil.newArrayList(updateObj.getId())); // 第一步对比新老数据获得添加修改删除的列表
// 数据库中的活动商品 List<CombinationProductDO> newList = CombinationActivityConvert.INSTANCE.convertList(products, activity);
Set<Long> convertSet = CollectionUtils.convertSet(combinationProductDOs, CombinationProductDO::getSkuId); List<CombinationProductDO> oldList = combinationProductMapper.selectListByActivityIds(CollUtil.newArrayList(activity.getId()));
// 前端传过来的活动商品 List<List<CombinationProductDO>> diffList = CollectionUtils.diffList(oldList, newList, (oldVal, newVal) -> {
Set<Long> convertSet1 = CollectionUtils.convertSet(products, CombinationProductUpdateReqVO::getSkuId); boolean same = ObjectUtil.equal(oldVal.getSkuId(), newVal.getSkuId());
// 删除后台存在的前端不存在的商品 if (same) {
List<Long> d = CollectionUtils.filterList(convertSet, item -> !convertSet1.contains(item)); newVal.setId(oldVal.getId());
if (CollUtil.isNotEmpty(d)) { }
combinationProductMapper.deleteBatchIds(d); return same;
});
// 第二步批量添加修改删除
if (CollUtil.isNotEmpty(diffList.get(0))) {
combinationProductMapper.insertBatch(diffList.get(0));
} }
// 前端存在的后端不存在的商品 if (CollUtil.isNotEmpty(diffList.get(1))) {
List<Long> c = CollectionUtils.filterList(convertSet1, item -> !convertSet.contains(item)); combinationProductMapper.updateBatch(diffList.get(1));
if (CollUtil.isNotEmpty(c)) {
List<CombinationProductUpdateReqVO> vos = CollectionUtils.filterList(products, item -> c.contains(item.getSkuId()));
List<CombinationProductDO> productDOs = CombinationActivityConvert.INSTANCE.convertList(updateObj, vos);
combinationProductMapper.insertBatch(productDOs);
} }
// 更新已存在的商品 if (CollUtil.isNotEmpty(diffList.get(2))) {
List<Long> u = CollectionUtils.filterList(convertSet1, convertSet::contains); combinationProductMapper.deleteBatchIds(CollectionUtils.convertList(diffList.get(2), CombinationProductDO::getId));
if (CollUtil.isNotEmpty(u)) {
List<CombinationProductUpdateReqVO> vos = CollectionUtils.filterList(products, item -> u.contains(item.getSkuId()));
List<CombinationProductDO> productDOs = CombinationActivityConvert.INSTANCE.convertList1(updateObj, vos, combinationProductDOs);
combinationProductMapper.updateBatch(productDOs);
} }
} }
@Override @Override
@Transactional(rollbackFor = Exception.class)
public void deleteCombinationActivity(Long id) { public void deleteCombinationActivity(Long id) {
// 校验存在 // 校验存在
CombinationActivityDO activityDO = validateCombinationActivityExists(id); CombinationActivityDO activityDO = validateCombinationActivityExists(id);
@ -175,7 +181,8 @@ public class CombinationActivityServiceImpl implements CombinationActivityServic
combinationActivityMapper.deleteById(id); combinationActivityMapper.deleteById(id);
} }
private CombinationActivityDO validateCombinationActivityExists(Long id) { @Override
public CombinationActivityDO validateCombinationActivityExists(Long id) {
CombinationActivityDO activityDO = combinationActivityMapper.selectById(id); CombinationActivityDO activityDO = combinationActivityMapper.selectById(id);
if (activityDO == null) { if (activityDO == null) {
throw exception(COMBINATION_ACTIVITY_NOT_EXISTS); throw exception(COMBINATION_ACTIVITY_NOT_EXISTS);
@ -188,99 +195,14 @@ public class CombinationActivityServiceImpl implements CombinationActivityServic
return validateCombinationActivityExists(id); return validateCombinationActivityExists(id);
} }
@Override
public List<CombinationActivityDO> getCombinationActivityList(Collection<Long> ids) {
return combinationActivityMapper.selectBatchIds(ids);
}
@Override @Override
public PageResult<CombinationActivityDO> getCombinationActivityPage(CombinationActivityPageReqVO pageReqVO) { public PageResult<CombinationActivityDO> getCombinationActivityPage(CombinationActivityPageReqVO pageReqVO) {
return combinationActivityMapper.selectPage(pageReqVO); return combinationActivityMapper.selectPage(pageReqVO);
} }
@Override @Override
public List<CombinationActivityDO> getCombinationActivityList(CombinationActivityExportReqVO exportReqVO) { public List<CombinationProductDO> getCombinationProductsByActivityIds(Collection<Long> activityIds) {
return combinationActivityMapper.selectList(exportReqVO); return combinationProductMapper.selectListByActivityIds(activityIds);
}
@Override
public List<CombinationProductDO> getProductsByActivityIds(Collection<Long> ids) {
return combinationProductMapper.selectListByActivityIds(ids);
}
@Override
public void updateRecordStatusByUserIdAndOrderId(Long userId, Long orderId, Integer status) {
// 校验拼团是否存在
CombinationRecordDO recordDO = validateCombinationRecord(userId, orderId);
// 更新状态
recordDO.setStatus(status);
recordMapper.updateById(recordDO);
}
@Override
@Transactional(rollbackFor = Exception.class)
public void updateRecordStatusAndStartTimeByUserIdAndOrderId(Long userId, Long orderId, Integer status, LocalDateTime startTime) {
CombinationRecordDO recordDO = validateCombinationRecord(userId, orderId);
// 更新状态
recordDO.setStatus(status);
// 更新开始时间
recordDO.setStartTime(startTime);
recordMapper.updateById(recordDO);
// 更新拼团参入人数
List<CombinationRecordDO> recordDOs = recordMapper.selectListByHeadIdAndStatus(recordDO.getHeadId(), status);
if (CollUtil.isNotEmpty(recordDOs)) {
recordDOs.forEach(item -> {
item.setUserCount(recordDOs.size());
// 校验拼团是否满足要求
if (recordDOs.size() >= recordDO.getUserSize()) {
item.setStatus(CombinationRecordStatusEnum.SUCCESS.getStatus());
}
});
}
recordMapper.updateBatch(recordDOs);
}
private CombinationRecordDO validateCombinationRecord(Long userId, Long orderId) {
// 校验拼团是否存在
CombinationRecordDO recordDO = recordMapper.selectRecord(userId, orderId);
if (recordDO == null) {
throw exception(COMBINATION_RECORD_NOT_EXISTS);
}
return recordDO;
}
@Override
public void createRecord(CombinationRecordReqDTO reqDTO) {
// 校验拼团活动
CombinationActivityDO activity = validateCombinationActivityExists(reqDTO.getActivityId());
// TODO @puhui999需要校验下它当前是不是已经参加了该拼团
// TODO @puhui999: 父拼团是否存在,是否已经满了
CombinationRecordDO record = CombinationActivityConvert.INSTANCE.convert(reqDTO);
record.setVirtualGroup(false);
// TODO @puhui999过期时间应该是 Date
record.setExpireTime(activity.getLimitDuration());
record.setUserSize(activity.getUserSize());
recordMapper.insert(record);
}
@Override
public boolean validateRecordStatusIsSuccess(Long userId, Long orderId) {
CombinationRecordDO record = validateCombinationRecord(userId, orderId);
// TODO @puhui999可以搞个 getRecrod 方法然后业务通过 CombinationRecordStatusEnum.isSuccess 方法校验
return ObjectUtil.equal(record.getStatus(), CombinationRecordStatusEnum.SUCCESS.getStatus());
}
// TODO @puhui999status 传入进来搞哈
/**
* APP 端获取开团记录
*
* @return 开团记录
*/
public List<CombinationRecordDO> getRecordList() {
return recordMapper.selectListByStatus(CombinationRecordStatusEnum.IN_PROGRESS.getStatus());
} }
} }

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