Merge branch 'refs/heads/feature/my-invitation' into preview

# Conflicts:
#	mcwl-common/src/main/java/com/mcwl/common/utils/ShareCodeUtils.java
feature/comment
yang 2025-01-02 14:13:18 +08:00
commit 8df1daac3e
22 changed files with 392 additions and 15 deletions

View File

@ -1,9 +1,12 @@
package com.mcwl;
import com.fasterxml.jackson.databind.SerializationFeature;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.autoconfigure.jackson.Jackson2ObjectMapperBuilderCustomizer;
import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration;
import org.springframework.context.annotation.Bean;
/**
*
@ -28,4 +31,10 @@ public class McWlApplication
" | | \\ / \\ / \n" +
" ''-' `'-' `-..-' ");
}
// 序列化枚举值为前端返回值
@Bean
public Jackson2ObjectMapperBuilderCustomizer customizer() {
return builder -> builder.featuresToEnable(SerializationFeature.WRITE_ENUMS_USING_TO_STRING);
}
}

View File

@ -1,13 +1,21 @@
package com.mcwl.web.controller.myInvitation;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import com.mcwl.common.annotation.Anonymous;
import com.mcwl.common.domain.IdsParam;
import org.springframework.web.bind.annotation.*;
@RestController()
@RequestMapping("/consume")
public class ConsumeController {
@PostMapping()
@Anonymous
public void removeByIds(@RequestBody IdsParam ids){
System.out.println(ids);
}

View File

@ -27,6 +27,9 @@ public class InvitationController {
public AjaxResult getInvitationCode() {
// 获取当前用户
Long userId = SecurityUtils.getUserId();
if (userId == null) {
return AjaxResult.warn("用户未登录");
}
String invitationCode = invitationService.getInvitationCode(userId);
return success("操作成功", invitationCode);
}

View File

@ -20,4 +20,15 @@ public class CodeMQConfig {
public Queue queue() {
return new Queue(QueueConstants.CODE_QUEUE, true);
}
@Bean
public Queue emptyPointsRemindQueue() {
return new Queue(QueueConstants.EMPTY_POINTS_REMIND_QUEUE, true);
}
@Bean
public Queue memberBillingQueue() {
return new Queue(QueueConstants.MEMBER_BILLING_QUEUE, true);
}
}

View File

@ -121,6 +121,8 @@ mybatis-plus:
# 关闭日志记录 (可单纯使用 p6spy 分析) org.apache.ibatis.logging.nologging.NoLoggingImpl
# 默认日志输出 org.apache.ibatis.logging.slf4j.Slf4jImpl
logImpl: org.apache.ibatis.logging.slf4j.Slf4jImpl
# 枚举处理器
default-enum-type-handler: com.baomidou.mybatisplus.core.handlers.MybatisEnumTypeHandler
global-config:
# 是否打印 Logo banner
banner: false

View File

@ -1,7 +1,12 @@
package com.mcwl.memberCenter;
import com.mcwl.McWlApplication;
import com.mcwl.common.utils.ShareCodeUtils;
import com.mcwl.memberCenter.consumer.EmptyPointsRemindConsumer;
import com.mcwl.memberCenter.domain.UserMember;
import com.mcwl.memberCenter.service.MemberService;
import com.mcwl.memberCenter.service.UserMemberService;
import com.mcwl.memberCenter.task.UserMemberTask;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
@ -16,6 +21,35 @@ public class MemberTest {
@Autowired
private MemberService memberService;
@Autowired
private UserMemberService userMemberService;
@Autowired
private UserMemberTask userMemberTask;
@Autowired
private EmptyPointsRemindConsumer emptyPointsRemindConsumer;
@Test
public void createUserMember() {
System.out.println(userMemberService.createUserMember(1L, 1013L, "wechat"));
}
@Test
public void emptyPointsTaskTest() {
userMemberTask.emptyPointsTsk();
}
@Test
public void updateSubscriptionStatusTaskTest() {
userMemberTask.updateSubscriptionStatusTask();
}
@Test
public void emptyPointsRemindTaskTst() {
userMemberTask.emptyPointsRemindTask();
}
@Test
public void memberServiceTest() {
System.out.println(memberService.list());

View File

@ -12,4 +12,15 @@ public class QueueConstants {
//发送手机号验证码短信的mq队列
public static final String CODE_QUEUE = "codeQueue";
// 积分清零提醒队列
public static final String EMPTY_POINTS_REMIND_QUEUE = "emptyPointsRemindQueue";
// 会员账单队列
public static final String MEMBER_BILLING_QUEUE = "memberBillingQueue";
}

View File

@ -4,6 +4,8 @@ import java.io.Serializable;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import com.baomidou.mybatisplus.annotation.TableField;
import com.fasterxml.jackson.annotation.JsonFormat;
import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.annotation.JsonInclude;
@ -19,6 +21,7 @@ public class BaseEntity implements Serializable
/** 搜索值 */
@JsonIgnore
@TableField(exist = false)
private String searchValue;
/** 创建者 */
@ -40,6 +43,7 @@ public class BaseEntity implements Serializable
/** 请求参数 */
@JsonInclude(JsonInclude.Include.NON_EMPTY)
@TableField(exist = false)
private Map<String, Object> params;
public String getSearchValue()

View File

@ -0,0 +1,8 @@
package com.mcwl.common.domain;
import lombok.Data;
@Data
public class IdsParam {
private Long[] ids;
}

View File

@ -97,10 +97,5 @@ public class ShareCodeUtils {
return result;
}
public static void main(String[] args) {
String code = idToCode(13653414955L);
System.out.println(code);
System.out.println(codeToId("IKGPUKXA"));
}
}

View File

@ -31,11 +31,23 @@
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.mcwl</groupId>
<artifactId>mcwl-system</artifactId>
</dependency>
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>${mybatis-plus.version}</version>
</dependency>
<!-- rabbitmq依赖 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-amqp</artifactId>
<version>3.1.2</version>
</dependency>
</dependencies>
</project>

View File

@ -0,0 +1,40 @@
package com.mcwl.memberCenter.consumer;
import com.mcwl.common.constant.QueueConstants;
import com.mcwl.memberCenter.domain.UserMember;
import com.mcwl.memberCenter.service.UserMemberService;
import com.mcwl.memberCenter.task.UserMemberTask;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.util.List;
@Slf4j
@Component
@RequiredArgsConstructor
public class EmptyPointsRemindConsumer {
private final UserMemberService userMemberService;
@RabbitListener(queues = QueueConstants.EMPTY_POINTS_REMIND_QUEUE)
public void emptyPointsRemind(List<UserMember> userMemberList) {
// TODO 发送短信提醒用户积分即将清零
log.info("消费者获取到积分清零提醒的数据:{}", userMemberList);
}
@RabbitListener(queues = QueueConstants.MEMBER_BILLING_QUEUE)
public void memberBillingQueue(UserMember userMember) {
// TODO 发送短信提醒用户会员账单如果支付成功更新last_payment_date并重新计算end_datestart_date + 1个月
log.info("消费者获取到会员账单的数据:{}", userMember);
}
}

View File

@ -17,17 +17,26 @@ public class Member extends BaseEntity {
private Long id;
// 会员类型
private String member_type;
private String memberType;
// 会员名称
private String member_name;
private String memberName;
// 会员价格
private Double unit_price;
private Double unitPrice;
// 会员原价
private Double original_price;
private Double originalPrice;
// 会员积分
private Integer points;
// 订阅周期(天)
private Integer subscriptionPeriod;
// 删除标志0代表存在 2代表删除
private String delFlag;
// 备注
private String remark;
}

View File

@ -13,7 +13,7 @@ import java.util.Date;
@Data
@EqualsAndHashCode(callSuper = false)
@TableName("mem_member")
@TableName("mem_user_member")
public class UserMember extends BaseEntity {
@TableId
@ -56,4 +56,7 @@ public class UserMember extends BaseEntity {
// 删除标志0代表存在 2代表删除
private String delFlag;
// 备注
private String remark;
}

View File

@ -1,5 +1,6 @@
package com.mcwl.memberCenter.enums;
import com.baomidou.mybatisplus.annotation.EnumValue;
import lombok.AllArgsConstructor;
import lombok.Getter;
@ -13,5 +14,6 @@ public enum MemberMenu {
private final String name;
@EnumValue
private final String value;
}

View File

@ -4,4 +4,14 @@ import com.baomidou.mybatisplus.extension.service.IService;
import com.mcwl.memberCenter.domain.UserMember;
public interface UserMemberService extends IService<UserMember> {
/**
*
* @param userId id
* @param memberId id
* @return
*/
UserMember createUserMember(Long userId, Long memberId, String paymentMethod);
}

View File

@ -1,11 +1,110 @@
package com.mcwl.memberCenter.service.impl;
import com.baomidou.mybatisplus.core.conditions.Wrapper;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.mcwl.common.core.domain.entity.SysUser;
import com.mcwl.common.exception.ServiceException;
import com.mcwl.common.utils.SecurityUtils;
import com.mcwl.memberCenter.domain.Member;
import com.mcwl.memberCenter.domain.UserMember;
import com.mcwl.memberCenter.enums.MemberMenu;
import com.mcwl.memberCenter.mapper.UserMemberMapper;
import com.mcwl.memberCenter.service.MemberService;
import com.mcwl.memberCenter.service.UserMemberService;
import com.mcwl.system.service.ISysUserService;
import lombok.RequiredArgsConstructor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.*;
@Service
@RequiredArgsConstructor
public class UserMemberServiceImpl extends ServiceImpl<UserMemberMapper, UserMember> implements UserMemberService {
private final MemberService memberService;
private final ISysUserService sysUserService;
public void aaa() {
LambdaQueryWrapper<Member> lqw = new LambdaQueryWrapper<>();
Member member = new Member();
memberService.update(lqw);
}
@Override
public UserMember createUserMember(Long userId, Long memberId, String paymentMethod) {
if (userId == null) {
throw new ServiceException("用户不能为空");
}
SysUser user = sysUserService.selectUserById(userId);
if (user == null) {
throw new ServiceException("用户不存在");
}
if (memberId == null) {
throw new ServiceException("会员不能为空");
}
Member member = memberService.getById(memberId);
if (member == null) {
throw new ServiceException("会员不存在");
}
// 查询用户是否已经存在会员
LambdaQueryWrapper<UserMember> lqw = new LambdaQueryWrapper<>();
lqw.eq(UserMember::getUserId, userId)
// subscriptionStatus不为expired
.ne(UserMember::getSubscriptionStatus, MemberMenu.MEMBER_CENTER_EXPIRED)
.orderBy(true, false, UserMember::getEndDate);
List<UserMember> userMemberList = baseMapper.selectList(lqw);
UserMember userMember = new UserMember();
// 设置用户id
userMember.setUserId(userId);
// 设置会员id
userMember.setMemberId(memberId);
if (userMemberList != null && !userMemberList.isEmpty()) {
UserMember lastUserMember = userMemberList.get(0);
Date endDate = lastUserMember.getEndDate();
// 设置会员开始时间和结束时间
Date startDate = new Date(endDate.getTime() + 1000L * 60L * 60L * 24L);
userMember.setStartDate(startDate);
userMember.setEndDate(new Date(startDate.getTime() + member.getSubscriptionPeriod() * 1000L * 60L * 60L * 24L));
} else {
// 用户不存在会员
// 设置会员开始时间和结束时间
Date startDate = new Date();
userMember.setStartDate(startDate);
userMember.setEndDate(new Date(startDate.getTime() + member.getSubscriptionPeriod() * 1000L * 60L * 60L * 24L));
}
// 设置积分
userMember.setPoints(member.getPoints());
// 设置订阅状态
if (member.getSubscriptionPeriod() == null) {
// 连续包月,会员状态为活跃
userMember.setSubscriptionStatus(MemberMenu.MEMBER_CENTER_ACTIVE);
Calendar calendar = Calendar.getInstance();
calendar.setTime(userMember.getEndDate());
calendar.add(Calendar.MONTH, 1);
userMember.setNextBillingDate(calendar.getTime());
} else {
userMember.setSubscriptionStatus(MemberMenu.MEMBER_CENTER_INACTIVE);
}
// 设置支付时间
userMember.setLastPaymentDate(new Date());
// 设置支付方式
userMember.setPaymentMethod(paymentMethod);
// 设置创建者
SysUser sysUser = sysUserService.selectUserById(userId);
userMember.setCreateBy(sysUser.getUserName());
userMember.setCreateTime(new Date());
userMember.setUpdateBy(sysUser.getUserName());
userMember.setUpdateTime(new Date());
baseMapper.insert(userMember);
return userMember;
}
}

View File

@ -0,0 +1,109 @@
package com.mcwl.memberCenter.task;
import cn.hutool.core.bean.BeanUtil;
import com.baomidou.mybatisplus.core.conditions.Wrapper;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.mcwl.common.constant.QueueConstants;
import com.mcwl.memberCenter.domain.UserMember;
import com.mcwl.memberCenter.enums.MemberMenu;
import com.mcwl.memberCenter.service.UserMemberService;
import lombok.RequiredArgsConstructor;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;
import java.util.Calendar;
import java.util.Date;
import java.util.List;
@Component("userMemberTask")
@RequiredArgsConstructor
public class UserMemberTask {
private final UserMemberService userMemberService;
private final RabbitTemplate rabbitTemplate;
/**
*
*/
public void emptyPointsRemindTask() {
List<UserMember> userMemberList = this.getUseUserMember();
// 发送积分清零消息
rabbitTemplate.convertAndSend(QueueConstants.EMPTY_POINTS_REMIND_QUEUE, userMemberList);
}
/**
*
*/
public void emptyPointsTsk() {
List<UserMember> userMemberList = this.getUseUserMember();
if (userMemberList == null || userMemberList.isEmpty()) {
return;
}
for (UserMember userMember : userMemberList) {
userMember.setPoints(0);
userMember.setUpdateTime(new Date());
}
userMemberService.updateBatchById(userMemberList);
}
/**
* 1h
*/
public void updateSubscriptionStatusTask() {
LambdaQueryWrapper<UserMember> qw = new LambdaQueryWrapper<>();
// endDate大于当前时间, subscriptionStatus不为过期
qw.gt(UserMember::getEndDate, System.currentTimeMillis())
.ne(UserMember::getSubscriptionStatus, MemberMenu.MEMBER_CENTER_EXPIRED);
List<UserMember> userMemberList = userMemberService.list(qw);
if (userMemberList == null || userMemberList.isEmpty()) {
return;
}
System.out.println("userMemberList = " + userMemberList);
for (UserMember userMember : userMemberList) {
MemberMenu subscriptionStatus = userMember.getSubscriptionStatus();
if (subscriptionStatus == MemberMenu.MEMBER_CENTER_ACTIVE) {
// 如果subscriptionStatus是活跃的表示连续包月。订阅状态改为"待支付"
userMember.setSubscriptionStatus(MemberMenu.MEMBER_CENTER_PENDING);
// nextBillingDate设置为当前会员结束日期的下个月的同一天,发送账单通知
Calendar calendar = Calendar.getInstance();
calendar.setTime(userMember.getEndDate());
calendar.add(Calendar.MONTH, 1);
userMember.setNextBillingDate(calendar.getTime());
userMemberService.updateById(userMember);
// 发送会员账单消息如果支付成功更新last_payment_date并重新计算end_datestart_date + 1个月
rabbitTemplate.convertAndSend(QueueConstants.MEMBER_BILLING_QUEUE, userMember);
} else if (subscriptionStatus == MemberMenu.MEMBER_CENTER_INACTIVE){
// 不是连续包月,会员状态改为过期,状态改为"1"
userMember.setSubscriptionStatus(MemberMenu.MEMBER_CENTER_EXPIRED);
userMember.setStatus("1");
userMember.setUpdateTime(new Date());
}
}
}
// 获取正常使用的会员
private List<UserMember> getUseUserMember() {
// startDate 小于等于当前时间、endDate 大于等于当前时间
// subscriptionStatus 不为 "过期" 或 "待支付"
// status 为 0 的
LambdaQueryWrapper<UserMember> qw = new LambdaQueryWrapper<>();
qw.le(UserMember::getStartDate, System.currentTimeMillis())
.ge(UserMember::getEndDate, System.currentTimeMillis())
.ne(UserMember::getSubscriptionStatus, MemberMenu.MEMBER_CENTER_EXPIRED)
.ne(UserMember::getSubscriptionStatus, MemberMenu.MEMBER_CENTER_PENDING)
.eq(UserMember::getStatus, '0');
return userMemberService.list();
}
}

View File

@ -30,6 +30,9 @@ public class Commission extends BaseEntity {
// 删除标志0代表存在 2代表删除
private String delFlag;
// 备注
private String remark;
@Override
public boolean equals(Object o) {
if (o == null || getClass() != o.getClass()) return false;

View File

@ -28,6 +28,9 @@ public class Consume extends BaseEntity {
// 删除标志0代表存在 2代表删除
private String delFlag;
// 备注
private String remark;
@Override
public boolean equals(Object o) {
if (o == null || getClass() != o.getClass()) return false;

View File

@ -28,6 +28,9 @@ public class Invitation extends BaseEntity {
// 删除标志0代表存在 2代表删除
private String delFlag;
// 备注
private String remark;
@Override
public boolean equals(Object o) {
if (o == null || getClass() != o.getClass()) return false;

View File

@ -3,6 +3,7 @@ package com.mcwl.myInvitation.service.impl;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.mcwl.common.constant.JwtConstants;
import com.mcwl.common.utils.JwtUtils;
import com.mcwl.common.utils.ShareCodeUtils;
import com.mcwl.myInvitation.domain.Invitation;
import com.mcwl.myInvitation.mapper.InvitationMapper;
import com.mcwl.myInvitation.service.InvitationService;
@ -20,9 +21,7 @@ public class InvitationServiceImpl extends ServiceImpl<InvitationMapper, Invitat
@Override
public String getInvitationCode(Long userId) {
// 生成邀请码
Map<String, Object> claims = new HashMap<>() ;
claims.put(JwtConstants.DETAILS_USER_ID, userId);
String invitationCode = JwtUtils.createToken(claims);
String invitationCode = ShareCodeUtils.idToCode(userId);
return invitationCode;
}
}