first commit

This commit is contained in:
2026-09-21 19:21:35 +08:00
commit 6c944c4ffd
2733 changed files with 296956 additions and 0 deletions
@@ -0,0 +1,143 @@
package com.ruoyi.admin.aspectj;
import cn.hutool.core.util.ObjectUtil;
import com.ruoyi.domain.entity.sys.TtUser;
import com.ruoyi.admin.service.TtUserService;
import com.ruoyi.common.constant.HttpStatus;
import com.ruoyi.common.core.domain.entity.UserData;
import com.ruoyi.common.core.domain.model.LoginUser;
import com.ruoyi.common.exception.ServiceException;
import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.common.utils.bean.BeanUtils;
import com.ruoyi.domain.common.constant.UserType;
import com.ruoyi.framework.web.service.TokenService;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import jakarta.servlet.http.HttpServletRequest;
import java.io.IOException;
@Aspect
@Component
@Order(1)
@Slf4j
public class UpdateUserCacheAspect {
private final TtUserService userService;
private final TokenService tokenService;
public UpdateUserCacheAspect(TtUserService userService,
TokenService tokenService) {
this.userService = userService;
this.tokenService = tokenService;
}
@Pointcut("@annotation(com.ruoyi.common.annotation.NewUserInfo)")
private void NewUserInfo() {
}
@Pointcut("@annotation(com.ruoyi.common.annotation.UpdateUserCache)")
private void permissionCheck() {
}
@Before("NewUserInfo()")
public void NewUserInfo(JoinPoint joinPoint) throws IOException {
// 获取request对象
ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
if (StringUtils.isNull(attributes)) return;
HttpServletRequest request = attributes.getRequest();
// 获取登录用户信息
LoginUser loginUser = tokenService.getLoginUser(request);
if (ObjectUtil.isEmpty(loginUser)) {
// 不能只 sendError 后 return:请求会继续进入 Controller,getLoginUser() 再抛异常,
// 响应已被提交导致错误信息丢失。直接抛 401,前端按 code=401 登出。
log.warn("登录过期,请重新登录。");
throw new ServiceException("登录过期,请重新登录。", HttpStatus.UNAUTHORIZED);
}
TtUser user = userService.getById(loginUser.getUserId());
if (stopIfUserDeleted(loginUser, user)) return;
// 设置更新后的属性
UserData userData = loginUser.getUserData();
// 对象拷贝
BeanUtils.copyBeanProp(userData, user);
// 获取上级用户
TtUser ParentUser = userService.getById(user.getParentId());
if (StringUtils.isNotNull(ParentUser))
userData.setParentInvitationCode(ParentUser.getInvitationCode()); // 上级邀请码
loginUser.setUserData(userData);
// 刷新token
tokenService.refreshToken(loginUser);
//log.info("用户数据已提前刷新");
}
@After("permissionCheck()")
public void afterAdvice(JoinPoint joinPoint) throws IOException {
// 获取request对象
ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
if (StringUtils.isNull(attributes)) return;
HttpServletRequest request = attributes.getRequest();
// 获取登录用户信息
LoginUser loginUser = tokenService.getLoginUser(request);
if (ObjectUtil.isEmpty(loginUser)) {
log.warn("登录过期,请重新登录。");
throw new ServiceException("登录过期,请重新登录。", HttpStatus.UNAUTHORIZED);
}
TtUser user = userService.getById(loginUser.getUserId());
if (stopIfUserDeleted(loginUser, user)) return;
// 设置更新后的属性
UserData userData = loginUser.getUserData();
if (userData == null) {
userData = UserData.builder().build();
}
// 对象拷贝
BeanUtils.copyBeanProp(userData, user);
// 获取上级用户
TtUser ParentUser = userService.getById(user.getParentId());
if (StringUtils.isNotNull(ParentUser))
userData.setParentInvitationCode(ParentUser.getInvitationCode()); // 上级邀请码
loginUser.setUserData(userData);
// 刷新token
tokenService.refreshToken(loginUser);
//log.info("用户数据缓存刷新完毕");
}
/**
* 登录态存在但用户记录已查不到(后台逻辑删除 del_flag=2 或真删除)时的兜底处理。
* <p>
* 后台删除用户不会动 Redis 里的 Token,若不处理,控制器会继续拿 null 用户执行,
* 表现为 /api/getAccountAmount 一直空指针(Cannot invoke ... because "ttUser" is null),
* 且客户端永远无法登出。此处清掉登录态并返回 401,前端据此自动跳登录页。
*
* @return true 表示请求不应继续(已抛 401 或后台/运营账号直接跳过缓存刷新)
*/
private boolean stopIfUserDeleted(LoginUser loginUser, TtUser user) {
if (ObjectUtil.isNotEmpty(user)) return false;
UserData userData = loginUser.getUserData();
// 只处理玩家账号(api_/promo_user_ 登录,身份在 tt_user):
// 后台 SysUser 账号 user 非 null;promo_ 超管账号身份在 promo_admin 表,都不应在此清登录态
boolean playerAccount = loginUser.getUser() == null && userData != null
&& !UserType.SUPER_ADMIN.getCode().equals(userData.getUserType());
if (!playerAccount) {
log.warn("用户缓存刷新跳过:userId={} 用户不存在(非玩家账号)", loginUser.getUserId());
return true;
}
tokenService.delLoginUser(loginUser.getToken());
log.warn("用户已不存在,清除登录态并返回401:userId={}", loginUser.getUserId());
throw new ServiceException("账号不存在或已被删除,请重新登录。", HttpStatus.UNAUTHORIZED);
}
}
@@ -0,0 +1,26 @@
package com.ruoyi.admin.cache;
import com.ruoyi.admin.model.BoxMockCache;
import com.ruoyi.common.core.redis.RedisCache;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.util.concurrent.TimeUnit;
@Component
public class BoxMockCacheRepository {
private static final String BOX_MOCK_CACHE_KEY = "ruoyi:box:mock:";
@Autowired
private RedisCache redisCache;
//将用户的临时爆率存储在redis中,存储七天
public void setMockResultCache(Integer uid, BoxMockCache value) {
redisCache.setCacheObject(BOX_MOCK_CACHE_KEY + uid, value, 7, TimeUnit.DAYS);
}
//根据用户的id,从redis中取出用户的临时爆率
public BoxMockCache getMockResultCache(Integer uid) {
return redisCache.getCacheObject(BOX_MOCK_CACHE_KEY + uid);
}
}
@@ -0,0 +1,100 @@
package com.ruoyi.admin.config;
public class RedisConstants {
// 整个应用的通用uid锁
public static final String COMMON_LOCK = "ruoyi:common:lock_";
// 游戏下注防重锁:控制层按 userId 加锁,tryLock wait=0 立即失败,锁包裹整个事务、解锁晚于提交;
// 锁粒度=单用户,仅串行同一用户的重复/并发下注,不影响其他用户,避免弱网重复提交导致重复扣款
// 注:幸运升级不在此列——其锁按 upgradeId+userType(保护跨用户共享概率计数器,属底层RTP机制),不能改为userId
public static final String OPEN_BOX_LOCK = "open_box:lock_"; // 经典开箱/盲盒
public static final String EXPONENT_JOIN_LOCK = "exponent_join:lock_"; // 指数盲盒
public static final String SUGAR_GAME_CACHE = "ruoyi:sugar:";
public static final String SUGAR_GAME_MOCK_QUEUE = "ruoyi:sugar:mock:";
public static final String SUGAR_GAME_USER_RECORD_CACHE = "ruoyi:sugar:user:record:";
public static final String SUGAR_GAME_CONFIG_CACHE = "ruoyi:sugar:config";
public static final String SUGAR_GAME_REWARD_POOL_CACHE = "ruoyi:sugar:reward:pool";
public static final String WHEEL_GAME_REWARD_POOL_CACHE = "ruoyi:wheel:reward:pool";
public static final String BULLET_GAME_REWARD_POOL_CACHE = "ruoyi:bullet:reward:pool";
// ========== Olympus 电子游戏 ==========
// 单局进行中缓存:ruoyi:olympus:{userId},存整局步骤,TTL 30 分钟
public static final String OLYMPUS_GAME_CACHE = "ruoyi:olympus:";
// 按箱奖池(水位):ruoyi:olympus:reward:pool:box:{boxId}:bet/:win/:adjust,仅统计真实玩家(白号隔离)
public static final String OLYMPUS_GAME_REWARD_POOL_CACHE = "ruoyi:olympus:reward:pool";
// 一轮内RTP动态收敛账本:Hash ruoyi:olympus:cycle:{boxId}:{audience},字段 drawn/mulSum/conv:{ornamentId}
public static final String OLYMPUS_GAME_CYCLE = "ruoyi:olympus:cycle:";
/**
* 开箱奖池
* 奖池key: baseKey:boxId:poolType
*
* @see com.ruoyi.admin.enums.BoxPoolType
*/
public static final String BASE_POOL_KEY = "prize_pool:";
// 对战模式
public static final String JOIN_FIGHT_LOCK = "join_fight:lock_";
public static final String JOIN_FIGHT_BEGIN_LOCK = "join_fight:lock_begin_";
public static final String JOIN_FIGHT_SEAT_READY_LOCK = "join_fight:lock_seat_ready_";
public static final String JOIN_FIGHT_END_LOCK = "join_fight:lock_end_";
// roll房间
public static final String JOIN_ROLL_LOCK = "join_roll:lock_";
public static final String RECEIVE_RED_PACKET_LOCK = "receive_red_packet:lock_";
public static final String CARD_PAY_LOCK = "CARD_PAY:lock_";
// 卡商生成卡密:控制层按卡商 userId 加锁(锁粒度=单卡商,不影响其他卡商),
// 锁包裹整个 @Transactional 生成过程,解锁晚于事务提交,
// 防弱网超时重试/多端重复提交导致同一批卡密生成两次、卡商余额扣两次
public static final String CARD_KEY_GENERATE_LOCK = "card_key_generate:lock_";
// 管理员变更卡商余额(充值/修改):控制层按卡商 userId 加锁(锁粒度=单卡商,不影响其他卡商),
// 防双击/弱网重试导致同一笔变动被应用两次(充值是多加一次钱,修改余额是并发下算出错误的差额)
public static final String CARD_MERCHANT_BALANCE_LOCK = "card_merchant_balance:lock_";
// 主播生成红包卡:控制层按主播 userId 加锁,防双击/弱网重试导致扣两次主播积分 + 生成两批卡
public static final String PROMO_RED_PACKET_GENERATE_LOCK = "promo_red_packet_generate:lock_";
// 主播生成 CDKEY:控制层按创建者 userId 加锁,防重复提交导致预扣两次主播余额(金额×次数×生成数量)
public static final String PROMO_CDKEY_GENERATE_LOCK = "promo_cdkey_generate:lock_";
// 管理后台生成卡密/空白卡密:控制层按管理员 userId 加锁,防重复提交生成两批卡密
public static final String RECHARGE_CARD_GENERATE_LOCK = "recharge_card_generate:lock_";
// 商城兑换 / 背包转赠:控制层按用户 userId 加锁(锁粒度=单用户,仅串行同一用户的并发请求,不影响其他用户),
// 锁包裹整个 @Transactional Service 调用,确保解锁发生在事务提交之后,杜绝弱网重复提交导致的重复扣费/重复发放
public static final String SHOPPING_EXCHANGE_LOCK = "shopping_exchange:lock_";
public static final String SHOPPING_INTEGRATING_CONVERSION_LOCK = "shopping_integrating_conversion:lock_";
public static final String TRANSFER_LOCK = "user_transfer:lock_";
// 幸运升级
public static final String UPGRADE_RANGE = "upgrade_range:"; // 概率区间 '业务key:饰品id:用户类型'
public static final String UPGRADE_RANGE_FIXED = "upgrade_range_fixed:"; // 固定概率 '业务key:饰品id:用户类型'
/**
* 抽奖box的奖品空间
* open_box_goods_apace:
* box_id:
* odds_key:
* valua
*/
public static final String OPEN_BOX_GOODS_SPACE = "open_box_goods_apace:";
public static final String OPEN_BOX_LOTTERY = "open_box_lottery:";
// 支付拉单频控:x分钟内y次拉单未支付则封禁z分钟(当前 x=5,y=3,z=10)
// 次数缓存:key=前缀+uid,值=累计未支付拉单次数,TTL=x分钟
public static final String PAY_PULL_UNPAID_COUNT = "pay:pull:unpaid:count_";
// 封禁缓存:key=前缀+uid,值=z,TTL=z分钟
public static final String PAY_PULL_BAN = "pay:pull:ban_";
// 流水抽奖:按 userId 加锁,防止并发重复消耗流水/重复发奖
public static final String TURNOVER_LOTTERY_DRAW_LOCK = "turnover_lottery:draw:lock_";
// 流水抽奖:按宝箱 lotteryId 加锁,防止不同用户并发导致奖品超发
public static final String TURNOVER_LOTTERY_DRAW_BOX_LOCK = "turnover_lottery:draw:box:lock_";
}
@@ -0,0 +1,55 @@
package com.ruoyi.admin.consumer;
import com.rabbitmq.client.Channel;
import com.ruoyi.admin.service.TtUserService;
import com.ruoyi.common.rabbitmq.config.DelayedQueueConfig;
import com.ruoyi.domain.common.constant.TtAccountRecordSource;
import lombok.extern.slf4j.Slf4j;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.amqp.support.AmqpHeaders;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.messaging.handler.annotation.Header;
import org.springframework.stereotype.Component;
import java.io.IOException;
import java.math.BigDecimal;
import java.util.Arrays;
import java.util.Map;
/**
* 游戏消费佣金分发消费者。
* 下注扣款事务提交后,生产者发消息到 wheel_commission_queue;本消费者消费后递归向上发佣金。
* 消费失败 nack requeue 重投(佣金失败均为 DB 瞬时异常,恢复后即可成功,不会丢)。
*/
@Component
@Slf4j
public class WheelCommissionConsumer {
@Autowired
private TtUserService ttUserService;
@RabbitListener(queues = DelayedQueueConfig.WHEEL_COMMISSION_QUEUE)
public void consume(Map<String, Object> msg, Channel channel,
@Header(AmqpHeaders.DELIVERY_TAG) long tag) {
try {
Integer userId = (Integer) msg.get("userId");
BigDecimal consumeAmount = new BigDecimal(msg.get("consumeAmount").toString());
int sourceCode = (Integer) msg.get("sourceCode");
TtAccountRecordSource source = Arrays.stream(TtAccountRecordSource.values())
.filter(s -> s.getCode() == sourceCode)
.findFirst()
.orElseThrow(() -> new RuntimeException("未知消费来源 code=" + sourceCode));
ttUserService.distributeGameCommission(userId, consumeAmount, source);
channel.basicAck(tag, false);
} catch (Exception e) {
log.error("佣金分发消费失败, msg={}, nack 重投", msg, e);
try {
// requeue=true:重新入队重试,直到成功消费(DB 恢复后即可成功)
channel.basicNack(tag, false, true);
} catch (IOException ioEx) {
log.error("佣金 nack 失败", ioEx);
}
}
}
}
@@ -0,0 +1,117 @@
package com.ruoyi.admin.controller;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.ruoyi.common.enums.BusinessType;
import com.ruoyi.common.annotation.Log;
import com.ruoyi.admin.config.RedisConstants;
import com.ruoyi.admin.mapper.TtBlankCardKeyMapper;
import com.ruoyi.admin.mapper.TtRechargeProdMapper;
import com.ruoyi.common.core.controller.BaseController;
import com.ruoyi.common.core.domain.R;
import com.ruoyi.common.redis.config.RedisLock;
import com.ruoyi.common.utils.DateUtils;
import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.common.utils.uuid.IdUtils;
import com.ruoyi.domain.entity.TtBlankCardKey;
import com.ruoyi.domain.entity.TtRechargeProd;
import io.swagger.annotations.ApiOperation;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import java.util.List;
import java.util.concurrent.TimeUnit;
/**
* 白号管理 - 空白卡密管理(管理后台生成,独立表 tt_blank_card_key)
*/
@RestController
@RequestMapping("/admin/blankCardKey")
public class AdminBlankCardKeyController extends BaseController {
@Autowired
private TtBlankCardKeyMapper blankCardKeyMapper;
@Autowired
private TtRechargeProdMapper rechargeProdMapper;
@Autowired
private RedisLock redisLock;
/**
* 获取充值产品列表(金额选项)
*/
@ApiOperation("获取充值产品列表")
@GetMapping("/rechargeList")
public R<List<TtRechargeProd>> getRechargeList() {
List<TtRechargeProd> list = rechargeProdMapper.selectList(
new LambdaQueryWrapper<TtRechargeProd>().orderByAsc(TtRechargeProd::getPrice));
return R.ok(list);
}
@Log(title = "生成空白卡密", action = "生成空白卡密", businessType = BusinessType.INSERT)
/**
* 生成空白卡密(管理后台,不扣余额)
*/
@ApiOperation("生成空白卡密")
@PostMapping("/generate")
public R<List<String>> generate(@RequestBody java.util.Map<String, Object> request) {
Integer rechargeListId = (Integer) request.get("rechargeListId");
Integer num = (Integer) request.get("num");
if (rechargeListId == null || num == null || num <= 0 || num > 100) {
return R.fail("参数不合法,生成数量需在1-100之间");
}
TtRechargeProd rechargeProd = rechargeProdMapper.selectById(rechargeListId);
if (rechargeProd == null) {
return R.fail("充值产品ID无效");
}
// 防重:按管理员 userId 加锁(锁粒度=单管理员),防双击/弱网重试一次生成两批空白卡密
Long operId = getUserId();
String lockKey = RedisConstants.RECHARGE_CARD_GENERATE_LOCK + operId;
if (!redisLock.tryLock(lockKey, 0L, 30L, TimeUnit.SECONDS)) {
return R.fail("空白卡密生成中,请勿重复提交");
}
try {
String creatorName = getUsername();
List<String> cardCodes = new java.util.ArrayList<>();
for (int i = 0; i < num; i++) {
String code = IdUtils.fastSimpleUUID().substring(0, 16).toUpperCase();
TtBlankCardKey cardKey = TtBlankCardKey.builder()
.cardCode(code)
.amount(rechargeProd.getPrice())
.creatorName(creatorName)
.status(0)
.createTime(DateUtils.getNowDate())
.build();
blankCardKeyMapper.insert(cardKey);
cardCodes.add(code);
}
return R.ok(cardCodes, "成功生成 " + cardCodes.size() + " 张空白卡密");
} finally {
redisLock.unlock(lockKey);
}
}
/**
* 获取空白卡密列表
*/
@ApiOperation("获取空白卡密列表")
@GetMapping("/list")
public R<List<TtBlankCardKey>> list(
@RequestParam(required = false) String usedByName,
@RequestParam(required = false) String creatorName) {
LambdaQueryWrapper<TtBlankCardKey> wrapper = new LambdaQueryWrapper<>();
if (StringUtils.isNotBlank(usedByName)) {
wrapper.like(TtBlankCardKey::getUsedByName, usedByName);
}
if (StringUtils.isNotBlank(creatorName)) {
wrapper.like(TtBlankCardKey::getCreatorName, creatorName);
}
wrapper.orderByDesc(TtBlankCardKey::getCreateTime);
return R.ok(blankCardKeyMapper.selectList(wrapper));
}
}
@@ -0,0 +1,91 @@
package com.ruoyi.admin.controller;
import com.ruoyi.common.enums.BusinessType;
import com.ruoyi.common.annotation.Log;
import com.ruoyi.admin.mapper.TtLossRebateMapper;
import com.ruoyi.admin.service.LossRebateService;
import com.ruoyi.common.core.controller.BaseController;
import com.ruoyi.common.core.domain.AjaxResult;
import com.ruoyi.common.core.domain.R;
import com.ruoyi.common.core.page.PageDataInfo;
import com.ruoyi.domain.entity.TtLossRebate;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.springframework.web.bind.annotation.*;
import java.math.BigDecimal;
import java.util.List;
/**
* 管理端 亏损返水(回血红包)
* <p>
* 数据由定时任务 lossRebateService.generateHalfMonthLossRebate() 每半月写入,
* 本页只做「查看 + 对超过单期上限的用户人工发放CDK」。
*/
@Api(tags = "管理端 亏损返水")
@RestController
@RequestMapping("/admin/lossRebate")
public class LossRebateController extends BaseController {
private final LossRebateService lossRebateService;
public LossRebateController(LossRebateService lossRebateService) {
this.lossRebateService = lossRebateService;
}
@ApiOperation("亏损返水结算明细列表")
@GetMapping("/list")
public PageDataInfo<TtLossRebate> list(@RequestParam(required = false) String period,
@RequestParam(required = false) Integer userId,
@RequestParam(required = false) Integer status) {
startPage();
List<TtLossRebate> list = lossRebateService.list(period, userId, status);
return getPageData(list);
}
@Log(title = "亏损返水", action = "发放CDK", businessType = BusinessType.GRANT,
entityClass = TtLossRebate.class, mapperClass = TtLossRebateMapper.class, idField = "id")
@ApiOperation("人工发放CDK(超过单期上限/自动发放失败的记录)")
@PostMapping("/grant")
public R<String> grant(@RequestBody GrantRequest request) {
if (request == null || request.getId() == null) return R.fail("缺少明细ID");
return lossRebateService.grantManually(request.getId(), request.getAmount(), getUsername());
}
@ApiOperation("读取单期返水上限")
@GetMapping("/config")
public AjaxResult getConfig() {
return AjaxResult.success(lossRebateService.getMaxAmount());
}
@Log(title = "亏损返水", action = "保存上限", businessType = BusinessType.UPDATE)
@ApiOperation("保存单期返水上限(返水超过该金额不自动发放,转人工;0=不设上限)")
@PostMapping("/config")
public AjaxResult saveConfig(@RequestParam(required = false) BigDecimal maxAmount) {
lossRebateService.saveMaxAmount(maxAmount);
return AjaxResult.success("保存成功,下次结算生效");
}
/** 人工发放入参 */
public static class GrantRequest {
private Long id;
/** 实发金额,不传则按明细里的应返水金额发放 */
private BigDecimal amount;
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public BigDecimal getAmount() {
return amount;
}
public void setAmount(BigDecimal amount) {
this.amount = amount;
}
}
}
@@ -0,0 +1,29 @@
package com.ruoyi.admin.controller;
import com.ruoyi.admin.service.PromoCdkeyRedeemService;
import com.ruoyi.common.core.controller.BaseController;
import com.ruoyi.common.core.page.PageDataInfo;
import com.ruoyi.domain.entity.PromoCdkeyRedeem;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.List;
@RestController
@RequestMapping("/admin/promoCdkeyRedeem")
public class PromoCdkeyRedeemController extends BaseController {
private final PromoCdkeyRedeemService promoCdkeyRedeemService;
public PromoCdkeyRedeemController(PromoCdkeyRedeemService promoCdkeyRedeemService) {
this.promoCdkeyRedeemService = promoCdkeyRedeemService;
}
@GetMapping("/list")
public PageDataInfo<PromoCdkeyRedeem> list(PromoCdkeyRedeem promoCdkeyRedeem) {
startPage();
List<PromoCdkeyRedeem> list = promoCdkeyRedeemService.queryList(promoCdkeyRedeem);
return getPageData(list);
}
}
@@ -0,0 +1,94 @@
package com.ruoyi.admin.controller;
import com.ruoyi.common.enums.BusinessType;
import com.ruoyi.common.annotation.Log;
import com.ruoyi.admin.service.TtOrnamentService;
import com.ruoyi.domain.entity.TtOrnament;
import com.ruoyi.admin.service.ShoppingService;
import com.ruoyi.domain.other.ShoppingBody;
import com.ruoyi.domain.vo.ShoppingDataVO;
import com.ruoyi.common.core.controller.BaseController;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.ruoyi.common.core.domain.R;
import com.ruoyi.common.core.page.PageDataInfo;
import com.ruoyi.common.utils.StringUtils;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.springframework.web.bind.annotation.*;
import java.math.BigDecimal;
import java.util.List;
import java.util.stream.Collectors;
@Api(tags = "管理端 商城管理")
@RestController
@RequestMapping("/admin/shopping")
public class ShoppingController extends BaseController {
private final ShoppingService shoppingService;
private final TtOrnamentService ornamentsService;
public ShoppingController(ShoppingService shoppingService,
TtOrnamentService ornamentsService) {
this.shoppingService = shoppingService;
this.ornamentsService = ornamentsService;
}
@ApiOperation("商品列表")
@GetMapping("/list")
public PageDataInfo<ShoppingDataVO> list(ShoppingBody shoppingBody) {
startPage();
return shoppingService.list(shoppingBody);
}
@Log(title = "商城列表", action = "上架/下架", businessType = BusinessType.UPDATE)
@PostMapping("/batchPutAwayOrSoldOut/{status}")
public R<Boolean> batchPutAwayOrSoldOut(@RequestBody List<TtOrnament> ornamentsList,
@PathVariable("status") String status) {
if (StringUtils.isNull(ornamentsList) || ornamentsList.isEmpty()) return R.fail();
// 上架(status=0)时,market_hash_name 为空或 store_price 为0/NULL 的饰品禁止上架
if ("0".equals(status)) {
boolean hasInvalid = ornamentsList.stream()
.anyMatch(o -> o.getMarketHashName() == null || o.getMarketHashName().trim().isEmpty());
if (hasInvalid) {
return R.fail("存在缺少第三方名称(market_hash_name)的饰品,无法上架,请先补全或删除该饰品");
}
boolean hasZeroPrice = ornamentsList.stream()
.anyMatch(o -> o.getStorePrice() == null || o.getStorePrice().compareTo(BigDecimal.ZERO) <= 0);
if (hasZeroPrice) {
return R.fail("存在商城价格(store_price)为0或未设置的饰品,无法上架,请先设置价格");
}
}
ornamentsList = ornamentsList.stream().peek(ttOrnaments -> ttOrnaments.setIsPutaway(status)).collect(Collectors.toList());
if (ornamentsService.updateBatchById(ornamentsList, 1)) return R.ok(true);
return R.fail(false);
}
@Log(title = "商城列表", action = "一键上架", businessType = BusinessType.UPDATE)
@ApiOperation("一键上架所有商品")
@PostMapping("/putAwayAll")
public R<Boolean> putAwayAll() {
LambdaUpdateWrapper<TtOrnament> updateWrapper = new LambdaUpdateWrapper<>();
updateWrapper.eq(TtOrnament::getIsPutaway, "1")
// market_hash_name 为空的饰品无法第三方提货,一键上架时跳过
.isNotNull(TtOrnament::getMarketHashName)
.ne(TtOrnament::getMarketHashName, "")
// 商城价格(store_price)为0或NULL的饰品一键上架时跳过
.isNotNull(TtOrnament::getStorePrice)
.gt(TtOrnament::getStorePrice, BigDecimal.ZERO)
.set(TtOrnament::getIsPutaway, "0");
ornamentsService.update(updateWrapper);
return R.ok(true);
}
@Log(title = "商城列表", action = "一键下架", businessType = BusinessType.UPDATE)
@ApiOperation("一键下架所有商品")
@PostMapping("/soldOutAll")
public R<Boolean> soldOutAll() {
LambdaUpdateWrapper<TtOrnament> updateWrapper = new LambdaUpdateWrapper<>();
updateWrapper.eq(TtOrnament::getIsPutaway, "0")
.set(TtOrnament::getIsPutaway, "1");
ornamentsService.update(updateWrapper);
return R.ok(true);
}
}
@@ -0,0 +1,58 @@
package com.ruoyi.admin.controller;
import com.ruoyi.admin.service.TtAdvertisementService;
import com.ruoyi.common.config.RuoYiConfig;
import com.ruoyi.common.core.controller.BaseController;
import com.ruoyi.common.core.domain.AjaxResult;
import com.ruoyi.common.core.domain.R;
import com.ruoyi.common.core.page.PageDataInfo;
import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.domain.other.TtAdvertisement;
import org.springframework.web.bind.annotation.*;
import java.util.Arrays;
import java.util.List;
@RestController
@RequestMapping("/admin/advertisement")
public class TtAdvertisementController extends BaseController {
private final TtAdvertisementService ttAdvertisementService;
public TtAdvertisementController(TtAdvertisementService ttAdvertisementService) {
this.ttAdvertisementService = ttAdvertisementService;
}
@GetMapping("/list")
public PageDataInfo<TtAdvertisement> list() {
startPage();
List<TtAdvertisement> list = ttAdvertisementService.list();
return getPageData(list);
}
@GetMapping(value = "/{id}")
public R<TtAdvertisement> getInfo(@PathVariable("id") Integer id) {
TtAdvertisement ttAdvertisement = ttAdvertisementService.getById(id);
// ttBanner.setPicture("");
return R.ok(ttAdvertisement);
}
@PostMapping
public AjaxResult add(@RequestBody TtAdvertisement ttAdvertisement) {
if (StringUtils.isEmpty(ttAdvertisement.getPicture())) ttAdvertisement.setPicture("");
else ttAdvertisement.setPicture(RuoYiConfig.getDomainName() + ttAdvertisement.getPicture());
return toAjax(ttAdvertisementService.save(ttAdvertisement));
}
@PutMapping
public AjaxResult edit(@RequestBody TtAdvertisement ttAdvertisement) {
String msg = ttAdvertisementService.updatePicById(ttAdvertisement);
return StringUtils.isEmpty(msg) ? AjaxResult.success() : AjaxResult.error(msg);
}
@DeleteMapping("/{ids}")
public AjaxResult remove(@PathVariable Integer[] ids) {
return toAjax(ttAdvertisementService.removeByIds(Arrays.asList(ids)));
}
}
@@ -0,0 +1,79 @@
package com.ruoyi.admin.controller;
import com.ruoyi.admin.mapper.TtAnnouncementMapper;
import com.ruoyi.common.enums.BusinessType;
import com.ruoyi.common.annotation.Log;
import com.ruoyi.admin.service.TtAnnouncementService;
import com.ruoyi.common.annotation.Anonymous;
import com.ruoyi.common.core.controller.BaseController;
import com.ruoyi.common.core.domain.AjaxResult;
import com.ruoyi.common.core.page.PageDataInfo;
import com.ruoyi.common.utils.SecurityUtils;
import com.ruoyi.domain.other.TtAnnouncement;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.MediaType;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.servlet.mvc.method.annotation.SseEmitter;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
@RestController
@RequestMapping("/admin/announcement")
public class TtAnnouncementController extends BaseController {
@Autowired
private TtAnnouncementService ttAnnouncementService;
/**
* 获取公告列表
*/
@GetMapping("/list")
public PageDataInfo<TtAnnouncement> list(TtAnnouncement query) {
startPage();
List<TtAnnouncement> announcementList = ttAnnouncementService.getAnnouncementList(query);
return getPageData(announcementList);
}
/**
* 获取公告详情
*/
@GetMapping("/{announcementId}")
public AjaxResult getAnnouncementByAnnouncementId(@PathVariable Integer announcementId) {
Long userId = SecurityUtils.getUserId();
TtAnnouncement ttAnnouncement = ttAnnouncementService.getAnnouncementByAnnouncementId(userId, announcementId);
return AjaxResult.success(ttAnnouncement);
}
@Log(title = "公告", action = "新增", businessType = BusinessType.INSERT,
entityClass = TtAnnouncement.class, mapperClass = TtAnnouncementMapper.class)
/**
* 新增公告
*/
@PostMapping
public AjaxResult addAnnouncement(@RequestBody TtAnnouncement ttAnnouncement) {
return ttAnnouncementService.addAnnouncement(ttAnnouncement) > 0 ? AjaxResult.success("新增成功") : AjaxResult.error("新增失败");
}
@Log(title = "公告", action = "修改", businessType = BusinessType.UPDATE,
entityClass = TtAnnouncement.class, mapperClass = TtAnnouncementMapper.class)
/**
* 修改公告
*/
@PutMapping
public AjaxResult editAnnouncement(@RequestBody TtAnnouncement ttAnnouncement) {
return ttAnnouncementService.editAnnouncement(ttAnnouncement) > 0 ? AjaxResult.success("修改成功") : AjaxResult.error("修改失败");
}
@Log(title = "公告", action = "删除", businessType = BusinessType.DELETE)
/**
* 删除公告
*/
@DeleteMapping("/{announcementId}")
public AjaxResult removeAnnouncementByAnnouncementId(@PathVariable Integer announcementId) {
return ttAnnouncementService.removeAnnouncementByAnnouncementId(announcementId) > 0 ? AjaxResult.success("删除成功") : AjaxResult.error("删除失败");
}
}
@@ -0,0 +1,67 @@
package com.ruoyi.admin.controller;
import com.ruoyi.admin.mapper.TtBannerMapper;
import com.ruoyi.common.enums.BusinessType;
import com.ruoyi.common.annotation.Log;
import com.ruoyi.domain.other.TtBanner;
import com.ruoyi.admin.service.TtBannerService;
import com.ruoyi.common.config.RuoYiConfig;
import com.ruoyi.common.annotation.Anonymous;
import com.ruoyi.common.core.controller.BaseController;
import com.ruoyi.common.core.domain.AjaxResult;
import com.ruoyi.common.core.domain.R;
import com.ruoyi.common.core.page.PageDataInfo;
import com.ruoyi.common.utils.StringUtils;
import org.springframework.web.bind.annotation.*;
import java.util.Arrays;
import java.util.List;
@RestController
@RequestMapping("/admin/banner")
public class TtBannerController extends BaseController {
private final TtBannerService bannerService;
public TtBannerController(TtBannerService bannerService) {
this.bannerService = bannerService;
}
@Anonymous
@GetMapping("/list")
public PageDataInfo<TtBanner> list() {
startPage();
List<TtBanner> list = bannerService.list();
return getPageData(list);
}
@GetMapping(value = "/{id}")
public R<TtBanner> getInfo(@PathVariable("id") Integer id) {
TtBanner ttBanner = bannerService.getById(id);
// ttBanner.setPicture("");
return R.ok(ttBanner);
}
@Log(title = "Banner设置", action = "新增", businessType = BusinessType.INSERT,
entityClass = TtBanner.class, mapperClass = TtBannerMapper.class)
@PostMapping
public AjaxResult add(@RequestBody TtBanner ttBanner) {
if (StringUtils.isEmpty(ttBanner.getPicture())) ttBanner.setPicture("");
else ttBanner.setPicture(RuoYiConfig.getDomainName() + ttBanner.getPicture());
return toAjax(bannerService.save(ttBanner));
}
@Log(title = "Banner设置", action = "修改", businessType = BusinessType.UPDATE,
entityClass = TtBanner.class, mapperClass = TtBannerMapper.class)
@PutMapping
public AjaxResult edit(@RequestBody TtBanner ttBanner) {
String msg = bannerService.updateBannerById(ttBanner);
return StringUtils.isEmpty(msg) ? AjaxResult.success() : AjaxResult.error(msg);
}
@Log(title = "Banner设置", action = "删除", businessType = BusinessType.DELETE)
@DeleteMapping("/{ids}")
public AjaxResult remove(@PathVariable Integer[] ids) {
return toAjax(bannerService.removeByIds(Arrays.asList(ids)));
}
}
@@ -0,0 +1,75 @@
package com.ruoyi.admin.controller;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.ruoyi.admin.mapper.TtBonusMapper;
import com.ruoyi.common.enums.BusinessType;
import com.ruoyi.common.annotation.Log;
import com.ruoyi.domain.other.TtBonus;
import com.ruoyi.admin.service.TtBonusService;
import com.ruoyi.common.config.RuoYiConfig;
import com.ruoyi.common.core.controller.BaseController;
import com.ruoyi.common.core.domain.AjaxResult;
import com.ruoyi.common.core.domain.R;
import com.ruoyi.common.core.page.PageDataInfo;
import com.ruoyi.common.utils.DateUtils;
import com.ruoyi.common.utils.StringUtils;
import org.springframework.web.bind.annotation.*;
import java.util.Arrays;
import java.util.List;
@RestController
@RequestMapping("/admin/bonus")
public class TtBonusController extends BaseController {
private final TtBonusService bonusService;
public TtBonusController(TtBonusService bonusService) {
this.bonusService = bonusService;
}
@GetMapping("/list")
public PageDataInfo<TtBonus> list(String type){
startPage();
LambdaQueryWrapper<TtBonus> wrapper = Wrappers.lambdaQuery();
if (StringUtils.isNotEmpty(type)) wrapper.eq(TtBonus::getType, type);
List<TtBonus> list = bonusService.list(wrapper);
return getPageData(list);
}
@GetMapping(value = "/{id}")
public R<TtBonus> getInfo(@PathVariable("id") Integer id) {
TtBonus bonus = bonusService.getById(id);
bonus.setCoverPicture("");
return R.ok(bonus);
}
@Log(title = "彩金", action = "新增", businessType = BusinessType.INSERT,
entityClass = TtBonus.class, mapperClass = TtBonusMapper.class)
@PostMapping
public AjaxResult add(@RequestBody TtBonus ttBonus) {
if (StringUtils.isEmpty(ttBonus.getCoverPicture())) ttBonus.setCoverPicture("");
else ttBonus.setCoverPicture(RuoYiConfig.getDomainName() + ttBonus.getCoverPicture());
ttBonus.setCreateBy(getUsername());
ttBonus.setCreateTime(DateUtils.getNowDate());
return toAjax(bonusService.save(ttBonus));
}
@Log(title = "彩金", action = "修改", businessType = BusinessType.UPDATE,
entityClass = TtBonus.class, mapperClass = TtBonusMapper.class)
@PutMapping
public AjaxResult edit(@RequestBody TtBonus ttBonus) {
ttBonus.setUpdateBy(getUsername());
ttBonus.setUpdateTime(DateUtils.getNowDate());
String msg = bonusService.updateBonusById(ttBonus);
return StringUtils.isEmpty(msg) ? AjaxResult.success() : AjaxResult.error(msg);
}
@Log(title = "彩金", action = "删除", businessType = BusinessType.DELETE)
@DeleteMapping("/{ids}")
public AjaxResult remove(@PathVariable Integer[] ids) {
return toAjax(bonusService.removeByIds(Arrays.asList(ids)));
}
}
@@ -0,0 +1,157 @@
package com.ruoyi.admin.controller;
import com.ruoyi.admin.mapper.TtBoxMapper;
import com.ruoyi.common.enums.BusinessType;
import com.ruoyi.common.annotation.Log;
import com.ruoyi.admin.domain.body.BoxMockRequest;
import com.ruoyi.admin.model.BoxMockCache;
import com.ruoyi.admin.service.BoxMockService;
import com.ruoyi.admin.service.TtBoxService;
import com.ruoyi.admin.util.core.fight.LotteryMachine;
import com.ruoyi.common.core.controller.BaseController;
import com.ruoyi.common.core.domain.AjaxResult;
import com.ruoyi.common.core.domain.R;
import com.ruoyi.common.core.page.PageDataInfo;
import com.ruoyi.common.utils.DateUtils;
import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.common.utils.poi.ExcelUtil;
import com.ruoyi.domain.other.TtBox;
import com.ruoyi.domain.other.TtBoxBody;
import com.ruoyi.domain.vo.BoxPoolStatisticsVO;
import com.ruoyi.domain.vo.TtBoxDataVO;
import com.ruoyi.domain.vo.box.TtBoxUserVO;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import jakarta.servlet.http.HttpServletResponse;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import java.util.Arrays;
import java.util.Date;
import java.util.List;
@Api(tags = "管理端 宝箱管理")
@RestController
@RequestMapping("/admin/box")
public class TtBoxController extends BaseController {
@Autowired
private TtBoxService boxService;
@Autowired
private LotteryMachine lotteryMachine;
@Autowired
private BoxMockService boxMockService;
@GetMapping("/test")
public AjaxResult test() {
return success();
}
@ApiOperation("获取宝箱列表")
@GetMapping("/list")
public PageDataInfo<TtBoxDataVO> list(TtBoxBody ttBoxBody) {
startPage();
return boxService.selectTtBoxList(ttBoxBody);
}
@GetMapping(value = "/{boxId}")
public R<TtBox> getInfo(@PathVariable("boxId") Long boxId) {
TtBox ttBox = boxService.getById(boxId);
return R.ok(ttBox);
}
@Log(title = "宝箱列表", action = "新增", businessType = BusinessType.INSERT,
entityClass = TtBox.class, mapperClass = TtBoxMapper.class)
@PostMapping
public AjaxResult add(@RequestBody TtBox ttBox) {
ttBox.setCreateBy(getUsername());
ttBox.setCreateTime(DateUtils.getNowDate());
return toAjax(boxService.save(ttBox));
}
@Log(title = "宝箱列表", action = "修改", businessType = BusinessType.UPDATE)
@ApiOperation("修改宝箱")
@PutMapping
public AjaxResult edit(@RequestBody TtBoxDataVO ttBoxDataVO) {
String msg = boxService.updateTtBoxById(ttBoxDataVO);
return StringUtils.isEmpty(msg) ? AjaxResult.success() : AjaxResult.error(msg);
}
@ApiOperation("清空当前奖池")
@GetMapping("clearPrizePool/{boxId}")
public R clearPrizePool(@PathVariable("boxId") Integer boxId) {
lotteryMachine.clearBoxPrizePool(boxId);
return R.ok("清空当前奖池成功。");
}
@Log(title = "宝箱列表", action = "删除", businessType = BusinessType.DELETE)
@DeleteMapping("/{boxIds}")
public AjaxResult remove(@PathVariable Long[] boxIds) {
return toAjax(boxService.removeByIds(Arrays.asList(boxIds)));
}
@Log(title = "宝箱列表", action = "重置宝箱", businessType = BusinessType.CLEAN,
entityClass = TtBox.class, mapperClass = TtBoxMapper.class, idField = "boxId")
@GetMapping("/resetBox/{boxId}")
public AjaxResult resetBox(@PathVariable Integer boxId) {
boxService.isReplenishment(boxId);
return AjaxResult.success();
}
@ApiOperation("宝箱统计(按奖池/开箱人类型拆分)")
@GetMapping("/statisticsBoxData/{boxId}")
public R<List<BoxPoolStatisticsVO>> statisticsBoxData(@PathVariable Integer boxId, @RequestParam(required = false) Date date) {
List<BoxPoolStatisticsVO> poolStatistics = boxService.statisticsBoxData(boxId, date);
return R.ok(poolStatistics);
}
@ApiOperation("添加宝箱三级爆率玩家范围")
@PostMapping("/createTtBoxThirdExplosiveUsers")
public AjaxResult createTtBoxThirdExplosiveUsers(@RequestBody TtBoxUserVO ttBoxUserVO) {
String msg = boxService.createTtBoxThirdExplosiveUsers(ttBoxUserVO);
return StringUtils.isEmpty(msg) ? AjaxResult.success() : AjaxResult.error(msg);
}
@ApiOperation("查询宝箱三级爆率玩家范围")
@GetMapping("/queryTtBoxThirdExplosiveUsers/{boxId}")
public AjaxResult queryBoxUsers(@PathVariable Integer boxId) {
return boxService.queryTtBoxThirdExplosiveUsers(boxId);
}
@ApiOperation("删除宝箱三级爆率玩家范围")
@PostMapping("/deleteTtBoxThirdExplosiveUsers")
public AjaxResult deleteTtBoxThirdExplosiveUsers(@RequestBody TtBoxUserVO ttBoxUserVO) {
return boxService.deleteTtBoxThirdExplosiveUsers(ttBoxUserVO);
}
@PostMapping("/export")
public void export(HttpServletResponse response, TtBoxBody ttBoxBody) {
var list = boxService.selectTtBoxList(ttBoxBody);
ExcelUtil<TtBoxDataVO> util = new ExcelUtil<>(TtBoxDataVO.class);
util.exportExcel(response, list.getRows(), "宝箱列表");
}
@ApiOperation("查询开箱临时爆率队列")
@GetMapping("/mockresult/list")
public R<List<BoxMockCache.MockItem>> getBoxMockResult(@RequestParam("uid") Integer uid) {
return R.ok(boxMockService.getMockResultList(uid));
}
@ApiOperation("设置开箱临时爆率队列")
@PostMapping("/mockresult/list")
public R<List<BoxMockCache.MockItem>> updateBoxMockResult(@RequestBody BoxMockRequest request) {
return R.ok(boxMockService.updateMockResultList(request));
}
}
@@ -0,0 +1,94 @@
package com.ruoyi.admin.controller;
import java.util.List;
import jakarta.servlet.http.HttpServletResponse;
import org.springframework.security.access.prepost.PreAuthorize;
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.PutMapping;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import com.ruoyi.admin.mapper.TtBoxOpenChanceMapper;
import com.ruoyi.common.annotation.Log;
import com.ruoyi.common.core.controller.BaseController;
import com.ruoyi.common.core.domain.AjaxResult;
import com.ruoyi.common.enums.BusinessType;
import com.ruoyi.admin.domain.TtBoxOpenChance;
import com.ruoyi.admin.service.TtBoxOpenChanceService;
import com.ruoyi.common.utils.poi.ExcelUtil;
import com.ruoyi.common.core.page.TableDataInfo;
/**
* 开箱机会Controller
*
* @author ruoyi
* @date 2024-07-09
*/
@RestController
@RequestMapping("/admin/chance")
public class TtBoxOpenChanceController extends BaseController
{
@Autowired
private TtBoxOpenChanceService ttBoxOpenChanceService;
/**
* 查询开箱机会列表
*/
@PreAuthorize("@ss.hasPermi('admin:chance:list')")
@GetMapping("/list")
public TableDataInfo list(TtBoxOpenChance ttBoxOpenChance)
{
startPage();
List<TtBoxOpenChance> list = ttBoxOpenChanceService.selectTtBoxOpenChanceList(ttBoxOpenChance);
return getDataTable(list);
}
/**
* 获取开箱机会详细信息
*/
@PreAuthorize("@ss.hasPermi('admin:chance:query')")
@GetMapping(value = "/{ornamentId}")
public AjaxResult getInfo(@PathVariable("ornamentId") Integer ornamentId)
{
return success(ttBoxOpenChanceService.selectTtBoxOpenChanceByOrnamentId(ornamentId));
}
/**
* 新增开箱机会
*/
@PreAuthorize("@ss.hasPermi('admin:chance:add')")
@Log(title = "开箱机会", action = "新增", businessType = BusinessType.INSERT,
entityClass = TtBoxOpenChance.class, mapperClass = TtBoxOpenChanceMapper.class)
@PostMapping
public AjaxResult add(@RequestBody TtBoxOpenChance ttBoxOpenChance)
{
return toAjax(ttBoxOpenChanceService.insertTtBoxOpenChance(ttBoxOpenChance));
}
/**
* 修改开箱机会
*/
@PreAuthorize("@ss.hasPermi('admin:chance:edit')")
@Log(title = "开箱机会", action = "修改", businessType = BusinessType.UPDATE,
entityClass = TtBoxOpenChance.class, mapperClass = TtBoxOpenChanceMapper.class)
@PutMapping
public AjaxResult edit(@RequestBody TtBoxOpenChance ttBoxOpenChance)
{
return toAjax(ttBoxOpenChanceService.updateTtBoxOpenChance(ttBoxOpenChance));
}
/**
* 删除开箱机会
*/
@PreAuthorize("@ss.hasPermi('admin:chance:remove')")
@Log(title = "开箱机会", action = "删除", businessType = BusinessType.DELETE)
@DeleteMapping("/{ornamentIds}")
public AjaxResult remove(@PathVariable Integer[] ornamentIds)
{
return toAjax(ttBoxOpenChanceService.deleteTtBoxOpenChanceByOrnamentIds(ornamentIds));
}
}
@@ -0,0 +1,132 @@
package com.ruoyi.admin.controller;
import com.ruoyi.admin.mapper.TtBoxOrnamentsMapper;
import com.ruoyi.common.enums.BusinessType;
import com.ruoyi.common.annotation.Log;
import com.ruoyi.domain.other.TtBoxOrnaments;
import com.ruoyi.admin.service.TtBoxOrnamentsService;
import com.ruoyi.domain.vo.TtBoxOrnamentsDataVO;
import com.ruoyi.common.core.controller.BaseController;
import com.ruoyi.common.core.domain.AjaxResult;
import com.ruoyi.common.core.domain.R;
import com.ruoyi.common.core.page.PageDataInfo;
import com.ruoyi.common.utils.DateUtils;
import com.ruoyi.common.utils.StringUtils;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.springframework.web.bind.annotation.*;
import jakarta.validation.constraints.NotEmpty;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@Api(tags = "管理端 宝箱物品")
@RestController
@RequestMapping("/admin/boxOrnaments")
public class TtBoxOrnamentsController extends BaseController {
private final TtBoxOrnamentsService boxOrnamentsService;
public TtBoxOrnamentsController(TtBoxOrnamentsService boxOrnamentsService) {
this.boxOrnamentsService = boxOrnamentsService;
}
@ApiOperation("宝箱物品详情")
@GetMapping("/list/{boxId}")
public PageDataInfo<TtBoxOrnamentsDataVO> list(@PathVariable("boxId") Integer boxId) {
// 在分页之前算总数(避免PageHelper干扰百分比计算)
int[] totals = boxOrnamentsService.sumOdds(boxId);
startPage();
List<TtBoxOrnamentsDataVO> list = boxOrnamentsService.selectTtBoxOrnamentsListWithTotals(boxId,
totals[0], totals[1], totals[2], totals[3], totals[4], totals[5], totals[6], totals[7]);
return getPageData(list);
}
@ApiOperation("宝箱统计数据")
@GetMapping("/globalData/{boxId}")
public R globalData(@PathVariable("boxId") Integer boxId) {
return boxOrnamentsService.globalData(boxId);
}
@GetMapping(value = "/{id}")
public R<TtBoxOrnaments> getInfo(@PathVariable("id") Integer id) {
TtBoxOrnaments ttBoxOrnaments = boxOrnamentsService.getById(id);
return R.ok(ttBoxOrnaments);
}
@Log(title = "宝箱列表", action = "新增", businessType = BusinessType.INSERT,
entityClass = TtBoxOrnaments.class, mapperClass = TtBoxOrnamentsMapper.class)
@PostMapping
public AjaxResult add(@RequestBody TtBoxOrnaments ttBoxOrnaments) {
ttBoxOrnaments.setCreateBy(getUsername());
ttBoxOrnaments.setCreateTime(DateUtils.getNowDate());
String msg = boxOrnamentsService.saveBoxOrnaments(ttBoxOrnaments);
return StringUtils.isEmpty(msg) ? AjaxResult.success() : AjaxResult.error(msg);
}
@Log(title = "宝箱列表", action = "修改", businessType = BusinessType.UPDATE)
/**
* 修改宝箱物品
*
* @param ttBoxOrnamentsDataVO
* @return
*/
@PutMapping
public AjaxResult edit(@RequestBody TtBoxOrnamentsDataVO ttBoxOrnamentsDataVO) {
String msg = boxOrnamentsService.updateBoxOrnamentsById(ttBoxOrnamentsDataVO);
return StringUtils.isEmpty(msg) ? AjaxResult.success() : AjaxResult.error(msg);
}
@Log(title = "宝箱列表", action = "删除", businessType = BusinessType.DELETE)
@DeleteMapping("/{boxId}/{ids}")
public AjaxResult remove(@PathVariable Integer boxId, @PathVariable Long[] ids) {
String msg = boxOrnamentsService.removeBoxOrnamentsByIds(boxId, Arrays.asList(ids));
return StringUtils.isEmpty(msg) ? AjaxResult.success() : AjaxResult.error(msg);
}
@GetMapping("/getProfitMargin/{boxId}")
public AjaxResult getProfitMargin(@PathVariable("boxId") Integer boxId) {
return boxOrnamentsService.getProfitMargin(boxId);
}
/**
* 校验饰品是否可添加到宝箱(饰品独占机制)
* 始终返回成功响应,通过 data.available 表示是否可用,data.msg 说明被哪个宝箱占用,
* 避免走全局错误拦截导致前端无法读取具体提示。
*/
@GetMapping("/checkOrnament/{ornamentId}")
public R<Map<String, Object>> checkOrnament(@PathVariable("ornamentId") Long ornamentId) {
String msg = boxOrnamentsService.checkOrnamentUnique(ornamentId, null);
Map<String, Object> result = new HashMap<>();
result.put("available", StringUtils.isEmpty(msg));
result.put("msg", msg == null ? "" : msg);
return R.ok(result);
}
@AllArgsConstructor
@NoArgsConstructor
@Data
@Builder
public static class batchAddParam{
private Integer boxId;
private Integer partyType;
// private List<Integer> ornamentsIds;
@NotEmpty(message = "物品id不能为空")
private List<Long> ornamentIds;
}
@Log(title = "宝箱列表", action = "批量填货", businessType = BusinessType.INSERT)
// 宝箱填货
@ApiOperation("宝箱填货")
@PostMapping("/batchAdd")
public AjaxResult batchAdd(@RequestBody batchAddParam param) {
return boxOrnamentsService.batchAdd(param);
}
}
@@ -0,0 +1,30 @@
package com.ruoyi.admin.controller;
import com.ruoyi.admin.service.TtBoxRecordsService;
import com.ruoyi.domain.other.TtBoxRecordsBody;
import com.ruoyi.domain.vo.TtBoxRecordsDataVO;
import com.ruoyi.common.core.controller.BaseController;
import com.ruoyi.common.core.page.PageDataInfo;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.List;
@RestController
@RequestMapping("/admin/boxRecords")
public class TtBoxRecordsController extends BaseController {
private final TtBoxRecordsService boxRecordsService;
public TtBoxRecordsController(TtBoxRecordsService boxRecordsService) {
this.boxRecordsService = boxRecordsService;
}
@GetMapping("/list")
public PageDataInfo<TtBoxRecordsDataVO> list(TtBoxRecordsBody ttBoxRecordsBody) {
startPage();
List<TtBoxRecordsDataVO> list = boxRecordsService.selectBoxRecordsList(ttBoxRecordsBody);
return getPageData(list);
}
}
@@ -0,0 +1,74 @@
package com.ruoyi.admin.controller;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.ruoyi.admin.mapper.TtBoxTypeMapper;
import com.ruoyi.common.enums.BusinessType;
import com.ruoyi.common.annotation.Log;
import com.ruoyi.domain.other.TtBoxType;
import com.ruoyi.admin.service.TtBoxTypeService;
import com.ruoyi.common.config.RuoYiConfig;
import com.ruoyi.common.core.controller.BaseController;
import com.ruoyi.common.core.domain.AjaxResult;
import com.ruoyi.common.core.domain.R;
import com.ruoyi.common.core.page.PageDataInfo;
import com.ruoyi.common.utils.DateUtils;
import com.ruoyi.common.utils.StringUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.*;
import java.util.Arrays;
import java.util.List;
@RestController
@RequestMapping("/admin/boxType")
@Slf4j
public class TtBoxTypeController extends BaseController {
private final TtBoxTypeService boxTypeService;
public TtBoxTypeController(TtBoxTypeService boxTypeService) {
this.boxTypeService = boxTypeService;
}
@GetMapping("/list")
public PageDataInfo<TtBoxType> list(@RequestParam(required = false) String isFightType) {
startPage();
LambdaQueryWrapper<TtBoxType> wrapper = Wrappers.lambdaQuery();
if (StringUtils.isNotEmpty(isFightType)) wrapper.eq(TtBoxType::getIsFightType, isFightType);
List<TtBoxType> list = boxTypeService.list(wrapper);
return getPageData(list);
}
@GetMapping(value = "/{id}")
public R<TtBoxType> getInfo(@PathVariable("id") Integer id) {
TtBoxType boxType = boxTypeService.getById(id);
return R.ok(boxType);
}
@Log(title = "宝箱分类", action = "新增", businessType = BusinessType.INSERT,
entityClass = TtBoxType.class, mapperClass = TtBoxTypeMapper.class)
@PostMapping
public AjaxResult add(@RequestBody TtBoxType ttBoxType) {
if (StringUtils.isEmpty(ttBoxType.getIcon())) ttBoxType.setIcon("");
else ttBoxType.setIcon(RuoYiConfig.getDomainName() + ttBoxType.getIcon());
ttBoxType.setCreateTime(DateUtils.getNowDate());
return toAjax(boxTypeService.save(ttBoxType));
}
@Log(title = "宝箱分类", action = "修改", businessType = BusinessType.UPDATE,
entityClass = TtBoxType.class, mapperClass = TtBoxTypeMapper.class)
@PutMapping
public AjaxResult edit(@RequestBody TtBoxType ttBoxType) {
ttBoxType.setUpdateTime(DateUtils.getNowDate());
String msg = boxTypeService.updateBoxTypeById(ttBoxType);
return StringUtils.isEmpty(msg) ? AjaxResult.success() : AjaxResult.error(msg);
}
@Log(title = "宝箱分类", action = "删除", businessType = BusinessType.DELETE)
@DeleteMapping("/{ids}")
public AjaxResult remove(@PathVariable Integer[] ids) {
return toAjax(boxTypeService.removeByIds(Arrays.asList(ids)));
}
}
@@ -0,0 +1,255 @@
package com.ruoyi.admin.controller;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.extension.conditions.query.LambdaQueryChainWrapper;
import com.ruoyi.common.enums.BusinessType;
import com.ruoyi.common.annotation.Log;
import com.ruoyi.admin.config.RedisConstants;
import com.ruoyi.admin.mapper.TtUserBlendErcashMapper;
import com.ruoyi.admin.mapper.TtUserMapper;
import com.ruoyi.admin.service.TtUserService;
import com.ruoyi.common.core.controller.BaseController;
import com.ruoyi.common.core.domain.AjaxResult;
import com.ruoyi.common.core.page.PageDataInfo;
import com.ruoyi.common.redis.config.RedisLock;
import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.common.utils.ip.IpUtils;
import com.ruoyi.domain.common.constant.TtAccountRecordSource;
import com.ruoyi.domain.common.constant.TtAccountRecordType;
import com.ruoyi.domain.common.constant.UserType;
import com.ruoyi.domain.entity.TtUserBlendErcash;
import com.ruoyi.domain.entity.sys.TtUser;
import com.ruoyi.domain.vo.user.TtUserVo;
import io.swagger.annotations.ApiOperation;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.*;
import java.math.BigDecimal;
import java.sql.Timestamp;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;
@RestController
@RequestMapping("/admin/cardMerchant")
public class TtCardMerchantController extends BaseController {
@Autowired
private TtUserService userService;
@Autowired
private TtUserMapper ttUserMapper;
@Autowired
private TtUserBlendErcashMapper blendErcashMapper;
@Autowired
private RedisLock redisLock;
@ApiOperation("获取卡商列表")
@GetMapping("/list")
public PageDataInfo<TtUserVo> cardMerchantList(
@RequestParam(required = false) Integer userId,
@RequestParam(required = false) String phoneNumber) {
startPage();
LambdaQueryChainWrapper<TtUser> query = new LambdaQueryChainWrapper<>(ttUserMapper)
.eq(TtUser::getUserType, UserType.CARD_MERCHANT.getCode())
.and(w -> w.eq(TtUser::getDelFlag, "0").or().isNull(TtUser::getDelFlag));
if (userId != null) {
query.eq(TtUser::getUserId, userId);
}
if (phoneNumber != null && !phoneNumber.isEmpty()) {
query.like(TtUser::getPhoneNumber, phoneNumber);
}
List<TtUser> merchants = query.orderByDesc(TtUser::getCreateTime).list();
PageDataInfo<TtUserVo> pageData = new PageDataInfo<>();
pageData.setCode(200);
pageData.setTotal(new com.github.pagehelper.PageInfo<>(merchants).getTotal());
List<TtUserVo> voList = new ArrayList<>();
for (TtUser m : merchants) {
TtUserVo vo = TtUserVo.builder()
.userId(m.getUserId())
.userName(m.getUserName())
.nickName(m.getNickName())
.phoneNumber(m.getPhoneNumber())
.merchantBalance(m.getMerchantBalance() != null ? m.getMerchantBalance() : BigDecimal.ZERO)
.status(m.getStatus())
.createTime(m.getCreateTime())
.build();
voList.add(vo);
}
pageData.setRows(voList);
return pageData;
}
@Log(title = "卡商充值", action = "确认充值", businessType = BusinessType.GRANT,
entityClass = TtUser.class, mapperClass = TtUserMapper.class, idField = "userId")
@ApiOperation("卡商充值(管理员给卡商增加余额)")
@PostMapping("/recharge")
public AjaxResult cardMerchantRecharge(@RequestBody Map<String, Object> params) {
Integer userId = (Integer) params.get("userId");
String amountStr = String.valueOf(params.get("amount"));
if (userId == null || amountStr == null) {
return AjaxResult.error("参数不完整");
}
BigDecimal amount;
try {
amount = new BigDecimal(amountStr);
} catch (NumberFormatException e) {
return AjaxResult.error("金额格式错误");
}
if (amount.compareTo(BigDecimal.ZERO) <= 0) {
return AjaxResult.error("充值金额必须大于0");
}
// 防重:按卡商加锁(锁粒度=单卡商,不影响其他卡商)。充值走的是「加钱」语义,
// 同一笔充值被应用两次就是多加一次钱,前端 :loading 是异步渲染挡不住双击/弱网重试
String lockKey = RedisConstants.CARD_MERCHANT_BALANCE_LOCK + userId;
if (!redisLock.tryLock(lockKey, 0L, 30L, TimeUnit.SECONDS)) {
return AjaxResult.error("该卡商余额正在变更,请勿重复提交");
}
try {
TtUser user = userService.getById(userId);
if (user == null) {
return AjaxResult.error("用户不存在");
}
if (!UserType.CARD_MERCHANT.getCode().equals(user.getUserType())) {
return AjaxResult.error("该用户不是卡商");
}
// 直接操作 merchant_balance 字段,不影响 account_amount/account_credits
int count = ttUserMapper.addMerchantBalance(Long.valueOf(userId), amount);
if (count <= 0) {
return AjaxResult.error("充值失败");
}
BigDecimal newBalance = (user.getMerchantBalance() != null ? user.getMerchantBalance() : BigDecimal.ZERO).add(amount);
// 操作人 + 登录IP 记入备注,便于审计是谁给卡商充值的
String operName = getUsername();
String operIp = getLoginUser().getIpaddr();
if (StringUtils.isEmpty(operIp)) {
operIp = IpUtils.getIpAddr();
}
String remark = TtAccountRecordSource.CARD_MERCHANT_RECHARGE.getMsg()
+ "(操作人:" + operName + ",登录IP:" + operIp + ")";
// 记录流水到 blend_ercash(仅用于卡商充值记录展示)
TtUserBlendErcash blendErcash = TtUserBlendErcash.builder()
.userId(userId)
.amount(BigDecimal.ZERO)
.finalAmount(user.getAccountAmount())
.credits(amount)
.finalCredits(newBalance)
.total(amount)
.type(TtAccountRecordType.INPUT.getCode())
.source(TtAccountRecordSource.CARD_MERCHANT_RECHARGE.getCode())
.remark(remark)
.createTime(new Timestamp(System.currentTimeMillis()))
.updateTime(new Timestamp(System.currentTimeMillis()))
.build();
blendErcashMapper.insert(blendErcash);
return AjaxResult.success("充值成功,当前卡商余额:" + newBalance);
} finally {
redisLock.unlock(lockKey);
}
}
@Log(title = "卡商充值", action = "确认修改", businessType = BusinessType.UPDATE,
entityClass = TtUser.class, mapperClass = TtUserMapper.class, idField = "userId")
@ApiOperation("修改卡商余额(直接设为指定值,按差额写审计流水)")
@PostMapping("/updateBalance")
@Transactional(rollbackFor = Exception.class)
public AjaxResult cardMerchantUpdateBalance(@RequestBody Map<String, Object> params) {
Integer userId = (Integer) params.get("userId");
Object balanceObj = params.get("balance");
if (userId == null || balanceObj == null) {
return AjaxResult.error("参数不完整");
}
BigDecimal newBalance;
try {
newBalance = new BigDecimal(String.valueOf(balanceObj));
} catch (NumberFormatException e) {
return AjaxResult.error("余额格式错误");
}
if (newBalance.compareTo(BigDecimal.ZERO) < 0) {
return AjaxResult.error("卡商余额不能为负数");
}
// 防重/防并发:按卡商加锁,锁覆盖「读旧余额 → 写新余额 → 记流水」全过程。
// 否则两个并发请求会各自读到同一个旧余额、各自算出差额,导致差额被加两次
String lockKey = RedisConstants.CARD_MERCHANT_BALANCE_LOCK + userId;
if (!redisLock.tryLock(lockKey, 0L, 30L, TimeUnit.SECONDS)) {
return AjaxResult.error("该卡商余额正在变更,请勿重复提交");
}
try {
TtUser user = userService.getById(userId);
if (user == null) {
return AjaxResult.error("用户不存在");
}
if (!UserType.CARD_MERCHANT.getCode().equals(user.getUserType())) {
return AjaxResult.error("该用户不是卡商");
}
BigDecimal oldBalance = user.getMerchantBalance() != null ? user.getMerchantBalance() : BigDecimal.ZERO;
BigDecimal delta = newBalance.subtract(oldBalance);
if (delta.compareTo(BigDecimal.ZERO) == 0) {
return AjaxResult.error("新余额与当前卡商余额相同,无需修改");
}
// 按绝对值写入(而不是 += 差额):天然幂等,弱网重试/重复提交只会把余额写成同一个值;
// 只 set merchant_balance 一列,不触碰 account_amount / account_credits
LambdaUpdateWrapper<TtUser> balanceUpdate = new LambdaUpdateWrapper<>();
balanceUpdate.eq(TtUser::getUserId, userId)
.set(TtUser::getMerchantBalance, newBalance);
if (ttUserMapper.update(null, balanceUpdate) <= 0) {
return AjaxResult.error("修改失败,请刷新后重试");
}
// 操作人 + 登录IP + 变更前后值 记入备注,便于审计是谁把卡商余额改成了多少
String operName = getUsername();
String operIp = getLoginUser().getIpaddr();
if (StringUtils.isEmpty(operIp)) {
operIp = IpUtils.getIpAddr();
}
String remark = TtAccountRecordSource.ADMIN_ADJUST_MERCHANT_BALANCE.getMsg()
+ "(" + oldBalance.toPlainString() + "→" + newBalance.toPlainString()
+ ",操作人:" + operName + ",登录IP:" + operIp + ")";
// 与 45/46/55 同一记账约定:amount=0、credits 携带卡商余额变动、finalCredits 为变动后卡商余额
TtUserBlendErcash blendErcash = TtUserBlendErcash.builder()
.userId(userId)
.amount(BigDecimal.ZERO)
.finalAmount(user.getAccountAmount())
.credits(delta)
.finalCredits(newBalance)
.total(delta)
.type(delta.compareTo(BigDecimal.ZERO) > 0
? TtAccountRecordType.INPUT.getCode()
: TtAccountRecordType.OUTPUT.getCode())
.source(TtAccountRecordSource.ADMIN_ADJUST_MERCHANT_BALANCE.getCode())
.remark(remark)
.createTime(new Timestamp(System.currentTimeMillis()))
.updateTime(new Timestamp(System.currentTimeMillis()))
.build();
blendErcashMapper.insert(blendErcash);
return AjaxResult.success("修改成功,当前卡商余额:" + newBalance.toPlainString());
} finally {
redisLock.unlock(lockKey);
}
}
@ApiOperation("卡商充值记录")
@GetMapping("/rechargeLog")
public PageDataInfo<TtUserBlendErcash> cardMerchantRechargeLog(@RequestParam(required = false) Integer userId) {
LambdaQueryChainWrapper<TtUserBlendErcash> wrapper = new LambdaQueryChainWrapper<>(blendErcashMapper);
// 包含四种类型:充值、生成卡密消费、销毁退款、管理员调整余额
wrapper.in(TtUserBlendErcash::getSource,
TtAccountRecordSource.CARD_MERCHANT_RECHARGE.getCode(), // 46 充值
TtAccountRecordSource.CARD_MERCHANT_GENERATE.getCode(), // 45 生成卡密消费
TtAccountRecordSource.CARD_MERCHANT_DESTROY_REFUND.getCode(), // 55 销毁退款
TtAccountRecordSource.ADMIN_ADJUST_MERCHANT_BALANCE.getCode()); // 67 管理员调整余额
if (userId != null) {
wrapper.eq(TtUserBlendErcash::getUserId, userId);
}
wrapper.orderByDesc(TtUserBlendErcash::getCreateTime);
startPage();
List<TtUserBlendErcash> records = wrapper.list();
return getPageData(records);
}
}
@@ -0,0 +1,61 @@
package com.ruoyi.admin.controller;
import com.ruoyi.admin.mapper.TtContentMapper;
import com.ruoyi.common.enums.BusinessType;
import com.ruoyi.common.annotation.Log;
import com.ruoyi.domain.other.TtContent;
import com.ruoyi.admin.service.TtContentService;
import com.ruoyi.common.core.controller.BaseController;
import com.ruoyi.common.core.domain.AjaxResult;
import com.ruoyi.common.core.domain.R;
import com.ruoyi.common.core.page.PageDataInfo;
import com.ruoyi.common.utils.DateUtils;
import org.springframework.web.bind.annotation.*;
import java.util.Arrays;
import java.util.List;
@RestController
@RequestMapping("/admin/content")
public class TtContentController extends BaseController {
private final TtContentService contentService;
public TtContentController(TtContentService contentService) {
this.contentService = contentService;
}
@GetMapping("/list")
public PageDataInfo<TtContent> list(TtContent ttContent) {
startPage();
List<TtContent> list = contentService.queryList(ttContent);
return getPageData(list);
}
@GetMapping(value = "/{id}")
public R<TtContent> getInfo(@PathVariable("id") Long id) {
return R.ok(contentService.getById(id));
}
@Log(title = "文章", action = "新增", businessType = BusinessType.INSERT,
entityClass = TtContent.class, mapperClass = TtContentMapper.class)
@PostMapping
public AjaxResult add(@RequestBody TtContent ttContent) {
ttContent.setCreateTime(DateUtils.getNowDate());
return toAjax(contentService.save(ttContent));
}
@Log(title = "文章", action = "修改", businessType = BusinessType.UPDATE,
entityClass = TtContent.class, mapperClass = TtContentMapper.class)
@PutMapping
public AjaxResult edit(@RequestBody TtContent ttContent) {
ttContent.setUpdateTime(DateUtils.getNowDate());
return toAjax(contentService.updateById(ttContent));
}
@Log(title = "文章", action = "删除", businessType = BusinessType.DELETE)
@DeleteMapping("/{ids}")
public AjaxResult remove(@PathVariable Integer[] ids) {
return toAjax(contentService.removeByIds(Arrays.asList(ids)));
}
}
@@ -0,0 +1,61 @@
package com.ruoyi.admin.controller;
import com.ruoyi.admin.mapper.TtContentTypeMapper;
import com.ruoyi.common.enums.BusinessType;
import com.ruoyi.common.annotation.Log;
import com.ruoyi.domain.other.TtContentType;
import com.ruoyi.admin.service.TtContentTypeService;
import com.ruoyi.common.core.controller.BaseController;
import com.ruoyi.common.core.domain.AjaxResult;
import com.ruoyi.common.core.domain.R;
import com.ruoyi.common.core.page.PageDataInfo;
import com.ruoyi.common.utils.DateUtils;
import org.springframework.web.bind.annotation.*;
import java.util.Arrays;
import java.util.List;
@RestController
@RequestMapping("/admin/contentType")
public class TtContentTypeController extends BaseController {
private final TtContentTypeService contentTypeService;
public TtContentTypeController(TtContentTypeService contentTypeService) {
this.contentTypeService = contentTypeService;
}
@GetMapping("/list")
public PageDataInfo<TtContentType> list(TtContentType ttContentType) {
startPage();
List<TtContentType> list = contentTypeService.queryList(ttContentType);
return getPageData(list);
}
@GetMapping(value = "/{id}")
public R<TtContentType> getInfo(@PathVariable("id") Long id) {
return R.ok(contentTypeService.getById(id));
}
@Log(title = "文章类型", action = "新增", businessType = BusinessType.INSERT,
entityClass = TtContentType.class, mapperClass = TtContentTypeMapper.class)
@PostMapping
public AjaxResult add(@RequestBody TtContentType ttContentType) {
ttContentType.setCreateTime(DateUtils.getNowDate());
return toAjax(contentTypeService.save(ttContentType));
}
@Log(title = "文章类型", action = "修改", businessType = BusinessType.UPDATE,
entityClass = TtContentType.class, mapperClass = TtContentTypeMapper.class)
@PutMapping
public AjaxResult edit(@RequestBody TtContentType ttContentType) {
ttContentType.setUpdateTime(DateUtils.getNowDate());
return toAjax(contentTypeService.updateById(ttContentType));
}
@Log(title = "文章类型", action = "删除", businessType = BusinessType.DELETE)
@DeleteMapping("/{ids}")
public AjaxResult remove(@PathVariable Integer[] ids) {
return toAjax(contentTypeService.removeByIds(Arrays.asList(ids)));
}
}
@@ -0,0 +1,62 @@
package com.ruoyi.admin.controller;
import com.ruoyi.common.enums.BusinessType;
import com.ruoyi.common.annotation.Log;
import com.ruoyi.admin.service.TtDeliveryRecordService;
import com.ruoyi.domain.other.TtDeliveryApplyBody;
import com.ruoyi.domain.vo.DeliveryApplyVO;
import com.ruoyi.domain.other.TtDeliveryRecordBody;
import com.ruoyi.domain.vo.TtDeliveryRecordDataVO;
import com.ruoyi.common.core.controller.BaseController;
import com.ruoyi.common.core.domain.R;
import com.ruoyi.common.core.page.PageDataInfo;
import com.ruoyi.common.utils.StringUtils;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.springframework.web.bind.annotation.*;
import java.util.List;
@Api(tags = "管理端 发货管理")
@RestController
@RequestMapping("/admin/deliverGoods")
public class TtDeliveryRecordController extends BaseController {
private final TtDeliveryRecordService deliveryRecordService;
public TtDeliveryRecordController(TtDeliveryRecordService deliveryRecordService) {
this.deliveryRecordService = deliveryRecordService;
}
@ApiOperation("发货申请列表")
@GetMapping("/getDeliveryApplyList")
public PageDataInfo<DeliveryApplyVO> getDeliveryApplyList(TtDeliveryApplyBody deliveryApplyBody) {
startPage();
List<DeliveryApplyVO> list = deliveryRecordService.getDeliveryApplyList(deliveryApplyBody);
return getPageData(list);
}
@ApiOperation("退回发货申请")
@PostMapping("/deliveryFail")
public R<Boolean> deliveryFail(@RequestParam("deliveryRecordId") Integer deliveryRecordId, @RequestParam("message") String message) {
String msg = deliveryRecordService.deliveryFail(deliveryRecordId, message);
return StringUtils.isEmpty(msg) ? R.ok(true, "操作成功!") : R.fail(false, msg);
}
@Log(title = "发货记录", action = "确认发货", businessType = BusinessType.GRANT)
@ApiOperation("审核通过发货申请")
@PostMapping("/deliveryApprove")
public R<Boolean> deliveryApprove(@RequestParam("deliveryRecordId") Integer deliveryRecordId) {
String msg = deliveryRecordService.deliveryApprove(deliveryRecordId);
return StringUtils.isEmpty(msg) ? R.ok(true, "操作成功!") : R.fail(false, msg);
}
@ApiOperation("发货记录申请")
@GetMapping("/getDeliveryRecordList")
public PageDataInfo<TtDeliveryRecordDataVO> getDeliveryRecordList(TtDeliveryRecordBody deliveryRecordBody) {
startPage();
List<TtDeliveryRecordDataVO> list = deliveryRecordService.getDeliveryRecordList(deliveryRecordBody);
return getPageData(list);
}
}
@@ -0,0 +1,39 @@
package com.ruoyi.admin.controller;
import com.ruoyi.domain.entity.fight.TtFight;
import com.ruoyi.admin.service.TtFightService;
import com.ruoyi.domain.vo.FightBoxDataVO;
import com.ruoyi.domain.other.TtFightBody;
import com.ruoyi.common.core.controller.BaseController;
import com.ruoyi.common.core.page.PageDataInfo;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.List;
@RestController
@RequestMapping("/admin/fight")
public class TtFightController extends BaseController {
private final TtFightService fightService;
public TtFightController(TtFightService fightService) {
this.fightService = fightService;
}
@GetMapping("/list")
public PageDataInfo<TtFight> list(TtFightBody ttFightBody) {
startPage();
List<TtFight> list = fightService.selectFightList(ttFightBody);
return getPageData(list);
}
@GetMapping("/getFightBoxList/{fightId}")
public PageDataInfo<FightBoxDataVO> getFightBoxList(@PathVariable("fightId") Integer fightId) {
startPage();
List<FightBoxDataVO> list = fightService.selectFightBoxList(fightId);
return getPageData(list);
}
}
@@ -0,0 +1,109 @@
package com.ruoyi.admin.controller;
import java.util.List;
import jakarta.servlet.http.HttpServletResponse;
import com.ruoyi.common.utils.StringUtils;
import org.springframework.security.access.prepost.PreAuthorize;
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.PutMapping;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import com.ruoyi.common.annotation.Log;
import com.ruoyi.common.core.controller.BaseController;
import com.ruoyi.common.core.domain.AjaxResult;
import com.ruoyi.common.enums.BusinessType;
import com.ruoyi.domain.other.TtFightRankingReward;
import com.ruoyi.admin.service.TtFightRankingRewardService;
import com.ruoyi.common.utils.poi.ExcelUtil;
import com.ruoyi.common.core.page.TableDataInfo;
/**
* 对战奖励金额Controller
*
* @author ruoyi
* @date 2024-07-04
*/
@RestController
@RequestMapping("/admin/reward")
public class TtFightRankingRewardController extends BaseController
{
@Autowired
private TtFightRankingRewardService ttFightRankingRewardService;
/**
* 查询对战奖励金额列表
*/
@PreAuthorize("@ss.hasPermi('admin:reward:list')")
@GetMapping("/list")
public TableDataInfo list(TtFightRankingReward ttFightRankingReward)
{
startPage();
List<TtFightRankingReward> list = ttFightRankingRewardService.selectTtFightRankingRewardList(ttFightRankingReward);
return getDataTable(list);
}
/**
* 获取对战奖励金额详细信息
*/
@PreAuthorize("@ss.hasPermi('admin:reward:query')")
@GetMapping(value = "/{id}")
public AjaxResult getInfo(@PathVariable("id") Integer id)
{
return success(ttFightRankingRewardService.selectTtFightRankingRewardById(id));
}
/**
* 新增对战奖励金额
*/
// @PreAuthorize("@ss.hasPermi('admin:reward:add')")
// @Log(title = "对战奖励金额", businessType = BusinessType.INSERT)
// @PostMapping
// public AjaxResult add(@RequestBody TtFightRankingReward ttFightRankingReward)
// {
// return toAjax(ttFightRankingRewardService.insertTtFightRankingReward(ttFightRankingReward));
// }
@PreAuthorize("@ss.hasPermi('admin:reward:add')")
@Log(title = "对战排行榜奖励", action = "生成排名奖励", businessType = BusinessType.UPDATE)
@PostMapping("/generateRankingReward")
public AjaxResult generatePromotionLevel() {
String msg = ttFightRankingRewardService.generateRankingReward();
return StringUtils.isEmpty(msg) ? AjaxResult.success("生成成功,请修改参数!") : AjaxResult.error(msg);
}
/**
* 修改对战奖励金额
*/
@PreAuthorize("@ss.hasPermi('admin:reward:edit')")
@Log(title = "对战排行榜奖励", action = "修改", businessType = BusinessType.UPDATE)
@PutMapping
public AjaxResult edit(@RequestBody TtFightRankingReward ttFightRankingReward)
{
return toAjax(ttFightRankingRewardService.updateTtFightRankingReward(ttFightRankingReward));
}
/**
* 删除对战奖励金额
*/
// @PreAuthorize("@ss.hasPermi('admin:reward:remove')")
// @Log(title = "对战奖励金额", businessType = BusinessType.DELETE)
// @DeleteMapping("/{ids}")
// public AjaxResult remove(@PathVariable Integer[] ids)
// {
// return toAjax(ttFightRankingRewardService.deleteTtFightRankingRewardByIds(ids));
// }
@PreAuthorize("@ss.hasPermi('admin:reward:remove')")
@Log(title = "对战排行榜奖励", action = "重置", businessType = BusinessType.CLEAN)
@DeleteMapping("/truncateRankingReward")
public AjaxResult truncateRankingReward() {
ttFightRankingRewardService.truncateRankingReward();
return AjaxResult.success("重置成功");
}
}
@@ -0,0 +1,33 @@
package com.ruoyi.admin.controller;
import com.ruoyi.admin.service.TtFightResultService;
import com.ruoyi.common.core.domain.R;
import com.ruoyi.domain.vo.FightResultDataVO;
import com.ruoyi.domain.vo.fight.FightResultVO;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
@RequestMapping("/admin/fightResult")
public class TtFightResultController {
private final TtFightResultService fightResultService;
public TtFightResultController(TtFightResultService fightResultService) {
this.fightResultService = fightResultService;
}
// @GetMapping("/getFightResult/{fightId}")
// public R<FightResultDataVO> getFightResult(@PathVariable("fightId") Integer fightId) {
// FightResultDataVO fightResultDataVO = fightResultService.getFightResult(fightId);
// return R.ok(fightResultDataVO);
// }
@GetMapping("/getFightResult/{fightId}")
public R<FightResultVO> getFightResult(@PathVariable("fightId") Integer fightId) {
FightResultVO fightResultVO = fightResultService.getFightResult(fightId);
return R.ok(fightResultVO);
}
}
@@ -0,0 +1,107 @@
package com.ruoyi.admin.controller;
import java.util.List;
import jakarta.servlet.http.HttpServletResponse;
import org.springframework.security.access.prepost.PreAuthorize;
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.PutMapping;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import com.ruoyi.admin.mapper.TtFirstRechargeMapper;
import com.ruoyi.common.annotation.Log;
import com.ruoyi.common.core.controller.BaseController;
import com.ruoyi.common.core.domain.AjaxResult;
import com.ruoyi.common.enums.BusinessType;
import com.ruoyi.domain.other.TtFirstRecharge;
import com.ruoyi.admin.service.TtFirstRechargeService;
import com.ruoyi.common.utils.poi.ExcelUtil;
import com.ruoyi.common.core.page.TableDataInfo;
/**
* 首充赠送Controller
*
* @author ruoyi
* @date 2024-06-21
*/
@RestController
@RequestMapping("/admin/recharge")
public class TtFirstRechargeController extends BaseController
{
@Autowired
private TtFirstRechargeService ttFirstRechargeService;
/**
* 查询首充赠送列表
*/
@PreAuthorize("@ss.hasPermi('admin:recharge:list')")
@GetMapping("/list")
public TableDataInfo list(TtFirstRecharge ttFirstRecharge)
{
startPage();
List<TtFirstRecharge> list = ttFirstRechargeService.selectTtFirstRechargeList(ttFirstRecharge);
return getDataTable(list);
}
/**
* 导出首充赠送列表
*/
@PreAuthorize("@ss.hasPermi('admin:recharge:export')")
@Log(title = "首充赠送", businessType = BusinessType.EXPORT)
@PostMapping("/export")
public void export(HttpServletResponse response, TtFirstRecharge ttFirstRecharge)
{
List<TtFirstRecharge> list = ttFirstRechargeService.selectTtFirstRechargeList(ttFirstRecharge);
ExcelUtil<TtFirstRecharge> util = new ExcelUtil<TtFirstRecharge>(TtFirstRecharge.class);
util.exportExcel(response, list, "首充赠送数据");
}
/**
* 获取首充赠送详细信息
*/
@PreAuthorize("@ss.hasPermi('admin:recharge:query')")
@GetMapping(value = "/{id}")
public AjaxResult getInfo(@PathVariable("id") Integer id)
{
return success(ttFirstRechargeService.selectTtFirstRechargeById(id));
}
/**
* 新增首充赠送
*/
@PreAuthorize("@ss.hasPermi('admin:recharge:add')")
@Log(title = "首充赠送", action = "新增", businessType = BusinessType.INSERT,
entityClass = TtFirstRecharge.class, mapperClass = TtFirstRechargeMapper.class)
@PostMapping
public AjaxResult add(@RequestBody TtFirstRecharge ttFirstRecharge)
{
return toAjax(ttFirstRechargeService.insertTtFirstRecharge(ttFirstRecharge));
}
/**
* 修改首充赠送
*/
@PreAuthorize("@ss.hasPermi('admin:recharge:edit')")
@Log(title = "首充赠送", action = "修改", businessType = BusinessType.UPDATE,
entityClass = TtFirstRecharge.class, mapperClass = TtFirstRechargeMapper.class)
@PutMapping
public AjaxResult edit(@RequestBody TtFirstRecharge ttFirstRecharge)
{
return toAjax(ttFirstRechargeService.updateTtFirstRecharge(ttFirstRecharge));
}
/**
* 删除首充赠送
*/
@PreAuthorize("@ss.hasPermi('admin:recharge:remove')")
@Log(title = "首充赠送", action = "删除", businessType = BusinessType.DELETE)
@DeleteMapping("/{ids}")
public AjaxResult remove(@PathVariable Integer[] ids)
{
return toAjax(ttFirstRechargeService.deleteTtFirstRechargeByIds(ids));
}
}
@@ -0,0 +1,67 @@
package com.ruoyi.admin.controller;
import com.ruoyi.domain.other.TtMessage;
import com.ruoyi.admin.service.TtMessageService;
import com.ruoyi.common.core.controller.BaseController;
import com.ruoyi.common.core.domain.AjaxResult;
import com.ruoyi.common.core.domain.R;
import com.ruoyi.common.core.page.PageDataInfo;
import com.ruoyi.common.utils.DateUtils;
import com.ruoyi.common.utils.StringUtils;
import org.springframework.web.bind.annotation.*;
import java.util.Arrays;
import java.util.List;
@RestController
@RequestMapping("/admin/message")
public class TtMessageController extends BaseController {
private final TtMessageService messageService;
public TtMessageController(TtMessageService messageService) {
this.messageService = messageService;
}
@GetMapping("/list")
public PageDataInfo<TtMessage> list(TtMessage ttMessage) {
startPage();
List<TtMessage> list = messageService.queryList(ttMessage);
return getPageData(list);
}
@GetMapping(value = "/{id}")
public R<TtMessage> getInfo(@PathVariable("id") Integer id) {
return R.ok(messageService.getById(id));
}
@PostMapping
public AjaxResult add(@RequestBody TtMessage ttMessage) {
ttMessage.setCreateTime(DateUtils.getNowDate());
return toAjax(messageService.save(ttMessage));
}
@PutMapping
public AjaxResult edit(@RequestBody TtMessage ttMessage) {
ttMessage.setUpdateTime(DateUtils.getNowDate());
return toAjax(messageService.updateById(ttMessage));
}
@DeleteMapping("/{ids}")
public AjaxResult remove(@PathVariable Integer[] ids) {
String msg = messageService.delByIds(Arrays.asList(ids));
return StringUtils.isEmpty(msg) ? AjaxResult.success() : AjaxResult.error(msg);
}
@PostMapping("/singleMessage/{messageId}/{userIds}")
public AjaxResult singleMessage(@PathVariable("messageId") Integer messageId, @PathVariable Integer[] userIds){
String msg = messageService.singleMessage(messageId, Arrays.asList(userIds));
return StringUtils.isEmpty(msg) ? AjaxResult.success() : AjaxResult.error(msg);
}
@PostMapping("/massMessaging/{messageId}")
public AjaxResult massMessaging(@PathVariable("messageId") Integer messageId){
String msg = messageService.massMessaging(messageId);
return StringUtils.isEmpty(msg) ? AjaxResult.success() : AjaxResult.error(msg);
}
}
@@ -0,0 +1,96 @@
package com.ruoyi.admin.controller;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.ruoyi.admin.mapper.TtOfficialRollConfigMapper;
import com.ruoyi.common.enums.BusinessType;
import com.ruoyi.common.annotation.Log;
import com.ruoyi.admin.service.TtOfficialRollConfigService;
import com.ruoyi.common.core.controller.BaseController;
import com.ruoyi.common.core.domain.AjaxResult;
import com.ruoyi.common.core.domain.R;
import com.ruoyi.common.core.page.PageDataInfo;
import com.ruoyi.common.utils.DateUtils;
import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.domain.entity.roll.TtOfficialRollConfig;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.springframework.web.bind.annotation.*;
import java.util.List;
@Api(tags = "管理端 官方周期Roll配置")
@RestController
@RequestMapping("/admin/officialRollConfig")
public class TtOfficialRollConfigController extends BaseController {
private final TtOfficialRollConfigService configService;
public TtOfficialRollConfigController(TtOfficialRollConfigService configService) {
this.configService = configService;
}
@ApiOperation("配置列表")
@GetMapping("/list")
public PageDataInfo<TtOfficialRollConfig> list(
@RequestParam(value = "configName", required = false) String configName,
@RequestParam(value = "periodType", required = false) String periodType,
@RequestParam(value = "status", required = false) String status) {
startPage();
LambdaQueryWrapper<TtOfficialRollConfig> wrapper = Wrappers.lambdaQuery();
if (StringUtils.isNotEmpty(configName)) wrapper.like(TtOfficialRollConfig::getConfigName, configName);
if (StringUtils.isNotEmpty(periodType)) wrapper.eq(TtOfficialRollConfig::getPeriodType, periodType);
if (StringUtils.isNotEmpty(status)) wrapper.eq(TtOfficialRollConfig::getStatus, status);
wrapper.orderByAsc(TtOfficialRollConfig::getSortBy).orderByDesc(TtOfficialRollConfig::getCreateTime);
List<TtOfficialRollConfig> configList = configService.list(wrapper);
return getPageData(configList);
}
@ApiOperation("配置详情")
@GetMapping("/{id}")
public R<TtOfficialRollConfig> getInfo(@PathVariable("id") Integer id) {
return R.ok(configService.getById(id));
}
@Log(title = "官方周期Roll配置", action = "新增", businessType = BusinessType.INSERT,
entityClass = TtOfficialRollConfig.class, mapperClass = TtOfficialRollConfigMapper.class)
@ApiOperation("新增配置")
@PostMapping
public AjaxResult add(@RequestBody TtOfficialRollConfig config) {
config.setCreateBy(getUsername());
config.setCreateTime(DateUtils.getNowDate());
return configService.addConfig(config);
}
@Log(title = "官方周期Roll配置", action = "修改", businessType = BusinessType.UPDATE,
entityClass = TtOfficialRollConfig.class, mapperClass = TtOfficialRollConfigMapper.class)
@ApiOperation("编辑配置")
@PutMapping
public AjaxResult edit(@RequestBody TtOfficialRollConfig config) {
config.setUpdateBy(getUsername());
config.setUpdateTime(DateUtils.getNowDate());
return configService.editConfig(config);
}
@Log(title = "官方周期Roll配置", action = "删除", businessType = BusinessType.DELETE)
@ApiOperation("删除配置")
@DeleteMapping("/{id}")
public AjaxResult remove(@PathVariable("id") Integer id) {
return configService.removeById(id) ? AjaxResult.success() : AjaxResult.error("删除失败");
}
@ApiOperation("启用/停用配置")
@PutMapping("/changeStatus")
public AjaxResult changeStatus(@RequestBody TtOfficialRollConfig config) {
if (config.getId() == null) return AjaxResult.error("配置ID不能为空");
if (!"0".equals(config.getStatus()) && !"1".equals(config.getStatus())) {
return AjaxResult.error("状态不合法");
}
TtOfficialRollConfig update = new TtOfficialRollConfig();
update.setId(config.getId());
update.setStatus(config.getStatus());
update.setUpdateBy(getUsername());
update.setUpdateTime(DateUtils.getNowDate());
return configService.updateById(update) ? AjaxResult.success() : AjaxResult.error("操作失败");
}
}
@@ -0,0 +1,33 @@
package com.ruoyi.admin.controller;
import com.ruoyi.admin.service.TtOrderService;
import com.ruoyi.common.core.controller.BaseController;
import com.ruoyi.common.core.domain.R;
import com.ruoyi.common.core.page.PageDataInfo;
import com.ruoyi.domain.dto.sys.OrderQueryCondition;
import com.ruoyi.domain.entity.TtOrder;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import java.util.List;
@Api(tags = "管理端 订单管理")
@RestController
@RequestMapping("/admin/order")
public class TtOrderController extends BaseController {
private final TtOrderService ttOrderService;
public TtOrderController(TtOrderService ttOrderService) {
this.ttOrderService = ttOrderService;
}
@ApiOperation("网站支付订单查询")
@PostMapping("/list")
public R list(@RequestBody @Validated OrderQueryCondition condition) {
return ttOrderService.adminList(condition);
}
}
@@ -0,0 +1,106 @@
package com.ruoyi.admin.controller;
import cn.hutool.core.util.ObjectUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.ruoyi.admin.mapper.TtOrnamentMapper;
import com.ruoyi.admin.service.TtOrnamentService;
import com.ruoyi.domain.entity.TtOrnament;
import com.ruoyi.domain.other.TtOrnamentsBody;
import com.ruoyi.common.annotation.Log;
import com.ruoyi.common.core.controller.BaseController;
import com.ruoyi.common.core.domain.AjaxResult;
import com.ruoyi.common.core.domain.R;
import com.ruoyi.common.enums.BusinessType;
import com.ruoyi.common.utils.poi.ExcelUtil;
import com.ruoyi.domain.other.TtOrnamentsPrice;
import com.ruoyi.domain.vo.TtOrnamentVO;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import jakarta.servlet.http.HttpServletResponse;
import java.util.List;
@Api(tags = "管理端 饰品管理")
@RestController
@RequestMapping("/admin/ornaments")
public class TtOrnamentsController extends BaseController {
@Autowired
private TtOrnamentService ornamentsService;
@Autowired
private TtOrnamentService ttOrnamentService;
// 饰品列表多条件筛选
@ApiOperation("饰品列表多条件筛选")
@GetMapping("/list")
public R list(TtOrnamentsBody param) {
Page<TtOrnamentVO> ttOrnamentVOPage = ttOrnamentService.listByParam(param);
return R.ok(ttOrnamentVOPage);
}
// TODO: 2024/3/29 !!!!!!
// 导出饰品数据
@Log(title = "饰品数据", businessType = BusinessType.EXPORT)
@PostMapping("/export")
public void export(HttpServletResponse response, TtOrnamentsBody ttOrnamentsBody) {
List<TtOrnamentVO> list = ttOrnamentService.listByParam(ttOrnamentsBody).getRecords();
ExcelUtil<TtOrnamentVO> util = new ExcelUtil<>(TtOrnamentVO.class);
util.exportExcel(response, list, "饰品数据数据");
}
@GetMapping(value = "/{id}")
public R<TtOrnament> getInfo(@PathVariable("id") Long id) {
return R.ok(ornamentsService.getById(id));
}
@Log(title = "饰品列表", action = "发放饰品", businessType = BusinessType.GRANT)
@ApiOperation("饰品发放")
@PostMapping("/grantOrnaments/{userId}/{ornamentsId}/{num}")
public AjaxResult grantOrnaments(@PathVariable("userId") Integer userId,
@PathVariable("ornamentsId") Long ornamentsId,
@RequestParam(name = "ornamentsLevelId", required = false) Integer ornamentsLevelId,
@PathVariable("num") Integer num) {
return ornamentsService.grantOrnaments(userId, ornamentsId, ornamentsLevelId, num);
}
@PutMapping("/updateOrnamentPrice")
public AjaxResult updateOrnamentPrice(@RequestBody TtOrnamentsPrice ttOrnamentsPrice) {
return ornamentsService.updateOrnamentPrice(ttOrnamentsPrice.getId(), ttOrnamentsPrice.getPrice());
}
@Log(title = "饰品列表", action = "新增饰品", businessType = BusinessType.INSERT,
entityClass = TtOrnament.class, mapperClass = TtOrnamentMapper.class)
@ApiOperation("新增饰品")
@PostMapping("/addTtOrnament")
public AjaxResult add(@RequestBody TtOrnament ttOrnament) {
if (ttOrnament.getId() == null) {
ttOrnament.setId(System.currentTimeMillis());
}
return toAjax(ornamentsService.save(ttOrnament));
}
@Log(title = "饰品列表", action = "编辑", businessType = BusinessType.UPDATE,
entityClass = TtOrnament.class, mapperClass = TtOrnamentMapper.class)
@ApiOperation("修改饰品")
@PostMapping("/editTtOrnament")
public AjaxResult edit(@RequestBody TtOrnament ttOrnament) {
return toAjax(ornamentsService.updateById(ttOrnament));
}
@Log(title = "饰品列表", action = "删除", businessType = BusinessType.DELETE)
@ApiOperation("删除饰品(支持批量)")
@DeleteMapping("/{ids}")
public AjaxResult delete(@PathVariable("ids") List<Long> ids) {
if (ids == null || ids.isEmpty()) {
return AjaxResult.error("请选择要删除的饰品");
}
LambdaQueryWrapper<TtOrnament> wrapper = new LambdaQueryWrapper<>();
wrapper.in(TtOrnament::getId, ids);
return toAjax(ornamentsService.remove(wrapper));
}
}
@@ -0,0 +1,65 @@
package com.ruoyi.admin.controller;
import com.ruoyi.admin.mapper.TtOrnamentsLevelMapper;
import com.ruoyi.common.enums.BusinessType;
import com.ruoyi.common.annotation.Log;
import com.ruoyi.domain.other.TtOrnamentsLevel;
import com.ruoyi.admin.service.TtOrnamentsLevelService;
import com.ruoyi.common.core.controller.BaseController;
import com.ruoyi.common.core.domain.AjaxResult;
import com.ruoyi.common.core.domain.R;
import com.ruoyi.common.core.page.PageDataInfo;
import com.ruoyi.common.utils.StringUtils;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.springframework.web.bind.annotation.*;
import java.util.List;
@Api(tags = "管理端 饰品等级信息")
@RestController
@RequestMapping("/admin/ornamentsLevel")
public class TtOrnamentsLevelController extends BaseController {
private final TtOrnamentsLevelService ornamentsLevelService;
public TtOrnamentsLevelController(TtOrnamentsLevelService ornamentsLevelService) {
this.ornamentsLevelService = ornamentsLevelService;
}
@ApiOperation("获取所有饰品等级背景")
@GetMapping("/list")
public PageDataInfo<TtOrnamentsLevel> list() {
startPage();
List<TtOrnamentsLevel> list = ornamentsLevelService.list();
return getPageData(list);
}
@GetMapping(value = "/{id}")
public R<TtOrnamentsLevel> getInfo(@PathVariable("id") Integer id) {
TtOrnamentsLevel ornamentsLevel = ornamentsLevelService.getById(id);
ornamentsLevel.setLevelImg("");
return R.ok(ornamentsLevel);
}
@Log(title = "饰品等级", action = "新增", businessType = BusinessType.INSERT)
@PostMapping("generateOrnamentsLevel/{num}")
public AjaxResult generateOrnamentsLevel(@PathVariable("num") Integer num) {
String msg = ornamentsLevelService.generateOrnamentsLevel(num);
return StringUtils.isEmpty(msg) ? AjaxResult.success("生成成功,请修改参数!") : AjaxResult.error(msg);
}
@Log(title = "饰品等级", action = "修改", businessType = BusinessType.UPDATE,
entityClass = TtOrnamentsLevel.class, mapperClass = TtOrnamentsLevelMapper.class)
@PutMapping
public AjaxResult edit(@RequestBody TtOrnamentsLevel ttOrnamentsLevel) {
String msg = ornamentsLevelService.updateOrnamentsLevelById(ttOrnamentsLevel);
return StringUtils.isEmpty(msg) ? AjaxResult.success() : AjaxResult.error(msg);
}
@PostMapping
public AjaxResult truncateOrnamentsLevel() {
ornamentsLevelService.truncateOrnamentsLevel();
return AjaxResult.success("重置成功,请重新设置!");
}
}
@@ -0,0 +1,47 @@
package com.ruoyi.admin.controller;
import com.ruoyi.admin.service.TtPromoTurnoverService;
import com.ruoyi.common.constant.HttpStatus;
import com.ruoyi.common.core.controller.BaseController;
import com.ruoyi.common.core.domain.AjaxResult;
import com.ruoyi.common.core.page.PageDataInfo;
import com.ruoyi.domain.param.promotion.AnchorDailyTurnoverParam;
import com.ruoyi.domain.param.promotion.AnchorRechargeParam;
import com.ruoyi.domain.vo.promotion.AnchorDailyTurnoverVo;
import io.swagger.annotations.ApiOperation;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import java.util.List;
@RestController
@RequestMapping("/admin/promo")
public class TtPromoTurnoverController extends BaseController {
@Autowired
private TtPromoTurnoverService ttPromoTurnoverService;
@ApiOperation("获取主播推广数据")
@GetMapping("/getAnchorPromotionData")
public PageDataInfo<AnchorDailyTurnoverVo> getAnchorPromotionData(AnchorDailyTurnoverParam param) {
List<AnchorDailyTurnoverVo> list = ttPromoTurnoverService.getAnchorDailyTurnover(param);
PageDataInfo<AnchorDailyTurnoverVo> pageDataInfo = new PageDataInfo();
pageDataInfo.setTotal(list.size());
pageDataInfo.setCode(HttpStatus.SUCCESS);
pageDataInfo.setMsg("查询成功");
int num = param.getNum() != null ? param.getNum() : 1;
int size = param.getSize() != null ? param.getSize() : 10;
int fromIndex = (num - 1) * size;
int toIndex = Math.min(fromIndex + size, list.size());
pageDataInfo.setRows(list.subList(fromIndex, toIndex));
return pageDataInfo;
}
@ApiOperation("主播充值")
@PostMapping("/recharge")
public AjaxResult recharge(@RequestBody AnchorRechargeParam param) {
return ttPromoTurnoverService.recharge(param);
}
}
@@ -0,0 +1,69 @@
package com.ruoyi.admin.controller;
import com.ruoyi.admin.mapper.TtPromotionLevelMapper;
import com.ruoyi.common.enums.BusinessType;
import com.ruoyi.common.annotation.Log;
import com.ruoyi.domain.entity.TtPromotionLevel;
import com.ruoyi.admin.service.TtPromotionLevelService;
import com.ruoyi.common.core.controller.BaseController;
import com.ruoyi.common.core.domain.AjaxResult;
import com.ruoyi.common.core.domain.R;
import com.ruoyi.common.core.page.PageDataInfo;
import com.ruoyi.common.utils.DateUtils;
import com.ruoyi.common.utils.StringUtils;
import org.springframework.web.bind.annotation.*;
import java.util.List;
@RestController
@RequestMapping("/admin/promotionLevel")
public class TtPromotionLevelController extends BaseController {
private final TtPromotionLevelService promotionLevelService;
public TtPromotionLevelController(TtPromotionLevelService promotionLevelService) {
this.promotionLevelService = promotionLevelService;
}
@GetMapping("/list")
public PageDataInfo<TtPromotionLevel> list() {
// 推广等级总量不多,后台设置页未接入分页组件,改为全量返回
List<TtPromotionLevel> list = promotionLevelService.list();
PageDataInfo<TtPromotionLevel> data = new PageDataInfo<>();
data.setRows(list);
data.setTotal(list == null ? 0 : list.size());
data.setCode(200);
data.setMsg("查询成功");
return data;
}
@GetMapping(value = "/{id}")
public R<TtPromotionLevel> getInfo(@PathVariable("id") Integer id) {
TtPromotionLevel ttPromotionLevel = promotionLevelService.getById(id);
ttPromotionLevel.setIcon("");
return R.ok(ttPromotionLevel);
}
@Log(title = "推广等级设置", action = "生成推广列表", businessType = BusinessType.INSERT)
@PostMapping("generatePromotionLevel/{num}")
public AjaxResult generatePromotionLevel(@PathVariable("num") Integer num) {
String msg = promotionLevelService.generateVipLevel(num);
return StringUtils.isEmpty(msg) ? AjaxResult.success("生成成功,请修改参数!") : AjaxResult.error(msg);
}
@Log(title = "推广等级设置", action = "修改", businessType = BusinessType.UPDATE,
entityClass = TtPromotionLevel.class, mapperClass = TtPromotionLevelMapper.class)
@PutMapping
public AjaxResult edit(@RequestBody TtPromotionLevel ttPromotionLevel) {
ttPromotionLevel.setUpdateTime(DateUtils.getNowDate());
String msg = promotionLevelService.updatePromotionLevelById(ttPromotionLevel);
return StringUtils.isEmpty(msg) ? AjaxResult.success() : AjaxResult.error(msg);
}
@Log(title = "推广等级设置", action = "重置", businessType = BusinessType.CLEAN)
@PostMapping
public AjaxResult truncateVipLevel() {
promotionLevelService.truncatePromotionLevel();
return AjaxResult.success("重置成功,请重新设置!");
}
}
@@ -0,0 +1,38 @@
package com.ruoyi.admin.controller;
import com.ruoyi.domain.entity.TtPromotionRecord;
import com.ruoyi.admin.service.TtPromotionRecordService;
import com.ruoyi.domain.vo.PromotionDataVO;
import com.ruoyi.common.core.controller.BaseController;
import com.ruoyi.common.core.domain.R;
import com.ruoyi.common.core.page.PageDataInfo;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.List;
@RestController
@RequestMapping("/admin/promotionRecord")
public class TtPromotionRecordController extends BaseController {
private final TtPromotionRecordService promotionRecordService;
public TtPromotionRecordController(TtPromotionRecordService promotionRecordService) {
this.promotionRecordService = promotionRecordService;
}
@GetMapping("/getPromotionRecord")
public PageDataInfo<TtPromotionRecord> getPromotionRecord(TtPromotionRecord ttPromotionRecord){
startPage();
List<TtPromotionRecord> list = promotionRecordService.getPromotionRecord(ttPromotionRecord);
return getPageData(list);
}
@GetMapping("/statisticsPromotionData/{userId}")
public R<PromotionDataVO> statisticsPromotionData(@PathVariable("userId") Integer userId){
PromotionDataVO data = promotionRecordService.statisticsPromotionData(userId);
return R.ok(data);
}
}
@@ -0,0 +1,83 @@
package com.ruoyi.admin.controller;
import com.ruoyi.common.enums.BusinessType;
import com.ruoyi.common.annotation.Log;
import com.ruoyi.admin.config.RedisConstants;
import com.ruoyi.domain.other.TtRechargeCard;
import com.ruoyi.admin.service.TtRechargeCardService;
import com.ruoyi.common.core.controller.BaseController;
import com.ruoyi.common.core.domain.R;
import com.ruoyi.common.core.page.PageDataInfo;
import com.ruoyi.common.redis.config.RedisLock;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import jakarta.servlet.http.HttpServletResponse;
import java.util.List;
import java.util.concurrent.TimeUnit;
@RestController
@RequestMapping("/admin/rechargeCard")
public class TtRechargeCardController extends BaseController {
private final TtRechargeCardService rechargeCardService;
private final RedisLock redisLock;
public TtRechargeCardController(TtRechargeCardService rechargeCardService, RedisLock redisLock) {
this.rechargeCardService = rechargeCardService;
this.redisLock = redisLock;
}
@GetMapping("/list")
public PageDataInfo<TtRechargeCard> list(TtRechargeCard ttRechargeCard) {
startPage();
List<TtRechargeCard> list = rechargeCardService.queryList(ttRechargeCard);
return getPageData(list);
}
@PostMapping("/export")
public void export(HttpServletResponse response, TtRechargeCard ttRechargeCard) {
rechargeCardService.export(response, ttRechargeCard);
}
@Log(title = "卡密", action = "生成卡密", businessType = BusinessType.INSERT)
@PostMapping("/generateCard/{rechargeListId}/{num}")
public R<List<String>> generateCard(@PathVariable("rechargeListId") Integer rechargeListId, @PathVariable("num") Integer num) {
if (num == null || num <= 0) {
return R.fail("生成数量必须大于0");
}
// 防重:按管理员 userId 加锁(锁粒度=单管理员,不影响其他管理员各自批量生成)
Long operId = getUserId();
String lockKey = RedisConstants.RECHARGE_CARD_GENERATE_LOCK + operId;
if (!redisLock.tryLock(lockKey, 0L, 30L, TimeUnit.SECONDS)) {
return R.fail("卡密生成中,请勿重复提交");
}
try {
List<String> cardList = rechargeCardService.generateCard(rechargeListId, num);
return R.ok(cardList);
} finally {
redisLock.unlock(lockKey);
}
}
@Log(title = "卡密", action = "生成空白卡密", businessType = BusinessType.INSERT)
@PostMapping("/generateBlankCard/{rechargeListId}/{num}")
public R<List<String>> generateBlankCard(@PathVariable("rechargeListId") Integer rechargeListId, @PathVariable("num") Integer num) {
if (num == null || num <= 0) {
return R.fail("生成数量必须大于0");
}
// 防重:同一把管理员锁
Long operId = getUserId();
String lockKey = RedisConstants.RECHARGE_CARD_GENERATE_LOCK + operId;
if (!redisLock.tryLock(lockKey, 0L, 30L, TimeUnit.SECONDS)) {
return R.fail("卡密生成中,请勿重复提交");
}
try {
List<String> cardList = rechargeCardService.generateBlankCard(rechargeListId, num);
return R.ok(cardList);
} finally {
redisLock.unlock(lockKey);
}
}
}
@@ -0,0 +1,65 @@
package com.ruoyi.admin.controller;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.ruoyi.admin.mapper.TtRechargeConfigMapper;
import com.ruoyi.common.enums.BusinessType;
import com.ruoyi.common.annotation.Log;
import com.ruoyi.admin.service.TtRechargeConfigService;
import com.ruoyi.common.core.controller.BaseController;
import com.ruoyi.common.core.domain.AjaxResult;
import com.ruoyi.common.core.domain.R;
import com.ruoyi.common.core.page.PageDataInfo;
import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.domain.entity.TtRechargeConfig;
import org.springframework.web.bind.annotation.*;
import java.util.Arrays;
import java.util.List;
@RestController
@RequestMapping("/admin/rechargeConfig")
public class TtRechargeConfigController extends BaseController {
private final TtRechargeConfigService rechargeConfigService;
public TtRechargeConfigController(TtRechargeConfigService rechargeConfigService) {
this.rechargeConfigService = rechargeConfigService;
}
@GetMapping("/list")
public PageDataInfo<TtRechargeConfig> list(@RequestParam(required = false) String status) {
startPage();
LambdaQueryWrapper<TtRechargeConfig> wrapper = Wrappers.lambdaQuery();
if (StringUtils.isNotEmpty(status)) wrapper.eq(TtRechargeConfig::getStatus, status);
List<TtRechargeConfig> list = rechargeConfigService.list(wrapper);
return getPageData(list);
}
@GetMapping(value = "/{id}")
public R<TtRechargeConfig> getInfo(@PathVariable("id") Integer id) {
TtRechargeConfig rechargeConfig = rechargeConfigService.getById(id);
return R.ok(rechargeConfig);
}
@Log(title = "网站货币管理", action = "新增", businessType = BusinessType.INSERT,
entityClass = TtRechargeConfig.class, mapperClass = TtRechargeConfigMapper.class)
@PostMapping
public AjaxResult add(@RequestBody TtRechargeConfig ttRechargeConfig) {
return toAjax(rechargeConfigService.save(ttRechargeConfig));
}
@Log(title = "网站货币管理", action = "修改", businessType = BusinessType.UPDATE,
entityClass = TtRechargeConfig.class, mapperClass = TtRechargeConfigMapper.class)
@PutMapping
public AjaxResult edit(@RequestBody TtRechargeConfig ttRechargeConfig) {
return toAjax(rechargeConfigService.updateById(ttRechargeConfig));
}
@Log(title = "网站货币管理", action = "删除", businessType = BusinessType.DELETE)
@DeleteMapping("/{ids}")
public AjaxResult remove(@PathVariable Integer[] ids) {
return toAjax(rechargeConfigService.removeByIds(Arrays.asList(ids)));
}
}
@@ -0,0 +1,67 @@
package com.ruoyi.admin.controller;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.ruoyi.admin.mapper.TtRechargeProdMapper;
import com.ruoyi.common.enums.BusinessType;
import com.ruoyi.common.annotation.Log;
import com.ruoyi.domain.entity.TtRechargeProd;
import com.ruoyi.admin.service.TtRechargeProdService;
import com.ruoyi.common.core.controller.BaseController;
import com.ruoyi.common.core.domain.AjaxResult;
import com.ruoyi.common.core.domain.R;
import com.ruoyi.common.core.page.PageDataInfo;
import com.ruoyi.common.utils.StringUtils;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.*;
import java.util.Arrays;
import java.util.List;
@RestController
@RequestMapping("/admin/rechargeList")
public class TtRechargeListController extends BaseController {
private final TtRechargeProdService rechargeListService;
public TtRechargeListController(TtRechargeProdService rechargeListService) {
this.rechargeListService = rechargeListService;
}
@GetMapping("/list")
public PageDataInfo<TtRechargeProd> list(@RequestParam(required = false) String status) {
startPage();
LambdaQueryWrapper<TtRechargeProd> wrapper = Wrappers.lambdaQuery();
if (StringUtils.isNotEmpty(status)) wrapper.eq(TtRechargeProd::getStatus, status);
List<TtRechargeProd> list = rechargeListService.list(wrapper);
return getPageData(list);
}
@PreAuthorize("@ss.hasPermi('admin:rechargeList:query')")
@GetMapping(value = "/{id}")
public R<TtRechargeProd> getInfo(@PathVariable("id") Integer id) {
TtRechargeProd rechargeList = rechargeListService.getById(id);
return R.ok(rechargeList);
}
@Log(title = "货币列表", action = "新增", businessType = BusinessType.INSERT,
entityClass = TtRechargeProd.class, mapperClass = TtRechargeProdMapper.class)
@PostMapping
public AjaxResult add(@RequestBody TtRechargeProd ttRechargeProd) {
return toAjax(rechargeListService.save(ttRechargeProd));
}
@Log(title = "货币列表", action = "修改", businessType = BusinessType.UPDATE,
entityClass = TtRechargeProd.class, mapperClass = TtRechargeProdMapper.class)
@PutMapping
public AjaxResult edit(@RequestBody TtRechargeProd ttRechargeProd) {
return toAjax(rechargeListService.updateById(ttRechargeProd));
}
@Log(title = "货币列表", action = "删除", businessType = BusinessType.DELETE)
@DeleteMapping("/{ids}")
public AjaxResult remove(@PathVariable Integer[] ids) {
return toAjax(rechargeListService.removeByIds(Arrays.asList(ids)));
}
}
@@ -0,0 +1,95 @@
package com.ruoyi.admin.controller;
import com.ruoyi.admin.service.TtRechargeRankingRewardService;
import com.ruoyi.common.annotation.Log;
import com.ruoyi.common.core.controller.BaseController;
import com.ruoyi.common.core.domain.AjaxResult;
import com.ruoyi.common.core.page.TableDataInfo;
import com.ruoyi.common.enums.BusinessType;
import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.domain.other.TtRechargeRankingReward;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.*;
import java.util.List;
/**
* 充值奖励金额Controller
*
* @author ruoyi
* @date 2024-07-04
*/
@RestController
@RequestMapping("/admin/rechargeRankingReward")
public class TtRechargeRankingRewardController extends BaseController
{
@Autowired
private TtRechargeRankingRewardService ttRechargeRankingRewardService;
/**
* 查询充值奖励金额列表
*/
@GetMapping("/list")
public TableDataInfo list(TtRechargeRankingReward ttRechargeRankingReward)
{
startPage();
List<TtRechargeRankingReward> list = ttRechargeRankingRewardService.selectTtRechargeRankingRewardList(ttRechargeRankingReward);
return getDataTable(list);
}
/**
* 获取充值奖励金额详细信息
*/
@GetMapping(value = "/{id}")
public AjaxResult getInfo(@PathVariable("id") Integer id)
{
return success(ttRechargeRankingRewardService.selectTtRechargeRankingRewardById(id));
}
/**
* 新增充值奖励金额
*/
// @PreAuthorize("@ss.hasPermi('admin:reward:add')")
// @Log(title = "充值奖励金额", businessType = BusinessType.INSERT)
// @PostMapping
// public AjaxResult add(@RequestBody TtRechargeRankingReward ttRechargeRankingReward)
// {
// return toAjax(ttRechargeRankingRewardService.insertTtRechargeRankingReward(ttRechargeRankingReward));
// }
@Log(title = "消费排行榜奖励", action = "生成消费奖励", businessType = BusinessType.UPDATE)
@PostMapping("/generateRankingReward")
public AjaxResult generatePromotionLevel() {
String msg = ttRechargeRankingRewardService.generateRankingReward();
return StringUtils.isEmpty(msg) ? AjaxResult.success("生成成功,请修改参数!") : AjaxResult.error(msg);
}
/**
* 修改充值奖励金额
*/
@Log(title = "消费排行榜奖励", action = "修改", businessType = BusinessType.UPDATE)
@PutMapping
public AjaxResult edit(@RequestBody TtRechargeRankingReward ttRechargeRankingReward)
{
return toAjax(ttRechargeRankingRewardService.updateTtRechargeRankingReward(ttRechargeRankingReward));
}
/**
* 删除充值奖励金额
*/
// @PreAuthorize("@ss.hasPermi('admin:reward:remove')")
// @Log(title = "充值奖励金额", businessType = BusinessType.DELETE)
// @DeleteMapping("/{ids}")
// public AjaxResult remove(@PathVariable Integer[] ids)
// {
// return toAjax(ttRechargeRankingRewardService.deleteTtRechargeRankingRewardByIds(ids));
// }
@Log(title = "消费排行榜奖励", action = "重置", businessType = BusinessType.CLEAN)
@DeleteMapping("/truncateRankingReward")
public AjaxResult truncateRankingReward() {
ttRechargeRankingRewardService.truncateRankingReward();
return AjaxResult.success("重置成功");
}
}
@@ -0,0 +1,470 @@
package com.ruoyi.admin.controller;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.conditions.query.LambdaQueryChainWrapper;
import com.ruoyi.admin.mapper.TtOrderMapper;
import com.ruoyi.admin.mapper.TtRechargeConfigMapper;
import com.ruoyi.admin.mapper.TtUserMapper;
import com.ruoyi.admin.mapper.TtDeliveryRecordMapper;
import com.ruoyi.common.core.domain.AjaxResult;
import com.ruoyi.domain.entity.delivery.TtDeliveryRecord;
import com.ruoyi.domain.common.constant.TtAccountRecordSource;
import com.ruoyi.domain.entity.TtOrder;
import com.ruoyi.domain.entity.TtRechargeConfig;
import com.ruoyi.domain.entity.TtUserBlendErcash;
import com.ruoyi.domain.entity.sys.TtUser;
import com.ruoyi.domain.other.TtRechargeRecord;
import com.ruoyi.admin.service.TtRechargeRecordService;
import com.ruoyi.domain.other.TtRechargeRecordBody;
import com.ruoyi.common.core.controller.BaseController;
import com.github.pagehelper.PageInfo;
import com.ruoyi.common.core.page.PageDataInfo;
import com.ruoyi.common.utils.poi.ExcelUtil;
import com.ruoyi.domain.other.TtRechargeRecordVo;
import org.apache.commons.collections4.CollectionUtils;
import org.springframework.beans.BeanUtils;
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.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import jakarta.servlet.http.HttpServletResponse;
import java.math.BigDecimal;
import java.sql.Timestamp;
import java.time.LocalDate;
import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;
@RestController
@RequestMapping("/admin/rechargeRecord")
public class TtRechargeRecordController extends BaseController {
private final TtRechargeRecordService rechargeRecordService;
public TtRechargeRecordController(TtRechargeRecordService rechargeRecordService) {
this.rechargeRecordService = rechargeRecordService;
}
@Autowired
private com.ruoyi.admin.mapper.TtUserBlendErcashMapper ttUserBlendErcashMapper;
@Autowired
private TtUserMapper ttUserMapper;
@Autowired
private TtOrderMapper ttOrderMapper;
@Autowired
private TtRechargeConfigMapper ttRechargeConfigMapper;
@Autowired
private TtDeliveryRecordMapper ttDeliveryRecordMapper;
@Autowired
private com.ruoyi.admin.mapper.TtBoxRecordsMapper ttBoxRecordsMapper;
@GetMapping("/list")
public PageDataInfo<TtRechargeRecordVo> list(TtRechargeRecordBody rechargeRecordBody) {
startPage();
List<TtRechargeRecord> list = rechargeRecordService.queryList(rechargeRecordBody);
if (CollectionUtils.isNotEmpty(list)) {
Set<Integer> userIds = new HashSet<>();
Set<String> orderIds = new HashSet<>();
for (TtRechargeRecord record : list) {
userIds.add(record.getUserId());
// 同时加载直属上级(主播/招商),用于推导招商ID = 上级的上级
if (record.getParentId() != null) {
userIds.add(record.getParentId());
}
orderIds.add(record.getOrderId());
}
List<TtUser> ttUsers = ttUserMapper.selectBatchIds(userIds);
Map<Integer, TtUser> userMap = ttUsers.stream().collect(Collectors.toMap(TtUser::getUserId, Function.identity()));
List<TtOrder> orders = new LambdaQueryChainWrapper<>(ttOrderMapper)
.in(TtOrder::getOrderId, orderIds).list();
Map<String, String> orderPicture = new HashMap<>();
if (CollectionUtils.isNotEmpty(orders)) {
Set<Integer> goodIds = orders.stream().map(TtOrder::getGoodsId).collect(Collectors.toSet());
List<TtRechargeConfig> configs = new LambdaQueryChainWrapper<>(ttRechargeConfigMapper).in(TtRechargeConfig::getId, goodIds).list();
Map<Integer, TtRechargeConfig> configMap = configs.stream().collect(Collectors.toMap(TtRechargeConfig::getId, Function.identity()));
for (TtOrder order : orders) {
TtRechargeConfig config = configMap.get(order.getGoodsId());
if (config != null) {
orderPicture.put(order.getOrderId(), config.getPicture());
}
}
}
List<TtRechargeRecordVo> vos = new ArrayList<>();
for (TtRechargeRecord record : list) {
TtRechargeRecordVo vo = new TtRechargeRecordVo();
BeanUtils.copyProperties(record, vo);
vos.add(vo);
// 招商ID = 充值用户的上级上级(直属上级[主播]的上级[招商])
TtUser parentUser = userMap.get(record.getParentId());
if (parentUser != null) {
vo.setMerchantId(parentUser.getParentId());
}
TtUser ttUser = userMap.get(record.getUserId());
if (ttUser == null) {
continue;
}
vo.setNickName(ttUser.getNickName());
vo.setPhoneNumber(ttUser.getPhoneNumber());
vo.setDeliveryAddress(ttUser.getDeliveryAddress());
vo.setPicture(orderPicture.getOrDefault(vo.getOrderId(), ""));
}
PageDataInfo<TtRechargeRecordVo> pageDataInfo = getPageData(vos);
pageDataInfo.setTotal(new PageInfo<>(list).getTotal());
return pageDataInfo;
} else {
return getPageData(new ArrayList<>());
}
}
@PostMapping("/export")
public void export(HttpServletResponse response, TtRechargeRecordBody rechargeRecordBody) {
List<TtRechargeRecord> list = rechargeRecordService.queryList(rechargeRecordBody);
ExcelUtil<TtRechargeRecord> util = new ExcelUtil<>(TtRechargeRecord.class);
util.exportExcel(response, list, "充值记录信息列表");
}
/**
* 首页折线图数据:支持按小时/天/周维度统计充值、开箱流水、对战开箱流水等。
* 优化:原先按时间桶循环执行 7(天)/24(小时)/4(周) 次数据库查询(N+1),现合并为
* 单次 GROUP BY (source, 时间桶) 聚合查询,配合 (source, create_time) 复合索引命中范围扫描,
* 消除多次 DB 往返。
* @param type 时间维度: hour(今日按小时), day(近7天按天), week(近4周按周)
*/
@GetMapping("/chartData")
public com.ruoyi.common.core.domain.R chartData(@RequestParam(defaultValue = "day") String type) {
List<String> dateList = new ArrayList<>();
List<BigDecimal> rechargeList = new ArrayList<>();
List<BigDecimal> boxOpenList = new ArrayList<>();
List<BigDecimal> fightBoxOpenList = new ArrayList<>();
List<BigDecimal> luckyUpgradeList = new ArrayList<>();
List<BigDecimal> westernDuelList = new ArrayList<>();
List<BigDecimal> wheelList = new ArrayList<>();
List<BigDecimal> roseladyList = new ArrayList<>();
List<Integer> sources = Arrays.asList(
TtAccountRecordSource.RECHARGE.getCode(),
TtAccountRecordSource.GAME_TYPE_01.getCode(),
TtAccountRecordSource.GAME_TYPE_02.getCode(),
TtAccountRecordSource.GOLD_DEVICE.getCode(),
TtAccountRecordSource.BULLET_SPIN.getCode(),
TtAccountRecordSource.LUCKLY_WHEEL_SPIN.getCode(),
TtAccountRecordSource.WHEEL_BET_REFUND.getCode(), // 转盘兜底退款:折线按净口径冲减
TtAccountRecordSource.OLYMPUS_SPIN.getCode());
LocalDate today = LocalDate.now();
// bucketKey -> (source -> 金额):原值与绝对值两份
Map<String, Map<Integer, BigDecimal>> rawByBucket = new HashMap<>();
Map<String, Map<Integer, BigDecimal>> absByBucket = new HashMap<>();
if ("hour".equals(type)) {
// 按小时:今日 0-23 点,单次查询按小时聚合
Timestamp start = Timestamp.valueOf(today.atStartOfDay());
Timestamp end = Timestamp.valueOf(today.plusDays(1).atStartOfDay());
indexRows(ttUserBlendErcashMapper.sumBySourcesGroupByHour(sources, start, end), rawByBucket, absByBucket);
for (int h = 0; h <= 23; h++) {
dateList.add(String.format("%02d:00", h));
appendPoint(Collections.singletonList(String.valueOf(h)), rawByBucket, absByBucket,
rechargeList, boxOpenList, fightBoxOpenList, luckyUpgradeList, westernDuelList, wheelList, roseladyList);
}
} else if ("week".equals(type)) {
// 按周:近4周,单次查询按日聚合,再在内存中合并为每周
LocalDate rangeStart = today.minusWeeks(3).with(java.time.DayOfWeek.MONDAY);
LocalDate rangeEnd = today.with(java.time.DayOfWeek.MONDAY).plusWeeks(1);
Timestamp start = Timestamp.valueOf(rangeStart.atStartOfDay());
Timestamp end = Timestamp.valueOf(rangeEnd.atStartOfDay());
indexRows(ttUserBlendErcashMapper.sumBySourcesGroupByDate(sources, start, end), rawByBucket, absByBucket);
for (int w = 3; w >= 0; w--) {
LocalDate weekStart = today.minusWeeks(w).with(java.time.DayOfWeek.MONDAY);
LocalDate weekEnd = weekStart.plusWeeks(1);
dateList.add(weekStart.getMonthValue() + "/" + weekStart.getDayOfMonth() + "-" + weekEnd.minusDays(1).getMonthValue() + "/" + weekEnd.minusDays(1).getDayOfMonth());
List<String> keys = new ArrayList<>();
for (LocalDate d = weekStart; d.isBefore(weekEnd); d = d.plusDays(1)) {
keys.add(d.toString());
}
appendPoint(keys, rawByBucket, absByBucket,
rechargeList, boxOpenList, fightBoxOpenList, luckyUpgradeList, westernDuelList, wheelList, roseladyList);
}
} else {
// 按天:近7天,单次查询按日聚合
LocalDate rangeStart = today.minusDays(6);
Timestamp start = Timestamp.valueOf(rangeStart.atStartOfDay());
Timestamp end = Timestamp.valueOf(today.plusDays(1).atStartOfDay());
indexRows(ttUserBlendErcashMapper.sumBySourcesGroupByDate(sources, start, end), rawByBucket, absByBucket);
for (int i = 6; i >= 0; i--) {
LocalDate date = today.minusDays(i);
dateList.add(date.getMonthValue() + "/" + date.getDayOfMonth());
appendPoint(Collections.singletonList(date.toString()), rawByBucket, absByBucket,
rechargeList, boxOpenList, fightBoxOpenList, luckyUpgradeList, westernDuelList, wheelList, roseladyList);
}
}
Map<String, Object> result = new HashMap<>();
result.put("dateList", dateList);
result.put("rechargeList", rechargeList);
result.put("boxOpenList", boxOpenList);
result.put("fightBoxOpenList", fightBoxOpenList);
result.put("luckyUpgradeList", luckyUpgradeList);
result.put("westernDuelList", westernDuelList);
result.put("wheelList", wheelList);
result.put("roseladyList", roseladyList);
return com.ruoyi.common.core.domain.R.ok(result);
}
/**
* 把 GROUP BY (source, bucket) 的聚合结果整理为 bucketKey -> (source -> 金额) 的双层 Map。
* bucket 对按天/周为 yyyy-MM-dd(DATE),对按小时为 0-23(HOUR)。
*/
private void indexRows(List<Map<String, Object>> rows,
Map<String, Map<Integer, BigDecimal>> rawByBucket,
Map<String, Map<Integer, BigDecimal>> absByBucket) {
if (rows == null) return;
for (Map<String, Object> row : rows) {
if (row == null || row.get("source") == null || row.get("bucket") == null) continue;
String bucket = row.get("bucket").toString();
Integer src = Integer.parseInt(row.get("source").toString());
BigDecimal amt = row.get("amt") != null ? new BigDecimal(row.get("amt").toString()) : BigDecimal.ZERO;
BigDecimal absAmt = row.get("absAmt") != null ? new BigDecimal(row.get("absAmt").toString()) : BigDecimal.ZERO;
rawByBucket.computeIfAbsent(bucket, k -> new HashMap<>()).put(src, amt);
absByBucket.computeIfAbsent(bucket, k -> new HashMap<>()).put(src, absAmt);
}
}
/**
* 汇总给定时间桶(可跨多天,如按周则传入该周 7 天的 key)在各 source 上的金额,追加到对应折线图数据列。
* 充值取原值(RECHARGE 为收入正值);各游戏消费取绝对值,与原 abs=true 语义一致。
*/
private void appendPoint(List<String> bucketKeys,
Map<String, Map<Integer, BigDecimal>> rawByBucket,
Map<String, Map<Integer, BigDecimal>> absByBucket,
List<BigDecimal> rechargeList, List<BigDecimal> boxOpenList,
List<BigDecimal> fightBoxOpenList, List<BigDecimal> luckyUpgradeList,
List<BigDecimal> westernDuelList, List<BigDecimal> wheelList,
List<BigDecimal> roseladyList) {
BigDecimal recharge = BigDecimal.ZERO;
BigDecimal box = BigDecimal.ZERO;
BigDecimal fightBox = BigDecimal.ZERO;
BigDecimal luckyUpgrade = BigDecimal.ZERO;
BigDecimal westernDuel = BigDecimal.ZERO;
BigDecimal wheel = BigDecimal.ZERO;
BigDecimal wheelRefund = BigDecimal.ZERO;
BigDecimal roselady = BigDecimal.ZERO;
for (String key : bucketKeys) {
Map<Integer, BigDecimal> raw = rawByBucket.getOrDefault(key, Collections.emptyMap());
Map<Integer, BigDecimal> abs = absByBucket.getOrDefault(key, Collections.emptyMap());
recharge = recharge.add(raw.getOrDefault(TtAccountRecordSource.RECHARGE.getCode(), BigDecimal.ZERO));
box = box.add(abs.getOrDefault(TtAccountRecordSource.GAME_TYPE_01.getCode(), BigDecimal.ZERO));
fightBox = fightBox.add(abs.getOrDefault(TtAccountRecordSource.GAME_TYPE_02.getCode(), BigDecimal.ZERO));
luckyUpgrade = luckyUpgrade.add(abs.getOrDefault(TtAccountRecordSource.GOLD_DEVICE.getCode(), BigDecimal.ZERO));
westernDuel = westernDuel.add(abs.getOrDefault(TtAccountRecordSource.BULLET_SPIN.getCode(), BigDecimal.ZERO));
wheel = wheel.add(abs.getOrDefault(TtAccountRecordSource.LUCKLY_WHEEL_SPIN.getCode(), BigDecimal.ZERO));
wheelRefund = wheelRefund.add(abs.getOrDefault(TtAccountRecordSource.WHEEL_BET_REFUND.getCode(), BigDecimal.ZERO));
roselady = roselady.add(abs.getOrDefault(TtAccountRecordSource.OLYMPUS_SPIN.getCode(), BigDecimal.ZERO));
}
rechargeList.add(recharge);
boxOpenList.add(box);
fightBoxOpenList.add(fightBox);
luckyUpgradeList.add(luckyUpgrade);
westernDuelList.add(westernDuel);
// 转盘取净口径:消费 − 兜底退款(退款局的注单没进奖池,毛口径会与奖池统计对不上)
wheelList.add(wheel.subtract(wheelRefund).max(BigDecimal.ZERO));
roseladyList.add(roselady);
}
/**
* 指定 source 的金额绝对值合计(可按时间窗口 + 有效用户过滤),用于把兜底退款从投注额里冲减。
* start/end 为 null 表示不限时间。
*/
private BigDecimal sumAbsBySource(Integer source, Timestamp start, Timestamp end, String validUserFilter) {
LambdaQueryWrapper<TtUserBlendErcash> wrapper = Wrappers.<TtUserBlendErcash>lambdaQuery()
.eq(TtUserBlendErcash::getSource, source)
.inSql(TtUserBlendErcash::getUserId, validUserFilter);
if (start != null) wrapper.ge(TtUserBlendErcash::getCreateTime, start);
if (end != null) wrapper.lt(TtUserBlendErcash::getCreateTime, end);
return ttUserBlendErcashMapper.selectList(wrapper).stream()
.map(r -> r.getAmount() != null ? r.getAmount().abs() : BigDecimal.ZERO)
.reduce(BigDecimal.ZERO, BigDecimal::add);
}
@GetMapping("/homeStats")
public com.ruoyi.common.core.domain.R homeStats() {
LocalDate today = LocalDate.now();
Timestamp startOfDay = Timestamp.valueOf(today.atStartOfDay());
Timestamp endOfDay = Timestamp.valueOf(today.plusDays(1).atStartOfDay());
String validUserFilter = "SELECT user_id FROM tt_user WHERE is_blank_account != 1 AND user_type != '03' AND status != '1' AND del_flag = '0'";
// 历史总充值(不限时间,统一排除:白号、机器人、封禁、逻辑删除、真删除用户;主表 + 归档表 UNION ALL)
BigDecimal totalRecharge = ttUserBlendErcashMapper.sumAmountBySourceAndTimeWithArchive(
TtAccountRecordSource.RECHARGE.getCode(), null, null);
// 今日总充值:source = 1(统一排除:白号、机器人、封禁、逻辑删除、真删除用户;主表 + 归档表 UNION ALL)
BigDecimal todayRecharge = ttUserBlendErcashMapper.sumAmountBySourceAndTimeWithArchive(
TtAccountRecordSource.RECHARGE.getCode(), startOfDay, endOfDay);
// 今日总投注:与今日总返奖口径对齐,覆盖全部7个游戏消费(含Roll房=6、荒野争锋=34)
// 统一排除:白号、机器人、封禁、逻辑删除、真删除用户
List<Integer> betSources = new ArrayList<>(TtAccountRecordSource.getGameBetCodes());
LambdaQueryWrapper<TtUserBlendErcash> betWrapper =
Wrappers.<TtUserBlendErcash>lambdaQuery()
.in(TtUserBlendErcash::getSource, betSources)
.ge(TtUserBlendErcash::getCreateTime, startOfDay)
.lt(TtUserBlendErcash::getCreateTime, endOfDay)
.inSql(TtUserBlendErcash::getUserId, validUserFilter);
BigDecimal todayBet = ttUserBlendErcashMapper.selectList(betWrapper).stream()
.map(r -> r.getAmount() != null ? r.getAmount().abs() : BigDecimal.ZERO)
.reduce(BigDecimal.ZERO, BigDecimal::add);
// 疯狂转盘净口径:扣掉兜底退款(source=64)。退款局从未开奖、也没进奖池,不扣会与奖池统计对不上
todayBet = todayBet.subtract(sumAbsBySource(
TtAccountRecordSource.WHEEL_BET_REFUND.getCode(), startOfDay, endOfDay, validUserFilter))
.max(BigDecimal.ZERO);
// 今日总返奖:唯一化改造后所有游戏产出均先入背包(自动分解也先入背包再分解),
// 今日返奖仅按背包产出统计(tt_box_records,7个游戏,按 create_time,不看 status),不再与金币流水交叉统计。
BigDecimal todayReward = ttBoxRecordsMapper.todayOrnamentRewardTotal(startOfDay, endOfDay);
// 历史总返奖:与今日总返奖同口径(tt_box_records,7个游戏,不看 status、含已分解),仅不限时间范围;
// 不再叠加早期金币返奖流水与单独的Roll房统计,保证两个指标仅相差时间范围。
BigDecimal historyReward = ttBoxRecordsMapper.historyOrnamentRewardTotal();
// 总发货金额:tt_delivery_record WHERE status=10(统一排除:白号、机器人、封禁、逻辑删除、真删除用户)
LambdaQueryWrapper<TtDeliveryRecord> deliveryWrapper =
Wrappers.<TtDeliveryRecord>lambdaQuery()
.eq(TtDeliveryRecord::getStatus, 10)
.inSql(TtDeliveryRecord::getUserId, validUserFilter);
BigDecimal totalDeliveryAmount = ttDeliveryRecordMapper.selectList(deliveryWrapper).stream()
.map(TtDeliveryRecord::getBuyPrice)
.filter(java.util.Objects::nonNull)
.reduce(BigDecimal.ZERO, BigDecimal::add);
// 总流水:所有用户(招商+主播+普通用户)的历史累计游戏消费总额(统一排除:白号、机器人、封禁、逻辑删除、真删除用户)
List<Integer> gameBetSources = new ArrayList<>(TtAccountRecordSource.getGameBetCodes());
LambdaQueryWrapper<TtUserBlendErcash> flowWrapper =
Wrappers.<TtUserBlendErcash>lambdaQuery()
.in(TtUserBlendErcash::getSource, gameBetSources)
.inSql(TtUserBlendErcash::getUserId, validUserFilter);
BigDecimal totalFlow = ttUserBlendErcashMapper.selectList(flowWrapper).stream()
.map(r -> r.getAmount() != null ? r.getAmount().abs() : BigDecimal.ZERO)
.reduce(BigDecimal.ZERO, BigDecimal::add);
// 与今日总投注同口径:扣掉疯狂转盘兜底退款
totalFlow = totalFlow.subtract(sumAbsBySource(
TtAccountRecordSource.WHEEL_BET_REFUND.getCode(), null, null, validUserFilter))
.max(BigDecimal.ZERO);
Map<String, Object> result = new HashMap<>();
result.put("totalRecharge", totalRecharge);
result.put("todayRecharge", todayRecharge);
result.put("todayBet", todayBet);
result.put("todayReward", todayReward);
result.put("historyReward", historyReward);
result.put("totalDeliveryAmount", totalDeliveryAmount);
result.put("totalFlow", totalFlow);
return com.ruoyi.common.core.domain.R.ok(result);
}
/**
* 实时RTP(Return To Player)统计:当日各游戏的投注/奖励/RTP百分比。
* 唯一化改造后所有产出先入背包,返奖统一按 tt_box_records 今日产出(按 source 分组、不看 status)统计,
* 投注仍取 tt_user_blend_ercash 各游戏消费 source;覆盖全部 8 个产出游戏(含玫瑰女郎)。
*/
@GetMapping("/realTimeRtp")
public AjaxResult realTimeRtp() {
LocalDate today = LocalDate.now();
Timestamp startOfDay = Timestamp.valueOf(today.atStartOfDay());
Timestamp endOfDay = Timestamp.valueOf(today.plusDays(1).atStartOfDay());
// 投注 source:7 个游戏消费(含 Roll房=6、荒野争锋=34)+ 玫瑰女郎=60 + 转盘兜底退款=64(净口径冲减用)
List<Integer> betSources = Arrays.asList(2, 4, 6, 34, 38, 40, 50, 60,
TtAccountRecordSource.WHEEL_BET_REFUND.getCode());
// 一次查询获取所有投注 source 的聚合数据,避免 N+1
List<Map<String, Object>> sumResult = ttUserBlendErcashMapper.sumBySourcesAndTime(betSources, startOfDay, endOfDay);
// 构建 source -> absAmt 的映射(各游戏今日投注额)
Map<Integer, BigDecimal> sourceAmtMap = new HashMap<>();
for (Map<String, Object> row : sumResult) {
Integer source = Integer.parseInt(row.get("source").toString());
BigDecimal absAmt = row.get("absAmt") != null ? new BigDecimal(row.get("absAmt").toString()) : BigDecimal.ZERO;
sourceAmtMap.put(source, absAmt);
}
// 返奖:唯一化改造后所有产出先入背包,今日返奖仅按背包产出统计(按 tt_box_records.source 分组、不看 status)
List<Map<String, Object>> ornamentResult = ttBoxRecordsMapper.todayOrnamentRewardBySource(startOfDay, endOfDay);
Map<Integer, BigDecimal> ornamentBySource = new HashMap<>();
if (ornamentResult != null) {
for (Map<String, Object> row : ornamentResult) {
Integer src = Integer.parseInt(row.get("source").toString());
BigDecimal totalPrice = row.get("totalPrice") != null ? new BigDecimal(row.get("totalPrice").toString()) : BigDecimal.ZERO;
ornamentBySource.put(src, totalPrice);
}
}
// 游戏配置:[投注 source(ercash), 饰品 source(box_records)]
int[][] gameConfig = {
{50, 11}, // 极速糖果
{38, 99}, // 疯狂转盘
{40, 4}, // 幸运升级
{2, 1}, // 经典开箱
{4, 2}, // 对战
{6, 3}, // Roll 房(索引 5)
{34, 12}, // 荒野争锋
{60, 13} // 玫瑰女郎(索引 7,投注=60,背包=13)
};
String[] gameNames = {"极速糖果", "疯狂转盘", "幸运升级", "经典开箱", "对战", "Roll 房", "荒野争锋", "玫瑰女郎"};
List<Map<String, Object>> data = new ArrayList<>();
BigDecimal rollRoomBet = BigDecimal.ZERO;
BigDecimal rollRoomReward = BigDecimal.ZERO;
for (int i = 0; i < gameConfig.length; i++) {
BigDecimal bet = sourceAmtMap.getOrDefault(gameConfig[i][0], BigDecimal.ZERO);
// 疯狂转盘取净口径:消费额 − 兜底退款(source=64)。退款注单所在回合从未开奖、也没进奖池,
// 不冲减会让首页投注/RTP 与奖池统计(真实池累计)对不上
if (gameConfig[i][0] == TtAccountRecordSource.LUCKLY_WHEEL_SPIN.getCode()) {
bet = bet.subtract(sourceAmtMap.getOrDefault(
TtAccountRecordSource.WHEEL_BET_REFUND.getCode(), BigDecimal.ZERO));
if (bet.compareTo(BigDecimal.ZERO) < 0) bet = BigDecimal.ZERO;
}
// 返奖 = 今日背包产出(该游戏 box source 的 ornaments_price 之和)
BigDecimal reward = ornamentBySource.getOrDefault(gameConfig[i][1], BigDecimal.ZERO);
// 累加 Roll 房汇总
if (i == 5) {
rollRoomBet = bet;
rollRoomReward = reward;
}
BigDecimal rtp = BigDecimal.ZERO;
if (bet.compareTo(BigDecimal.ZERO) > 0) {
rtp = reward.multiply(new BigDecimal("100")).divide(bet, 2, java.math.RoundingMode.HALF_UP);
}
Map<String, Object> item = new LinkedHashMap<>();
item.put("name", gameNames[i]);
item.put("bet", bet.setScale(2, java.math.RoundingMode.HALF_UP));
item.put("reward", reward.setScale(2, java.math.RoundingMode.HALF_UP));
item.put("rtp", rtp);
data.add(item);
}
// 额外返回 Roll 房汇总(仅今日返奖,因为 Roll 房无下注,只统计返奖)
Map<String, Object> rollRoomSummary = new LinkedHashMap<>();
rollRoomSummary.put("reward", rollRoomReward.setScale(2, java.math.RoundingMode.HALF_UP));
Map<String, Object> result = new HashMap<>();
result.put("games", data);
result.put("rollRoom", rollRoomSummary);
return AjaxResult.success(result);
}
}
@@ -0,0 +1,109 @@
package com.ruoyi.admin.controller;
import com.ruoyi.admin.mapper.TtRedPackMapper;
import com.ruoyi.admin.service.TtRedPackService;
import com.ruoyi.common.annotation.Log;
import com.ruoyi.common.core.controller.BaseController;
import com.ruoyi.common.core.domain.AjaxResult;
import com.ruoyi.common.core.page.TableDataInfo;
import com.ruoyi.common.enums.BusinessType;
import com.ruoyi.common.utils.poi.ExcelUtil;
import com.ruoyi.domain.other.TtRedPack;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.*;
import jakarta.servlet.http.HttpServletResponse;
import java.util.List;
/**
* 【请填写功能名称】Controller
*
* @author ruoyi
* @date 2023-06-29
*/
@RestController
@RequestMapping("/admin/redPack")
public class TtRedPackController extends BaseController
{
@Autowired
private TtRedPackService ttRedPackService;
/**
* 查询【请填写功能名称】列表
*/
@PreAuthorize("@ss.hasPermi('skinsback:ttRedPack:list')")
@GetMapping("/list")
public TableDataInfo list(TtRedPack ttRedPack)
{
startPage();
List<TtRedPack> list = ttRedPackService.selectTtRedPackList(ttRedPack);
return getDataTable(list);
}
@PreAuthorize("@ss.hasPermi('skinsback:ttRedPack:listAll')")
@GetMapping("/listAll")
public TableDataInfo listAll(TtRedPack ttRedPack)
{
List<TtRedPack> list = ttRedPackService.selectTtRedPackList(ttRedPack);
return getDataTable(list);
}
/**
* 导出【请填写功能名称】列表
*/
@PreAuthorize("@ss.hasPermi('skinsback:ttRedPack:export')")
@Log(title = "【请填写功能名称】", businessType = BusinessType.EXPORT)
@PostMapping("/export")
public void export(HttpServletResponse response, TtRedPack ttRedPack)
{
List<TtRedPack> list = ttRedPackService.selectTtRedPackList(ttRedPack);
ExcelUtil<TtRedPack> util = new ExcelUtil<TtRedPack>(TtRedPack.class);
util.exportExcel(response, list, "【请填写功能名称】数据");
}
/**
* 获取【请填写功能名称】详细信息
*/
@PreAuthorize("@ss.hasPermi('skinsback:ttRedPack:query')")
@GetMapping(value = "/{id}")
public AjaxResult getInfo(@PathVariable("id") Long id)
{
return success(ttRedPackService.selectTtRedPackById(id));
}
/**
* 新增【请填写功能名称】
*/
@PreAuthorize("@ss.hasPermi('skinsback:ttRedPack:add')")
@Log(title = "CDK管理", action = "新增", businessType = BusinessType.INSERT,
entityClass = TtRedPack.class, mapperClass = TtRedPackMapper.class)
@PostMapping
public AjaxResult add(@RequestBody TtRedPack ttRedPack)
{
ttRedPack.setValidCount(ttRedPack.getPackCount());
ttRedPack.setStatus(0l);
return toAjax(ttRedPackService.insertTtRedPack(ttRedPack));
}
/**
* 修改【请填写功能名称】
*/
@PreAuthorize("@ss.hasPermi('skinsback:ttRedPack:edit')")
@Log(title = "CDK管理", action = "修改", businessType = BusinessType.UPDATE,
entityClass = TtRedPack.class, mapperClass = TtRedPackMapper.class)
@PutMapping
public AjaxResult edit(@RequestBody TtRedPack ttRedPack)
{
return toAjax(ttRedPackService.updateTtRedPack(ttRedPack));
}
/**
* 删除【请填写功能名称】
*/
@PreAuthorize("@ss.hasPermi('skinsback:ttRedPack:remove')")
@Log(title = "CDK管理", action = "删除", businessType = BusinessType.DELETE)
@DeleteMapping("/{ids}")
public AjaxResult remove(@PathVariable Long[] ids)
{
return toAjax(ttRedPackService.deleteTtRedPackByIds(ids));
}
}
@@ -0,0 +1,74 @@
package com.ruoyi.admin.controller;
import com.ruoyi.admin.mapper.TtRedPacketMapper;
import com.ruoyi.common.enums.BusinessType;
import com.ruoyi.common.annotation.Log;
import com.ruoyi.admin.service.TtRedPacketService;
import com.ruoyi.domain.other.TtRedPacket;
import com.ruoyi.domain.other.TtRedPacketBody;
import com.ruoyi.domain.vo.TtRedPacketDataVO;
import com.ruoyi.common.core.controller.BaseController;
import com.ruoyi.common.core.domain.AjaxResult;
import com.ruoyi.common.core.domain.R;
import com.ruoyi.common.core.page.PageDataInfo;
import com.ruoyi.common.utils.DateUtils;
import com.ruoyi.common.utils.StringUtils;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.springframework.web.bind.annotation.*;
import java.util.Arrays;
import java.util.List;
@Api(tags = "管理端 红包")
@RestController
@RequestMapping("/admin/redPacket")
public class TtRedPacketController extends BaseController {
private final TtRedPacketService redPacketService;
public TtRedPacketController(TtRedPacketService redPacketService) {
this.redPacketService = redPacketService;
}
@GetMapping("/list")
public PageDataInfo<TtRedPacketDataVO> list(TtRedPacketBody ttRedPacketBody) {
startPage();
List<TtRedPacketDataVO> list = redPacketService.queryList(ttRedPacketBody);
return getPageData(list);
}
@GetMapping(value = "/{id}")
public R<TtRedPacketDataVO> getInfo(@PathVariable("id") Integer id) {
TtRedPacketDataVO data = redPacketService.queryList(TtRedPacketBody.builder().id(id).build()).get(0);
return R.ok(data);
}
@Log(title = "CDK口令", action = "新增", businessType = BusinessType.INSERT)
@ApiOperation("生成红包")
@PostMapping
public AjaxResult add(@RequestBody TtRedPacketDataVO ttRedPacketDataVO) {
List<String> passwordList = redPacketService.insertRedPacket(ttRedPacketDataVO);
return StringUtils.isNotNull(passwordList) ? AjaxResult.success("生成成功!", passwordList) : AjaxResult.error("生成红包异常");
}
@Log(title = "CDK口令", action = "修改", businessType = BusinessType.UPDATE,
entityClass = TtRedPacket.class, mapperClass = TtRedPacketMapper.class)
@PutMapping
public AjaxResult edit(@RequestBody TtRedPacket redPacket) {
redPacket.setUpdateBy(getUsername());
redPacket.setUpdateTime(DateUtils.getNowDate());
return redPacketService.updateRedPacketById(redPacket);
// return StringUtils.isEmpty(msg) ? AjaxResult.success() : AjaxResult.error(msg);
}
@Log(title = "CDK口令", action = "删除", businessType = BusinessType.DELETE)
@DeleteMapping("/{ids}")
public AjaxResult remove(@PathVariable Integer[] ids) {
boolean b = redPacketService.removeByIds(Arrays.asList(ids));
if (b) return AjaxResult.success();
return AjaxResult.error();
}
}
@@ -0,0 +1,30 @@
package com.ruoyi.admin.controller;
import com.ruoyi.admin.service.TtRedPacketRecordService;
import com.ruoyi.domain.other.TtRedPacketRecordBody;
import com.ruoyi.domain.vo.TtRedPacketRecordDataVO;
import com.ruoyi.common.core.controller.BaseController;
import com.ruoyi.common.core.page.PageDataInfo;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.List;
@RestController
@RequestMapping("/admin/redPacketRecord")
public class TtRedPacketRecordController extends BaseController {
private final TtRedPacketRecordService redPacketRecordService;
public TtRedPacketRecordController(TtRedPacketRecordService redPacketRecordService) {
this.redPacketRecordService = redPacketRecordService;
}
@GetMapping("/getRedPacketRecordList")
public PageDataInfo<TtRedPacketRecordDataVO> getRedPacketRecordList(TtRedPacketRecordBody ttRedPacketRecordBody) {
startPage();
List<TtRedPacketRecordDataVO> list = redPacketRecordService.queryList(ttRedPacketRecordBody);
return getPageData(list);
}
}
@@ -0,0 +1,101 @@
package com.ruoyi.admin.controller;
import com.ruoyi.admin.mapper.TtReplacementRecordMapper;
import com.ruoyi.admin.service.TtReplacementRecordService;
import com.ruoyi.common.annotation.Log;
import com.ruoyi.common.core.controller.BaseController;
import com.ruoyi.common.core.domain.AjaxResult;
import com.ruoyi.common.core.page.TableDataInfo;
import com.ruoyi.common.enums.BusinessType;
import com.ruoyi.common.utils.poi.ExcelUtil;
import com.ruoyi.domain.other.TtReplacementRecord;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.*;
import jakarta.servlet.http.HttpServletResponse;
import java.util.List;
/**
* 汰换记录Controller
*
* @author junhai
* @date 2023-09-10
*/
@RestController
@RequestMapping("/admin/replacementRecord")
public class TtReplacementRecordController extends BaseController
{
@Autowired
private TtReplacementRecordService ttReplacementRecordService;
/**
* 查询汰换记录列表
*/
@PreAuthorize("@ss.hasPermi('skinsback:replacementRecord:list')")
@GetMapping("/list")
public TableDataInfo list(TtReplacementRecord ttReplacementRecord)
{
startPage();
List<TtReplacementRecord> list = ttReplacementRecordService.selectTtReplacementRecordList(ttReplacementRecord);
return getDataTable(list);
}
/**
* 导出汰换记录列表
*/
@PreAuthorize("@ss.hasPermi('skinsback:replacementRecord:export')")
@Log(title = "汰换记录", businessType = BusinessType.EXPORT)
@PostMapping("/export")
public void export(HttpServletResponse response, TtReplacementRecord ttReplacementRecord)
{
List<TtReplacementRecord> list = ttReplacementRecordService.selectTtReplacementRecordList(ttReplacementRecord);
ExcelUtil<TtReplacementRecord> util = new ExcelUtil<TtReplacementRecord>(TtReplacementRecord.class);
util.exportExcel(response, list, "汰换记录数据");
}
/**
* 获取汰换记录详细信息
*/
@PreAuthorize("@ss.hasPermi('skinsback:replacementRecord:query')")
@GetMapping(value = "/{id}")
public AjaxResult getInfo(@PathVariable("id") Long id)
{
return success(ttReplacementRecordService.selectTtReplacementRecordById(id));
}
/**
* 新增汰换记录
*/
@PreAuthorize("@ss.hasPermi('skinsback:replacementRecord:add')")
@Log(title = "汰换记录", action = "新增", businessType = BusinessType.INSERT,
entityClass = TtReplacementRecord.class, mapperClass = TtReplacementRecordMapper.class)
@PostMapping
public AjaxResult add(@RequestBody TtReplacementRecord ttReplacementRecord)
{
return toAjax(ttReplacementRecordService.insertTtReplacementRecord(ttReplacementRecord));
}
/**
* 修改汰换记录
*/
@PreAuthorize("@ss.hasPermi('skinsback:replacementRecord:edit')")
@Log(title = "汰换记录", action = "修改", businessType = BusinessType.UPDATE,
entityClass = TtReplacementRecord.class, mapperClass = TtReplacementRecordMapper.class)
@PutMapping
public AjaxResult edit(@RequestBody TtReplacementRecord ttReplacementRecord)
{
return toAjax(ttReplacementRecordService.updateTtReplacementRecord(ttReplacementRecord));
}
/**
* 删除汰换记录
*/
@PreAuthorize("@ss.hasPermi('skinsback:replacementRecord:remove')")
@Log(title = "汰换记录", action = "删除", businessType = BusinessType.DELETE)
@DeleteMapping("/{ids}")
public AjaxResult remove(@PathVariable Long[] ids)
{
return toAjax(ttReplacementRecordService.deleteTtReplacementRecordByIds(ids));
}
}
@@ -0,0 +1,200 @@
package com.ruoyi.admin.controller;
import java.math.BigDecimal;
import java.util.List;
import jakarta.servlet.http.HttpServletResponse;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import com.ruoyi.admin.mapper.TtRobotFightGroupBoxMapper;
import com.ruoyi.common.annotation.Log;
import com.ruoyi.common.core.controller.BaseController;
import com.ruoyi.common.core.domain.AjaxResult;
import com.ruoyi.common.enums.BusinessType;
import com.ruoyi.domain.other.TtBox;
import com.ruoyi.domain.other.TtRobotFightGroup;
import com.ruoyi.domain.other.TtRobotFightGroupBox;
import com.ruoyi.domain.other.TtRobotFightPriceConfig;
import com.ruoyi.admin.mapper.TtBoxMapper;
import com.ruoyi.admin.mapper.TtRobotFightGroupMapper;
import com.ruoyi.admin.mapper.TtRobotFightPriceConfigMapper;
import com.ruoyi.admin.service.TtRobotFightGroupBoxService;
import com.ruoyi.common.utils.poi.ExcelUtil;
import com.ruoyi.common.core.page.TableDataInfo;
/**
* 机器人对战分组宝箱Controller
*
* @author ruoyi
* @date 2024-06-28
*/
@RestController
@RequestMapping("/admin/group/box")
public class TtRobotFightGroupBoxController extends BaseController
{
@Autowired
private TtRobotFightGroupBoxService ttRobotFightGroupBoxService;
@Autowired
private TtBoxMapper ttBoxMapper;
@Autowired
private TtRobotFightGroupMapper ttRobotFightGroupMapper;
@Autowired
private TtRobotFightPriceConfigMapper ttRobotFightPriceConfigMapper;
/**
* 查询机器人对战分组宝箱列表
*/
@PreAuthorize("@ss.hasPermi('admin:box:list')")
@GetMapping("/list/{groupId}")
public TableDataInfo list(
@PathVariable("groupId") Integer groupId,
TtRobotFightGroupBox ttRobotFightGroupBox
)
{
startPage();
List<TtRobotFightGroupBox> list = ttRobotFightGroupBoxService
.selectTtRobotFightGroupBoxList(groupId, ttRobotFightGroupBox);
return getDataTable(list);
}
/**
* 获取机器人对战分组宝箱详细信息
*/
@PreAuthorize("@ss.hasPermi('admin:box:query')")
@GetMapping(value = "/{groupId}/{boxId}")
public AjaxResult getInfo(
@PathVariable("groupId") Integer groupId,
@PathVariable("boxId") Integer boxId
)
{
return success(ttRobotFightGroupBoxService.selectTtRobotFightGroupBoxByBoxId(groupId, boxId));
}
/**
* 新增机器人对战分组宝箱
*/
@PreAuthorize("@ss.hasPermi('admin:box:add')")
@Log(title = "机器人对战分组宝箱", action = "新增", businessType = BusinessType.INSERT,
entityClass = TtRobotFightGroupBox.class, mapperClass = TtRobotFightGroupBoxMapper.class)
@PostMapping
public AjaxResult add(@Validated @RequestBody TtRobotFightGroupBox ttRobotFightGroupBox)
{
// 检查该分组下是否已存在该宝箱
TtRobotFightGroupBox existing = ttRobotFightGroupBoxService
.selectTtRobotFightGroupBoxByBoxId(ttRobotFightGroupBox.getGroupId(), ttRobotFightGroupBox.getBoxId());
if (existing != null) {
return AjaxResult.error("该宝箱已存在于当前分组中,请勿重复添加");
}
// 校验新增后分组总价值是否超过档位上限
AjaxResult check = validateTotalPrice(ttRobotFightGroupBox.getGroupId(),
ttRobotFightGroupBox.getBoxId(), ttRobotFightGroupBox.getBoxNum(), null, null);
if (check != null) return check;
return toAjax(ttRobotFightGroupBoxService.insertTtRobotFightGroupBox(ttRobotFightGroupBox));
}
/**
* 修改机器人对战分组宝箱
*/
@PreAuthorize("@ss.hasPermi('admin:box:edit')")
@Log(title = "机器人对战分组宝箱", action = "修改", businessType = BusinessType.UPDATE,
entityClass = TtRobotFightGroupBox.class, mapperClass = TtRobotFightGroupBoxMapper.class)
@PutMapping
public AjaxResult edit(@Validated @RequestBody TtRobotFightGroupBox ttRobotFightGroupBox)
{
// 校验修改后分组总价值是否超过档位上限(排除被修改的那条旧记录)
AjaxResult check = validateTotalPrice(ttRobotFightGroupBox.getGroupId(),
ttRobotFightGroupBox.getBoxId(), ttRobotFightGroupBox.getBoxNum(),
ttRobotFightGroupBox.getOldBoxId(), ttRobotFightGroupBox.getGroupId());
if (check != null) return check;
return toAjax(ttRobotFightGroupBoxService.updateTtRobotFightGroupBox(ttRobotFightGroupBox));
}
/**
* 校验新增/修改后分组宝箱总价值是否超过档位上限,以及所有宝箱的总数量是否超过 15
*
* @param groupId 分组ID
* @param newBoxId 本次操作的宝箱ID
* @param newBoxNum 本次操作的宝箱数量
* @param excludeBoxId 修改时需排除的旧宝箱ID(新增传null)
* @param excludeGroupId 修改时需排除的旧分组ID(新增传null)
*/
private AjaxResult validateTotalPrice(Integer groupId, Integer newBoxId, Integer newBoxNum,
Integer excludeBoxId, Integer excludeGroupId) {
if (groupId == null) return null;
// 查出该分组已有的所有宝箱记录
List<TtRobotFightGroupBox> existingList = ttRobotFightGroupBoxService
.selectTtRobotFightGroupBoxList(groupId, new TtRobotFightGroupBox());
// 计算现有宝箱的总数量(排除被修改的旧记录)
int totalNum = 0;
BigDecimal total = BigDecimal.ZERO;
for (TtRobotFightGroupBox item : existingList) {
if (excludeBoxId != null && item.getBoxId().equals(excludeBoxId)) {
continue; // 修改时跳过旧记录
}
if (item.getBoxNum() != null) {
totalNum += item.getBoxNum();
}
TtBox itemBox = ttBoxMapper.selectById(item.getBoxId());
if (itemBox != null && itemBox.getPrice() != null && item.getBoxNum() != null) {
total = total.add(itemBox.getPrice().multiply(BigDecimal.valueOf(item.getBoxNum())));
}
}
// 加上本次新增/修改的数量和价值
if (newBoxNum != null) {
totalNum += newBoxNum;
}
if (newBoxId != null && newBoxNum != null) {
TtBox newBox = ttBoxMapper.selectById(newBoxId);
if (newBox == null) return AjaxResult.error("宝箱不存在");
if (newBox.getPrice() != null) {
total = total.add(newBox.getPrice().multiply(BigDecimal.valueOf(newBoxNum)));
}
}
// 校验总数量不超过 15
if (totalNum > 15) {
return AjaxResult.error("操作后分组宝箱总数量为 " + totalNum + ",超过上限 15 个,请减少宝箱数量");
}
// 校验分组宝箱总价值不超过档位上限
TtRobotFightGroup group = ttRobotFightGroupMapper.selectTtRobotFightGroupByGroupId(groupId);
if (group != null && group.getPriceConfigId() != null) {
TtRobotFightPriceConfig priceConfig = ttRobotFightPriceConfigMapper
.selectTtRobotFightPriceConfigById(group.getPriceConfigId());
if (priceConfig != null && priceConfig.getPriceLimit() != null) {
BigDecimal priceLimit = priceConfig.getPriceLimit();
if (total.compareTo(priceLimit) > 0) {
return AjaxResult.error("操作后分组宝箱总价值 ¥" + total.stripTrailingZeros().toPlainString()
+ " 超过档位上限 ¥" + priceLimit.stripTrailingZeros().toPlainString()
+ ",请调整宝箱数量或选择价格更低的宝箱");
}
}
}
return null;
}
/**
* 删除机器人对战分组宝箱
*/
@PreAuthorize("@ss.hasPermi('admin:box:remove')")
@Log(title = "机器人对战分组宝箱", action = "删除", businessType = BusinessType.DELETE)
@DeleteMapping("/{groupId}/{boxIds}")
public AjaxResult remove(@PathVariable Integer groupId, @PathVariable Integer[] boxIds)
{
return toAjax(ttRobotFightGroupBoxService.deleteTtRobotFightGroupBoxByGroupIds(groupId, boxIds));
}
}
@@ -0,0 +1,129 @@
package com.ruoyi.admin.controller;
import java.util.List;
import jakarta.servlet.http.HttpServletResponse;
import com.ruoyi.admin.mapper.TtRobotFightGroupMapper;
import com.ruoyi.admin.mapper.TtRobotFightPriceConfigMapper;
import org.springframework.security.access.prepost.PreAuthorize;
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.PutMapping;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import com.ruoyi.common.annotation.Log;
import com.ruoyi.common.core.controller.BaseController;
import com.ruoyi.common.core.domain.AjaxResult;
import com.ruoyi.common.enums.BusinessType;
import com.ruoyi.domain.other.TtRobotFightGroup;
import com.ruoyi.domain.other.TtRobotFightPriceConfig;
import com.ruoyi.admin.service.TtRobotFightGroupService;
import com.ruoyi.common.utils.poi.ExcelUtil;
import com.ruoyi.common.core.page.TableDataInfo;
/**
* 机器人对战分组Controller
*
* @author ruoyi
* @date 2024-06-28
*/
@RestController
@RequestMapping("/admin/group")
public class TtRobotFightGroupController extends BaseController
{
@Autowired
private TtRobotFightGroupService ttRobotFightGroupService;
@Autowired
private TtRobotFightPriceConfigMapper ttRobotFightPriceConfigMapper;
/**
* 查询机器人对战分组列表
*/
@GetMapping("/list")
public TableDataInfo list(TtRobotFightGroup ttRobotFightGroup)
{
startPage();
List<TtRobotFightGroup> list = ttRobotFightGroupService.selectTtRobotFightGroupList(ttRobotFightGroup);
return getDataTable(list);
}
/**
* 导出机器人对战分组列表
*/
@Log(title = "机器人对战分组", businessType = BusinessType.EXPORT)
@PostMapping("/export")
public void export(HttpServletResponse response, TtRobotFightGroup ttRobotFightGroup)
{
List<TtRobotFightGroup> list = ttRobotFightGroupService.selectTtRobotFightGroupList(ttRobotFightGroup);
ExcelUtil<TtRobotFightGroup> util = new ExcelUtil<TtRobotFightGroup>(TtRobotFightGroup.class);
util.exportExcel(response, list, "机器人对战分组数据");
}
/**
* 获取机器人对战分组详细信息
*/
@GetMapping(value = "/{groupId}")
public AjaxResult getInfo(@PathVariable("groupId") Integer groupId)
{
return success(ttRobotFightGroupService.selectTtRobotFightGroupByGroupId(groupId));
}
/**
* 新增机器人对战分组
*/
@Log(title = "机器人对战分组", action = "新增", businessType = BusinessType.INSERT,
entityClass = TtRobotFightGroup.class, mapperClass = TtRobotFightGroupMapper.class)
@PostMapping
public AjaxResult add(@RequestBody TtRobotFightGroup ttRobotFightGroup)
{
// 支持 2 人(1v1)、3 人(1v1v1)、4 人(2v2 组队)三种对战模式
if (ttRobotFightGroup.getSeatNum() != 2 && ttRobotFightGroup.getSeatNum() != 3 && ttRobotFightGroup.getSeatNum() != 4) {
return AjaxResult.error("座位数量只能为 2、3 或 4");
}
if (ttRobotFightGroup.getPriceConfigId() == null) {
return AjaxResult.error("请选择价格档位");
}
TtRobotFightPriceConfig priceConfig = ttRobotFightPriceConfigMapper.selectTtRobotFightPriceConfigById(ttRobotFightGroup.getPriceConfigId());
if (priceConfig == null || !"0".equals(priceConfig.getStatus())) {
return AjaxResult.error("价格档位不存在或已停用");
}
return toAjax(ttRobotFightGroupService.insertTtRobotFightGroup(ttRobotFightGroup));
}
/**
* 修改机器人对战分组
*/
@Log(title = "机器人对战分组", action = "修改", businessType = BusinessType.UPDATE,
entityClass = TtRobotFightGroup.class, mapperClass = TtRobotFightGroupMapper.class)
@PutMapping
public AjaxResult edit(@RequestBody TtRobotFightGroup ttRobotFightGroup)
{
// 支持 2 人(1v1)、3 人(1v1v1)、4 人(2v2 组队)三种对战模式
if (ttRobotFightGroup.getSeatNum() != 2 && ttRobotFightGroup.getSeatNum() != 3 && ttRobotFightGroup.getSeatNum() != 4) {
return AjaxResult.error("座位数量只能为 2、3 或 4");
}
if (ttRobotFightGroup.getPriceConfigId() == null) {
return AjaxResult.error("请选择价格档位");
}
TtRobotFightPriceConfig priceConfig = ttRobotFightPriceConfigMapper.selectTtRobotFightPriceConfigById(ttRobotFightGroup.getPriceConfigId());
if (priceConfig == null || !"0".equals(priceConfig.getStatus())) {
return AjaxResult.error("价格档位不存在或已停用");
}
return toAjax(ttRobotFightGroupService.updateTtRobotFightGroup(ttRobotFightGroup));
}
/**
* 删除机器人对战分组
*/
@Log(title = "机器人对战分组", action = "删除", businessType = BusinessType.DELETE)
@DeleteMapping("/{groupIds}")
public AjaxResult remove(@PathVariable Integer[] groupIds)
{
return toAjax(ttRobotFightGroupService.deleteTtRobotFightGroupByGroupIds(groupIds));
}
}
@@ -0,0 +1,147 @@
package com.ruoyi.admin.controller;
import java.math.BigDecimal;
import java.util.List;
import org.springframework.security.access.prepost.PreAuthorize;
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.PutMapping;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import com.ruoyi.admin.mapper.TtRobotFightJoinConfigMapper;
import com.ruoyi.common.annotation.Log;
import com.ruoyi.common.core.controller.BaseController;
import com.ruoyi.common.core.domain.AjaxResult;
import com.ruoyi.common.enums.BusinessType;
import com.ruoyi.domain.other.TtRobotFightJoinConfig;
import com.ruoyi.admin.service.TtRobotFightJoinConfigService;
import com.ruoyi.common.core.page.TableDataInfo;
/**
* 机器人对战进房时间配置Controller
*
* @author ruoyi
* @date 2026-07-23
*/
@RestController
@RequestMapping("/admin/robotFightConfig")
public class TtRobotFightJoinConfigController extends BaseController
{
@Autowired
private TtRobotFightJoinConfigService ttRobotFightJoinConfigService;
/**
* 查询机器人对战进房时间配置列表
*/
@PreAuthorize("@ss.hasPermi('admin:robotFightConfig:list')")
@GetMapping("/list")
public TableDataInfo list(TtRobotFightJoinConfig ttRobotFightJoinConfig)
{
startPage();
List<TtRobotFightJoinConfig> list = ttRobotFightJoinConfigService.selectTtRobotFightJoinConfigList(ttRobotFightJoinConfig);
return getDataTable(list);
}
/**
* 获取机器人对战进房时间配置详细信息
*/
@PreAuthorize("@ss.hasPermi('admin:robotFightConfig:query')")
@GetMapping(value = "/{id}")
public AjaxResult getInfo(@PathVariable("id") Integer id)
{
return success(ttRobotFightJoinConfigService.selectTtRobotFightJoinConfigById(id));
}
/**
* 新增机器人对战进房时间配置
*/
@PreAuthorize("@ss.hasPermi('admin:robotFightConfig:add')")
@Log(title = "机器人对战配置", action = "新增", businessType = BusinessType.INSERT,
entityClass = TtRobotFightJoinConfig.class, mapperClass = TtRobotFightJoinConfigMapper.class)
@PostMapping
public AjaxResult add(@RequestBody TtRobotFightJoinConfig ttRobotFightJoinConfig)
{
AjaxResult check = validate(ttRobotFightJoinConfig);
if (check != null) {
return check;
}
return toAjax(ttRobotFightJoinConfigService.insertTtRobotFightJoinConfig(ttRobotFightJoinConfig));
}
/**
* 修改机器人对战进房时间配置
*/
@PreAuthorize("@ss.hasPermi('admin:robotFightConfig:edit')")
@Log(title = "机器人对战配置", action = "修改", businessType = BusinessType.UPDATE,
entityClass = TtRobotFightJoinConfig.class, mapperClass = TtRobotFightJoinConfigMapper.class)
@PutMapping
public AjaxResult edit(@RequestBody TtRobotFightJoinConfig ttRobotFightJoinConfig)
{
AjaxResult check = validate(ttRobotFightJoinConfig);
if (check != null) {
return check;
}
return toAjax(ttRobotFightJoinConfigService.updateTtRobotFightJoinConfig(ttRobotFightJoinConfig));
}
/**
* 删除机器人对战进房时间配置
*/
@PreAuthorize("@ss.hasPermi('admin:robotFightConfig:remove')")
@Log(title = "机器人对战配置", action = "删除", businessType = BusinessType.DELETE)
@DeleteMapping("/{ids}")
public AjaxResult remove(@PathVariable Integer[] ids)
{
return toAjax(ttRobotFightJoinConfigService.deleteTtRobotFightJoinConfigByIds(ids));
}
/**
* 保存前校验:金额区间合法、进房秒数为正,且与其他启用档位区间不重叠
*/
private AjaxResult validate(TtRobotFightJoinConfig config)
{
if (config.getMinAmount() == null || config.getMaxAmount() == null) {
return AjaxResult.error("金额区间不能为空");
}
if (config.getMinAmount().compareTo(BigDecimal.ZERO) < 0) {
return AjaxResult.error("最小金额不能小于0");
}
if (config.getMinAmount().compareTo(config.getMaxAmount()) >= 0) {
return AjaxResult.error("最小金额必须小于最大金额");
}
if (config.getJoinSeconds() == null || config.getJoinSeconds() <= 0) {
return AjaxResult.error("进房秒数必须大于0");
}
if (config.getRandomSeconds() == null || config.getRandomSeconds() < 0) {
return AjaxResult.error("随机秒数不能为空且必须大于等于0");
}
// 停用的档位不参与匹配,无需重叠校验
if ("1".equals(config.getStatus())) {
return null;
}
// 调度任务按 min_amount 升序取第一条命中档位,区间重叠会导致新档位永远不生效,这里直接拒绝保存
TtRobotFightJoinConfig query = new TtRobotFightJoinConfig();
query.setStatus("0");
List<TtRobotFightJoinConfig> enabledList = ttRobotFightJoinConfigService.selectTtRobotFightJoinConfigList(query);
for (TtRobotFightJoinConfig exist : enabledList) {
if (config.getId() != null && config.getId().equals(exist.getId())) {
continue;
}
if (exist.getMinAmount() == null || exist.getMaxAmount() == null) {
continue;
}
// 区间为 (min, max],重叠条件:newMin < exMax 且 exMin < newMax
if (config.getMinAmount().compareTo(exist.getMaxAmount()) < 0
&& exist.getMinAmount().compareTo(config.getMaxAmount()) < 0) {
return AjaxResult.error("金额区间与已启用档位[" + exist.getMinAmount().stripTrailingZeros().toPlainString()
+ "-" + exist.getMaxAmount().stripTrailingZeros().toPlainString()
+ "]重叠,请先修改或停用该档位");
}
}
return null;
}
}
@@ -0,0 +1,143 @@
package com.ruoyi.admin.controller;
import java.math.BigDecimal;
import java.util.List;
import org.springframework.security.access.prepost.PreAuthorize;
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.PutMapping;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import com.ruoyi.admin.mapper.TtRobotFightPriceConfigMapper;
import com.ruoyi.common.annotation.Log;
import com.ruoyi.common.core.controller.BaseController;
import com.ruoyi.common.core.domain.AjaxResult;
import com.ruoyi.common.enums.BusinessType;
import com.ruoyi.domain.other.TtRobotFightPriceConfig;
import com.ruoyi.admin.service.TtRobotFightPriceConfigService;
import com.ruoyi.admin.mapper.TtRobotFightGroupMapper;
import com.ruoyi.common.core.page.TableDataInfo;
/**
* 机器人对战价格档位配置Controller
*
* @author ruoyi
* @date 2026-08-13
*/
@RestController
@RequestMapping("/admin/robotFightPriceConfig")
public class TtRobotFightPriceConfigController extends BaseController
{
@Autowired
private TtRobotFightPriceConfigService ttRobotFightPriceConfigService;
@Autowired
private TtRobotFightGroupMapper ttRobotFightGroupMapper;
/**
* 查询机器人对战价格档位配置列表
*/
@PreAuthorize("@ss.hasPermi('admin:robotFightPriceConfig:list')")
@GetMapping("/list")
public TableDataInfo list(TtRobotFightPriceConfig ttRobotFightPriceConfig)
{
startPage();
List<TtRobotFightPriceConfig> list = ttRobotFightPriceConfigService.selectTtRobotFightPriceConfigList(ttRobotFightPriceConfig);
return getDataTable(list);
}
/**
* 获取机器人对战价格档位配置详细信息
*/
@PreAuthorize("@ss.hasPermi('admin:robotFightPriceConfig:query')")
@GetMapping(value = "/{id}")
public AjaxResult getInfo(@PathVariable("id") Integer id)
{
return success(ttRobotFightPriceConfigService.selectTtRobotFightPriceConfigById(id));
}
/**
* 新增机器人对战价格档位配置
*/
@PreAuthorize("@ss.hasPermi('admin:robotFightPriceConfig:add')")
@Log(title = "机器人对战配置", action = "新增", businessType = BusinessType.INSERT,
entityClass = TtRobotFightPriceConfig.class, mapperClass = TtRobotFightPriceConfigMapper.class)
@PostMapping
public AjaxResult add(@RequestBody TtRobotFightPriceConfig ttRobotFightPriceConfig)
{
AjaxResult check = validate(ttRobotFightPriceConfig);
if (check != null) {
return check;
}
return toAjax(ttRobotFightPriceConfigService.insertTtRobotFightPriceConfig(ttRobotFightPriceConfig));
}
/**
* 修改机器人对战价格档位配置
*/
@PreAuthorize("@ss.hasPermi('admin:robotFightPriceConfig:edit')")
@Log(title = "机器人对战配置", action = "修改", businessType = BusinessType.UPDATE,
entityClass = TtRobotFightPriceConfig.class, mapperClass = TtRobotFightPriceConfigMapper.class)
@PutMapping
public AjaxResult edit(@RequestBody TtRobotFightPriceConfig ttRobotFightPriceConfig)
{
AjaxResult check = validate(ttRobotFightPriceConfig);
if (check != null) {
return check;
}
return toAjax(ttRobotFightPriceConfigService.updateTtRobotFightPriceConfig(ttRobotFightPriceConfig));
}
/**
* 删除机器人对战价格档位配置
*/
@PreAuthorize("@ss.hasPermi('admin:robotFightPriceConfig:remove')")
@Log(title = "机器人对战配置", action = "删除", businessType = BusinessType.DELETE)
@DeleteMapping("/{ids}")
public AjaxResult remove(@PathVariable Integer[] ids)
{
for (Integer id : ids) {
int count = ttRobotFightGroupMapper.selectCountByPriceConfigId(id);
if (count > 0) {
return AjaxResult.error("删除失败,该价格档位已被" + count + "个机器人对战分组引用");
}
}
return toAjax(ttRobotFightPriceConfigService.deleteTtRobotFightPriceConfigByIds(ids));
}
/**
* 保存前校验:价格上限、目标数量、排序必须为正,启用档位 price_limit 不能重复
*/
private AjaxResult validate(TtRobotFightPriceConfig config)
{
if (config.getPriceLimit() == null || config.getPriceLimit().compareTo(BigDecimal.ZERO) <= 0) {
return AjaxResult.error("价格上限必须大于0");
}
if (config.getTargetCount() == null || config.getTargetCount() <= 0) {
return AjaxResult.error("目标数量必须大于0");
}
if (config.getSortOrder() == null || config.getSortOrder() <= 0) {
return AjaxResult.error("排序序号必须大于0");
}
// 停用的档位不参与匹配,无需重复校验
if ("1".equals(config.getStatus())) {
return null;
}
TtRobotFightPriceConfig query = new TtRobotFightPriceConfig();
query.setStatus("0");
List<TtRobotFightPriceConfig> enabledList = ttRobotFightPriceConfigService.selectTtRobotFightPriceConfigList(query);
for (TtRobotFightPriceConfig exist : enabledList) {
if (config.getId() != null && config.getId().equals(exist.getId())) {
continue;
}
if (config.getPriceLimit().compareTo(exist.getPriceLimit()) == 0) {
return AjaxResult.error("价格上限与已启用档位[" + exist.getPriceLimit().stripTrailingZeros().toPlainString() + "]重复");
}
}
return null;
}
}
@@ -0,0 +1,198 @@
package com.ruoyi.admin.controller;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.ruoyi.admin.mapper.TtRollMapper;
import com.ruoyi.common.enums.BusinessType;
import com.ruoyi.common.annotation.Log;
import com.ruoyi.admin.domain.body.AddRobotBody;
import com.ruoyi.admin.domain.body.AddUserBody;
import com.ruoyi.admin.service.TtRollService;
import com.ruoyi.admin.service.TtRollUserService;
import com.ruoyi.common.core.controller.BaseController;
import com.ruoyi.common.core.domain.AjaxResult;
import com.ruoyi.common.core.domain.R;
import com.ruoyi.common.core.page.PageDataInfo;
import com.ruoyi.common.utils.DateUtils;
import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.common.utils.poi.ExcelUtil;
import com.ruoyi.domain.dto.roll.GetRollPrizePool;
import com.ruoyi.domain.dto.roll.InviteRollUser;
import com.ruoyi.domain.entity.roll.TtRoll;
import com.ruoyi.domain.entity.roll.TtRollBody;
import com.ruoyi.domain.entity.roll.TtRollUser;
import com.ruoyi.domain.entity.sys.TtUser;
import com.ruoyi.domain.vo.TtRollPrizeDataVO;
import com.ruoyi.domain.vo.roll.RollJackpotOrnamentsByPageVO;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.Data;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import jakarta.servlet.http.HttpServletResponse;
import jakarta.validation.constraints.NotNull;
import java.util.List;
import java.util.Map;
@Api(tags = "管理端 roll房")
@RestController
@RequestMapping("/admin/roll")
public class TtRollController extends BaseController {
private final TtRollService rollService;
private final TtRollUserService rollUserService;
public TtRollController(TtRollService rollService,
TtRollUserService rollUserService) {
this.rollService = rollService;
this.rollUserService = rollUserService;
}
@GetMapping("/list")
public PageDataInfo<TtRoll> list(TtRollBody ttRollBody) {
startPage();
List<TtRoll> list = rollService.queryList(ttRollBody);
return getPageData(list);
}
/**
* 导出信息
* @param response
* @param ttRollBody
*/
@PostMapping("/export")
public void export(HttpServletResponse response, TtRollBody ttRollBody) {
List<TtRoll> list = rollService.queryList(ttRollBody);
ExcelUtil<TtRoll> util = new ExcelUtil<>(TtRoll.class);
util.exportExcel(response, list, "Roll房信息列表");
}
@GetMapping(value = "/{rollId}")
public R<TtRoll> getInfo(@PathVariable("rollId") Long rollId) {
TtRoll roll = rollService.getById(rollId);
return R.ok(roll);
}
@Log(title = "Roll房列表", action = "新增", businessType = BusinessType.INSERT,
entityClass = TtRoll.class, mapperClass = TtRollMapper.class)
// 创建roll房
@ApiOperation("创建roll房")
@PostMapping
public AjaxResult add(@RequestBody TtRoll ttRoll) {
ttRoll.setCreateBy(getUsername());
ttRoll.setCreateTime(DateUtils.getNowDate());
return rollService.createRoll(ttRoll);
}
// roll房拉人
@ApiOperation("roll房拉人")
@PostMapping("/inviteRollUser")
public R inviteRollUser(@RequestBody InviteRollUser InviteRollUser) {
return rollService.inviteRollUser(InviteRollUser);
}
// 获取roll房成员信息
@ApiOperation("获取roll房成员信息")
@GetMapping("getRollUsers/{rollId}")
public AjaxResult getRollUsers(@PathVariable("rollId") Integer rollId) {
return rollService.getRollUsers(rollId);
}
@Log(title = "Roll房列表", action = "修改", businessType = BusinessType.UPDATE,
entityClass = TtRoll.class, mapperClass = TtRollMapper.class)
@ApiOperation("编辑roll房")
@PutMapping
public AjaxResult edit(@RequestBody TtRoll ttRoll) {
ttRoll.setUpdateBy(getUsername());
ttRoll.setUpdateTime(DateUtils.getNowDate());
return rollService.updateRollById(ttRoll);
}
@Log(title = "Roll房列表", action = "删除", businessType = BusinessType.DELETE)
@ApiOperation("删除roll房")
@DeleteMapping("/remove/{rollId}")
public AjaxResult remove(@PathVariable Long rollId) {
return rollService.removeRollById(rollId, getUsername());
}
// @ApiOperation("roll房奖品列表")
// @PostMapping("/getRollPrizeList")
// public R<List<TtRollPrizeDataVO>> getRollPrizeList(@RequestBody RollPrizesCondition condition) {
//
// List<TtRollPrizeDataVO> list = rollService.getRollPrizeList(condition);
//
// return R.ok(list);
//
// }
@ApiOperation("roll房奖品列表")
@GetMapping("/getRollPrizeList/{rollId}")
public R<List<TtRollPrizeDataVO>> getRollPrizeList(@PathVariable("rollId") Integer rollId) {
List<TtRollPrizeDataVO> list = rollService.getRollPrizeList(rollId);
return R.ok(list);
}
@ApiOperation("获取 roll房奖池详情")
@PostMapping("/getRollPrizePool")
public R<RollJackpotOrnamentsByPageVO> getRollPrizePool(@RequestBody @Validated GetRollPrizePool param) {
return rollService.getRollPrizePool(param);
}
@ApiOperation("roll房的指定获奖人名单")
@GetMapping("/rollWinners/{rollId}")
public R rollWinners(@PathVariable Integer rollId) {
return rollUserService.rollWinners(rollId);
}
@ApiOperation("roll房实际中奖记录(开奖后参与用户中了什么饰品)")
@GetMapping("/winningRecords/{rollId}")
public R<List<Map<String, Object>>> winningRecords(@PathVariable("rollId") Integer rollId) {
return rollService.winningRecords(rollId);
}
@Log(title = "装备列表", action = "指定获奖者", businessType = BusinessType.INSERT)
@ApiOperation("指定roll房winner")
@PostMapping("/namedWinner")
public AjaxResult namedWinner(@RequestBody @Validated TtRollPrizeDataVO param) {
return rollService.namedWinner(param);
}
@Log(title = "装备列表", action = "取消奖品", businessType = BusinessType.DELETE)
@ApiOperation("取消指定roll房奖品")
@DeleteMapping("/cancelNamedWinner")
public R cancelNamedWinner(@RequestBody List<Integer> rollUserPrizeIds) {
return rollService.cancelNamedWinner(rollUserPrizeIds);
}
@ApiOperation("获取ROLL房用户")
@GetMapping("/getRollUser/{rollId}")
public AjaxResult getRollUser(@PathVariable("rollId") Integer rollId) {
List<TtUser> rollUserList = rollService.getRollUser(rollId);
return success(rollUserList);
}
@Log(title = "房间用户", action = "加入机器人", businessType = BusinessType.INSERT)
@ApiOperation("加入机器人")
@PostMapping("/addRobot")
public AjaxResult addRobot(@RequestBody AddRobotBody addRobotBody) {
return rollService.addRobot(addRobotBody);
}
@Log(title = "房间用户", action = "加入用户", businessType = BusinessType.INSERT)
@ApiOperation("强制加入普通用户")
@PostMapping("/addUser")
public AjaxResult addUser(@RequestBody AddUserBody addUserBody) {
return rollService.addUser(addUserBody);
}
}
@@ -0,0 +1,78 @@
package com.ruoyi.admin.controller;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.ruoyi.admin.mapper.TtRollJackpotMapper;
import com.ruoyi.common.enums.BusinessType;
import com.ruoyi.common.annotation.Log;
import com.ruoyi.domain.entity.roll.TtRollJackpot;
import com.ruoyi.admin.service.TtRollJackpotService;
import com.ruoyi.common.core.controller.BaseController;
import com.ruoyi.common.core.domain.AjaxResult;
import com.ruoyi.common.core.domain.R;
import com.ruoyi.common.core.page.PageDataInfo;
import com.ruoyi.common.utils.DateUtils;
import com.ruoyi.common.utils.StringUtils;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.springframework.web.bind.annotation.*;
import java.math.BigDecimal;
import java.util.List;
@Api(tags = "管理端 roll奖池")
@RestController
@RequestMapping("/admin/rollJackpot")
public class TtRollJackpotController extends BaseController {
private final TtRollJackpotService rollJackpotService;
public TtRollJackpotController(TtRollJackpotService rollJackpotService) {
this.rollJackpotService = rollJackpotService;
}
@ApiOperation("奖池列表")
@GetMapping("/list")
public PageDataInfo<TtRollJackpot> list(@RequestParam(value = "jackpotName", required = false) String jackpotName) {
startPage();
LambdaQueryWrapper<TtRollJackpot> wrapper = Wrappers.lambdaQuery();
if (StringUtils.isNotEmpty(jackpotName)) {
wrapper.like(TtRollJackpot::getJackpotName, jackpotName);
}
List<TtRollJackpot> list = rollJackpotService.list(wrapper);
return getPageData(list);
}
@GetMapping(value = "/{jackpotId}")
public R<TtRollJackpot> getInfo(@PathVariable("jackpotId") Long jackpotId) {
TtRollJackpot rollJackpot = rollJackpotService.getById(jackpotId);
return R.ok(rollJackpot);
}
@Log(title = "奖池列表", action = "新增", businessType = BusinessType.INSERT,
entityClass = TtRollJackpot.class, mapperClass = TtRollJackpotMapper.class)
@ApiOperation("添加奖池")
@PostMapping
public AjaxResult add(@RequestBody TtRollJackpot ttRollJackpot) {
ttRollJackpot.setCreateBy(getUsername());
ttRollJackpot.setCreateTime(DateUtils.getNowDate());
ttRollJackpot.setTotalPrice(BigDecimal.ZERO);
return toAjax(rollJackpotService.save(ttRollJackpot));
}
@Log(title = "奖池列表", action = "修改", businessType = BusinessType.UPDATE,
entityClass = TtRollJackpot.class, mapperClass = TtRollJackpotMapper.class)
@PutMapping
public AjaxResult edit(@RequestBody TtRollJackpot ttRollJackpot) {
ttRollJackpot.setUpdateBy(getUsername());
ttRollJackpot.setUpdateTime(DateUtils.getNowDate());
return toAjax(rollJackpotService.updateById(ttRollJackpot));
}
@Log(title = "奖池列表", action = "删除", businessType = BusinessType.DELETE)
@DeleteMapping("/remove/{jackpotId}")
public AjaxResult remove(@PathVariable Long jackpotId) {
String msg = rollJackpotService.removeRollJackpotById(jackpotId);
return StringUtils.isEmpty(msg) ? AjaxResult.success() : AjaxResult.error(msg);
}
}
@@ -0,0 +1,91 @@
package com.ruoyi.admin.controller;
import com.baomidou.mybatisplus.extension.conditions.query.LambdaQueryChainWrapper;
import com.ruoyi.admin.mapper.TtRollJackpotOrnamentsMapper;
import com.ruoyi.common.enums.BusinessType;
import com.ruoyi.common.annotation.Log;
import com.ruoyi.domain.dto.rollJackpotOrnament.RollJOEdit;
import com.ruoyi.domain.entity.roll.TtRoll;
import com.ruoyi.domain.entity.roll.TtRollJackpotOrnaments;
import com.ruoyi.admin.service.TtRollJackpotOrnamentsService;
import com.ruoyi.admin.service.TtRollService;
import com.ruoyi.domain.entity.roll.TtRollJackpotOrnamentsBody;
import com.ruoyi.domain.vo.TtRollJackpotOrnamentsDataVO;
import com.ruoyi.common.core.controller.BaseController;
import com.ruoyi.common.core.domain.AjaxResult;
import com.ruoyi.common.core.domain.R;
import com.ruoyi.common.core.page.PageDataInfo;
import com.ruoyi.common.utils.StringUtils;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.springframework.web.bind.annotation.*;
import java.util.Arrays;
import java.util.List;
@Api(tags = "管理端 roll奖池物品管理")
@RestController
@RequestMapping("/admin/rollJackpotOrnaments")
public class TtRollJackpotOrnamentsController extends BaseController {
private final TtRollService rollService;
private final TtRollJackpotOrnamentsService rollJackpotOrnamentsService;
public TtRollJackpotOrnamentsController(TtRollService rollService,
TtRollJackpotOrnamentsService rollJackpotOrnamentsService) {
this.rollService = rollService;
this.rollJackpotOrnamentsService = rollJackpotOrnamentsService;
}
@ApiOperation("物品列表")
@GetMapping("/list")
public PageDataInfo<TtRollJackpotOrnamentsDataVO> list(TtRollJackpotOrnamentsBody rollJackpotOrnamentsBody) {
startPage();
List<TtRollJackpotOrnamentsDataVO> list = rollJackpotOrnamentsService.queryList(rollJackpotOrnamentsBody);
return getPageData(list);
}
@GetMapping(value = "/{rollJackpotOrnamentsId}")
public R<TtRollJackpotOrnaments> getInfo(@PathVariable("rollJackpotOrnamentsId") Long rollJackpotOrnamentsId) {
TtRollJackpotOrnaments rollJackpotOrnaments = rollJackpotOrnamentsService.getById(rollJackpotOrnamentsId);
return R.ok(rollJackpotOrnaments);
}
@Log(title = "奖池列表", action = "新增", businessType = BusinessType.INSERT,
entityClass = TtRollJackpotOrnaments.class, mapperClass = TtRollJackpotOrnamentsMapper.class)
@PostMapping
public AjaxResult add(@RequestBody TtRollJackpotOrnaments ttRollJackpotOrnaments) {
String msg = rollJackpotOrnamentsService.insertRollJackpotOrnaments(ttRollJackpotOrnaments);
return StringUtils.isEmpty(msg) ? AjaxResult.success() : AjaxResult.error(msg);
}
@Log(title = "奖池列表", action = "修改", businessType = BusinessType.UPDATE,
entityClass = TtRollJackpotOrnaments.class, mapperClass = TtRollJackpotOrnamentsMapper.class)
@ApiOperation("修改奖池道具")
@PutMapping
public AjaxResult edit(@RequestBody TtRollJackpotOrnaments rollJOEdit) {
String msg = rollJackpotOrnamentsService.updateRollJackpotOrnamentsById(rollJOEdit);
return StringUtils.isEmpty(msg) ? AjaxResult.success() : AjaxResult.error(msg);
}
@Log(title = "奖池列表", action = "删除", businessType = BusinessType.DELETE)
@DeleteMapping("/{jackpotId}/{rollJackpotOrnamentsIds}")
public AjaxResult remove(@PathVariable("jackpotId") Integer jackpotId,
@PathVariable("rollJackpotOrnamentsIds") Long[] rollJackpotOrnamentsIds) {
List<TtRoll> rollList = new LambdaQueryChainWrapper<>(rollService.getBaseMapper()).eq(TtRoll::getJackpotId, jackpotId)
.eq(TtRoll::getRollStatus, "0").eq(TtRoll::getDelFlag, "0").list();
if (StringUtils.isNotNull(rollList) && !rollList.isEmpty())
return AjaxResult.error("该奖池正在被进行中的Roll房使用,禁止删除奖品!");
boolean ok = rollJackpotOrnamentsService.removeByIds(Arrays.asList(rollJackpotOrnamentsIds));
// 删除饰品后重算奖池总价
rollJackpotOrnamentsService.recalcJackpotTotalPrice(jackpotId);
return toAjax(ok);
}
@ApiOperation("奖池批量填货")
@PostMapping("/batchAdd/{rollJackpotId}/{OrnamentsIds}")
public AjaxResult batchAdd(@PathVariable Integer rollJackpotId, @PathVariable Long[] OrnamentsIds) {
String msg = rollJackpotOrnamentsService.batchAdd(rollJackpotId, Arrays.asList(OrnamentsIds));
return StringUtils.isEmpty(msg) ? AjaxResult.success("批量填货成功,请手动修改饰品数量!") : AjaxResult.error(msg);
}
}
@@ -0,0 +1,97 @@
package com.ruoyi.admin.controller;
import java.util.List;
import jakarta.servlet.http.HttpServletResponse;
import org.springframework.security.access.prepost.PreAuthorize;
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.PutMapping;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import com.ruoyi.admin.mapper.TtTaskCenterMapper;
import com.ruoyi.common.annotation.Log;
import com.ruoyi.common.core.controller.BaseController;
import com.ruoyi.common.core.domain.AjaxResult;
import com.ruoyi.common.enums.BusinessType;
import com.ruoyi.domain.other.TtTaskCenter;
import com.ruoyi.admin.service.TtTaskCenterService;
import com.ruoyi.common.utils.poi.ExcelUtil;
import com.ruoyi.common.core.page.TableDataInfo;
/**
* 任务中心Controller
*
* @author ruoyi
* @date 2024-05-25
*/
@RestController
@RequestMapping("/admin/taskCenter")
public class TtTaskCenterController extends BaseController
{
@Autowired
private TtTaskCenterService ttTaskCenterService;
/**
* 查询任务列表
*/
@PreAuthorize("isAuthenticated()")
@GetMapping("/list")
public TableDataInfo list(TtTaskCenter ttTaskCenter)
{
startPage();
List<TtTaskCenter> list = ttTaskCenterService.selectTtTaskCenterList(ttTaskCenter);
return getDataTable(list);
}
/**
* 获取任务详细信息
*/
@PreAuthorize("isAuthenticated()")
@GetMapping(value = "/{taskId}")
public AjaxResult getInfo(@PathVariable("taskId") Integer taskId)
{
return success(ttTaskCenterService.selectTtTaskCenterByTaskId(taskId));
}
/**
* 新增任务
*/
@PreAuthorize("isAuthenticated()")
@Log(title = "任务列表", action = "新增", businessType = BusinessType.INSERT,
entityClass = TtTaskCenter.class, mapperClass = TtTaskCenterMapper.class)
@PostMapping
public AjaxResult add(@RequestBody TtTaskCenter ttTaskCenter)
{
ttTaskCenter.setCreateBy(getUsername());
return toAjax(ttTaskCenterService.insertTtTaskCenter(ttTaskCenter));
}
/**
* 修改任务
*/
@PreAuthorize("isAuthenticated()")
@Log(title = "任务列表", action = "修改", businessType = BusinessType.UPDATE,
entityClass = TtTaskCenter.class, mapperClass = TtTaskCenterMapper.class)
@PutMapping
public AjaxResult edit(@RequestBody TtTaskCenter ttTaskCenter)
{
ttTaskCenter.setUpdateBy(getUsername());
return toAjax(ttTaskCenterService.updateTtTaskCenter(ttTaskCenter));
}
/**
* 删除任务
*/
@PreAuthorize("isAuthenticated()")
@Log(title = "任务列表", action = "删除", businessType = BusinessType.DELETE)
@DeleteMapping("/{taskIds}")
public AjaxResult remove(@PathVariable Integer[] taskIds)
{
return error("任务创建后无法删除");
// return toAjax(ttTaskCenterService.deleteTtTaskCenterByTaskIds(taskIds));
}
}
@@ -0,0 +1,89 @@
package com.ruoyi.admin.controller;
import com.ruoyi.admin.mapper.TtTimeRollMapper;
import com.ruoyi.common.enums.BusinessType;
import com.ruoyi.common.annotation.Log;
import com.ruoyi.domain.entity.roll.TtTimeRoll;
import com.ruoyi.admin.service.TtTimeRollService;
import com.ruoyi.domain.vo.TtRollPrizeDataVO;
import com.ruoyi.common.core.controller.BaseController;
import com.ruoyi.common.core.domain.AjaxResult;
import com.ruoyi.common.core.domain.R;
import com.ruoyi.common.core.page.PageDataInfo;
import com.ruoyi.common.exception.job.TaskException;
import com.ruoyi.common.utils.DateUtils;
import com.ruoyi.common.utils.StringUtils;
import org.quartz.SchedulerException;
import org.springframework.web.bind.annotation.*;
import java.util.List;
import java.util.stream.Collectors;
@RestController
@RequestMapping("/admin/timeRoll")
public class TtTimeRollController extends BaseController {
private final TtTimeRollService timeRollService;
public TtTimeRollController(TtTimeRollService timeRollService) {
this.timeRollService = timeRollService;
}
@GetMapping("/list")
public PageDataInfo<TtTimeRoll> list(){
startPage();
List<TtTimeRoll> list = timeRollService.list();
return getPageData(list);
}
@GetMapping(value = "/{timeRollId}")
public R<TtTimeRoll> getInfo(@PathVariable("timeRollId") Integer timeRollId) {
TtTimeRoll timeRoll = timeRollService.getById(timeRollId);
return R.ok(timeRoll);
}
@Log(title = "时间roll房", action = "新增", businessType = BusinessType.INSERT,
entityClass = TtTimeRoll.class, mapperClass = TtTimeRollMapper.class)
@PostMapping
public AjaxResult add(@RequestBody TtTimeRoll ttTimeRoll) throws SchedulerException, TaskException {
ttTimeRoll.setCreateBy(getUsername());
ttTimeRoll.setCreateTime(DateUtils.getNowDate());
String msg = timeRollService.insertTimeRoll(ttTimeRoll);
return StringUtils.isEmpty(msg) ? AjaxResult.success("新增成功!") : AjaxResult.error(msg);
}
@Log(title = "时间roll房", action = "修改", businessType = BusinessType.UPDATE,
entityClass = TtTimeRoll.class, mapperClass = TtTimeRollMapper.class)
@PutMapping
public AjaxResult edit(@RequestBody TtTimeRoll ttTimeRoll) {
ttTimeRoll.setUpdateBy(getUsername());
ttTimeRoll.setUpdateTime(DateUtils.getNowDate());
return toAjax(timeRollService.updateById(ttTimeRoll));
}
@PutMapping("/changeStatus")
public AjaxResult changeStatus(@RequestBody TtTimeRoll ttTimeRoll) throws SchedulerException {
String msg = timeRollService.changeStatus(ttTimeRoll);
return StringUtils.isEmpty(msg) ? AjaxResult.success() : AjaxResult.error(msg);
}
@Log(title = "时间roll房", action = "删除", businessType = BusinessType.DELETE)
@DeleteMapping("/remove/{id}")
public AjaxResult remove(@PathVariable Integer id) throws SchedulerException {
return timeRollService.removeTimeRollById(id);
}
@GetMapping("/getTimeRollPrizeList/{id}")
public R<List<TtRollPrizeDataVO>> getTimeRollPrizeList(@PathVariable("id") Integer id) {
List<TtRollPrizeDataVO> list = timeRollService.getTimeRollPrizeList(id);
List<TtRollPrizeDataVO> sortedList = list.stream().sorted((a, b) -> b.getUsePrice().compareTo(a.getUsePrice())).collect(Collectors.toList());
return R.ok(sortedList);
}
@PostMapping("/namedWinner")
public AjaxResult namedWinner(@RequestBody TtRollPrizeDataVO rollPrizeData) {
String msg = timeRollService.namedWinner(rollPrizeData);
return StringUtils.isEmpty(msg) ? AjaxResult.success() : AjaxResult.error(msg);
}
}
@@ -0,0 +1,116 @@
package com.ruoyi.admin.controller;
import com.ruoyi.admin.service.TtTransferApplyService;
import com.ruoyi.common.annotation.Log;
import com.ruoyi.common.core.controller.BaseController;
import com.ruoyi.common.core.domain.R;
import com.ruoyi.common.core.page.PageDataInfo;
import com.ruoyi.common.enums.BusinessType;
import com.ruoyi.common.redis.config.RedisLock;
import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.domain.other.TransferApplyBody;
import com.ruoyi.domain.vo.transfer.TransferApplyBatchVO;
import com.ruoyi.domain.vo.transfer.TransferApplyVO;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.springframework.web.bind.annotation.*;
import java.util.List;
import java.util.concurrent.TimeUnit;
@Api(tags = "管理端 转赠申请管理")
@RestController
@RequestMapping("/admin/transferApply")
public class TtTransferApplyController extends BaseController {
private final TtTransferApplyService transferApplyService;
private final RedisLock redisLock;
public TtTransferApplyController(TtTransferApplyService transferApplyService,
RedisLock redisLock) {
this.transferApplyService = transferApplyService;
this.redisLock = redisLock;
}
@ApiOperation("转赠申请列表(按饰品逐条)")
@GetMapping("/list")
public PageDataInfo<TransferApplyVO> list(TransferApplyBody body) {
startPage();
List<TransferApplyVO> list = transferApplyService.getTransferApplyList(body);
return getPageData(list);
}
@ApiOperation("转赠申请批次列表(按批次聚合,含饰品明细)")
@GetMapping("/batchList")
public PageDataInfo<TransferApplyBatchVO> batchList(TransferApplyBody body) {
startPage();
List<TransferApplyBatchVO> list = transferApplyService.getTransferApplyBatchList(body);
return getPageData(list);
}
@ApiOperation("审核通过(单条,兼容旧接口)")
@Log(title = "转赠申请", action = "同意", businessType = BusinessType.GRANT)
@PostMapping("/approve")
public R<Boolean> approve(@RequestParam("id") Integer id) {
String lockKey = "admin:transfer:apply:" + id;
if (!redisLock.tryLock(lockKey, 0L, 30L, TimeUnit.SECONDS)) {
return R.fail(false, "正在处理该申请,请勿重复操作");
}
try {
String msg = transferApplyService.approve(id);
return StringUtils.isEmpty(msg) ? R.ok(true, "审核通过成功!") : R.fail(false, msg);
} finally {
redisLock.unlock(lockKey);
}
}
@ApiOperation("审核驳回(单条,兼容旧接口)")
@Log(title = "转赠申请", action = "驳回", businessType = BusinessType.GRANT)
@PostMapping("/reject")
public R<Boolean> reject(@RequestParam("id") Integer id,
@RequestParam("rejectReason") String rejectReason) {
String lockKey = "admin:transfer:apply:" + id;
if (!redisLock.tryLock(lockKey, 0L, 30L, TimeUnit.SECONDS)) {
return R.fail(false, "正在处理该申请,请勿重复操作");
}
try {
String msg = transferApplyService.reject(id, rejectReason);
return StringUtils.isEmpty(msg) ? R.ok(true, "已驳回该申请!") : R.fail(false, msg);
} finally {
redisLock.unlock(lockKey);
}
}
@ApiOperation("批次审核通过(整个批次一起通过)")
@Log(title = "转赠申请", action = "确定同意", businessType = BusinessType.GRANT)
@PostMapping("/approveBatch")
public R<Boolean> approveBatch(@RequestParam("batchId") String batchId) {
String lockKey = "admin:transfer:batch:" + batchId;
if (!redisLock.tryLock(lockKey, 0L, 30L, TimeUnit.SECONDS)) {
return R.fail(false, "正在处理该批次,请勿重复操作");
}
try {
String msg = transferApplyService.approveBatch(batchId);
return StringUtils.isEmpty(msg) ? R.ok(true, "批次审核通过成功!") : R.fail(false, msg);
} finally {
redisLock.unlock(lockKey);
}
}
@ApiOperation("批次审核驳回(整个批次一起驳回)")
@Log(title = "转赠申请", action = "驳回", businessType = BusinessType.GRANT)
@PostMapping("/rejectBatch")
public R<Boolean> rejectBatch(@RequestParam("batchId") String batchId,
@RequestParam("rejectReason") String rejectReason) {
String lockKey = "admin:transfer:batch:" + batchId;
if (!redisLock.tryLock(lockKey, 0L, 30L, TimeUnit.SECONDS)) {
return R.fail(false, "正在处理该批次,请勿重复操作");
}
try {
String msg = transferApplyService.rejectBatch(batchId, rejectReason);
return StringUtils.isEmpty(msg) ? R.ok(true, "批次已驳回!") : R.fail(false, msg);
} finally {
redisLock.unlock(lockKey);
}
}
}
@@ -0,0 +1,88 @@
package com.ruoyi.admin.controller;
import com.ruoyi.common.enums.BusinessType;
import com.ruoyi.common.annotation.Log;
import com.ruoyi.admin.service.TtUpgradeFailOrnamentsService;
import com.ruoyi.domain.other.TtUpgradeFailOrnaments;
import com.ruoyi.domain.vo.TtUpgradeFailOrnamentsDataVO;
import com.ruoyi.common.core.controller.BaseController;
import com.ruoyi.common.core.domain.AjaxResult;
import com.ruoyi.common.core.page.PageDataInfo;
import com.ruoyi.common.utils.StringUtils;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiModelProperty;
import io.swagger.annotations.ApiOperation;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import jakarta.validation.constraints.Min;
import jakarta.validation.constraints.NotEmpty;
import jakarta.validation.constraints.NotNull;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
@Api(tags = "管理端 失败物品奖励")
@RestController
@RequestMapping("/admin/upgradeFailOrnaments")
public class TtUpgradeFailOrnamentsController extends BaseController {
private final TtUpgradeFailOrnamentsService upgradeFailOrnamentsService;
public TtUpgradeFailOrnamentsController(TtUpgradeFailOrnamentsService upgradeFailOrnamentsService) {
this.upgradeFailOrnamentsService = upgradeFailOrnamentsService;
}
@AllArgsConstructor
@NoArgsConstructor
@Data
public static class listParam {
@NotNull(message = "参与升级物品id不能为空")
private Integer upgradeOrnamentId;
}
@ApiOperation("失败奖励列表")
@PostMapping("/list")
public PageDataInfo<TtUpgradeFailOrnamentsDataVO> list(@RequestBody listParam param) {
startPage();
List<TtUpgradeFailOrnamentsDataVO> list = upgradeFailOrnamentsService.queryList(param);
return getPageData(list);
}
@AllArgsConstructor
@NoArgsConstructor
@Data
public static class BatchAddParam{
@NotNull(message = "升级物品id不能为空")
private Integer upgradeId;
// @NotEmpty(message = "失败物品列表不能为空")
private Map<Long,Integer> ornamentsInfo;
@NotEmpty(message = "失败物品列表不能为空")
private List<Long> ornamentsIds;
//是否应用所有
private Boolean useAllFlag;
}
@Log(title = "失败奖励", action = "新增", businessType = BusinessType.INSERT)
@ApiOperation("批量添加失败奖励")
@PostMapping("/batchAdd")
public AjaxResult batchAdd(@RequestBody @Validated BatchAddParam param) {
return upgradeFailOrnamentsService.batchAdd(param);
}
@Log(title = "失败奖励", action = "修改", businessType = BusinessType.UPDATE)
@PutMapping
public AjaxResult edit(@RequestBody TtUpgradeFailOrnamentsDataVO ttUpgradeFailOrnamentsDataVO) {
String msg = upgradeFailOrnamentsService.updateUpgradeFailOrnamentsById(ttUpgradeFailOrnamentsDataVO);
return StringUtils.isEmpty(msg) ? AjaxResult.success() : AjaxResult.error(msg);
}
@Log(title = "失败奖励", action = "删除", businessType = BusinessType.DELETE)
@DeleteMapping("/{ids}")
public AjaxResult remove(@PathVariable Integer[] ids) {
return toAjax(upgradeFailOrnamentsService.removeByIds(Arrays.asList(ids)));
}
}
@@ -0,0 +1,86 @@
package com.ruoyi.admin.controller;
import com.baomidou.mybatisplus.extension.conditions.query.LambdaQueryChainWrapper;
import com.ruoyi.common.enums.BusinessType;
import com.ruoyi.common.annotation.Log;
import com.ruoyi.domain.other.TtUpgradeFailOrnaments;
import com.ruoyi.domain.other.TtUpgradeOrnaments;
import com.ruoyi.admin.service.TtUpgradeFailOrnamentsService;
import com.ruoyi.admin.service.TtUpgradeOrnamentsService;
import com.ruoyi.domain.other.TtUpgradeOrnamentsBody;
import com.ruoyi.domain.vo.TtUpgradeOrnamentsDataVO;
import com.ruoyi.common.core.controller.BaseController;
import com.ruoyi.common.core.domain.AjaxResult;
import com.ruoyi.common.core.domain.R;
import com.ruoyi.common.core.page.PageDataInfo;
import com.ruoyi.common.utils.StringUtils;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.springframework.web.bind.annotation.*;
import java.math.BigDecimal;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
@Api(tags = "管理端 幸运升级")
@RestController
@RequestMapping("/admin/upgradeOrnaments")
public class TtUpgradeOrnamentsController extends BaseController {
private final TtUpgradeFailOrnamentsService upgradeFailOrnamentsService;
private final TtUpgradeOrnamentsService upgradeOrnamentsService;
public TtUpgradeOrnamentsController(TtUpgradeFailOrnamentsService upgradeFailOrnamentsService,
TtUpgradeOrnamentsService upgradeOrnamentsService) {
this.upgradeFailOrnamentsService = upgradeFailOrnamentsService;
this.upgradeOrnamentsService = upgradeOrnamentsService;
}
@ApiOperation("获取参与幸运升级的物品")
@GetMapping("/list")
public PageDataInfo<TtUpgradeOrnamentsDataVO> list(TtUpgradeOrnamentsBody ttUpgradeOrnamentsBody){
startPage();
List<TtUpgradeOrnamentsDataVO> list = upgradeOrnamentsService.queryList(ttUpgradeOrnamentsBody);
return getPageData(list);
}
@GetMapping(value = "/{id}")
public R<TtUpgradeOrnaments> getInfo(@PathVariable("id") Integer id) {
TtUpgradeOrnaments ttUpgradeOrnaments = upgradeOrnamentsService.getById(id);
return R.ok(ttUpgradeOrnaments);
}
@Log(title = "饰品列表", action = "新增", businessType = BusinessType.INSERT)
@ApiOperation("批量填货")
@PostMapping("/batchAdd/{ornamentsIds}")
public AjaxResult batchAdd(@PathVariable Long[] ornamentsIds) {
String msg = upgradeOrnamentsService.batchAdd(Arrays.asList(ornamentsIds));
return StringUtils.isEmpty(msg) ? AjaxResult.success("批量上架成功,请手动修改幸运区间!") : AjaxResult.error(msg);
}
@Log(title = "饰品列表", action = "修改", businessType = BusinessType.UPDATE)
@PutMapping
public AjaxResult edit(@RequestBody TtUpgradeOrnamentsDataVO ttUpgradeOrnamentsDataVO) {
String msg = upgradeOrnamentsService.updateUpgradeOrnamentsById(ttUpgradeOrnamentsDataVO);
return StringUtils.isEmpty(msg) ? AjaxResult.success() : AjaxResult.error(msg);
}
@Log(title = "饰品列表", action = "删除", businessType = BusinessType.DELETE)
@DeleteMapping("/{ids}")
public AjaxResult remove(@PathVariable Integer[] ids) {
List<TtUpgradeFailOrnaments> upgradeFailOrnamentsList = new LambdaQueryChainWrapper<>(upgradeFailOrnamentsService.getBaseMapper())
.in(TtUpgradeFailOrnaments::getUpgradeId, Arrays.asList(ids)).list();
List<Integer> list = upgradeFailOrnamentsList.stream().map(TtUpgradeFailOrnaments::getId).collect(Collectors.toList());
upgradeFailOrnamentsService.removeByIds(list);
return toAjax(upgradeOrnamentsService.removeByIds(Arrays.asList(ids)));
}
@GetMapping("/getUpgradeProfitStatistics/{id}")
public R<Object> getUpgradeProfitStatistics(@PathVariable("id") Integer id){
Map<String, BigDecimal> map = upgradeOrnamentsService.getUpgradeProfitStatistics(id);
return R.ok(map);
}
}
@@ -0,0 +1,36 @@
package com.ruoyi.admin.controller;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.ruoyi.admin.service.TtUpgradeRecordService;
import com.ruoyi.common.annotation.Anonymous;
import com.ruoyi.common.core.domain.R;
import com.ruoyi.domain.dto.upgrade.UpgradeCondition;
import com.ruoyi.domain.other.TtUpgradeRecord;
import com.ruoyi.domain.other.TtUpgradeRecordBody;
import com.ruoyi.common.core.controller.BaseController;
import com.ruoyi.common.core.page.PageDataInfo;
import com.ruoyi.domain.vo.upgrade.UpgradeRecordVO;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import java.util.List;
@Api(tags = "管理端 幸运升级日志")
@RestController
@RequestMapping("/admin/upgradeRecord")
public class TtUpgradeRecordController extends BaseController {
private final TtUpgradeRecordService upgradeRecordService;
public TtUpgradeRecordController(TtUpgradeRecordService upgradeRecordService) {
this.upgradeRecordService = upgradeRecordService;
}
@ApiOperation("幸运升级日志")
@PostMapping("/list")
public R<Page<UpgradeRecordVO>> list(@RequestBody @Validated UpgradeCondition param){
return upgradeRecordService.adminGetLog(param);
}
}
@@ -0,0 +1,125 @@
package com.ruoyi.admin.controller;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.ruoyi.common.core.domain.R;
import com.ruoyi.domain.entity.recorde.TtUserAmountRecords;
import com.ruoyi.admin.service.TtUserAmountRecordsService;
import com.ruoyi.admin.mapper.TtUserBlendErcashMapper;
import com.ruoyi.system.config.ArchiveDaysConfig;
import com.ruoyi.domain.other.TtUserAmountRecordsBody;
import com.ruoyi.common.core.controller.BaseController;
import com.ruoyi.common.core.page.PageDataInfo;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.util.List;
import java.util.Map;
@Slf4j
@Api(tags = "管理端 金币账户")
@RestController
@RequestMapping("/admin/userAmountRecords")
public class TtUserAmountRecordsController extends BaseController {
private static final DateTimeFormatter DATE_FMT = DateTimeFormatter.ofPattern("yyyy-MM-dd");
private final TtUserAmountRecordsService userAmountRecordsService;
@Autowired
private TtUserBlendErcashMapper ttUserBlendErcashMapper;
public TtUserAmountRecordsController(TtUserAmountRecordsService userAmountRecordsService) {
this.userAmountRecordsService = userAmountRecordsService;
}
@ApiOperation("获取列表")
@PostMapping("/list")
public R list(@RequestBody @Validated TtUserAmountRecordsBody ttUserAmountRecordsBody) {
return userAmountRecordsService.queryList(ttUserAmountRecordsBody);
}
/** 聚合类排序字段集合(这些字段需要全局排序,不能用当页排序) */
private static final java.util.Set<String> AGG_SORT_FIELDS = java.util.Set.of(
"totalRecharge", "totalTurnover", "classicBox", "fightGame",
"luckyUpgrade", "wheelGame", "olympusGame", "rollRoom");
/**
* 用户流水统计列表
* 路由策略:
* - userId 排序 → 快速模式(先分页用户再聚合当页数据,Java内存排序)
* - 聚合字段排序 → 全局排序模式(先聚合所有用户→SQL排序→分页),确保全局排序正确
*/
@ApiOperation("用户流水统计")
@GetMapping("/userTurnover")
public R userTurnover(
@RequestParam(required = false) Integer userId,
@RequestParam(required = false) String nickName,
@RequestParam(required = false) String phone,
@RequestParam(required = false) String startTime,
@RequestParam(required = false) String endTime,
@RequestParam(required = false, defaultValue = "totalTurnover") String sortField,
@RequestParam(required = false, defaultValue = "desc") String sortOrder,
@RequestParam(defaultValue = "1") int pageNum,
@RequestParam(defaultValue = "10") int pageSize) {
int offset = (pageNum - 1) * pageSize;
int total = ttUserBlendErcashMapper.userTurnoverCount(userId, nickName, phone);
// 统一走流水明细/归档表:日报表只有 source+total,无法区分 source=56 的金币退款与积分退款。
// 统计口径要求按 amount(金币字段)计算 roll房净消费
boolean includeArchive = shouldIncludeArchive(endTime);
List<Map<String, Object>> rows;
if (AGG_SORT_FIELDS.contains(sortField)) {
rows = ttUserBlendErcashMapper.userTurnoverListSorted(
userId, nickName, phone, startTime, endTime, includeArchive, sortField, sortOrder, offset, pageSize);
} else {
rows = ttUserBlendErcashMapper.userTurnoverList(
userId, nickName, phone, startTime, endTime, includeArchive, offset, pageSize);
sortRowsInMemory(rows, sortField, sortOrder);
}
return R.ok(Map.of("rows", rows, "total", total));
}
/**
* 判断 UNION ALL 时是否需要包含归档表:
* 归档任务只迁移 7 天前的数据,若查询结束日期在最近 7 天内,归档表无数据,可跳过。
*/
private boolean shouldIncludeArchive(String endTime) {
if (endTime == null || endTime.isEmpty()) {
return true;
}
try {
LocalDate endDate = LocalDate.parse(endTime.substring(0, 10), DATE_FMT);
LocalDate archiveThreshold = LocalDate.now().minusDays(ArchiveDaysConfig.getRetainDays());
return endDate.isBefore(archiveThreshold);
} catch (Exception e) {
return true;
}
}
/**
* 对查询结果做内存排序(pageSize 通常 5~50 条,排序零耗时)
*/
private void sortRowsInMemory(List<Map<String, Object>> rows, String sortField, String sortOrder) {
if (rows == null || rows.size() <= 1 || sortField == null) return;
boolean asc = "asc".equalsIgnoreCase(sortOrder);
rows.sort((a, b) -> {
Object va = a.get(sortField);
Object vb = b.get(sortField);
if (va == null && vb == null) return 0;
if (va == null) return asc ? -1 : 1;
if (vb == null) return asc ? 1 : -1;
if (va instanceof Number && vb instanceof Number) {
double da = ((Number) va).doubleValue();
double db = ((Number) vb).doubleValue();
return asc ? Double.compare(da, db) : Double.compare(db, da);
}
return asc ? va.toString().compareTo(vb.toString()) : vb.toString().compareTo(va.toString());
});
}
}
@@ -0,0 +1,67 @@
package com.ruoyi.admin.controller;
import com.ruoyi.admin.mapper.TtUserAvatarMapper;
import com.ruoyi.common.enums.BusinessType;
import com.ruoyi.common.annotation.Log;
import com.ruoyi.domain.other.TtUserAvatar;
import com.ruoyi.admin.service.TtUserAvatarService;
import com.ruoyi.common.config.RuoYiConfig;
import com.ruoyi.common.core.controller.BaseController;
import com.ruoyi.common.core.domain.AjaxResult;
import com.ruoyi.common.core.domain.R;
import com.ruoyi.common.core.page.PageDataInfo;
import com.ruoyi.common.utils.StringUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.*;
import java.util.Arrays;
import java.util.List;
@RestController
@RequestMapping("/admin/userAvatar")
@Slf4j
public class TtUserAvatarController extends BaseController {
private final TtUserAvatarService userAvatarService;
public TtUserAvatarController(TtUserAvatarService userAvatarService) {
this.userAvatarService = userAvatarService;
}
@GetMapping("/list")
public PageDataInfo<TtUserAvatar> list() {
startPage();
List<TtUserAvatar> list = userAvatarService.list();
return getPageData(list);
}
@GetMapping(value = "/{id}")
public R<TtUserAvatar> getInfo(@PathVariable("id") Integer id) {
TtUserAvatar ttUserAvatar = userAvatarService.getById(id);
ttUserAvatar.setAvatar("");
return R.ok(ttUserAvatar);
}
@Log(title = "头像设置", action = "新增", businessType = BusinessType.INSERT,
entityClass = TtUserAvatar.class, mapperClass = TtUserAvatarMapper.class)
@PostMapping
public AjaxResult add(@RequestBody TtUserAvatar ttUserAvatar) {
if (StringUtils.isEmpty(ttUserAvatar.getAvatar())) ttUserAvatar.setAvatar("");
else ttUserAvatar.setAvatar(RuoYiConfig.getDomainName() + ttUserAvatar.getAvatar());
return toAjax(userAvatarService.save(ttUserAvatar));
}
@Log(title = "头像设置", action = "修改", businessType = BusinessType.UPDATE,
entityClass = TtUserAvatar.class, mapperClass = TtUserAvatarMapper.class)
@PutMapping
public AjaxResult edit(@RequestBody TtUserAvatar ttUserAvatar) {
String msg = userAvatarService.updateUserAvatarById(ttUserAvatar);
return StringUtils.isEmpty(msg) ? AjaxResult.success() : AjaxResult.error(msg);
}
@Log(title = "头像设置", action = "删除", businessType = BusinessType.DELETE)
@DeleteMapping("/{ids}")
public AjaxResult remove(@PathVariable Integer[] ids) {
return toAjax(userAvatarService.removeByIds(Arrays.asList(ids)));
}
}
@@ -0,0 +1,38 @@
package com.ruoyi.admin.controller;
import com.ruoyi.admin.service.TtUserBlendErcashService;
import com.ruoyi.common.core.controller.BaseController;
import com.ruoyi.common.core.domain.R;
import com.ruoyi.domain.dto.userRecord.BlendErcashCondition;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@Api(tags = "管理端 收支明细")
@RestController
@RequestMapping("/admin/blendErcash")
@Slf4j
public class TtUserBlendErcashController extends BaseController {
@Autowired
private TtUserBlendErcashService ttUserBlendErcashService;
@ApiOperation("收支明细")
@PostMapping("/list")
public R list(@RequestBody @Validated BlendErcashCondition condition) {
return ttUserBlendErcashService.byCondition(condition);
}
@ApiOperation("收支明细-仅归档表")
@PostMapping("/archive/list")
public R archiveList(@RequestBody @Validated BlendErcashCondition condition) {
return ttUserBlendErcashService.byConditionArchive(condition);
}
}
@@ -0,0 +1,276 @@
package com.ruoyi.admin.controller;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.ruoyi.common.enums.BusinessType;
import com.ruoyi.common.annotation.Log;
import com.ruoyi.admin.mapper.TtPromotionUpdateMapper;
import com.ruoyi.admin.mapper.TtUserMapper;
import com.ruoyi.admin.service.TtBoxRecordsService;
import com.ruoyi.admin.service.TtUserService;
import com.ruoyi.common.constant.CacheConstants;
import com.ruoyi.common.core.controller.BaseController;
import com.ruoyi.common.core.domain.AjaxResult;
import com.ruoyi.common.core.domain.R;
import com.ruoyi.common.core.domain.model.LoginUser;
import com.ruoyi.common.core.page.PageDataInfo;
import com.ruoyi.common.core.redis.RedisCache;
import com.ruoyi.common.utils.DateUtils;
import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.common.utils.ip.IpUtils;
import com.ruoyi.common.utils.poi.ExcelUtil;
import com.ruoyi.domain.common.constant.TtboxRecordStatus;
import com.ruoyi.domain.entity.TtBoxRecords;
import com.ruoyi.domain.entity.sys.TtPromotionUpdate;
import com.ruoyi.domain.entity.sys.TtUser;
import com.ruoyi.domain.other.ApiUserOnline;
import com.ruoyi.domain.other.TtUserBody;
import com.ruoyi.domain.other.TtUserPackSackBody;
import com.ruoyi.domain.vo.TtUserPackSackDataVO;
import com.ruoyi.domain.vo.user.TtUserVo;
import io.swagger.annotations.ApiOperation;
import jakarta.servlet.http.HttpServletResponse;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.tuple.Pair;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import java.math.BigDecimal;
import java.util.*;
import java.util.stream.Collectors;
@Slf4j
@RestController
@RequestMapping("/admin/user")
public class TtUserController extends BaseController {
private final TtUserService userService;
private final RedisCache redisCache;
private final TtBoxRecordsService boxRecordsService;
public TtUserController(TtUserService ttUserService,
RedisCache redisCache,
TtBoxRecordsService boxRecordsService) {
this.userService = ttUserService;
this.redisCache = redisCache;
this.boxRecordsService = boxRecordsService;
}
@Autowired
private TtUserMapper ttUserMapper;
@Autowired
private TtPromotionUpdateMapper promotionUpdateMapper;
@GetMapping("/list")
public PageDataInfo<TtUserVo> list(TtUserBody ttUserBody) {
startPage();
Pair<Integer, List<TtUserVo>> list = userService.queryList(ttUserBody);
list.getValue().forEach(ttUser -> ttUser.setPassword(""));
PageDataInfo<TtUserVo> pageDataInfo = getPageData(list.getValue());
pageDataInfo.setTotal(list.getKey());
return pageDataInfo;
}
@PostMapping("/export")
public void export(HttpServletResponse response, TtUserBody ttUserBody) {
Pair<Integer, List<TtUserVo>> list = userService.queryList(ttUserBody);
ExcelUtil<TtUserVo> util = new ExcelUtil<>(TtUserVo.class);
util.exportExcel(response, list.getValue(), "用户信息列表");
}
@GetMapping(value = "/{userId}")
public R<TtUser> getInfo(@PathVariable("userId") Long userId) {
TtUser user = userService.getById(userId);
user.setPassword(null);
user.setSafePassword(null);
if (user.getRemark() != null && user.getRemark().length() > 5) user.setRemark(user.getRemark().substring(5));
return R.ok(user);
}
@Log(title = "用户列表", action = "生成招商账号", businessType = BusinessType.INSERT)
@ApiOperation("生成招商账号")
@PostMapping("/generateAccount")
public void generateAccount(HttpServletResponse response, @RequestBody GenerateAccountBody body) {
List<TtUser> userList = userService.getAccountList(body.getNum(), body.getCustomPhoneNumbers());
userService.generateAccount(response, userList);
}
@ApiOperation("生成账号")
@GetMapping("/generateAccountByPhoneNum")
public R generateAccountByPhoneNum(HttpServletResponse response, @RequestParam("phoneNum") String phoneNum,
@RequestParam("password") String password) {
TtUser user = userService.getAccountList(phoneNum, password);
return R.ok(user);
}
@Log(title = "用户列表", action = "生成机器人", businessType = BusinessType.INSERT)
@ApiOperation("生成机器人")
@PostMapping("/generateRobot/{num}")
public void generateRobot(HttpServletResponse response, @PathVariable("num") Integer num) {
List<TtUser> userList = userService.getRobotList(num);
userService.generateAccount(response, userList);
}
@Log(title = "用户列表", action = "生成白号", businessType = BusinessType.INSERT)
@ApiOperation("生成白号")
@PostMapping("/generateBlankAccount")
public void generateBlankAccount(HttpServletResponse response, @RequestBody GenerateAccountBody body) {
List<TtUser> userList = userService.getBlankAccountList(body.getNum(), body.getCustomPhoneNumbers());
userService.generateAccount(response, userList);
}
@Log(title = "用户列表", action = "生成卡商账号", businessType = BusinessType.INSERT)
@ApiOperation("生成卡商账号")
@PostMapping("/generateCardMerchant")
public void generateCardMerchant(HttpServletResponse response, @RequestBody GenerateAccountBody body) {
List<TtUser> userList = userService.getCardMerchantList(body.getNum(), body.getCustomPhoneNumbers());
userService.generateAccount(response, userList);
}
@Log(title = "用户列表", action = "修改", businessType = BusinessType.UPDATE,
entityClass = TtUser.class, mapperClass = TtUserMapper.class)
@ApiOperation("修改用户信息")
@PutMapping
public AjaxResult edit(@RequestBody TtUser ttUser) {
ttUser.setUpdateBy(getUsername());
ttUser.setUpdateTime(DateUtils.getNowDate());
// 余额/积分变动写入流水(source=65 管理员调整余额 / source=66 管理员调整积分),操作人+登录IP记入备注
String operIp = getLoginUser().getIpaddr();
if (StringUtils.isEmpty(operIp)) {
operIp = IpUtils.getIpAddr();
}
userService.recordAdminBalanceCreditChange(ttUser, getUsername(), operIp);
return userService.updateUserById(ttUser);
}
@Log(title = "用户列表", action = "修改邀请码", businessType = BusinessType.UPDATE,
entityClass = TtUser.class, mapperClass = TtUserMapper.class)
@ApiOperation("修改邀请码")
@PostMapping("/editInvitationCode")
public AjaxResult editInvitationCode(@RequestBody TtUser ttUser) {
ttUser.setUpdateBy(getUsername());
ttUser.setUpdateTime(DateUtils.getNowDate());
return userService.updateUserInvitationCodeById(ttUser);
}
@Log(title = "用户列表", action = "删除", businessType = BusinessType.DELETE)
@DeleteMapping("/{userIds}")
public AjaxResult remove(@PathVariable Long[] userIds) {
// 逻辑删除前级联解绑:将每个用户的所有下级 parent_id 置空
for (Long userId : userIds) {
try {
userService.cascadeUnbindChildren(userId.intValue());
} catch (Exception e) {
log.error("[逻辑删除] userId={} 级联解绑失败", userId, e);
}
}
return toAjax(userService.removeByIds(Arrays.asList(userIds)));
}
@GetMapping("/online/list")
public PageDataInfo<ApiUserOnline> list(String ipaddr, String userName) {
startPage();
Collection<String> redisKeys = redisCache.keys(CacheConstants.LOGIN_TOKEN_KEY + "*");
List<ApiUserOnline> userOnlineList = redisKeys.stream().map(redisKey -> {
LoginUser user = redisCache.getCacheObject(redisKey);
if (StringUtils.isNull(user)) {
return null;
}
// 仅保留有活跃心跳的用户(心跳由 JwtAuthenticationTokenFilter 随请求写入,TTL 3分钟),
// 避免把所有未过期 token(30天)都算作在线导致首页在线用户虚高
if (!redisCache.hasKey(CacheConstants.ONLINE_HEARTBEAT_KEY + user.getToken())) {
return null;
}
if (StringUtils.isNotEmpty(ipaddr) && StringUtils.isNotEmpty(userName)) {
return userService.selectOnlineByInfo(ipaddr, userName, user);
} else if (StringUtils.isNotEmpty(ipaddr)) {
return userService.selectOnlineByIpaddr(ipaddr, user);
} else if (StringUtils.isNotEmpty(userName) && StringUtils.isNotNull(user.getUser())) {
return userService.selectOnlineByUserName(userName, user);
} else {
return userService.loginUserToUserOnline(user);
}
}).collect(Collectors.toList());
userOnlineList.removeAll(Collections.singleton(null));
// 按最新登录时间降序排列
userOnlineList.sort(Comparator.comparing(ApiUserOnline::getLoginTime,
Comparator.nullsLast(Comparator.reverseOrder())));
return getPageData(userOnlineList);
}
@GetMapping("/getPackSack")
public PageDataInfo<TtUserPackSackDataVO> getPackSack(TtUserPackSackBody ttUserPackSackBody) {
startPage();
List<TtUserPackSackDataVO> list = userService.getPackSack(ttUserPackSackBody);
return getPageData(list);
}
@Log(title = "背包列表", action = "删除", businessType = BusinessType.DELETE)
@PostMapping("/removeUserPackSackData/{ids}")
public AjaxResult removeUserPackSackData(@PathVariable Long[] ids) {
List<TtBoxRecords> boxRecordsList = boxRecordsService.getBaseMapper().selectBatchIds(Arrays.asList(ids));
boxRecordsList = boxRecordsList.stream().peek(ttBoxRecords -> {
ttBoxRecords.setStatus(TtboxRecordStatus.ADMIN_DELETE.getCode());
ttBoxRecords.setUpdateTime(DateUtils.getNowDate());
}).collect(Collectors.toList());
return toAjax(boxRecordsService.updateBatchById(boxRecordsList, 1));
}
@GetMapping("/getUserProfitStatistics/{userId}")
public R<Object> getUserProfitStatistics(@PathVariable("userId") Integer userId) {
Map<String, BigDecimal> map = userService.getUserProfitStatistics(userId);
return R.ok(map);
}
@Log(title = "用户列表", action = "重置余额积分", businessType = BusinessType.CLEAN,
entityClass = TtUser.class, mapperClass = TtUserMapper.class, idField = "userId")
@ApiOperation("重置用户余额和积分")
@PostMapping("/resetBalance/{userId}")
public AjaxResult resetUserBalance(@PathVariable("userId") Integer userId){
TtUser ttUser = new TtUser();
ttUser.setUserId(userId);
ttUser.setAccountAmount(BigDecimal.ZERO);
ttUser.setAccountCredits(BigDecimal.ZERO);
ttUser.setMerchantBalance(BigDecimal.ZERO);
ttUser.setUpdateBy(getUsername());
ttUser.setUpdateTime(DateUtils.getNowDate());
return userService.updateUserById(ttUser);
}
@Log(title = "用户列表", action = "真删除", businessType = BusinessType.FORCE)
@ApiOperation("真删除用户(数据库删除,不可恢复)")
@DeleteMapping("/forceDelete/{userId}")
public AjaxResult forceDelete(@PathVariable("userId") Integer userId) {
// 0. 先清登录态:物理删除后 tt_user 查不到该用户,若不清 Redis Token,
// 已登录客户端仍能带旧 Token 调接口(/api/getAccountAmount 会一直空指针且无法登出)
userService.kickOutLoginUsers(Collections.singletonList(userId.longValue()), "您的账号已被删除");
// 1. 级联解绑:将该用户的所有下级(含下级的下级)parent_id 置空
try {
userService.cascadeUnbindChildren(userId);
} catch (Exception e) {
log.error("[真删除] userId={} 级联解绑失败", userId, e);
}
// 2. 清空该用户背包中的饰品记录(holder_user_id = userId)
boxRecordsService.remove(new LambdaQueryWrapper<TtBoxRecords>()
.eq(TtBoxRecords::getHolderUserId, userId));
// 3. 清理推广更新记录,避免该 userId 被重新分配后注册冲突
promotionUpdateMapper.delete(new LambdaQueryWrapper<TtPromotionUpdate>()
.eq(TtPromotionUpdate::getEmployeeId, userId));
// 4. 清理副号绑定关系,避免该 userId 被重新分配后绑定冲突
ttUserMapper.removeUserSubAccountByUserId(userId);
// 5. 删除用户
ttUserMapper.removeByUserId(userId);
return AjaxResult.success("用户已彻底删除,背包已清空,下级已解绑");
}
/**
* 生成账号请求体:num-数量;customPhoneNumbers-自定义手机号(按位置对应,留空则随机生成)
*/
@Data
public static class GenerateAccountBody {
private Integer num;
private List<String> customPhoneNumbers;
}
}
@@ -0,0 +1,30 @@
package com.ruoyi.admin.controller;
import com.ruoyi.domain.entity.recorde.TtUserCreditsRecords;
import com.ruoyi.admin.service.TtUserCreditsRecordsService;
import com.ruoyi.domain.other.TtUserCreditsRecordsBody;
import com.ruoyi.common.core.controller.BaseController;
import com.ruoyi.common.core.page.PageDataInfo;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.List;
@RestController
@RequestMapping("/admin/userCreditsRecords")
public class TtUserCreditsRecordsController extends BaseController {
private final TtUserCreditsRecordsService userCreditsRecordsService;
public TtUserCreditsRecordsController(TtUserCreditsRecordsService userCreditsRecordsService) {
this.userCreditsRecordsService = userCreditsRecordsService;
}
@GetMapping("/list")
public PageDataInfo<TtUserCreditsRecords> list(TtUserCreditsRecordsBody ttUserCreditsRecordsBody) {
startPage();
List<TtUserCreditsRecords> list = userCreditsRecordsService.queryList(ttUserCreditsRecordsBody);
return getPageData(list);
}
}
@@ -0,0 +1,69 @@
package com.ruoyi.admin.controller;
import com.ruoyi.admin.mapper.TtVipLevelMapper;
import com.ruoyi.common.enums.BusinessType;
import com.ruoyi.common.annotation.Log;
import com.ruoyi.domain.other.TtVipLevel;
import com.ruoyi.admin.service.TtVipLevelService;
import com.ruoyi.common.core.controller.BaseController;
import com.ruoyi.common.core.domain.AjaxResult;
import com.ruoyi.common.core.domain.R;
import com.ruoyi.common.core.page.PageDataInfo;
import com.ruoyi.common.utils.DateUtils;
import com.ruoyi.common.utils.StringUtils;
import org.springframework.web.bind.annotation.*;
import java.util.List;
@RestController
@RequestMapping("/admin/vipLevel")
public class TtVipLevelController extends BaseController {
private final TtVipLevelService vipLevelService;
public TtVipLevelController(TtVipLevelService vipLevelService) {
this.vipLevelService = vipLevelService;
}
@GetMapping("/list")
public PageDataInfo<TtVipLevel> list() {
// VIP 等级总量不多,后台设置页也未接入分页组件,改为全量返回
List<TtVipLevel> list = vipLevelService.list();
PageDataInfo<TtVipLevel> data = new PageDataInfo<>();
data.setRows(list);
data.setTotal(list == null ? 0 : list.size());
data.setCode(200);
data.setMsg("查询成功");
return data;
}
@GetMapping(value = "/{id}")
public R<TtVipLevel> getInfo(@PathVariable("id") Integer id) {
TtVipLevel ttVipLevel = vipLevelService.getById(id);
ttVipLevel.setIcon("");
return R.ok(ttVipLevel);
}
@Log(title = "VIP等级设置", action = "生成VIP等级", businessType = BusinessType.INSERT)
@PostMapping("generateVipLevel/{num}")
public AjaxResult generateVipLevel(@PathVariable("num") Integer num) {
String msg = vipLevelService.generateVipLevel(num);
return StringUtils.isEmpty(msg) ? AjaxResult.success("生成成功,请修改参数!") : AjaxResult.error(msg);
}
@Log(title = "VIP等级设置", action = "修改", businessType = BusinessType.UPDATE,
entityClass = TtVipLevel.class, mapperClass = TtVipLevelMapper.class)
@PutMapping
public AjaxResult edit(@RequestBody TtVipLevel ttVipLevel) {
ttVipLevel.setUpdateTime(DateUtils.getNowDate());
String msg = vipLevelService.updateVipLevelById(ttVipLevel);
return StringUtils.isEmpty(msg) ? AjaxResult.success() : AjaxResult.error(msg);
}
@Log(title = "VIP等级设置", action = "重置", businessType = BusinessType.CLEAN)
@PostMapping
public AjaxResult truncateVipLevel() {
vipLevelService.truncateVipLevel();
return AjaxResult.success("重置成功,请重新设置!");
}
}
@@ -0,0 +1,148 @@
package com.ruoyi.admin.controller;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.ruoyi.admin.mapper.TtWelfareMapper;
import com.ruoyi.admin.service.TtBoxRecordsService;
import com.ruoyi.admin.service.TtWelfareService;
import com.ruoyi.common.annotation.Log;
import com.ruoyi.common.core.controller.BaseController;
import com.ruoyi.common.core.domain.AjaxResult;
import com.ruoyi.common.core.page.TableDataInfo;
import com.ruoyi.common.enums.BusinessType;
import com.ruoyi.common.utils.poi.ExcelUtil;
import com.ruoyi.domain.entity.TtBoxRecords;
import com.ruoyi.domain.other.TtBoxRecordsBody;
import com.ruoyi.domain.other.TtWelfare;
import com.ruoyi.domain.vo.TtBoxRecordsDataVO;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.*;
import jakarta.servlet.http.HttpServletResponse;
import java.util.Arrays;
import java.util.List;
/**
* 福利列表Controller
*
* @author ruoyi
* @date 2024-05-11
*/
@RestController
@RequestMapping("/admin/welfare")
public class TtWelfareController extends BaseController
{
@Autowired
private TtWelfareService ttWelfareService;
@Autowired
private TtBoxRecordsService ttBoxRecordsService;
/**
* 查询福利列表
*/
@PreAuthorize("isAuthenticated()")
@GetMapping("/list")
public TableDataInfo list(TtWelfare ttWelfare)
{
startPage();
List<TtWelfare> list = ttWelfareService.selectTtWelfareList(ttWelfare);
return getDataTable(list);
}
/**
* 导出福利列表
*/
@PreAuthorize("isAuthenticated()")
@Log(title = "福利列表", businessType = BusinessType.EXPORT)
@PostMapping("/export")
public void export(HttpServletResponse response, TtWelfare ttWelfare)
{
List<TtWelfare> list = ttWelfareService.selectTtWelfareList(ttWelfare);
ExcelUtil<TtWelfare> util = new ExcelUtil<TtWelfare>(TtWelfare.class);
util.exportExcel(response, list, "福利列表数据");
}
/**
* 获取福利列表详细信息
*/
@PreAuthorize("isAuthenticated()")
@GetMapping(value = "/{welfareId}")
public AjaxResult getInfo(@PathVariable("welfareId") Integer welfareId)
{
return success(ttWelfareService.selectTtWelfareByWelfareId(welfareId));
}
/**
* 新增福利列表
*/
@PreAuthorize("isAuthenticated()")
@Log(title = "福利列表", action = "新增", businessType = BusinessType.INSERT,
entityClass = TtWelfare.class, mapperClass = TtWelfareMapper.class)
@PostMapping
public AjaxResult add(@RequestBody TtWelfare ttWelfare)
{
return toAjax(ttWelfareService.insertTtWelfare(ttWelfare));
}
/**
* 修改福利列表
*/
@PreAuthorize("isAuthenticated()")
@Log(title = "福利列表", action = "修改", businessType = BusinessType.UPDATE,
entityClass = TtWelfare.class, mapperClass = TtWelfareMapper.class)
@PutMapping
public AjaxResult edit(@RequestBody TtWelfare ttWelfare)
{
return toAjax(ttWelfareService.updateTtWelfare(ttWelfare));
}
/**
* 删除福利列表
*/
@PreAuthorize("isAuthenticated()")
@Log(title = "福利列表", action = "删除", businessType = BusinessType.DELETE)
@DeleteMapping("/{welfareIds}")
public AjaxResult remove(@PathVariable Integer[] welfareIds)
{
return toAjax(ttWelfareService.deleteTtWelfareByWelfareIds(welfareIds));
}
/**
* 查询福利箱子开箱记录
*/
@PreAuthorize("isAuthenticated()")
@GetMapping("/boxRecords")
public TableDataInfo boxRecordsList(TtBoxRecordsBody ttBoxRecordsBody)
{
startPage();
List<TtBoxRecordsDataVO> list = ttBoxRecordsService.selectWelfareBoxRecordsList(ttBoxRecordsBody);
return getDataTable(list);
}
/**
* 删除福利箱子开箱记录(支持批量)
*/
@PreAuthorize("isAuthenticated()")
@Log(title = "福利开箱记录", action = "删除", businessType = BusinessType.DELETE)
@DeleteMapping("/boxRecords/{ids}")
public AjaxResult removeBoxRecords(@PathVariable Long[] ids)
{
return toAjax(ttBoxRecordsService.removeByIds(Arrays.asList(ids)));
}
/**
* 清空全部福利开箱记录(source=10)
*/
@PreAuthorize("isAuthenticated()")
@Log(title = "福利开箱记录", action = "清空全部记录", businessType = BusinessType.CLEAN)
@DeleteMapping("/boxRecords/clear")
public AjaxResult clearBoxRecords()
{
return toAjax(ttBoxRecordsService.remove(
new LambdaQueryWrapper<TtBoxRecords>()
.eq(TtBoxRecords::getSource, 10)
));
}
}
@@ -0,0 +1,107 @@
package com.ruoyi.admin.controller;
import java.util.List;
import jakarta.servlet.http.HttpServletResponse;
import org.springframework.security.access.prepost.PreAuthorize;
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.PutMapping;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import com.ruoyi.admin.mapper.TtWelfareMonthlyRechargesMapper;
import com.ruoyi.common.annotation.Log;
import com.ruoyi.common.core.controller.BaseController;
import com.ruoyi.common.core.domain.AjaxResult;
import com.ruoyi.common.enums.BusinessType;
import com.ruoyi.domain.other.TtWelfareMonthlyRecharges;
import com.ruoyi.admin.service.ITtWelfareMonthlyRechargesService;
import com.ruoyi.common.utils.poi.ExcelUtil;
import com.ruoyi.common.core.page.TableDataInfo;
/**
* 每月充值福利Controller
*
* @author ruoyi
* @date 2024-06-24
*/
@RestController
@RequestMapping("/admin/recharges")
public class TtWelfareMonthlyRechargesController extends BaseController
{
@Autowired
private ITtWelfareMonthlyRechargesService ttWelfareMonthlyRechargesService;
/**
* 查询每月充值福利列表
*/
@PreAuthorize("@ss.hasPermi('admin:recharges:list')")
@GetMapping("/list")
public TableDataInfo list(TtWelfareMonthlyRecharges ttWelfareMonthlyRecharges)
{
startPage();
List<TtWelfareMonthlyRecharges> list = ttWelfareMonthlyRechargesService.selectTtWelfareMonthlyRechargesList(ttWelfareMonthlyRecharges);
return getDataTable(list);
}
/**
* 导出每月充值福利列表
*/
@PreAuthorize("@ss.hasPermi('admin:recharges:export')")
@Log(title = "每月充值福利", businessType = BusinessType.EXPORT)
@PostMapping("/export")
public void export(HttpServletResponse response, TtWelfareMonthlyRecharges ttWelfareMonthlyRecharges)
{
List<TtWelfareMonthlyRecharges> list = ttWelfareMonthlyRechargesService.selectTtWelfareMonthlyRechargesList(ttWelfareMonthlyRecharges);
ExcelUtil<TtWelfareMonthlyRecharges> util = new ExcelUtil<TtWelfareMonthlyRecharges>(TtWelfareMonthlyRecharges.class);
util.exportExcel(response, list, "每月充值福利数据");
}
/**
* 获取每月充值福利详细信息
*/
@PreAuthorize("@ss.hasPermi('admin:recharges:query')")
@GetMapping(value = "/{id}")
public AjaxResult getInfo(@PathVariable("id") Integer id)
{
return success(ttWelfareMonthlyRechargesService.selectTtWelfareMonthlyRechargesById(id));
}
/**
* 新增每月充值福利
*/
@PreAuthorize("@ss.hasPermi('admin:recharges:add')")
@Log(title = "每月充值福利", action = "新增", businessType = BusinessType.INSERT,
entityClass = TtWelfareMonthlyRecharges.class, mapperClass = TtWelfareMonthlyRechargesMapper.class)
@PostMapping
public AjaxResult add(@RequestBody TtWelfareMonthlyRecharges ttWelfareMonthlyRecharges)
{
return toAjax(ttWelfareMonthlyRechargesService.insertTtWelfareMonthlyRecharges(ttWelfareMonthlyRecharges));
}
/**
* 修改每月充值福利
*/
@PreAuthorize("@ss.hasPermi('admin:recharges:edit')")
@Log(title = "每月充值福利", action = "修改", businessType = BusinessType.UPDATE,
entityClass = TtWelfareMonthlyRecharges.class, mapperClass = TtWelfareMonthlyRechargesMapper.class)
@PutMapping
public AjaxResult edit(@RequestBody TtWelfareMonthlyRecharges ttWelfareMonthlyRecharges)
{
return toAjax(ttWelfareMonthlyRechargesService.updateTtWelfareMonthlyRecharges(ttWelfareMonthlyRecharges));
}
/**
* 删除每月充值福利
*/
@PreAuthorize("@ss.hasPermi('admin:recharges:remove')")
@Log(title = "每月充值福利", action = "删除", businessType = BusinessType.DELETE)
@DeleteMapping("/{ids}")
public AjaxResult remove(@PathVariable Integer[] ids)
{
return toAjax(ttWelfareMonthlyRechargesService.deleteTtWelfareMonthlyRechargesByIds(ids));
}
}
@@ -0,0 +1,250 @@
package com.ruoyi.admin.controller;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.ruoyi.common.enums.BusinessType;
import com.ruoyi.common.annotation.Log;
import com.ruoyi.admin.config.RedisConstants;
import com.ruoyi.admin.mapper.TtOrnamentMapper;
import com.ruoyi.admin.mapper.TurnoverLotteryMapper;
import com.ruoyi.admin.mapper.TurnoverLotteryPrizeMapper;
import com.ruoyi.admin.mapper.TurnoverLotteryRecordMapper;
import com.ruoyi.admin.service.TurnoverLotteryService;
import com.ruoyi.common.core.controller.BaseController;
import com.ruoyi.common.core.domain.R;
import com.ruoyi.common.core.page.PageDataInfo;
import com.ruoyi.common.redis.config.RedisLock;
import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.domain.entity.TtOrnament;
import com.ruoyi.domain.entity.lottery.TtTurnoverLottery;
import com.ruoyi.domain.entity.lottery.TtTurnoverLotteryPrize;
import com.ruoyi.domain.entity.lottery.TtTurnoverLotteryRecord;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import java.math.BigDecimal;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;
/**
* 后台管理 - 流水抽奖配置
*/
@Api(tags = "后台流水抽奖管理")
@RestController
@RequestMapping("/admin/turnoverLottery")
public class TurnoverLotteryAdminController extends BaseController {
@Autowired
private TurnoverLotteryService lotteryService;
@Autowired
private TurnoverLotteryMapper lotteryMapper;
@Autowired
private TurnoverLotteryPrizeMapper prizeMapper;
@Autowired
private TtOrnamentMapper ornamentMapper;
@Autowired
private TurnoverLotteryRecordMapper recordMapper;
@Autowired
private RedisLock redisLock;
/**
* 获取抽奖活动列表
*/
@ApiOperation("获取抽奖活动列表")
@GetMapping("/list")
public PageDataInfo<TtTurnoverLottery> list(
@RequestParam(required = false) String lotteryName,
@RequestParam(required = false) Integer status) {
LambdaQueryWrapper<TtTurnoverLottery> wrapper = new LambdaQueryWrapper<>();
wrapper.like(StringUtils.isNotBlank(lotteryName), TtTurnoverLottery::getLotteryName, lotteryName)
.eq(status != null, TtTurnoverLottery::getStatus, status)
.orderByAsc(TtTurnoverLottery::getSort, TtTurnoverLottery::getId);
startPage();
List<TtTurnoverLottery> list = lotteryMapper.selectList(wrapper);
// 动态计算奖品总价值(按初始真实数量 × 单价累加,与用户端 myStats 口径一致)
for (TtTurnoverLottery lottery : list) {
LambdaQueryWrapper<TtTurnoverLotteryPrize> prizeWrapper = new LambdaQueryWrapper<>();
prizeWrapper.eq(TtTurnoverLotteryPrize::getLotteryId, lottery.getId());
List<TtTurnoverLotteryPrize> prizes = prizeMapper.selectList(prizeWrapper);
BigDecimal totalValue = prizes.stream()
.map(p -> {
BigDecimal price = p.getPrice() != null ? p.getPrice() : BigDecimal.ZERO;
int count = p.getInitialRealCount() != null ? p.getInitialRealCount()
: (p.getRealCount() != null ? p.getRealCount() : 0);
return price.multiply(new BigDecimal(count));
})
.reduce(BigDecimal.ZERO, BigDecimal::add);
lottery.setTotalValue(totalValue);
}
return getPageData(list);
}
/**
* 保存抽奖奖品配置
*/
@ApiOperation("保存抽奖奖品")
@PostMapping("/save/{lotteryId}")
public R<String> savePrizes(
@PathVariable("lotteryId") Long lotteryId,
@RequestBody List<Map<String, Object>> prizeList) {
String lockKey = RedisConstants.TURNOVER_LOTTERY_DRAW_BOX_LOCK + lotteryId;
boolean locked = redisLock.tryLock(lockKey, 0L, -1L, TimeUnit.SECONDS);
if (!locked) {
return R.fail("奖品配置保存中,请稍后再试");
}
try {
return lotteryService.savePrizes(lotteryId, prizeList);
} finally {
redisLock.unlock(lockKey);
}
}
/**
* 更新抽奖活动状态
*/
@ApiOperation("更新抽奖状态")
@PostMapping("/toggleStatus")
public R<String> toggleStatus(@RequestBody Map<String, Object> body) {
Long lotteryId = body.get("lotteryId") != null ? ((Number) body.get("lotteryId")).longValue() : null;
Integer status = body.get("status") != null ? ((Number) body.get("status")).intValue() : null;
if (lotteryId == null || status == null) {
return R.fail("参数错误");
}
// 加宝箱锁,串行"关闭活动"与"抽奖中"的竞态(避免关闭后仍抽出一两单)
String lockKey = RedisConstants.TURNOVER_LOTTERY_DRAW_BOX_LOCK + lotteryId;
boolean locked = redisLock.tryLock(lockKey, 0L, -1L, TimeUnit.SECONDS);
if (!locked) {
return R.fail("操作处理中,请稍后再试");
}
try {
return lotteryService.toggleStatus(lotteryId, status);
} finally {
redisLock.unlock(lockKey);
}
}
@Log(title = "抽奖活动", action = "新增抽奖活动", businessType = BusinessType.INSERT)
/**
* 创建新的抽奖活动
*/
@ApiOperation("创建抽奖活动")
@PostMapping("/create")
public R<TtTurnoverLottery> create(@RequestBody Map<String, Object> body) {
String lotteryName = body.get("lotteryName") != null ? body.get("lotteryName").toString() : null;
Integer turnoverThreshold = body.get("turnoverThreshold") != null
? ((Number) body.get("turnoverThreshold")).intValue() : 3000;
if (lotteryName == null || lotteryName.trim().isEmpty()) {
return R.fail("抽奖名称不能为空");
}
if (turnoverThreshold == null || turnoverThreshold <= 0) {
return R.fail("流水门槛必须大于0");
}
TtTurnoverLottery lottery = new TtTurnoverLottery();
lottery.setLotteryName(lotteryName);
lottery.setTurnoverThreshold(turnoverThreshold);
lottery.setLotteryType(1); // 流水抽奖类型
lottery.setStatus(0); // 默认关闭
lottery.setSort(1);
lottery.setCreateBy(getUsername());
lottery.setCreateTime(new java.util.Date());
lotteryMapper.insert(lottery);
return R.ok(lottery);
}
@Log(title = "抽奖活动", action = "删除", businessType = BusinessType.DELETE)
/**
* 删除抽奖活动
*/
@ApiOperation("删除抽奖活动")
@DeleteMapping("/delete/{lotteryId}")
public R<String> delete(@PathVariable("lotteryId") Long lotteryId) {
lotteryMapper.deleteById(lotteryId);
return R.ok("删除成功");
}
/**
* 搜索饰品 (用于奖品配置时调用)
*/
@ApiOperation("搜索饰品")
@GetMapping("/searchOrnaments")
public R<List<TtOrnament>> searchOrnaments(
@RequestParam(value = "name", required = false) String name,
@RequestParam(value = "limit", defaultValue = "50") Integer limit) {
LambdaQueryWrapper<TtOrnament> wrapper = new LambdaQueryWrapper<>();
if (StringUtils.isNotEmpty(name)) {
wrapper.and(w -> w
.like(TtOrnament::getName, name)
.or().like(TtOrnament::getShortName, name)
.or().like(TtOrnament::getMarketHashName, name));
}
wrapper.orderByAsc(TtOrnament::getUsePrice)
.last("LIMIT " + Math.min(limit, 100));
return R.ok(ornamentMapper.selectList(wrapper));
}
@Log(title = "抽奖活动", action = "修改", businessType = BusinessType.UPDATE)
/**
* 更新抽奖活动基础信息
*/
@ApiOperation("更新抽奖活动")
@PostMapping("/update")
public R<String> update(@RequestBody Map<String, Object> body) {
Long lotteryId = body.get("lotteryId") != null ? ((Number) body.get("lotteryId")).longValue() : null;
if (lotteryId == null) {
lotteryId = body.get("id") != null ? ((Number) body.get("id")).longValue() : null;
}
String lotteryName = body.get("lotteryName") != null ? body.get("lotteryName").toString() : null;
Integer turnoverThreshold = body.get("turnoverThreshold") != null
? ((Number) body.get("turnoverThreshold")).intValue() : null;
Integer sort = body.get("sort") != null ? ((Number) body.get("sort")).intValue() : null;
if (lotteryId == null) {
return R.fail("抽奖ID不能为空");
}
if (turnoverThreshold != null && turnoverThreshold <= 0) {
return R.fail("流水门槛必须大于0");
}
TtTurnoverLottery lottery = new TtTurnoverLottery();
lottery.setId(lotteryId);
if (StringUtils.isNotEmpty(lotteryName)) {
lottery.setLotteryName(lotteryName);
}
if (turnoverThreshold != null) {
lottery.setTurnoverThreshold(turnoverThreshold);
}
if (sort != null) {
lottery.setSort(sort);
}
lottery.setUpdateTime(new java.util.Date());
lotteryMapper.updateById(lottery);
return R.ok("更新成功");
}
public String getUsername() {
var loginUser = getLoginUser();
return loginUser != null && loginUser.getUserData() != null
? loginUser.getUserData().getUserName()
: "admin";
}
}
@@ -0,0 +1,258 @@
package com.ruoyi.admin.controller;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.ruoyi.common.enums.BusinessType;
import com.ruoyi.common.annotation.Log;
import com.ruoyi.admin.config.RedisConstants;
import com.ruoyi.admin.mapper.TurnoverLotteryMapper;
import com.ruoyi.admin.mapper.TurnoverLotteryPrizeMapper;
import com.ruoyi.admin.mapper.TtOrnamentsLevelMapper;
import com.ruoyi.admin.service.TurnoverLotteryService;
import com.ruoyi.common.core.controller.BaseController;
import com.ruoyi.common.core.domain.AjaxResult;
import com.ruoyi.common.core.domain.R;
import com.ruoyi.common.core.page.PageDataInfo;
import com.ruoyi.common.redis.config.RedisLock;
import com.ruoyi.common.utils.DateUtils;
import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.domain.entity.lottery.TtTurnoverLottery;
import com.ruoyi.domain.entity.lottery.TtTurnoverLotteryPrize;
import com.ruoyi.domain.other.TtOrnamentsLevel;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import java.math.BigDecimal;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;
/**
* 流水抽奖奖品管理 (仿宝箱饰品管理 boxOrnaments)
*/
@Api(tags = "流水抽奖奖品管理")
@RestController
@RequestMapping("/admin/turnoverLotteryPrize")
public class TurnoverLotteryPrizeController extends BaseController {
@Autowired
private TurnoverLotteryPrizeMapper prizeMapper;
@Autowired
private TurnoverLotteryMapper lotteryMapper;
@Autowired
private TurnoverLotteryService lotteryService;
@Autowired
private TtOrnamentsLevelMapper ornamentsLevelMapper;
@Autowired
private RedisLock redisLock;
/**
* 获取奖品列表 (分页,含爆率百分比计算)
*/
@ApiOperation("奖品列表")
@GetMapping("/list/{lotteryId}")
public PageDataInfo<TtTurnoverLotteryPrize> list(@PathVariable("lotteryId") Long lotteryId) {
// 先算总数(避免 PageHelper 干扰百分比计算)
int[] totals = sumOdds(lotteryId);
startPage();
LambdaQueryWrapper<TtTurnoverLotteryPrize> wrapper = new LambdaQueryWrapper<>();
wrapper.eq(TtTurnoverLotteryPrize::getLotteryId, lotteryId);
wrapper.orderByAsc(TtTurnoverLotteryPrize::getSort, TtTurnoverLotteryPrize::getId);
List<TtTurnoverLotteryPrize> list = prizeMapper.selectList(wrapper);
// 填充计算字段
int totalDisplay = Math.max(totals[0], 1);
int totalReal = Math.max(totals[1], 1);
// 批量获取等级图片
List<TtOrnamentsLevel> levelList = ornamentsLevelMapper.selectList(null);
Map<Integer, String> levelImgMap = levelList.stream()
.collect(Collectors.toMap(TtOrnamentsLevel::getId, TtOrnamentsLevel::getLevelImg, (a, b) -> a));
for (TtTurnoverLotteryPrize prize : list) {
int dc = prize.getDisplayCount() != null ? prize.getDisplayCount() : 0;
int rc = prize.getRealCount() != null ? prize.getRealCount() : 0;
int tc = prize.getTotalCount() != null ? prize.getTotalCount() : 0;
// 显示爆率百分比
double displayPct = (double) dc / totalDisplay * 100;
prize.setTheoreticalRate(Math.round(displayPct * 100.0) / 100.0);
prize.setDisplayPercent(String.format("%.2f%%", displayPct));
// 真实爆率百分比(基于当前剩余库存 realCount,与抽奖实际权重、用户端 myStats 一致)
double realPct = (double) rc / totalReal * 100;
prize.setRealRate(Math.round(realPct * 100.0) / 100.0);
prize.setRealPercent(String.format("%.2f%%", realPct));
// 当前剩余库存 = realCount(当前剩余)
prize.setRealRemaining(Math.max(rc, 0));
// 等级图片
Integer levelId = prize.getOrnamentLevel();
if (levelId != null) {
prize.setLevelImg(levelImgMap.get(levelId));
}
}
return getPageData(list);
}
/**
* 获取单个奖品详情
*/
@ApiOperation("奖品详情")
@GetMapping("/{id}")
public R<TtTurnoverLotteryPrize> getInfo(@PathVariable("id") Long id) {
return R.ok(prizeMapper.selectById(id));
}
@Log(title = "奖项配置", action = "新增", businessType = BusinessType.INSERT)
/**
* 新增奖品
*/
@ApiOperation("新增奖品")
@PostMapping
public AjaxResult add(@RequestBody TtTurnoverLotteryPrize prize) {
if (prize == null || prize.getLotteryId() == null) {
return AjaxResult.error("抽奖活动ID不能为空");
}
if (prize.getOrnamentName() == null || prize.getOrnamentName().trim().isEmpty()) {
return AjaxResult.error("奖品名称不能为空");
}
if (prize.getPrice() == null || prize.getPrice().compareTo(BigDecimal.ZERO) < 0) {
return AjaxResult.error("奖品金额不能小于0");
}
// 兼容旧前端:未传 initialRealCount 时取 realCount
if (prize.getInitialRealCount() == null) {
prize.setInitialRealCount(prize.getRealCount());
}
// 新建时当前剩余等于初始配置
if (prize.getRealCount() == null) {
prize.setRealCount(prize.getInitialRealCount());
}
// 初始真实数量(奖池权重)必须大于 0,否则该奖品永远不会被抽中
if (prize.getInitialRealCount() == null || prize.getInitialRealCount() <= 0) {
return AjaxResult.error("真实数量必须大于0");
}
if (prize.getDisplayCount() != null && prize.getDisplayCount() < 0) {
return AjaxResult.error("展示数量不能小于0");
}
// 校验奖品数量上限:每个宝箱最多 8 个奖品
LambdaQueryWrapper<TtTurnoverLotteryPrize> countWrapper = new LambdaQueryWrapper<>();
countWrapper.eq(TtTurnoverLotteryPrize::getLotteryId, prize.getLotteryId());
Long count = prizeMapper.selectCount(countWrapper);
if (count != null && count >= 8) {
return AjaxResult.error("每个宝箱最多配置 8 个奖品,当前已满");
}
prize.setCreateTime(DateUtils.getNowDate());
prizeMapper.insert(prize);
return AjaxResult.success();
}
@Log(title = "奖项配置", action = "修改", businessType = BusinessType.UPDATE)
/**
* 修改奖品
*/
@ApiOperation("修改奖品")
@PutMapping
public AjaxResult edit(@RequestBody TtTurnoverLotteryPrize prize) {
Long lotteryId = prize.getLotteryId();
String lockKey = lotteryId != null ? RedisConstants.TURNOVER_LOTTERY_DRAW_BOX_LOCK + lotteryId : null;
boolean locked = false;
if (lockKey != null) {
locked = redisLock.tryLock(lockKey, 0L, -1L, TimeUnit.SECONDS);
if (!locked) {
return AjaxResult.error("奖品配置处理中,请稍后再试");
}
}
try {
prize.setUpdateTime(DateUtils.getNowDate());
// 兼容旧前端:只传了 realCount 未传 initialRealCount 时,视为修改初始配置
if (prize.getInitialRealCount() == null && prize.getRealCount() != null) {
prize.setInitialRealCount(prize.getRealCount());
}
// 参照经典开箱:修改“数量(initialRealCount)”时,
// “当前剩余库存(realCount)”同步增减相同差值
if (prize.getId() != null && prize.getInitialRealCount() != null) {
TtTurnoverLotteryPrize old = prizeMapper.selectById(prize.getId());
if (old != null) {
int oldInitial = old.getInitialRealCount() != null ? old.getInitialRealCount() : 0;
int delta = prize.getInitialRealCount() - oldInitial;
if (delta != 0) {
int oldReal = old.getRealCount() != null ? old.getRealCount() : 0;
prize.setRealCount(Math.max(oldReal + delta, 0));
}
}
}
prizeMapper.updateById(prize);
return AjaxResult.success();
} finally {
if (locked) {
redisLock.unlock(lockKey);
}
}
}
@Log(title = "奖项配置", action = "删除", businessType = BusinessType.DELETE)
/**
* 删除奖品
*/
@ApiOperation("删除奖品")
@DeleteMapping("/{lotteryId}/{ids}")
public AjaxResult remove(@PathVariable Long lotteryId, @PathVariable Long[] ids) {
String lockKey = RedisConstants.TURNOVER_LOTTERY_DRAW_BOX_LOCK + lotteryId;
boolean locked = redisLock.tryLock(lockKey, 0L, -1L, TimeUnit.SECONDS);
if (!locked) {
return AjaxResult.error("奖品配置处理中,请稍后再试");
}
try {
// 校验不能删光奖品:至少保留一个,否则抽奖会报"奖品配置为空"
Long totalCount = prizeMapper.selectCount(
new LambdaQueryWrapper<TtTurnoverLotteryPrize>()
.eq(TtTurnoverLotteryPrize::getLotteryId, lotteryId));
int deleteCount = ids == null ? 0 : ids.length;
if (totalCount != null && totalCount - deleteCount <= 0) {
return AjaxResult.error("不能删除全部奖品,至少保留一个");
}
prizeMapper.deleteBatchIds(Arrays.asList(ids));
return AjaxResult.success();
} finally {
redisLock.unlock(lockKey);
}
}
/**
* 计算显示数量和真实数量的总和
*/
private int[] sumOdds(Long lotteryId) {
LambdaQueryWrapper<TtTurnoverLotteryPrize> wrapper = new LambdaQueryWrapper<>();
wrapper.eq(TtTurnoverLotteryPrize::getLotteryId, lotteryId);
wrapper.select(
TtTurnoverLotteryPrize::getDisplayCount,
TtTurnoverLotteryPrize::getRealCount);
List<TtTurnoverLotteryPrize> list = prizeMapper.selectList(wrapper);
int totalDisplay = 0;
int totalReal = 0;
for (TtTurnoverLotteryPrize p : list) {
totalDisplay += p.getDisplayCount() != null ? p.getDisplayCount() : 0;
totalReal += p.getRealCount() != null ? p.getRealCount() : 0;
}
return new int[]{totalDisplay, totalReal};
}
}
@@ -0,0 +1,69 @@
package com.ruoyi.admin.controller;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.ruoyi.admin.mapper.TurnoverLotteryRecordMapper;
import com.ruoyi.admin.mapper.TurnoverLotteryMapper;
import com.ruoyi.common.core.controller.BaseController;
import com.ruoyi.common.core.domain.R;
import com.ruoyi.common.core.page.PageDataInfo;
import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.domain.entity.lottery.TtTurnoverLotteryRecord;
import com.ruoyi.domain.entity.lottery.TtTurnoverLottery;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import java.util.List;
/**
* 后台管理 - 抽奖记录查询
*/
@Api(tags = "后台抽奖记录管理")
@RestController
@RequestMapping("/admin/turnoverLotteryRecord")
public class TurnoverLotteryRecordController extends BaseController {
@Autowired
private TurnoverLotteryRecordMapper recordMapper;
@Autowired
private TurnoverLotteryMapper lotteryMapper;
/**
* 查询抽奖记录列表
*/
@ApiOperation("查询抽奖记录")
@GetMapping("/list")
public PageDataInfo<TtTurnoverLotteryRecord> list(
@RequestParam(value = "userId", required = false) Long userId,
@RequestParam(value = "lotteryId", required = false) Long lotteryId) {
LambdaQueryWrapper<TtTurnoverLotteryRecord> wrapper = new LambdaQueryWrapper<>();
if (userId != null) {
wrapper.eq(TtTurnoverLotteryRecord::getUserId, userId);
}
if (lotteryId != null) {
wrapper.eq(TtTurnoverLotteryRecord::getLotteryId, lotteryId);
}
wrapper.orderByDesc(TtTurnoverLotteryRecord::getCreateTime);
startPage();
List<TtTurnoverLotteryRecord> list = recordMapper.selectList(wrapper);
return getPageData(list);
}
/**
* 获取所有抽奖活动(用于下拉选择)
*/
@ApiOperation("获取抽奖活动选项")
@GetMapping("/lotteryOptions")
public R<List<TtTurnoverLottery>> lotteryOptions() {
LambdaQueryWrapper<TtTurnoverLottery> wrapper = new LambdaQueryWrapper<>();
wrapper.orderByAsc(TtTurnoverLottery::getSort, TtTurnoverLottery::getId);
List<TtTurnoverLottery> list = lotteryMapper.selectList(wrapper);
return R.ok(list);
}
}
@@ -0,0 +1,139 @@
package com.ruoyi.admin.controller;
import com.ruoyi.admin.config.RedisConstants;
import com.ruoyi.admin.service.TurnoverLotteryService;
import com.ruoyi.common.core.controller.BaseController;
import com.ruoyi.common.core.domain.R;
import com.ruoyi.common.redis.config.RedisLock;
import com.ruoyi.common.utils.StringUtils;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import java.util.Map;
import java.math.BigDecimal;
import java.util.concurrent.TimeUnit;
/**
* 用户端 - 流水抽奖
*/
@Api(tags = "用户流水抽奖")
@RestController
@RequestMapping("/api/turnoverLottery")
public class TurnoverLotteryUserController extends BaseController {
@Autowired
private TurnoverLotteryService lotteryService;
@Autowired
private RedisLock redisLock;
/**
* 获取用户今日流水统计和可参与的抽奖宝箱
*/
@ApiOperation("获取抽奖信息")
@PostMapping("/myStats")
public R<Map<String, Object>> getMyStats() {
Integer userId = getUserId().intValue();
return lotteryService.getUserStats(userId);
}
/**
* 执行抽奖
*/
@ApiOperation("执行抽奖")
@PostMapping("/draw")
public R<Map<String, Object>> draw(@RequestBody Map<String, Object> params) {
Integer userId = getUserId().intValue();
if (params == null || params.get("lotteryId") == null) {
return R.fail("参数错误:lotteryId 不能为空");
}
Long lotteryId;
try {
lotteryId = Long.valueOf(params.get("lotteryId").toString());
} catch (NumberFormatException e) {
return R.fail("参数错误:lotteryId 格式不正确");
}
// 1. 先按 userId 加锁,串行同一用户的并发点击
String userLockKey = RedisConstants.TURNOVER_LOTTERY_DRAW_LOCK + userId;
boolean userLocked = redisLock.tryLock(userLockKey, 0L, -1L, TimeUnit.SECONDS);
if (!userLocked) {
return R.fail("抽奖处理中,请勿重复操作");
}
try {
// 2. 再按宝箱 lotteryId 加锁,串行不同用户对同一宝箱的并发抽奖,防止奖品超发
String boxLockKey = RedisConstants.TURNOVER_LOTTERY_DRAW_BOX_LOCK + lotteryId;
boolean boxLocked = redisLock.tryLock(boxLockKey, 0L, -1L, TimeUnit.SECONDS);
if (!boxLocked) {
return R.fail("抽奖处理中,请稍后再试");
}
try {
return lotteryService.draw(userId, lotteryId);
} finally {
redisLock.unlock(boxLockKey);
}
} finally {
redisLock.unlock(userLockKey);
}
}
/**
* 查询我的抽奖记录(分页)
*/
@ApiOperation("我的抽奖记录")
@PostMapping("/myRecords")
public R<Map<String, Object>> myRecords(@RequestBody(required = false) Map<String, Object> params) {
Integer userId = getUserId().intValue();
Long lotteryId = null;
Integer pageNum = null;
Integer pageSize = null;
if (params != null) {
Object lotteryIdVal = params.get("lotteryId");
if (lotteryIdVal != null && StringUtils.isNotBlank(lotteryIdVal.toString())) {
lotteryId = Long.valueOf(lotteryIdVal.toString());
}
Object pageNumVal = params.get("pageNum");
if (pageNumVal != null && StringUtils.isNotBlank(pageNumVal.toString())) {
pageNum = Integer.valueOf(pageNumVal.toString());
}
Object pageSizeVal = params.get("pageSize");
if (pageSizeVal != null && StringUtils.isNotBlank(pageSizeVal.toString())) {
pageSize = Integer.valueOf(pageSizeVal.toString());
}
}
return lotteryService.getUserRecords(userId, lotteryId, pageNum, pageSize);
}
/**
* 查询全服中奖记录(分页,已排除白号/机器人/封禁/已删除用户)
*/
@ApiOperation("全服中奖记录")
@PostMapping("/globalRecords")
public R<Map<String, Object>> globalRecords(@RequestBody(required = false) Map<String, Object> params) {
Long lotteryId = null;
BigDecimal minPrice = null;
Integer pageNum = null;
Integer pageSize = null;
if (params != null) {
Object lotteryIdVal = params.get("lotteryId");
if (lotteryIdVal != null && StringUtils.isNotBlank(lotteryIdVal.toString())) {
lotteryId = Long.valueOf(lotteryIdVal.toString());
}
Object minPriceVal = params.get("minPrice");
if (minPriceVal != null && StringUtils.isNotBlank(minPriceVal.toString())) {
minPrice = new BigDecimal(minPriceVal.toString());
}
Object pageNumVal = params.get("pageNum");
if (pageNumVal != null && StringUtils.isNotBlank(pageNumVal.toString())) {
pageNum = Integer.valueOf(pageNumVal.toString());
}
Object pageSizeVal = params.get("pageSize");
if (pageSizeVal != null && StringUtils.isNotBlank(pageSizeVal.toString())) {
pageSize = Integer.valueOf(pageSizeVal.toString());
}
}
return lotteryService.getGlobalRecords(lotteryId, minPrice, pageNum, pageSize);
}
}
@@ -0,0 +1,82 @@
package com.ruoyi.admin.controller;
import com.ruoyi.common.enums.BusinessType;
import com.ruoyi.common.annotation.Log;
import com.ruoyi.admin.service.TtOrnamentService;
import com.ruoyi.admin.service.WebsitePropertyService;
import com.ruoyi.common.core.page.TableDataInfo;
import com.ruoyi.domain.dto.queryCondition.OrnamentCondition;
import com.ruoyi.domain.vo.WebsitePropertyDataVO;
import com.ruoyi.common.core.controller.BaseController;
import com.ruoyi.common.core.domain.AjaxResult;
import com.ruoyi.common.core.domain.R;
import com.ruoyi.common.core.page.PageDataInfo;
import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.domain.vo.upgrade.SimpleOrnamentVO;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.*;
import java.util.Arrays;
import java.util.List;
@Api(tags = "管理端 道具管理")
@RestController
@RequestMapping("/admin/websiteProperty")
@Slf4j
public class WebsitePropertyController extends BaseController {
private final WebsitePropertyService websitePropertyService;
private final TtOrnamentService ornamentsService;
public WebsitePropertyController(WebsitePropertyService websitePropertyService,
TtOrnamentService ornamentsService) {
this.websitePropertyService = websitePropertyService;
this.ornamentsService = ornamentsService;
}
// @ApiOperation("获取道具列表")
// @GetMapping("/list")
// public PageDataInfo<WebsitePropertyDataVO> list() {
// startPage();
// List<WebsitePropertyDataVO> list = websitePropertyService.list();
// return getPageData(Arrays.asList());
// }
@ApiOperation("获取道具列表")
@GetMapping("/list")
public TableDataInfo list(OrnamentCondition condition) {
startPage();
List<SimpleOrnamentVO> list = ornamentsService.byCondition(condition);
return getDataTable(list);
}
@GetMapping(value = "/{id}")
public R<WebsitePropertyDataVO> getInfo(@PathVariable("id") Integer id) {
WebsitePropertyDataVO websitePropertyDataVO = websitePropertyService.getById(id);
websitePropertyDataVO.setImageUrl("");
return R.ok(websitePropertyDataVO);
}
@Log(title = "网站道具", action = "新增", businessType = BusinessType.INSERT)
@PostMapping
public AjaxResult add(@RequestBody WebsitePropertyDataVO websitePropertyDataVO) {
String msg = websitePropertyService.save(websitePropertyDataVO);
return StringUtils.isEmpty(msg) ? AjaxResult.success("新增网站道具成功!") : AjaxResult.error(msg);
}
@Log(title = "网站道具", action = "修改", businessType = BusinessType.UPDATE)
@PutMapping
public AjaxResult edit(@RequestBody WebsitePropertyDataVO websitePropertyDataVO) {
String msg = websitePropertyService.updateWebsitePropertyById(websitePropertyDataVO);
return StringUtils.isEmpty(msg) ? AjaxResult.success() : AjaxResult.error(msg);
}
@Log(title = "网站道具", action = "删除", businessType = BusinessType.DELETE)
@DeleteMapping("/{ids}")
public AjaxResult remove(@PathVariable Integer[] ids) {
// return toAjax(ornamentsService.removeByIds(Arrays.asList(ids)));
return toAjax(websitePropertyService.deleteWebsitePropertyByIds(ids));
}
}
@@ -0,0 +1,43 @@
package com.ruoyi.admin.controller;
import com.ruoyi.common.enums.BusinessType;
import com.ruoyi.common.annotation.Log;
import com.ruoyi.admin.service.WebsiteSetupService;
import com.ruoyi.domain.other.OperationalStatistics;
import com.ruoyi.domain.other.ParameterSettingBody;
import com.ruoyi.common.core.controller.BaseController;
import com.ruoyi.common.core.domain.AjaxResult;
import com.ruoyi.common.core.domain.R;
import com.ruoyi.common.utils.StringUtils;
import org.springframework.web.bind.annotation.*;
import java.util.List;
@RestController
@RequestMapping("/admin/websiteSetup")
public class WebsiteSetupController extends BaseController {
private final WebsiteSetupService websiteSetupService;
public WebsiteSetupController(WebsiteSetupService websiteSetupService) {
this.websiteSetupService = websiteSetupService;
}
@GetMapping("getOperationalStatistics")
public R<List<OperationalStatistics>> getOperationalStatistics() {
List<OperationalStatistics> list = websiteSetupService.getOperationalStatistics();
return R.ok(list);
}
@PostMapping("/getParameterSetting")
public R<ParameterSettingBody> getParameterSetting() {
return R.ok(websiteSetupService.getParameterSetting());
}
@Log(title = "网站设置", action = "保存", businessType = BusinessType.UPDATE)
@PostMapping("/updateParameterSetting")
public AjaxResult updateParameterSetting(@RequestBody ParameterSettingBody parameterSettingBody) {
String msg = websiteSetupService.updateParameterSetting(parameterSettingBody);
return StringUtils.isEmpty(msg) ? AjaxResult.success() : AjaxResult.error(msg);
}
}
@@ -0,0 +1,14 @@
package com.ruoyi.admin.domain.body;
import lombok.Data;
import jakarta.validation.constraints.NotNull;
@Data
public class AddRobotBody {
@NotNull(message = "ROLL房ID不能为空")
private Integer rollId;
private Integer robotNum;
}
@@ -0,0 +1,14 @@
package com.ruoyi.admin.domain.body;
import jakarta.validation.constraints.NotNull;
import lombok.Data;
@Data
public class AddUserBody {
@NotNull(message = "rollId不能为空")
private Integer rollId;
@NotNull(message = "userId不能为空")
private Integer userId;
}
@@ -0,0 +1,24 @@
package com.ruoyi.admin.domain.body;
import lombok.Data;
import java.io.Serializable;
import java.math.BigDecimal;
import java.util.List;
//设置开箱临时爆率请求参数
@Data
public class BoxMockRequest {
private Integer uid;
//临时爆率列表
private List<MockItem> items;
@Data
public static class MockItem implements Serializable {
//最低价格(包含)
private BigDecimal lowPrice;
//最高价格(包含)
private BigDecimal highPrice;
}
}
@@ -0,0 +1,36 @@
package com.ruoyi.admin.enums;
import lombok.AllArgsConstructor;
import lombok.Getter;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;
@AllArgsConstructor
@Getter
public enum BoxPoolType {
ANCHOR_PLAYER("01", "主播用户奖池"),
NORMAL_PLAYER("02", "普通用户奖池"),
COMPENSATION("03", "补偿奖池"),
THIRD_EXPLOSIVE("04", "三级爆率奖池"),
ROBOT_PLAYER("05", "机器人用户奖池"),
ROBOT_PLAYER_LUCKY("06", "机器人用户奖池(欧皇)"),
ROBOT_PLAYER_UNLUCKY("07", "机器人用户奖池(非酋)"),
WHITE_PLAYER("08", "白号用户奖池");
private final String id;
private final String desc;
public static List<BoxPoolType> allTypes() {
return Arrays.stream(values()).collect(Collectors.toList());
}
public static BoxPoolType fromId(String id) {
for (BoxPoolType type : values()) {
if (type.getId().equals(id)) {
return type;
}
}
return null;
}
}
@@ -0,0 +1,23 @@
package com.ruoyi.admin.event;
import org.springframework.context.ApplicationEvent;
/**
* 维护开关开启事件。
* 当管理后台将 websiteMaintenance 或 wheelMaintenance 设为 "1" 时发布,
* 各游戏服务监听此事件并强制结算所有活跃游戏,避免已扣款用户在维护期间丢失奖励。
*/
public class MaintenanceEnabledEvent extends ApplicationEvent {
/** 触发来源:"website" 或 "wheel" */
private final String source_type;
public MaintenanceEnabledEvent(Object source, String sourceType) {
super(source);
this.source_type = sourceType;
}
public String getSourceType() {
return source_type;
}
}
@@ -0,0 +1,31 @@
package com.ruoyi.admin.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.ruoyi.domain.entity.PromoCdkeyRedeem;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;
import org.apache.ibatis.annotations.Select;
import java.util.List;
@Mapper
public interface AdminCdkeyRedeemMapper extends BaseMapper<PromoCdkeyRedeem> {
@Select("<script>" +
"SELECT r.*, c.creator_name AS creatorName, u.nick_name AS redeemerNickName" +
" FROM promo_cdkey_redeem r" +
" LEFT JOIN promo_cdkey c ON r.cdkey_id = c.id" +
" LEFT JOIN tt_user u ON r.redeemer_id = u.user_id" +
"<where>" +
"<if test='cdkeyCode != null and cdkeyCode != \"\"'> AND r.cdkey_code LIKE CONCAT('%', #{cdkeyCode}, '%')</if>" +
"<if test='redeemerId != null'> AND r.redeemer_id = #{redeemerId}</if>" +
"<if test='redeemerName != null and redeemerName != \"\"'> AND r.redeemer_name LIKE CONCAT('%', #{redeemerName}, '%')</if>" +
"<if test='creatorId != null'> AND c.creator_id = #{creatorId}</if>" +
"</where>" +
" ORDER BY r.redeem_time DESC" +
"</script>")
List<PromoCdkeyRedeem> selectRedeemListWithCreator(@Param("cdkeyCode") String cdkeyCode,
@Param("redeemerId") Long redeemerId,
@Param("redeemerName") String redeemerName,
@Param("creatorId") Long creatorId);
}
@@ -0,0 +1,9 @@
package com.ruoyi.admin.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.ruoyi.domain.entity.TtUserSubAccount;
import org.apache.ibatis.annotations.Mapper;
@Mapper
public interface ApiUserSubAccountMapper extends BaseMapper<TtUserSubAccount> {
}
@@ -0,0 +1,12 @@
package com.ruoyi.admin.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.ruoyi.domain.entity.BoxTransferRecord;
import org.apache.ibatis.annotations.Mapper;
/**
* 转赠记录 Mapper(admin 端使用,用于审核通过后写入转赠记录)
*/
@Mapper
public interface BoxTransferRecordAdminMapper extends BaseMapper<BoxTransferRecord> {
}
@@ -0,0 +1,9 @@
package com.ruoyi.admin.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.ruoyi.domain.other.ConfigData;
import org.apache.ibatis.annotations.Mapper;
@Mapper
public interface ConfigMapper extends BaseMapper<ConfigData> {
}
@@ -0,0 +1,20 @@
package com.ruoyi.admin.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.ruoyi.domain.entity.sys.PromoAdmin;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;
import org.apache.ibatis.annotations.Select;
@Mapper
public interface PromoAdminMapper extends BaseMapper<PromoAdmin> {
@Select("SELECT * FROM promo_admin WHERE username = #{username} AND status = '0' LIMIT 1")
PromoAdmin findByUsername(@Param("username") String username);
/**
* 按登录账号或手机号查询(推广后台超管用手机号登录)
*/
@Select("SELECT * FROM promo_admin WHERE status = '0' AND (username = #{account} OR phone_number = #{account}) LIMIT 1")
PromoAdmin findByAccount(@Param("account") String account);
}
@@ -0,0 +1,9 @@
package com.ruoyi.admin.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.ruoyi.domain.other.TtAdvertisement;
import org.apache.ibatis.annotations.Mapper;
@Mapper
public interface TtAdvertisementMapper extends BaseMapper<TtAdvertisement> {
}
@@ -0,0 +1,22 @@
package com.ruoyi.admin.mapper;
import com.ruoyi.domain.other.TtAnnouncement;
import org.apache.ibatis.annotations.Mapper;
import java.util.List;
@Mapper
public interface TtAnnouncementMapper {
List<TtAnnouncement> getAnnouncementList(TtAnnouncement query);
TtAnnouncement getAnnouncementByAnnouncementId(Integer announcementId);
int addAnnouncement(TtAnnouncement ttAnnouncement);
int countSystemAnnouncement();
int editAnnouncement(TtAnnouncement ttAnnouncement);
int removeAnnouncementByAnnouncementId(Integer announcementId);
}
@@ -0,0 +1,9 @@
package com.ruoyi.admin.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.ruoyi.domain.other.TtBanner;
import org.apache.ibatis.annotations.Mapper;
@Mapper
public interface TtBannerMapper extends BaseMapper<TtBanner> {
}
@@ -0,0 +1,9 @@
package com.ruoyi.admin.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.ruoyi.domain.entity.TtBlankCardKey;
import org.apache.ibatis.annotations.Mapper;
@Mapper
public interface TtBlankCardKeyMapper extends BaseMapper<TtBlankCardKey> {
}
@@ -0,0 +1,9 @@
package com.ruoyi.admin.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.ruoyi.domain.other.TtBonus;
import org.apache.ibatis.annotations.Mapper;
@Mapper
public interface TtBonusMapper extends BaseMapper<TtBonus> {
}
@@ -0,0 +1,9 @@
package com.ruoyi.admin.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.ruoyi.domain.other.TtBonusReceiveRecord;
import org.apache.ibatis.annotations.Mapper;
@Mapper
public interface TtBonusReceiveRecordMapper extends BaseMapper<TtBonusReceiveRecord> {
}
@@ -0,0 +1,18 @@
package com.ruoyi.admin.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.ruoyi.domain.other.TtBox;
import com.ruoyi.domain.other.TtBoxBody;
import com.ruoyi.domain.vo.TtBoxDataVO;
import com.ruoyi.domain.vo.box.BoxGlobalData;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;
import java.util.List;
@Mapper
public interface TtBoxMapper extends BaseMapper<TtBox> {
List<TtBoxDataVO> selectTtBoxList(TtBoxBody ttBoxBody);
BoxGlobalData globalData(@Param("boxId") Integer boxId);
}
@@ -0,0 +1,61 @@
package com.ruoyi.admin.mapper;
import java.util.List;
import com.ruoyi.admin.domain.TtBoxOpenChance;
/**
* 开箱机会Mapper接口
*
* @author ruoyi
* @date 2024-07-09
*/
public interface TtBoxOpenChanceMapper
{
/**
* 查询开箱机会
*
* @param ornamentId 开箱机会主键
* @return 开箱机会
*/
public TtBoxOpenChance selectTtBoxOpenChanceByOrnamentId(Integer ornamentId);
/**
* 查询开箱机会列表
*
* @param ttBoxOpenChance 开箱机会
* @return 开箱机会集合
*/
public List<TtBoxOpenChance> selectTtBoxOpenChanceList(TtBoxOpenChance ttBoxOpenChance);
/**
* 新增开箱机会
*
* @param ttBoxOpenChance 开箱机会
* @return 结果
*/
public int insertTtBoxOpenChance(TtBoxOpenChance ttBoxOpenChance);
/**
* 修改开箱机会
*
* @param ttBoxOpenChance 开箱机会
* @return 结果
*/
public int updateTtBoxOpenChance(TtBoxOpenChance ttBoxOpenChance);
/**
* 删除开箱机会
*
* @param ornamentId 开箱机会主键
* @return 结果
*/
public int deleteTtBoxOpenChanceByOrnamentId(Integer ornamentId);
/**
* 批量删除开箱机会
*
* @param ornamentIds 需要删除的数据主键集合
* @return 结果
*/
public int deleteTtBoxOpenChanceByOrnamentIds(Integer[] ornamentIds);
}
@@ -0,0 +1,53 @@
package com.ruoyi.admin.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.ruoyi.domain.other.TtBoxLevelA;
import com.ruoyi.domain.other.TtBoxOrnaments;
import com.ruoyi.domain.vo.TtBoxOrnamentsDataVO;
import com.ruoyi.domain.vo.upgrade.SimpleOrnamentVO;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;
import java.util.List;
@Mapper
public interface TtBoxOrnamentsMapper extends BaseMapper<TtBoxOrnaments> {
List<Integer> selectBoxIdList();
/** 简单查询(仅 boxId,百分比使用子查询,分页可能不准) */
List<TtBoxOrnamentsDataVO> selectTtBoxOrnamentsList(@Param("boxId") Integer boxId);
/** 精确查询(传入各类型总数,百分比计算准确) */
List<TtBoxOrnamentsDataVO> selectTtBoxOrnamentsListWithTotals(@Param("boxId") Integer boxId,
@Param("totalOdds") Integer totalOdds,
@Param("totalRealOdds") Integer totalRealOdds,
@Param("totalAnchorOdds") Integer totalAnchorOdds,
@Param("totalRobotOdds") Integer totalRobotOdds,
@Param("totalRobotOddsLucky") Integer totalRobotOddsLucky,
@Param("totalRobotOddsUnlucky") Integer totalRobotOddsUnlucky,
@Param("totalWhiteOdds") Integer totalWhiteOdds,
@Param("totalThirdExplosiveOdds") Integer totalThirdExplosiveOdds);
List<TtBoxOrnamentsDataVO> ornametBelongbox(Integer integer);
List<SimpleOrnamentVO> simpleBoxDetail(Integer boxId);
List<Long> allOrnId(@Param("boxId") Integer boxId);
/**
* 开箱后扣减对应奖池类型的库存数量
* @param boxId 宝箱ID
* @param ornamentId 饰品ID
* @param poolType 奖池类型:01主播 02普通 03补偿 04三级爆率 05机器人
*/
int decrementOdds(@Param("boxId") Integer boxId, @Param("ornamentId") Long ornamentId, @Param("poolType") String poolType);
/** 按饰品品级汇总箱子概率 */
List<TtBoxLevelA> getProbabilityDistribution(@Param("boxId") Integer boxId);
/**
* 批量查询多个箱子的饰品数据(精简版,无百分比计算)
*/
List<TtBoxOrnamentsDataVO> selectTtBoxOrnamentsListByBoxIds(@Param("boxIds") List<Integer> boxIds);
}
@@ -0,0 +1,133 @@
package com.ruoyi.admin.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.ruoyi.domain.dto.boxRecords.TtBoxRecordsNum;
import com.ruoyi.domain.dto.boxRecords.TtBoxRecordsPoolStat;
import com.ruoyi.domain.dto.packSack.DecomposeLogCondition;
import com.ruoyi.domain.dto.roll.GetRollOpenPrizeParam;
import com.ruoyi.domain.entity.TtBoxRecords;
import com.ruoyi.domain.other.TtBoxRecordsBody;
import com.ruoyi.domain.other.TtBoxUserIdPrice;
import com.ruoyi.domain.vo.TtBoxRecordsDataVO;
import com.ruoyi.domain.vo.TtUserPackSackDataVO;
import com.ruoyi.domain.vo.boxRecords.TtBoxRecordsVO;
import org.apache.ibatis.annotations.Insert;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;
import java.math.BigDecimal;
import java.sql.Timestamp;
import java.util.List;
import java.util.Map;
@Mapper
public interface TtBoxRecordsMapper extends BaseMapper<TtBoxRecords> {
List<TtBoxRecordsDataVO> selectBoxRecordsList(TtBoxRecordsBody ttBoxRecordsBody);
/**
* 查询福利箱子开箱记录(source=10)
*/
List<TtBoxRecordsDataVO> selectWelfareBoxRecordsList(TtBoxRecordsBody ttBoxRecordsBody);
/**
* 某宝箱某天的开箱记录按开箱人类型(奖池)汇总:开箱次数 + 爆出饰品总价值
*
* @param sources 计入的流水来源(经典宝箱=常规开箱,对战宝箱=急速对战)
*/
TtBoxRecordsPoolStat selectBoxRecordsPoolStat(@Param("boxId") Integer boxId,
@Param("formattedDate") String formattedDate,
@Param("sources") List<Integer> sources);
List<TtBoxRecordsNum> selectBoxRecordsByOrnamentIds(@Param("boxId") Integer boxId, @Param("ornamentIds") List<Long> ornamentIds, @Param("beginTime") String beginTime);
List<TtBoxRecordsDataVO> decomposeLog(DecomposeLogCondition param);
List<Integer> myOwnFights(@Param("playerId") Integer playerId);
List<TtBoxRecordsVO> byCondition(@Param("userId") Integer userId,
@Param("limit") Integer limit,
@Param("size") Integer size,
@Param("orderByFie") Integer orderByFie,
@Param("boxRecordId") Long boxRecordId,
@Param("boxId") Integer boxId,
@Param("userType") String userType,
@Param("source") List<Integer> source,
@Param("status") List<Integer> status,
@Param("ornamentPriceMin") BigDecimal ornamentPriceMin,
@Param("ornamentPriceMax") BigDecimal ornamentPriceMax,
@Param("ornamentLevelIds") List<Integer> ornamentLevelIds
);
List<TtBoxRecordsVO> tenTopQuery(
@Param("limit") Integer limit,
@Param("size") Integer size,
@Param("source") List<Integer> source,
@Param("status") List<Integer> status
);
List<TtBoxRecordsVO> topHundredQuery(
@Param("size") Integer size,
@Param("status") List<Integer> status,
@Param("source") List<Integer> source,
@Param("todayOnly") boolean todayOnly
);
List<TtUserPackSackDataVO> propRankOfDay(@Param("beginT") String beginT,
@Param("endT") String endT,
@Param("sources") Integer[] sources,
@Param("number") Integer number);
List<TtBoxRecordsVO> rollOpenPrize(GetRollOpenPrizeParam param);
Integer checkDeliveryAble(@Param("packSackIds") List<Long> packSackIds);
Integer checkAllDeliveryAble(@Param("userId") Integer userId);
/**
* 批量插入背包记录(疯狂转盘结算发奖用,避免逐条 insert)。
* 调用方需自行分批,单批建议 ≤500 条。
*/
@Insert("<script>" +
"INSERT INTO tt_box_records " +
"(user_id, holder_user_id, box_id, box_name, box_price, period_no, ornament_id, ornaments_price, ornament_name, image_url, ornaments_level_id, ornament_level_img, source, status, is_show, create_time) VALUES " +
"<foreach collection='list' item='r' separator=','>" +
"(#{r.userId}, #{r.holderUserId}, #{r.boxId}, #{r.boxName}, #{r.boxPrice}, #{r.periodNo}, #{r.ornamentId}, #{r.ornamentsPrice}, #{r.ornamentName}, #{r.imageUrl}, #{r.ornamentsLevelId}, #{r.ornamentLevelImg}, #{r.source}, #{r.status}, #{r.isShow}, #{r.createTime})" +
"</foreach>" +
"</script>")
int insertBatch(@Param("list") List<TtBoxRecords> records);
/**
* 汰换后的状态更新
*/
int updateStatusByIds(@Param("list") List<Long> list, @Param("status") String status);
List<TtBoxUserIdPrice> boxUserIdPrice(@Param("userIds") List<Integer> userIds, @Param("startDate") String startDate, @Param("endDate") String endDate);
/**
* 统计今日游戏饰品返奖总额(玩家选择保留饰品的 ornaments_price)
* 游戏 source:1=经典开箱, 2=对战, 3=roll房, 4=幸运升级, 11=极速糖果, 12=荒野争锋, 99=疯狂转盘
*/
BigDecimal todayOrnamentRewardTotal(@Param("startOfDay") java.sql.Timestamp startOfDay,
@Param("endOfDay") java.sql.Timestamp endOfDay);
/**
* 统计历史游戏饰品返奖总额:与今日总返奖(todayOrnamentRewardTotal)同口径,仅不限时间范围
* 游戏 source:1=经典开箱, 2=对战, 3=roll房, 4=幸运升级, 11=极速糖果, 12=荒野争锋, 99=疯狂转盘;不看 status(含已分解)
*/
BigDecimal historyOrnamentRewardTotal();
/**
* 按source分组统计今日饰品返奖(status=0 保留在背包中的饰品价值)
* 返回 List<Map>,每个Map包含 source(Integer) 和 totalPrice(BigDecimal)
*/
List<Map<String, Object>> todayOrnamentRewardBySource(@Param("startOfDay") Timestamp startOfDay,
@Param("endOfDay") Timestamp endOfDay);
/**
* 跨天分解污染值:非今日产出但今日被分解的饰品总价值,按游戏source分组。
* 用于从Part A奖励中扣除跨天分解产生的虚高流水。
*/
List<Map<String, Object>> crossDayDecomposeBySource(@Param("startOfDay") Timestamp startOfDay,
@Param("endOfDay") Timestamp endOfDay);
}
@@ -0,0 +1,10 @@
package com.ruoyi.admin.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.ruoyi.domain.entity.box.TtBoxThirdExplosiveUser;
import org.apache.ibatis.annotations.Mapper;
@Mapper
public interface TtBoxThirdExplosiveUserMapper extends BaseMapper<TtBoxThirdExplosiveUser> {
}
@@ -0,0 +1,9 @@
package com.ruoyi.admin.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.ruoyi.domain.other.TtBoxType;
import org.apache.ibatis.annotations.Mapper;
@Mapper
public interface TtBoxTypeMapper extends BaseMapper<TtBoxType> {
}
@@ -0,0 +1,23 @@
package com.ruoyi.admin.mapper;
import com.ruoyi.domain.other.TtCompRecord;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;
@Mapper
public interface TtCompRecordMapper {
public TtCompRecord selectTtCompRecord(
@Param("userId") Integer userId,
@Param("boxId") Integer boxId
);
public int insertTtCompRecord(TtCompRecord ttCompRecord);
public int updateTtCompRecord(TtCompRecord ttCompRecord);
public int deleteTtCompRecord(
@Param("userId") Integer userId,
@Param("boxId") Integer boxId
);
}
@@ -0,0 +1,9 @@
package com.ruoyi.admin.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.ruoyi.domain.other.TtContent;
import org.apache.ibatis.annotations.Mapper;
@Mapper
public interface TtContentMapper extends BaseMapper<TtContent> {
}
@@ -0,0 +1,9 @@
package com.ruoyi.admin.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.ruoyi.domain.other.TtContentType;
import org.apache.ibatis.annotations.Mapper;
@Mapper
public interface TtContentTypeMapper extends BaseMapper<TtContentType> {
}
@@ -0,0 +1,34 @@
package com.ruoyi.admin.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.ruoyi.domain.dto.userRecord.DeliveryRecordsConfition;
import com.ruoyi.domain.entity.delivery.TtDeliveryRecord;
import com.ruoyi.domain.other.TtDeliveryApplyBody;
import com.ruoyi.domain.other.TtUidTotalRechargeRecord;
import com.ruoyi.domain.vo.DeliveryApplyVO;
import com.ruoyi.domain.other.TtDeliveryRecordBody;
import com.ruoyi.domain.vo.TtDeliveryRecordDataVO;
import com.ruoyi.domain.vo.delivery.DeliveryRecordVO;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;
import java.util.List;
@Mapper
public interface TtDeliveryRecordMapper extends BaseMapper<TtDeliveryRecord> {
List<DeliveryApplyVO> getDeliveryApplyList(TtDeliveryApplyBody deliveryApplyBody);
List<TtDeliveryRecordDataVO> getDeliveryRecordList(TtDeliveryRecordBody deliveryRecordBody);
List<TtDeliveryRecordDataVO> getDeliveryRecordByUserList(TtDeliveryRecordBody deliveryRecordBody);
List<DeliveryRecordVO> byCondition(@Param("statusList") List<Integer> statusList,
@Param("uidList") List<Integer> uidList,
@Param("limit") Integer limit,
@Param("size") Integer size);
/**
* 批量查询用户CS340提货成功总额(status=10 且 thirdparty_delivery=1)
*/
List<TtUidTotalRechargeRecord> getTotalDeliveryByUserIds(@Param("userIds") List<Integer> userIds);
}
@@ -0,0 +1,17 @@
package com.ruoyi.admin.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.ruoyi.domain.dto.exponent.ExponentOpenBoxVo;
import com.ruoyi.domain.entity.exponent.TtExponent;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;
import java.util.List;
@Mapper
public interface TtExponentMapper extends BaseMapper<TtExponent> {
/**
* 获取开箱记录
*/
List<ExponentOpenBoxVo> exponentOpenBox(@Param("userId") Integer userId);
}
@@ -0,0 +1,10 @@
package com.ruoyi.admin.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.ruoyi.domain.entity.exponent.TtExponentUserBox;
import org.apache.ibatis.annotations.Mapper;
@Mapper
public interface TtExponentUserBoxMapper extends BaseMapper<TtExponentUserBox> {
}
@@ -0,0 +1,10 @@
package com.ruoyi.admin.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.ruoyi.domain.entity.exponent.TtExponentUser;
import org.apache.ibatis.annotations.Mapper;
@Mapper
public interface TtExponentUserMapper extends BaseMapper<TtExponentUser> {
}
@@ -0,0 +1,9 @@
package com.ruoyi.admin.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.ruoyi.domain.entity.fight.TtFight;
import org.apache.ibatis.annotations.Mapper;
@Mapper
public interface TtFightMapper extends BaseMapper<TtFight> {
}
@@ -0,0 +1,63 @@
package com.ruoyi.admin.mapper;
import java.util.List;
import com.ruoyi.domain.other.TtFightRankingReward;
/**
* 对战奖励金额Mapper接口
*
* @author ruoyi
* @date 2024-07-04
*/
public interface TtFightRankingRewardMapper
{
/**
* 查询对战奖励金额
*
* @param id 对战奖励金额主键
* @return 对战奖励金额
*/
public TtFightRankingReward selectTtFightRankingRewardById(Integer id);
/**
* 查询对战奖励金额列表
*
* @param ttFightRankingReward 对战奖励金额
* @return 对战奖励金额集合
*/
public List<TtFightRankingReward> selectTtFightRankingRewardList(TtFightRankingReward ttFightRankingReward);
/**
* 新增对战奖励金额
*
* @param ttFightRankingReward 对战奖励金额
* @return 结果
*/
public int insertTtFightRankingReward(TtFightRankingReward ttFightRankingReward);
/**
* 修改对战奖励金额
*
* @param ttFightRankingReward 对战奖励金额
* @return 结果
*/
public int updateTtFightRankingReward(TtFightRankingReward ttFightRankingReward);
/**
* 删除对战奖励金额
*
* @param id 对战奖励金额主键
* @return 结果
*/
public int deleteTtFightRankingRewardById(Integer id);
/**
* 批量删除对战奖励金额
*
* @param ids 需要删除的数据主键集合
* @return 结果
*/
public int deleteTtFightRankingRewardByIds(Integer[] ids);
public void truncateRankingReward();
}

Some files were not shown because too many files have changed in this diff Show More