add 积分系统功能

This commit is contained in:
Guoqs
2025-12-24 15:41:11 +08:00
parent c2a1ae1966
commit e135db56b0
11 changed files with 917 additions and 0 deletions

View File

@@ -0,0 +1,65 @@
package com.jsowell.pile.service;
import com.jsowell.pile.domain.MemberPointsInfo;
import com.jsowell.pile.domain.MemberPointsRecord;
import java.math.BigDecimal;
import java.util.List;
/**
* 用户积分Service接口
*/
public interface MemberPointsInfoService {
/**
* 根据会员ID查询积分信息
*
* @param memberId 会员ID
* @return 积分信息
*/
MemberPointsInfo selectByMemberId(String memberId);
/**
* 获取会员积分余额
*
* @param memberId 会员ID
* @return 积分余额
*/
BigDecimal getPointsBalance(String memberId);
/**
* 增加积分(充电奖励)
*
* @param memberId 会员ID
* @param points 积分数量
* @param orderCode 关联订单号
* @return 操作结果
*/
boolean addPoints(String memberId, BigDecimal points, String orderCode);
/**
* 扣减积分(消费抵扣)
*
* @param memberId 会员ID
* @param points 积分数量
* @param orderCode 关联订单号
* @return 操作结果
*/
boolean deductPoints(String memberId, BigDecimal points, String orderCode);
/**
* 查询会员积分流水列表
*
* @param memberId 会员ID
* @return 积分流水列表
*/
List<MemberPointsRecord> getPointsRecordList(String memberId);
/**
* 初始化会员积分账户
*
* @param memberId 会员ID
* @return 操作结果
*/
int initMemberPoints(String memberId);
}

View File

@@ -0,0 +1,43 @@
package com.jsowell.pile.service;
import com.jsowell.pile.domain.MemberPointsRecord;
import java.util.List;
/**
* 积分流水Service接口
*/
public interface MemberPointsRecordService {
/**
* 根据主键查询
*
* @param id 主键
* @return 积分流水记录
*/
MemberPointsRecord selectByPrimaryKey(Long id);
/**
* 根据会员ID查询积分流水列表
*
* @param memberId 会员ID
* @return 积分流水列表
*/
List<MemberPointsRecord> selectByMemberId(String memberId);
/**
* 根据订单号查询积分流水
*
* @param orderCode 订单号
* @return 积分流水列表
*/
List<MemberPointsRecord> selectByOrderCode(String orderCode);
/**
* 插入积分流水记录
*
* @param record 积分流水记录
* @return 操作结果
*/
int insert(MemberPointsRecord record);
}

View File

@@ -0,0 +1,156 @@
package com.jsowell.pile.service.impl;
import com.jsowell.common.exception.BusinessException;
import com.jsowell.common.util.StringUtils;
import com.jsowell.pile.domain.MemberPointsInfo;
import com.jsowell.pile.domain.MemberPointsRecord;
import com.jsowell.pile.mapper.MemberPointsInfoMapper;
import com.jsowell.pile.mapper.MemberPointsRecordMapper;
import com.jsowell.pile.service.MemberPointsInfoService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import javax.annotation.Resource;
import java.math.BigDecimal;
import java.util.Date;
import java.util.List;
/**
* 用户积分Service实现类
*/
@Service
public class MemberPointsInfoServiceImpl implements MemberPointsInfoService {
private static final Logger logger = LoggerFactory.getLogger(MemberPointsInfoServiceImpl.class);
/**
* 积分类型:充电奖励
*/
private static final int POINTS_TYPE_CHARGE_REWARD = 1;
/**
* 积分类型:消费抵扣
*/
private static final int POINTS_TYPE_CONSUME_DEDUCT = 2;
@Resource
private MemberPointsInfoMapper memberPointsInfoMapper;
@Resource
private MemberPointsRecordMapper memberPointsRecordMapper;
@Override
public MemberPointsInfo selectByMemberId(String memberId) {
return memberPointsInfoMapper.selectByMemberId(memberId);
}
@Override
public BigDecimal getPointsBalance(String memberId) {
MemberPointsInfo pointsInfo = memberPointsInfoMapper.selectByMemberId(memberId);
if (pointsInfo == null) {
return BigDecimal.ZERO;
}
return pointsInfo.getTotalPoints() == null ? BigDecimal.ZERO : pointsInfo.getTotalPoints();
}
@Override
@Transactional(rollbackFor = Exception.class)
public boolean addPoints(String memberId, BigDecimal points, String orderCode) {
if (StringUtils.isBlank(memberId) || points == null || points.compareTo(BigDecimal.ZERO) <= 0) {
throw new BusinessException("参数错误");
}
// 检查积分账户是否存在,不存在则初始化
MemberPointsInfo pointsInfo = memberPointsInfoMapper.selectByMemberId(memberId);
if (pointsInfo == null) {
initMemberPoints(memberId);
pointsInfo = memberPointsInfoMapper.selectByMemberId(memberId);
}
// 记录变动前积分
BigDecimal beforePoints = pointsInfo.getTotalPoints() == null ? BigDecimal.ZERO : pointsInfo.getTotalPoints();
// 原子性增加积分
int updateResult = memberPointsInfoMapper.addPoints(memberId, points);
if (updateResult <= 0) {
logger.error("增加积分失败memberId: {}, points: {}", memberId, points);
throw new BusinessException("增加积分失败");
}
// 计算变动后积分
BigDecimal afterPoints = beforePoints.add(points);
// 插入积分流水记录
MemberPointsRecord record = MemberPointsRecord.builder()
.memberId(memberId)
.points(points)
.type(POINTS_TYPE_CHARGE_REWARD)
.orderCode(orderCode)
.beforePoints(beforePoints)
.afterPoints(afterPoints)
.createTime(new Date())
.build();
memberPointsRecordMapper.insert(record);
logger.info("增加积分成功memberId: {}, points: {}, beforePoints: {}, afterPoints: {}, orderCode: {}",
memberId, points, beforePoints, afterPoints, orderCode);
return true;
}
@Override
@Transactional(rollbackFor = Exception.class)
public boolean deductPoints(String memberId, BigDecimal points, String orderCode) {
if (StringUtils.isBlank(memberId) || points == null || points.compareTo(BigDecimal.ZERO) <= 0) {
throw new BusinessException("参数错误");
}
// 检查积分余额是否充足
BigDecimal beforePoints = getPointsBalance(memberId);
if (beforePoints.compareTo(points) < 0) {
throw new BusinessException("积分余额不足");
}
// 原子性扣减积分
int updateResult = memberPointsInfoMapper.deductPoints(memberId, points);
if (updateResult <= 0) {
logger.error("扣减积分失败memberId: {}, points: {}", memberId, points);
throw new BusinessException("扣减积分失败");
}
// 计算变动后积分
BigDecimal afterPoints = beforePoints.subtract(points);
// 插入积分流水记录(扣减积分记录为负数)
MemberPointsRecord record = MemberPointsRecord.builder()
.memberId(memberId)
.points(points.negate())
.type(POINTS_TYPE_CONSUME_DEDUCT)
.orderCode(orderCode)
.beforePoints(beforePoints)
.afterPoints(afterPoints)
.createTime(new Date())
.build();
memberPointsRecordMapper.insert(record);
logger.info("扣减积分成功memberId: {}, points: {}, beforePoints: {}, afterPoints: {}, orderCode: {}",
memberId, points, beforePoints, afterPoints, orderCode);
return true;
}
@Override
public List<MemberPointsRecord> getPointsRecordList(String memberId) {
return memberPointsRecordMapper.selectByMemberIdWithPage(memberId);
}
@Override
public int initMemberPoints(String memberId) {
MemberPointsInfo pointsInfo = MemberPointsInfo.builder()
.memberId(memberId)
.totalPoints(BigDecimal.ZERO)
.updateTime(new Date())
.build();
return memberPointsInfoMapper.insert(pointsInfo);
}
}

View File

@@ -0,0 +1,39 @@
package com.jsowell.pile.service.impl;
import com.jsowell.pile.domain.MemberPointsRecord;
import com.jsowell.pile.mapper.MemberPointsRecordMapper;
import com.jsowell.pile.service.MemberPointsRecordService;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
import java.util.List;
/**
* 积分流水Service实现类
*/
@Service
public class MemberPointsRecordServiceImpl implements MemberPointsRecordService {
@Resource
private MemberPointsRecordMapper memberPointsRecordMapper;
@Override
public MemberPointsRecord selectByPrimaryKey(Long id) {
return memberPointsRecordMapper.selectByPrimaryKey(id);
}
@Override
public List<MemberPointsRecord> selectByMemberId(String memberId) {
return memberPointsRecordMapper.selectByMemberId(memberId);
}
@Override
public List<MemberPointsRecord> selectByOrderCode(String orderCode) {
return memberPointsRecordMapper.selectByOrderCode(orderCode);
}
@Override
public int insert(MemberPointsRecord record) {
return memberPointsRecordMapper.insert(record);
}
}