feat(memberCenter): 新增会员促销活动功能

- 新增积分奖励活动类型
- 实现活动期间内订阅或续订会员的积分加成
- 增加活动参与记录和状态管理
- 优化活动列表展示逻辑
- 修复活动开始时间不能大于结束时间的问题
feature/comment
yang 2025-01-05 18:35:08 +08:00
parent 40bc8128eb
commit 4fc9909191
10 changed files with 137 additions and 26 deletions

View File

@ -18,6 +18,7 @@ import lombok.RequiredArgsConstructor;
import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.StringUtils;
import org.springframework.web.bind.annotation.*; import org.springframework.web.bind.annotation.*;
import javax.validation.Valid;
import java.util.List; import java.util.List;
import java.util.Optional; import java.util.Optional;
@ -43,10 +44,11 @@ public class MemberController {
* @return * @return
*/ */
@PostMapping("createMember") @PostMapping("createMember")
public AjaxResult createMemberCenter(@RequestBody UserMemberDto userMemberDto) { public AjaxResult createMemberCenter(@RequestBody @Valid UserMemberDto userMemberDto) {
Long userId = userMemberDto.getUserId(); Long userId = userMemberDto.getUserId();
Long memberLevelId = userMemberDto.getMemberLevelId(); Long memberLevelId = userMemberDto.getMemberLevelId();
String paymentMethod = userMemberDto.getPaymentMethod(); String paymentMethod = userMemberDto.getPaymentMethod();
Long promotionId = userMemberDto.getPromotionId();
SysUser sysUser = sysUserService.selectUserById(userId); SysUser sysUser = sysUserService.selectUserById(userId);
if (!Optional.ofNullable(sysUser).isPresent()) { if (!Optional.ofNullable(sysUser).isPresent()) {
@ -58,7 +60,7 @@ public class MemberController {
return AjaxResult.warn("会员等级不存在"); return AjaxResult.warn("会员等级不存在");
} }
Member member = memberService.createUserMember(userId, memberLevelId, paymentMethod); Member member = memberService.createUserMember(userId, memberLevelId, paymentMethod, promotionId);
if (!Optional.ofNullable(member).isPresent()) { if (!Optional.ofNullable(member).isPresent()) {
return AjaxResult.warn("创建会员失败"); return AjaxResult.warn("创建会员失败");
} }
@ -69,6 +71,7 @@ public class MemberController {
/** /**
* *
*
* @return * @return
*/ */
@GetMapping("getPoints") @GetMapping("getPoints")
@ -99,7 +102,7 @@ public class MemberController {
* *
*/ */
@PostMapping("rechargePoints") @PostMapping("rechargePoints")
public AjaxResult rechargePoints(@RequestBody RechargePointsDto rechargePointsDto) { public AjaxResult rechargePoints(@RequestBody @Valid RechargePointsDto rechargePointsDto) {
Long userId = rechargePointsDto.getUserId(); Long userId = rechargePointsDto.getUserId();
Double amount = rechargePointsDto.getAmount(); Double amount = rechargePointsDto.getAmount();

View File

@ -4,12 +4,15 @@ package com.mcwl.web.controller.memberCenter;
import cn.hutool.core.bean.BeanUtil; import cn.hutool.core.bean.BeanUtil;
import com.mcwl.common.core.domain.AjaxResult; import com.mcwl.common.core.domain.AjaxResult;
import com.mcwl.common.utils.SecurityUtils; import com.mcwl.common.utils.SecurityUtils;
import com.mcwl.memberCenter.domain.Member;
import com.mcwl.memberCenter.domain.MemberPromotion; import com.mcwl.memberCenter.domain.MemberPromotion;
import com.mcwl.memberCenter.domain.Promotion; import com.mcwl.memberCenter.domain.Promotion;
import com.mcwl.memberCenter.domain.dto.JoinPromotionDto; import com.mcwl.memberCenter.domain.dto.JoinPromotionDto;
import com.mcwl.memberCenter.domain.dto.PromotionDto; import com.mcwl.memberCenter.domain.dto.PromotionDto;
import com.mcwl.memberCenter.enums.MemberEnum;
import com.mcwl.memberCenter.enums.PromotionEnum; import com.mcwl.memberCenter.enums.PromotionEnum;
import com.mcwl.memberCenter.service.MemberPromotionService; import com.mcwl.memberCenter.service.MemberPromotionService;
import com.mcwl.memberCenter.service.MemberService;
import com.mcwl.memberCenter.service.PromotionService; import com.mcwl.memberCenter.service.PromotionService;
import lombok.RequiredArgsConstructor; import lombok.RequiredArgsConstructor;
import org.springframework.web.bind.annotation.*; import org.springframework.web.bind.annotation.*;
@ -32,6 +35,8 @@ public class PromotionController {
private final MemberPromotionService memberPromotionService; private final MemberPromotionService memberPromotionService;
private final MemberService memberService;
/** /**
* *
@ -39,6 +44,11 @@ public class PromotionController {
@PostMapping("createPromotion") @PostMapping("createPromotion")
public AjaxResult createPromotion(@RequestBody @Valid PromotionDto promotionDto) { public AjaxResult createPromotion(@RequestBody @Valid PromotionDto promotionDto) {
Date startTime = promotionDto.getStartTime();
Date endTime = promotionDto.getEndTime();
if (startTime.after(endTime)) {
return AjaxResult.warn("活动开始时间不能大于结束时间");
}
Promotion promotion = new Promotion(); Promotion promotion = new Promotion();
BeanUtil.copyProperties(promotionDto, promotion); BeanUtil.copyProperties(promotionDto, promotion);
@ -55,7 +65,7 @@ public class PromotionController {
@GetMapping("promotionList") @GetMapping("promotionList")
public AjaxResult promotionList() { public AjaxResult promotionList() {
List<Promotion> promotionList = promotionService.lambdaQuery() List<Promotion> promotionList = promotionService.lambdaQuery()
.lt(Promotion::getEndTime, new Date()) .gt(Promotion::getEndTime, new Date())
.list(); .list();
return AjaxResult.success(promotionList); return AjaxResult.success(promotionList);
} }
@ -68,7 +78,7 @@ public class PromotionController {
// 获取当前用户 // 获取当前用户
Long userId = SecurityUtils.getUserId(); Long userId = SecurityUtils.getUserId();
List<MemberPromotion> memberPromotionList = memberPromotionService.lambdaQuery() List<MemberPromotion> memberPromotionList = memberPromotionService.lambdaQuery()
.eq(MemberPromotion::getMemberId, userId) .eq(MemberPromotion::getUserId, userId)
.list(); .list();
return AjaxResult.success(memberPromotionList); return AjaxResult.success(memberPromotionList);
} }
@ -98,20 +108,63 @@ public class PromotionController {
return AjaxResult.warn("活动已过期"); return AjaxResult.warn("活动已过期");
} }
String memberLevelIds = promotion.getMemberLevelId(); // 获取当前用户是否参与过该活动
if (!memberLevelIds.contains(userId.toString())) { if (isJoinPromotion(userId, promotionId)) {
return AjaxResult.warn("您已参与过该活动");
}
// 是否在活动期间内订阅或续订会员
// if (!isSubscribe(userId, promotion)) {
// return AjaxResult.warn("请在活动期间内订阅或续期会员后参加该活动");
// }
Member member = memberService.getUseUserMemberByUserId(userId);
String memberLevelIds = promotion.getMemberLevelIds();
if (!memberLevelIds.contains(member.getMemberLevelId().toString())) {
return AjaxResult.warn("无法参与该活动,请查看活动条件"); return AjaxResult.warn("无法参与该活动,请查看活动条件");
} }
MemberPromotion memberPromotion = new MemberPromotion(); MemberPromotion memberPromotion = getMemberPromotion(userId, promotionId);
memberPromotion.setMemberId(userId);
memberPromotion.setPromotionId(promotionId);
memberPromotion.setStatus(PromotionEnum.EXPIRED);
memberPromotion.setParticipationTime(new Date());
memberPromotionService.save(memberPromotion); memberPromotionService.save(memberPromotion);
return AjaxResult.success(); return AjaxResult.success();
} }
// private boolean isSubscribe(Long userId, Promotion promotion) {
// if (promotion.getActivityType() == PromotionEnum.SUBSCRIBE) {
// // 获取当前用户最新的订阅或续订
// Member member = memberService.latestSubscription(userId);
// if (!Optional.ofNullable(member).isPresent()) {
// return false;
// }
// Date createTime = member.getCreateTime();
// // 会员创建时间在活动开始时间之前,说明用户不符合“活动期间内订阅或续订会员”的条件
// return !createTime.before(promotion.getStartTime());
// }
// return true;
// }
private boolean isJoinPromotion(Long userId, Long promotionId) {
MemberPromotion memberPromotion = memberPromotionService.lambdaQuery()
.eq(MemberPromotion::getUserId, userId)
.eq(MemberPromotion::getPromotionId, promotionId)
.one();
return memberPromotion != null;
}
private static MemberPromotion getMemberPromotion(Long userId, Long promotionId) {
MemberPromotion memberPromotion = new MemberPromotion();
memberPromotion.setUserId(userId);
memberPromotion.setPromotionId(promotionId);
memberPromotion.setStatus(PromotionEnum.PARTICIPATE);
memberPromotion.setParticipationTime(new Date());
memberPromotion.setCreateBy(SecurityUtils.getUsername());
memberPromotion.setCreateTime(new Date());
memberPromotion.setUpdateBy(SecurityUtils.getUsername());
memberPromotion.setUpdateTime(new Date());
return memberPromotion;
}
} }

View File

@ -38,7 +38,7 @@ public class MemberCenterTest {
private EmptyPointsRemindConsumer emptyPointsRemindConsumer; private EmptyPointsRemindConsumer emptyPointsRemindConsumer;
@Test @Test
public void createUserMember() { public void createUserMember() {
System.out.println(memberService.createUserMember(1L, 1013L, "wechat")); System.out.println(memberService.createUserMember(1L, 1013L, "wechat",1L));
} }
@Test @Test

View File

@ -20,9 +20,9 @@ public class MemberPromotion extends BaseEntity {
private Long id; private Long id;
/** /**
* ID * ID
*/ */
private Long memberId; private Long userId;
/** /**
* ID * ID

View File

@ -3,6 +3,7 @@ package com.mcwl.memberCenter.domain;
import com.baomidou.mybatisplus.annotation.TableId; import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName; import com.baomidou.mybatisplus.annotation.TableName;
import com.mcwl.common.core.domain.BaseEntity; import com.mcwl.common.core.domain.BaseEntity;
import com.mcwl.memberCenter.enums.PromotionEnum;
import lombok.Data; import lombok.Data;
import lombok.EqualsAndHashCode; import lombok.EqualsAndHashCode;
@ -35,9 +36,9 @@ public class Promotion extends BaseEntity {
private Date endTime; private Date endTime;
/** /**
* *
*/ */
private String activityType; private PromotionEnum activityType;
/** /**
* / 0.88 * / 0.88
@ -52,7 +53,7 @@ public class Promotion extends BaseEntity {
/** /**
* ID * ID
*/ */
private String memberLevelId; private String memberLevelIds;

View File

@ -3,8 +3,10 @@ package com.mcwl.memberCenter.domain.dto;
import com.baomidou.mybatisplus.annotation.TableId; import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName; import com.baomidou.mybatisplus.annotation.TableName;
import com.mcwl.common.core.domain.BaseEntity; import com.mcwl.common.core.domain.BaseEntity;
import com.mcwl.memberCenter.enums.PromotionEnum;
import lombok.Data; import lombok.Data;
import lombok.EqualsAndHashCode; import lombok.EqualsAndHashCode;
import org.springframework.format.annotation.DateTimeFormat;
import javax.validation.constraints.Min; import javax.validation.constraints.Min;
import javax.validation.constraints.NotBlank; import javax.validation.constraints.NotBlank;
@ -30,19 +32,21 @@ public class PromotionDto {
* *
*/ */
@NotNull(message = "活动开始时间不能为空") @NotNull(message = "活动开始时间不能为空")
@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private Date startTime; private Date startTime;
/** /**
* *
*/ */
@NotNull(message = "活动结束时间不能为空") @NotNull(message = "活动结束时间不能为空")
@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private Date endTime; private Date endTime;
/** /**
* *
*/ */
@NotBlank(message = "活动类型不能为空") @NotNull()
private String activityType; private PromotionEnum activityType;
/** /**
* / 0.88 * / 0.88
@ -59,7 +63,7 @@ public class PromotionDto {
/** /**
* ID * ID
*/ */
private String memberLevelId; private String memberLevelIds;

View File

@ -23,4 +23,7 @@ public class UserMemberDto {
@NotBlank(message = "支付方式不能为空") @NotBlank(message = "支付方式不能为空")
private String paymentMethod; private String paymentMethod;
// 活动ID
private Long promotionId;
} }

View File

@ -18,7 +18,20 @@ public enum PromotionEnum {
/** /**
* *
*/ */
EXPIRED("expired", "过期"); EXPIRED("expired", "过期"),
// /**
// * 订阅/续订会员
// */
// SUBSCRIBE("subscribe", "订阅/续订会员"),
/**
*
*/
DISCOUNT("discount", "限时折扣"),
/**
*
*/
POINTS("points", "积分奖励");
private final String name; private final String name;
@EnumValue @EnumValue

View File

@ -12,9 +12,11 @@ public interface MemberService extends IService<Member> {
* *
* @param userId id * @param userId id
* @param memberLevelId id * @param memberLevelId id
* @param paymentMethod
* @param promotionId id
* @return * @return
*/ */
Member createUserMember(Long userId, Long memberLevelId, String paymentMethod); Member createUserMember(Long userId, Long memberLevelId, String paymentMethod, Long promotionId);
/** /**
* *
@ -31,4 +33,6 @@ public interface MemberService extends IService<Member> {
Member rechargePoints(Long userId, Double points); Member rechargePoints(Long userId, Double points);
Member latestSubscription(Long userId);
} }

View File

@ -7,13 +7,17 @@ import com.mcwl.common.exception.ServiceException;
import com.mcwl.memberCenter.domain.MemberBenefit; import com.mcwl.memberCenter.domain.MemberBenefit;
import com.mcwl.memberCenter.domain.MemberLevel; import com.mcwl.memberCenter.domain.MemberLevel;
import com.mcwl.memberCenter.domain.Member; import com.mcwl.memberCenter.domain.Member;
import com.mcwl.memberCenter.domain.Promotion;
import com.mcwl.memberCenter.enums.MemberBenefitTypeEnum; import com.mcwl.memberCenter.enums.MemberBenefitTypeEnum;
import com.mcwl.memberCenter.enums.MemberEnum; import com.mcwl.memberCenter.enums.MemberEnum;
import com.mcwl.memberCenter.enums.MemberPeriodicEnum; import com.mcwl.memberCenter.enums.MemberPeriodicEnum;
import com.mcwl.memberCenter.enums.PromotionEnum;
import com.mcwl.memberCenter.mapper.MemberMapper; import com.mcwl.memberCenter.mapper.MemberMapper;
import com.mcwl.memberCenter.mapper.PromotionMapper;
import com.mcwl.memberCenter.service.MemberBenefitService; import com.mcwl.memberCenter.service.MemberBenefitService;
import com.mcwl.memberCenter.service.MemberLevelService; import com.mcwl.memberCenter.service.MemberLevelService;
import com.mcwl.memberCenter.service.MemberService; import com.mcwl.memberCenter.service.MemberService;
import com.mcwl.memberCenter.service.PromotionService;
import com.mcwl.system.service.ISysUserService; import com.mcwl.system.service.ISysUserService;
import lombok.RequiredArgsConstructor; import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
@ -31,8 +35,10 @@ public class MemberServiceImpl extends ServiceImpl<MemberMapper, Member> impleme
private final MemberBenefitService memberBenefitService; private final MemberBenefitService memberBenefitService;
private final PromotionMapper promotionMapper;
@Override @Override
public Member createUserMember(Long userId, Long memberLevelId, String paymentMethod) { public Member createUserMember(Long userId, Long memberLevelId, String paymentMethod, Long promotionId) {
if (userId == null) { if (userId == null) {
return null; return null;
} }
@ -79,7 +85,15 @@ public class MemberServiceImpl extends ServiceImpl<MemberMapper, Member> impleme
.eq(MemberBenefit::getBenefitType, MemberBenefitTypeEnum.POINTS) .eq(MemberBenefit::getBenefitType, MemberBenefitTypeEnum.POINTS)
.one(); .one();
if (memberBenefit != null) { if (memberBenefit != null) {
member.setPoints(memberBenefit.getBenefitDiscount()); Double points = memberBenefit.getBenefitDiscount();
// 根据活动id查询活动类型如果为积分则积分加成
if (promotionId != null) {
Promotion promotion = promotionMapper.selectById(promotionId);
if (promotion.getActivityType() == PromotionEnum.POINTS) {
points = points + promotion.getActivityValue();
}
}
member.setPoints(points);
} }
// 设置订阅状态 // 设置订阅状态
@ -143,6 +157,21 @@ public class MemberServiceImpl extends ServiceImpl<MemberMapper, Member> impleme
return null; return null;
} }
@Override
public Member latestSubscription(Long userId) {
// 根据userId 查询会员,按创建时间降序,获取最新的会员
LambdaQueryWrapper<Member> qw = new LambdaQueryWrapper<>();
qw.eq(Member::getUserId, userId)
.ne(Member::getSubscriptionStatus, MemberEnum.MEMBER_CENTER_EXPIRED)
.ne(Member::getSubscriptionStatus, MemberEnum.MEMBER_CENTER_PENDING)
.orderByDesc(Member::getCreateTime);
List<Member> memberList = baseMapper.selectList(qw);
if (memberList != null && !memberList.isEmpty()) {
return memberList.get(0);
}
return null;
}
private List<Member> getUseUserMember(Long userId) { private List<Member> getUseUserMember(Long userId) {
// startDate 小于等于当前时间、endDate 大于等于当前时间 // startDate 小于等于当前时间、endDate 大于等于当前时间
// subscriptionStatus 不为 "过期" 或 "待支付" // subscriptionStatus 不为 "过期" 或 "待支付"
@ -160,8 +189,9 @@ public class MemberServiceImpl extends ServiceImpl<MemberMapper, Member> impleme
/** /**
* *
*
* @param subscriptionPeriod * @param subscriptionPeriod
* @param calendar * @param calendar
* @return * @return
*/ */
private Date getEndDate(MemberPeriodicEnum subscriptionPeriod, Calendar calendar) { private Date getEndDate(MemberPeriodicEnum subscriptionPeriod, Calendar calendar) {