公会-土耳其-公会水晶-兑换

This commit is contained in:
2025-08-20 16:23:01 +08:00
parent 0bb8700959
commit d26cd0996c
8 changed files with 222 additions and 1 deletions

View File

@@ -275,6 +275,9 @@ public enum BillObjTypeEnum {
LUCKY_GIFT_INCOME_ALLOT( 182, "幸运礼物价值分成", BillTypeEnum.IN, CurrencyEnum.GUILD_CRYSTAL, BillDomainTypeEnum.GUILD_POLICY2),
NORMAL_GIFT_INCOME_ALLOT( 183, "普通礼物价值分成", BillTypeEnum.IN, CurrencyEnum.GUILD_CRYSTAL, BillDomainTypeEnum.GUILD_POLICY2),
GUILD_POLICY2_CRYSTAL_SETTLEMENT( 184, "公会紫晶结算", BillTypeEnum.OUT, CurrencyEnum.GUILD_CRYSTAL, BillDomainTypeEnum.GUILD_POLICY2),
EXCHANGE_GUILD_CRYSTAL_TO_DIAMOND_PAY( 185, "公会紫晶兑换金币支出", BillTypeEnum.OUT, CurrencyEnum.GUILD_CRYSTAL, BillDomainTypeEnum.EXCHANGE),
EXCHANGE_GUILD_CRYSTAL_TO_DIAMOND_INCOME( 186, "公会紫晶兑换金币收入", BillTypeEnum.IN, CurrencyEnum.DIAMOND, BillDomainTypeEnum.EXCHANGE),
;
BillObjTypeEnum(int value, String desc, BillTypeEnum type, CurrencyEnum currency, BillDomainTypeEnum domain) {

View File

@@ -0,0 +1,25 @@
package com.accompany.business.vo.guildpolicy;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import java.math.BigDecimal;
@ApiModel
@Data
public class GuildCrystalExchangeConfigVo {
@ApiModelProperty("uid")
private Long uid;
@ApiModelProperty("公会紫晶余额")
private Double guildCrystalNum;
@ApiModelProperty("比例")
private BigDecimal rate;
@ApiModelProperty("最小兑换紫晶数量")
private Long minCrystalNumLimit;
@ApiModelProperty("允许兑换倍数最小单位")
private Long multipleUnit;
}

View File

@@ -48,6 +48,8 @@ public interface UserPurseMapper extends BaseMapper<UserPurse> {
int updateSettlementGuildCrystal(@Param("uid") Long uid, @Param("guildCrystal") Double guildCrystal);
int excGuildCrystalToDiamond(@Param("uid") Long uid, @Param("excNum") Double excNum, @Param("diamondNum") Double diamondNum);
UserPurse queryByUid(@Param("uid") Long uid);
}

View File

@@ -0,0 +1,98 @@
package com.accompany.business.service.guildpolicy2;
import com.accompany.business.model.UserPurse;
import com.accompany.business.model.guild.GuildMember;
import com.accompany.business.service.guild.GuildMemberService;
import com.accompany.business.service.purse.UserPurseService;
import com.accompany.business.service.user.UsersService;
import com.accompany.business.vo.guildpolicy.GuildCrystalExchangeConfigVo;
import com.accompany.common.constant.Constant;
import com.accompany.common.status.BusiStatus;
import com.accompany.core.enumeration.PartitionEnum;
import com.accompany.core.exception.ServiceException;
import com.accompany.core.model.Users;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service;
import java.math.BigDecimal;
@Slf4j
@Service
public class GuildCrystalExchangeService {
@Autowired
@Lazy
private UserPurseService userPurseService;
@Autowired
private UsersService usersService;
@Autowired
private GuildMemberService guildMemberService;
private final BigDecimal RATE = BigDecimal.ONE;
private final long EXCHANGE_LIMIT = 1000L;
public GuildCrystalExchangeConfigVo buildVo(Long uid){
Users u = usersService.getNotNullUsersByUid(uid);
PartitionEnum partitionEnum = PartitionEnum.getByPartitionId(u.getPartitionId());
if (!Constant.ClanMode.GUILD_POLICY2.equals(partitionEnum.getClanMode())){
throw new ServiceException(BusiStatus.PARTITION_ERROR);
}
GuildMember guildMember = guildMemberService.getVaildGuildMemberByUid(uid);
if (guildMember == null){
throw new ServiceException(BusiStatus.PARTITION_ERROR);
}
UserPurse userPurse = userPurseService.queryUserPurse(uid);
GuildCrystalExchangeConfigVo vo = new GuildCrystalExchangeConfigVo();
vo.setUid(uid);
vo.setGuildCrystalNum(userPurse.getGuildCrystal());
vo.setRate(RATE);
vo.setMinCrystalNumLimit(EXCHANGE_LIMIT);
vo.setMultipleUnit(EXCHANGE_LIMIT);
return vo;
}
public void exchange(Long uid, Long guildCrystalNum) {
if (null == guildCrystalNum || guildCrystalNum <= 0L){
throw new ServiceException(BusiStatus.PARAMERROR);
}
if (guildCrystalNum < EXCHANGE_LIMIT || guildCrystalNum % EXCHANGE_LIMIT != 0L){
throw new ServiceException(BusiStatus.PARAMERROR);
}
Users u = usersService.getNotNullUsersByUid(uid);
PartitionEnum partitionEnum = PartitionEnum.getByPartitionId(u.getPartitionId());
if (!Constant.ClanMode.GUILD_POLICY2.equals(partitionEnum.getClanMode())){
throw new ServiceException(BusiStatus.PARTITION_ERROR);
}
GuildMember guildMember = guildMemberService.getVaildGuildMemberByUid(uid);
if (guildMember == null){
throw new ServiceException(BusiStatus.PARTITION_ERROR);
}
Double guildCrystalNumD = guildCrystalNum.doubleValue();
UserPurse userPurse = userPurseService.queryUserPurse(uid);
Double currentGuildCrystalNum = userPurse.getGuildCrystal();
if (Double.compare(currentGuildCrystalNum, guildCrystalNumD) < 0){
log.error("[guild crystal 兑换] {} 钱包 guild crystal 数 {} 少于兑换需要扣 guild crystal 数 {}", uid, currentGuildCrystalNum, guildCrystalNumD);
throw new ServiceException(BusiStatus.PURSE_MONEY_NOT_ENOUGH);
}
Double diamondD = BigDecimal.valueOf(guildCrystalNum).multiply(RATE).doubleValue();
userPurseService.excGuildCrystalToDiamond(uid, guildCrystalNumD, diamondD, BusiStatus.PURSE_MONEY_NOT_ENOUGH);
insertGuildCrystalExchangeRecord(uid, guildMember, guildCrystalNumD, diamondD, RATE);
log.info("[guild crystal 兑换] {} guild crystal {} 要兑换的金币数 {} 比率 {} 成功", uid, guildCrystalNum, diamondD, RATE);
}
}

View File

@@ -723,4 +723,34 @@ public class UserPurseService extends ServiceImpl<UserPurseMapper,UserPurse> {
billRecordService.insertGeneralBillRecord(uid, objTypeEnum, guildUsdNum.doubleValue(), after);
return after;
}
@Frozen
@Transactional(rollbackFor = Exception.class, transactionManager = "mybatisplusTransactionManager")
public UserPurse excGuildCrystalToDiamond(Long uid, Double guildCrystalNumD, Double diamondD, BusiStatus busiStatus) {
if (guildCrystalNumD <= 0d) {
throw new ServiceException(BusiStatus.AMOUNT_PARAM_ERROR);
}
UserPurse after = withLock(uid, RedisKey.lock_user_guild_crystal, userPurse -> {
double restNum = DoubleUtil.sub(userPurse.getGuildCrystal(), guildCrystalNumD);
if (restNum < 0d){
throw new ServiceException(busiStatus);
}
//保持操作原子性
int ret = baseMapper.excGuildCrystalToDiamond(uid, guildCrystalNumD, diamondD);
boolean result = SqlHelper.retBool(ret);
if(!result) {
throw new ServiceException(BusiStatus.SERVERBUSY);
}
userPurse.setGuildCrystal(restNum);
userPurse.setDiamonds(DoubleUtil.add(userPurse.getDiamonds(), diamondD));
userPurse.setUpdateTime(new Date());
log.info("excGuildCrystalToDiamond,uid:{}, exchangeNum:{},result:{}",uid, guildCrystalNumD, result);
return userPurse;
});
billRecordService.insertGeneralBillRecord(uid, BillObjTypeEnum.EXCHANGE_CRYSTAL_TO_DIAMOND_PAY, guildCrystalNumD, after);
billRecordService.insertGeneralBillRecord(uid, BillObjTypeEnum.EXCHANGE_CRYSTAL_TO_DIAMOND_INCOME, diamondD, after);
return after;
}
}

View File

@@ -104,4 +104,9 @@
where uid=#{uid}
</update>
<update id="excGuildCrystalToDiamond">
update user_purse set guild_crystal = guild_crystal - #{excNum},diamonds = diamonds + #{diamondNum}, update_time=now()
where uid=#{uid} and guild_crystal &gt;= #{excNum}
</update>
</mapper>

View File

@@ -0,0 +1,59 @@
package com.accompany.business.controller.guildpolicy;
import com.accompany.business.common.BaseController;
import com.accompany.business.service.guildpolicy2.GuildCrystalExchangeService;
import com.accompany.business.vo.guildpolicy.GuildCrystalExchangeConfigVo;
import com.accompany.common.annotation.Authorization;
import com.accompany.common.annotation.H5Authorization;
import com.accompany.common.result.BusiResult;
import com.accompany.common.status.BusiStatus;
import com.accompany.core.exception.ServiceException;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiImplicitParam;
import io.swagger.annotations.ApiImplicitParams;
import io.swagger.annotations.ApiOperation;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import javax.servlet.http.HttpServletRequest;
@Api(tags = "公会紫晶兑换", value = "公会紫晶兑换")
@RestController
@RequestMapping("/guild/guildCrystalExchange")
public class GuildCrystalExchangeController extends BaseController {
@Autowired
private GuildCrystalExchangeService service;
@Authorization
@H5Authorization
@ApiOperation("获取配置")
@GetMapping(value = "/getConfig")
public BusiResult<GuildCrystalExchangeConfigVo> getConfig(HttpServletRequest request) {
Long uid = getUid(request);
GuildCrystalExchangeConfigVo configVo = service.buildVo(uid);
return new BusiResult<>(configVo);
}
@Authorization
@H5Authorization
@ApiOperation("兑换")
@ApiImplicitParams({
@ApiImplicitParam(name = "guildCrystalNum", value = "公会紫晶数量", required = true, dataType = "Long", paramType = "query")
})
@PostMapping(value = "/exchange")
public BusiResult<Void> exchange(HttpServletRequest request, Long guildCrystalNum) {
if (null == guildCrystalNum || guildCrystalNum < 0) {
throw new ServiceException(BusiStatus.PARAMERROR);
}
Long uid = getUid(request);
service.exchange(uid, guildCrystalNum);
return new BusiResult<>(BusiStatus.GOLD_EXCHANGE_DIAMOND_SUCCESS);
}
}

View File

@@ -33,7 +33,6 @@ public class GuildPolicy2Controller {
@Autowired
private GuildMemberRoomMicRecordService guildMemberRoomMicRecordService;
@ApiOperation(value = "公会收入统计", httpMethod = "GET")
@ApiImplicitParams({
@ApiImplicitParam(name = "cycleBeginDate", value = "周期开始日期yyyy-MM-dd", required = true, dataType = "String", paramType = "query")