19 changed files with 436 additions and 47 deletions
@ -1,16 +1,31 @@ |
|||||
package com.youlai.boot.mini.converter; |
package com.youlai.boot.mini.converter; |
||||
|
|
||||
import com.baomidou.mybatisplus.core.metadata.IPage; |
|
||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page; |
import com.baomidou.mybatisplus.extension.plugins.pagination.Page; |
||||
import com.youlai.boot.mini.model.entity.MiniPointRule; |
import com.youlai.boot.mini.model.entity.MiniPointRule; |
||||
|
import com.youlai.boot.mini.model.form.AddPointRuleForm; |
||||
import com.youlai.boot.mini.model.vo.RuleListVO; |
import com.youlai.boot.mini.model.vo.RuleListVO; |
||||
import org.mapstruct.Mapper; |
import org.mapstruct.Mapper; |
||||
|
import org.mapstruct.Mapping; |
||||
|
|
||||
|
/** |
||||
|
* 积分规则对象转换器 |
||||
|
*/ |
||||
@Mapper(componentModel = "spring") |
@Mapper(componentModel = "spring") |
||||
public interface MiniPointRuleConverter { |
public interface MiniPointRuleConverter { |
||||
|
|
||||
IPage<RuleListVO> toRulePageVo(Page<MiniPointRule> pageList); |
/** |
||||
|
* 分页对象转换 |
||||
|
*/ |
||||
|
Page<RuleListVO> toRulePageVo(Page<MiniPointRule> pageList); |
||||
|
|
||||
|
/** |
||||
|
* 单个对象转换 |
||||
|
*/ |
||||
RuleListVO toRuleVo(MiniPointRule entity); |
RuleListVO toRuleVo(MiniPointRule entity); |
||||
|
|
||||
|
/** |
||||
|
* 新增表单转实体 |
||||
|
*/ |
||||
|
MiniPointRule toEntity(AddPointRuleForm form); |
||||
|
|
||||
} |
} |
||||
|
|||||
@ -1,20 +1,46 @@ |
|||||
package com.youlai.boot.mini.model.vo; |
package com.youlai.boot.mini.model.vo; |
||||
|
|
||||
|
import com.fasterxml.jackson.annotation.JsonFormat; |
||||
import io.swagger.v3.oas.annotations.media.Schema; |
import io.swagger.v3.oas.annotations.media.Schema; |
||||
import lombok.Builder; |
import lombok.Builder; |
||||
import lombok.Data; |
import lombok.Data; |
||||
import lombok.EqualsAndHashCode; |
import lombok.EqualsAndHashCode; |
||||
|
|
||||
|
import java.util.Date; |
||||
|
|
||||
@Data |
@Data |
||||
@Builder |
@Builder |
||||
@EqualsAndHashCode(callSuper = false) |
@EqualsAndHashCode(callSuper = false) |
||||
@Schema(description = "用户积分信息VO") |
@Schema(description = "用户积分信息VO") |
||||
public class PointAccountVO { |
public class PointAccountVO { |
||||
|
|
||||
@Schema(description = "uuid") |
@Schema(description = "积分账户ID") |
||||
|
private Long id; |
||||
|
|
||||
|
@Schema(description = "uuid唯一标识") |
||||
private String uuid; |
private String uuid; |
||||
|
|
||||
|
@Schema(description = "用户ID") |
||||
|
private Long userId; |
||||
|
|
||||
|
@Schema(description = "用户昵称") |
||||
|
private String nickname; |
||||
|
|
||||
|
@Schema(description = "用户手机号") |
||||
|
private String mobile; |
||||
|
|
||||
|
@Schema(description = "用户头像") |
||||
|
private String avatar; |
||||
|
|
||||
@Schema(description = "用户积分") |
@Schema(description = "用户积分") |
||||
private Integer points; |
private Integer points; |
||||
|
|
||||
|
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8") |
||||
|
@Schema(description = "创建时间") |
||||
|
private Date createTime; |
||||
|
|
||||
|
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8") |
||||
|
@Schema(description = "更新时间") |
||||
|
private Date updateTime; |
||||
|
|
||||
} |
} |
||||
|
|||||
@ -1,13 +1,53 @@ |
|||||
package com.youlai.boot.mini.model.vo; |
package com.youlai.boot.mini.model.vo; |
||||
|
|
||||
|
import com.fasterxml.jackson.annotation.JsonFormat; |
||||
import io.swagger.v3.oas.annotations.media.Schema; |
import io.swagger.v3.oas.annotations.media.Schema; |
||||
|
import lombok.AllArgsConstructor; |
||||
import lombok.Builder; |
import lombok.Builder; |
||||
import lombok.Data; |
import lombok.Data; |
||||
import lombok.EqualsAndHashCode; |
import lombok.NoArgsConstructor; |
||||
|
|
||||
|
import java.time.LocalDateTime; |
||||
|
|
||||
@Data |
@Data |
||||
@Builder |
@Builder |
||||
@EqualsAndHashCode(callSuper = false) |
@NoArgsConstructor |
||||
|
@AllArgsConstructor |
||||
@Schema(description = "积分流水列表VO") |
@Schema(description = "积分流水列表VO") |
||||
public class PointRecordVO { |
public class PointRecordVO { |
||||
|
|
||||
|
@Schema(description = "积分记录ID") |
||||
|
private Long id; |
||||
|
|
||||
|
@Schema(description = "唯一标识uuid") |
||||
|
private String uuid; |
||||
|
|
||||
|
@Schema(description = "用户ID") |
||||
|
private Long userId; |
||||
|
|
||||
|
@Schema(description = "用户昵称") |
||||
|
private String userNickname; |
||||
|
|
||||
|
@Schema(description = "用户手机号") |
||||
|
private String userMobile; |
||||
|
|
||||
|
@Schema(description = "积分变化值,正数增加,负数扣减") |
||||
|
private Integer changeAmount; |
||||
|
|
||||
|
@Schema(description = "变更后积分余额") |
||||
|
private Integer balanceAfter; |
||||
|
|
||||
|
@Schema(description = "业务类型,sign_in签到/system_increase后台增加等") |
||||
|
private String bizType; |
||||
|
|
||||
|
@Schema(description = "备注说明") |
||||
|
private String remark; |
||||
|
|
||||
|
@Schema(description = "操作人ID") |
||||
|
private Long createBy; |
||||
|
|
||||
|
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8") |
||||
|
@Schema(description = "创建时间/操作时间") |
||||
|
private LocalDateTime createTime; |
||||
|
|
||||
} |
} |
||||
|
|||||
@ -1,4 +1,25 @@ |
|||||
package com.youlai.boot.mini.service; |
package com.youlai.boot.mini.service; |
||||
|
|
||||
public interface MiniPointRecordService { |
import com.baomidou.mybatisplus.core.metadata.IPage; |
||||
|
import com.baomidou.mybatisplus.extension.service.IService; |
||||
|
import com.youlai.boot.mini.model.entity.MiniPointRecord; |
||||
|
import com.youlai.boot.mini.model.form.AdjustUserPointForm; |
||||
|
import com.youlai.boot.mini.model.query.PointRecordQuery; |
||||
|
import com.youlai.boot.mini.model.vo.PointRecordVO; |
||||
|
|
||||
|
public interface MiniPointRecordService extends IService<MiniPointRecord> { |
||||
|
|
||||
|
/** |
||||
|
* 后台手动调整用户积分 |
||||
|
* @param form 调整参数 |
||||
|
*/ |
||||
|
void adjustPoint(AdjustUserPointForm form); |
||||
|
|
||||
|
/** |
||||
|
* 分页查询所有积分记录(后台管理端) |
||||
|
* @param query 查询参数 |
||||
|
* @return 分页结果 |
||||
|
*/ |
||||
|
IPage<PointRecordVO> pageAllRecord(PointRecordQuery query); |
||||
|
|
||||
} |
} |
||||
|
|||||
@ -1,9 +1,29 @@ |
|||||
package com.youlai.boot.mini.service; |
package com.youlai.boot.mini.service; |
||||
|
|
||||
import com.baomidou.mybatisplus.core.metadata.IPage; |
import com.baomidou.mybatisplus.core.metadata.IPage; |
||||
|
import com.baomidou.mybatisplus.extension.service.IService; |
||||
|
import com.youlai.boot.mini.model.entity.MiniPointRule; |
||||
|
import com.youlai.boot.mini.model.form.AddPointRuleForm; |
||||
import com.youlai.boot.mini.model.query.RulePageQuery; |
import com.youlai.boot.mini.model.query.RulePageQuery; |
||||
import com.youlai.boot.mini.model.vo.RuleListVO; |
import com.youlai.boot.mini.model.vo.RuleListVO; |
||||
|
|
||||
public interface MiniPointRuleService { |
public interface MiniPointRuleService extends IService<MiniPointRule> { |
||||
IPage<RuleListVO> pageRule(RulePageQuery queryParams); |
IPage<RuleListVO> pageRule(RulePageQuery queryParams); |
||||
|
|
||||
|
/** |
||||
|
* 新增积分规则 |
||||
|
*/ |
||||
|
void addRule(AddPointRuleForm form); |
||||
|
|
||||
|
/** |
||||
|
* 逻辑删除积分规则 |
||||
|
*/ |
||||
|
void deleteRule(Long id); |
||||
|
|
||||
|
/** |
||||
|
* 启用/禁用积分规则 |
||||
|
* @param id 规则ID |
||||
|
* @param status 状态:false-启用,true-禁用 |
||||
|
*/ |
||||
|
void changeStatus(Long id, Boolean status); |
||||
} |
} |
||||
|
|||||
@ -1,15 +1,84 @@ |
|||||
package com.youlai.boot.mini.service.impl; |
package com.youlai.boot.mini.service.impl; |
||||
|
|
||||
|
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; |
||||
|
import com.baomidou.mybatisplus.core.metadata.IPage; |
||||
|
import com.baomidou.mybatisplus.extension.plugins.pagination.Page; |
||||
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; |
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; |
||||
|
import com.youlai.boot.common.exception.MsgException; |
||||
|
import com.youlai.boot.framework.security.util.SecurityUtils; |
||||
import com.youlai.boot.mini.mapper.MiniPointRecordMapper; |
import com.youlai.boot.mini.mapper.MiniPointRecordMapper; |
||||
|
import com.youlai.boot.mini.model.entity.MiniPointAccount; |
||||
import com.youlai.boot.mini.model.entity.MiniPointRecord; |
import com.youlai.boot.mini.model.entity.MiniPointRecord; |
||||
|
import com.youlai.boot.mini.model.form.AdjustUserPointForm; |
||||
|
import com.youlai.boot.mini.model.query.PointRecordQuery; |
||||
|
import com.youlai.boot.mini.model.vo.PointRecordVO; |
||||
|
import com.youlai.boot.mini.service.MiniPointAccountService; |
||||
import com.youlai.boot.mini.service.MiniPointRecordService; |
import com.youlai.boot.mini.service.MiniPointRecordService; |
||||
import lombok.RequiredArgsConstructor; |
import lombok.RequiredArgsConstructor; |
||||
import lombok.extern.slf4j.Slf4j; |
import lombok.extern.slf4j.Slf4j; |
||||
import org.springframework.stereotype.Service; |
import org.springframework.stereotype.Service; |
||||
|
import org.springframework.transaction.annotation.Transactional; |
||||
|
|
||||
|
import java.util.Date; |
||||
|
import java.util.UUID; |
||||
|
|
||||
@Service |
@Service |
||||
@RequiredArgsConstructor |
@RequiredArgsConstructor |
||||
@Slf4j |
@Slf4j |
||||
public class MiniPointRecordServiceImpl extends ServiceImpl<MiniPointRecordMapper, MiniPointRecord> implements MiniPointRecordService { |
public class MiniPointRecordServiceImpl extends ServiceImpl<MiniPointRecordMapper, MiniPointRecord> implements MiniPointRecordService { |
||||
|
|
||||
|
private final MiniPointAccountService miniPointAccountService; |
||||
|
|
||||
|
|
||||
|
@Override |
||||
|
@Transactional(rollbackFor = Exception.class) |
||||
|
public void adjustPoint(AdjustUserPointForm form) { |
||||
|
// 1. 参数校验:调整值不能为0
|
||||
|
if (form.getChangeAmount() == null || form.getChangeAmount() == 0) { |
||||
|
throw new MsgException("积分调整值不能为0"); |
||||
|
} |
||||
|
|
||||
|
// 2. 直接根据前端传的用户主键userId查询积分账户(后台操作接口,不需要转uuid,直接用主键更高效)
|
||||
|
MiniPointAccount account = miniPointAccountService.getOne(new LambdaQueryWrapper<MiniPointAccount>() |
||||
|
.eq(MiniPointAccount::getUserId, form.getUserId()) |
||||
|
.eq(MiniPointAccount::getDeleted, false)); |
||||
|
if (account == null) { |
||||
|
throw new MsgException("用户积分账户不存在"); |
||||
|
} |
||||
|
|
||||
|
// 4. 计算变更后余额,校验扣减后不能为负数
|
||||
|
Integer afterBalance = account.getPoints() + form.getChangeAmount(); |
||||
|
if (afterBalance < 0) { |
||||
|
throw new MsgException("积分不足,扣减后余额不能为负数"); |
||||
|
} |
||||
|
|
||||
|
// 5. 更新用户积分账户余额
|
||||
|
MiniPointAccount updateAccount = new MiniPointAccount(); |
||||
|
updateAccount.setId(account.getId()); |
||||
|
updateAccount.setPoints(afterBalance); |
||||
|
updateAccount.setUpdateBy(SecurityUtils.getUserId()); |
||||
|
updateAccount.setUpdateTime(new Date()); |
||||
|
updateAccount.setUpdateTimestamp(System.currentTimeMillis()); |
||||
|
miniPointAccountService.updateById(updateAccount); |
||||
|
|
||||
|
// 6. 插入积分流水记录
|
||||
|
MiniPointRecord record = new MiniPointRecord(); |
||||
|
record.setUuid(UUID.randomUUID().toString().replace("-", "")); |
||||
|
record.setUserId(account.getUserId()); |
||||
|
record.setChangeAmount(form.getChangeAmount()); |
||||
|
record.setBalanceAfter(afterBalance); |
||||
|
record.setBizType(form.getBizType()); |
||||
|
record.setBizId(UUID.randomUUID().toString().replace("-", "")); // 业务唯一ID,保证幂等
|
||||
|
record.setCreateBy(SecurityUtils.getUserId()); |
||||
|
record.setCreateTime(new Date()); |
||||
|
record.setCreateTimestamp(System.currentTimeMillis()); |
||||
|
this.save(record); |
||||
|
} |
||||
|
|
||||
|
@Override |
||||
|
public IPage<PointRecordVO> pageAllRecord(PointRecordQuery query) { |
||||
|
Page<MiniPointRecord> page = new Page<>(query.getPageNum(), query.getPageSize()); |
||||
|
// 调用mapper关联查询,直接返回VO分页结果
|
||||
|
return baseMapper.pageAllRecord(page, query); |
||||
|
} |
||||
} |
} |
||||
|
|||||
Loading…
Reference in new issue