feat(tenant-balance): 新增余额充值及自查询接口

This commit is contained in:
2025-12-25 21:39:06 +08:00
parent ccbbcbff53
commit e2269e1ff4
9 changed files with 220 additions and 1 deletions

View File

@@ -101,4 +101,28 @@ public class TenantBalanceController {
BeanUtils.toBean(list, TenantBalanceRespVO.class)); BeanUtils.toBean(list, TenantBalanceRespVO.class));
} }
@PostMapping("/addAmount")
@Operation(summary = "添加租户余额")
@PreAuthorize("@ss.hasPermission('system:tenant-balance:add')")
public CommonResult<Boolean> addTenantBalance(@Valid @RequestBody TenantBalanceAddReqVO addReqVO) {
tenantBalanceService.addTenantBalance(addReqVO);
return success(true);
}
@GetMapping("/get-self-amount")
@Operation(summary = "获得自己的余额")
@PreAuthorize("@ss.hasPermission('system:tenant-balance:self-amount')")
public CommonResult<TenantBalanceRespVO> getTenantBalance() {
TenantBalanceDO tenantBalance = tenantBalanceService.getSelfBalance();
return success(BeanUtils.toBean(tenantBalance, TenantBalanceRespVO.class));
}
@GetMapping("/get-self-subordinate-amount-page")
@Operation(summary = "获得自己下级余额的分页")
@PreAuthorize("@ss.hasPermission('system:tenant-balance:self-subordinate')")
public CommonResult<PageResult<TenantBalanceRespVO>> getSelfSubordinate(@Valid TenantBalancePageReqVO pageReqVO) {
PageResult<TenantBalanceRespVO> tenantBalancePage = tenantBalanceService.getSelfSubordinateTenantBalancePage(pageReqVO);
return success(BeanUtils.toBean(tenantBalancePage, TenantBalanceRespVO.class));
}
} }

View File

@@ -0,0 +1,24 @@
package com.yolo.keyboard.controller.admin.tenantbalance.vo;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import java.math.BigDecimal;
/*
* @author: ziin
* @date: 2025/11/19 21:05
*/
@Schema(description = "管理后台 - 租户余额添加VO")
@Data
public class TenantBalanceAddReqVO {
@Schema(description = "租户 Id", requiredMode = Schema.RequiredMode.REQUIRED, example = "19954")
private Long id;
@Schema(description = "增加的余额", requiredMode = Schema.RequiredMode.REQUIRED, example = "1000000")
private BigDecimal amount;
@Schema(description = "备注", example = "备注")
private String remark;
}

View File

@@ -2,6 +2,8 @@ package com.yolo.keyboard.dal.dataobject.tenantbalance;
import com.yolo.keyboard.framework.tenant.core.aop.TenantIgnore; import com.yolo.keyboard.framework.tenant.core.aop.TenantIgnore;
import lombok.*; import lombok.*;
import java.math.BigDecimal;
import java.util.*; import java.util.*;
import java.time.LocalDateTime; import java.time.LocalDateTime;
import com.baomidou.mybatisplus.annotation.*; import com.baomidou.mybatisplus.annotation.*;
@@ -31,10 +33,11 @@ public class TenantBalanceDO extends BaseDO {
/** /**
* 当前积分余额 * 当前积分余额
*/ */
private Integer balance; private BigDecimal balance;
/** /**
* 乐观锁版本号 * 乐观锁版本号
*/ */
@Version
private Integer version; private Integer version;
/** /**
* 更新时间 * 更新时间

View File

@@ -0,0 +1,70 @@
package com.yolo.keyboard.dal.dataobject.tenantbalancetransaction;
import com.yolo.keyboard.framework.tenant.core.aop.TenantIgnore;
import lombok.*;
import java.math.BigDecimal;
import java.util.*;
import java.time.LocalDateTime;
import com.baomidou.mybatisplus.annotation.*;
import com.yolo.keyboard.framework.mybatis.core.dataobject.BaseDO;
/**
* 租户积分记录 DO
*
* @author 芋道源码
*/
@TableName("system_tenant_balance_transaction")
@KeySequence("system_tenant_balance_transaction_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。
@Data
@ToString(callSuper = true)
@Builder
@NoArgsConstructor
@AllArgsConstructor
@TenantIgnore
public class TenantBalanceTransactionDO {
/**
* 主键
*/
@TableId
private Long id;
/**
* 本次变动点数,正加负减
*/
private BigDecimal points;
/**
* 变动后余额快照(冗余)
*/
private BigDecimal balance;
/**
* 变动类型,如 TRANSFER_IN, WITHDRAWREFUND_COMMISSION RECHARGE_COMMISSION
*/
private String type;
/**
* 变动描述
*/
private String description;
/**
* 订单 Id/业务单号
*/
private String orderId;
/**
* 业务流水号(转账、订单等唯一标识)
*/
private String bizNo;
/**
* 操作人 Id
*/
private Long operatorId;
/**
* 创建时间
*/
private LocalDateTime createdAt;
/**
* 备注
*/
private String remark;
private Long tenantId;
}

View File

@@ -0,0 +1,14 @@
package com.yolo.keyboard.dal.mysql.tenantbalancetransaction;
import com.yolo.keyboard.dal.dataobject.tenantbalancetransaction.TenantBalanceTransactionDO;
import com.yolo.keyboard.framework.mybatis.core.mapper.BaseMapperX;
import org.apache.ibatis.annotations.Mapper;
/**
* 租户积分记录 Mapper
*
* @author 芋道源码
*/
@Mapper
public interface TenantBalanceTransactionMapper extends BaseMapperX<TenantBalanceTransactionDO> {
}

View File

@@ -59,4 +59,26 @@ public interface TenantBalanceService {
*/ */
PageResult<TenantBalanceDO> getTenantBalancePage(TenantBalancePageReqVO pageReqVO); PageResult<TenantBalanceDO> getTenantBalancePage(TenantBalancePageReqVO pageReqVO);
/**
* 添加租户余额
*
* @param addReqVO 添加信息
*/
void addTenantBalance(@Valid TenantBalanceAddReqVO addReqVO);
/**
* 获得自己的余额
*
* @return 租户余额
*/
TenantBalanceDO getSelfBalance();
/**
* 获得自己下级余额的分页
*
* @param pageReqVO 分页查询
* @return 租户余额分页
*/
PageResult<TenantBalanceRespVO> getSelfSubordinateTenantBalancePage(TenantBalancePageReqVO pageReqVO);
} }

View File

@@ -1,11 +1,16 @@
package com.yolo.keyboard.service.tenantbalance; package com.yolo.keyboard.service.tenantbalance;
import cn.hutool.core.collection.CollUtil; import cn.hutool.core.collection.CollUtil;
import com.yolo.keyboard.dal.dataobject.tenantbalancetransaction.TenantBalanceTransactionDO;
import com.yolo.keyboard.dal.mysql.tenantbalancetransaction.TenantBalanceTransactionMapper;
import com.yolo.keyboard.framework.tenant.core.context.TenantContextHolder;
import com.yolo.keyboard.utils.BizNoGenerator;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import jakarta.annotation.Resource; import jakarta.annotation.Resource;
import org.springframework.validation.annotation.Validated; import org.springframework.validation.annotation.Validated;
import org.springframework.transaction.annotation.Transactional; import org.springframework.transaction.annotation.Transactional;
import java.math.BigDecimal;
import java.util.*; import java.util.*;
import com.yolo.keyboard.controller.admin.tenantbalance.vo.*; import com.yolo.keyboard.controller.admin.tenantbalance.vo.*;
import com.yolo.keyboard.dal.dataobject.tenantbalance.TenantBalanceDO; import com.yolo.keyboard.dal.dataobject.tenantbalance.TenantBalanceDO;
@@ -32,6 +37,9 @@ public class TenantBalanceServiceImpl implements TenantBalanceService {
@Resource @Resource
private TenantBalanceMapper tenantBalanceMapper; private TenantBalanceMapper tenantBalanceMapper;
@Resource
private TenantBalanceTransactionMapper tenantBalanceTransactionMapper;
@Override @Override
public Long createTenantBalance(TenantBalanceSaveReqVO createReqVO) { public Long createTenantBalance(TenantBalanceSaveReqVO createReqVO) {
// 插入 // 插入
@@ -82,4 +90,47 @@ public class TenantBalanceServiceImpl implements TenantBalanceService {
return tenantBalanceMapper.selectPage(pageReqVO); return tenantBalanceMapper.selectPage(pageReqVO);
} }
@Override
@Transactional
public void addTenantBalance(TenantBalanceAddReqVO addReqVO) {
// 1. 根据ID查询租户余额记录校验是否存在
TenantBalanceDO balance = tenantBalanceMapper.selectById(addReqVO.getId());
if (balance == null) {
throw exception(TENANT_BALANCE_NOT_EXISTS);
}
// 2. 计算新的余额(当前余额 + 充值金额)
BigDecimal newBalance = balance.getBalance().add(new BigDecimal(String.valueOf(addReqVO.getAmount())));
// 3. 更新租户余额(使用乐观锁)
balance.setBalance(newBalance);
int updateCount = tenantBalanceMapper.updateById(balance);
if (updateCount == 0) {
throw exception(TENANT_BALANCE_NOT_EXISTS);
}
// 4. 创建余额交易记录
TenantBalanceTransactionDO transaction = TenantBalanceTransactionDO.builder()
.bizNo(BizNoGenerator.generate("RECHARGE")) // 生成充值业务编号
.points(new BigDecimal(String.valueOf(addReqVO.getAmount()))) // 充值金额
.balance(newBalance) // 充值后余额
.tenantId(addReqVO.getId())
.type("RECHARGE") // 交易类型:充值
.description("余额充值") // 交易描述
.remark(addReqVO.getRemark()) // 备注信息
.operatorId(TenantContextHolder.getTenantId()) // 操作人ID当前租户ID
.build();
// 5. 插入交易记录到数据库
tenantBalanceTransactionMapper.insert(transaction);
}
@Override
public TenantBalanceDO getSelfBalance() {
return null;
}
@Override
public PageResult<TenantBalanceRespVO> getSelfSubordinateTenantBalancePage(TenantBalancePageReqVO pageReqVO) {
return null;
}
} }

View File

@@ -0,0 +1,9 @@
package com.yolo.keyboard.utils;
import cn.hutool.core.util.IdUtil;
public class BizNoGenerator {
public static String generate(String prefix) {
return prefix + "-" + IdUtil.getSnowflakeNextIdStr();
}
}

View File

@@ -14,6 +14,7 @@ import com.baomidou.mybatisplus.extension.incrementer.*;
import com.baomidou.mybatisplus.extension.parser.JsqlParserGlobal; import com.baomidou.mybatisplus.extension.parser.JsqlParserGlobal;
import com.baomidou.mybatisplus.extension.parser.cache.JdkSerialCaffeineJsqlParseCache; import com.baomidou.mybatisplus.extension.parser.cache.JdkSerialCaffeineJsqlParseCache;
import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor; import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor;
import com.baomidou.mybatisplus.extension.plugins.inner.OptimisticLockerInnerInterceptor;
import com.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerInterceptor; import com.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerInterceptor;
import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.ObjectMapper;
import org.apache.ibatis.annotations.Mapper; import org.apache.ibatis.annotations.Mapper;
@@ -48,6 +49,7 @@ public class YoloMybatisAutoConfiguration {
public MybatisPlusInterceptor mybatisPlusInterceptor() { public MybatisPlusInterceptor mybatisPlusInterceptor() {
MybatisPlusInterceptor mybatisPlusInterceptor = new MybatisPlusInterceptor(); MybatisPlusInterceptor mybatisPlusInterceptor = new MybatisPlusInterceptor();
mybatisPlusInterceptor.addInnerInterceptor(new PaginationInnerInterceptor()); // 分页插件 mybatisPlusInterceptor.addInnerInterceptor(new PaginationInnerInterceptor()); // 分页插件
mybatisPlusInterceptor.addInnerInterceptor(new OptimisticLockerInnerInterceptor()); // 乐观锁插件
// ↓↓↓ 按需开启,可能会影响到 updateBatch 的地方:例如说文件配置管理 ↓↓↓ // ↓↓↓ 按需开启,可能会影响到 updateBatch 的地方:例如说文件配置管理 ↓↓↓
// mybatisPlusInterceptor.addInnerInterceptor(new BlockAttackInnerInterceptor()); // 拦截没有指定条件的 update 和 delete 语句 // mybatisPlusInterceptor.addInnerInterceptor(new BlockAttackInnerInterceptor()); // 拦截没有指定条件的 update 和 delete 语句
return mybatisPlusInterceptor; return mybatisPlusInterceptor;