This commit is contained in:
2025-09-28 11:58:47 +08:00
parent 56bf486adf
commit b3f84a4402
23 changed files with 885 additions and 6 deletions

View File

@@ -402,6 +402,11 @@ public class AdminUserService extends BaseService {
return adminUserMapper.selectByExample(example); return adminUserMapper.selectByExample(example);
} }
/**
* 特殊方法,不能当通用后台用
* @param adminId
* @return
*/
public AdminUserVo getByAdminId(Integer adminId) { public AdminUserVo getByAdminId(Integer adminId) {
AdminUser adminUserById = this.getAdminUserById(adminId); AdminUser adminUserById = this.getAdminUserById(adminId);
List<AdminRefUserRoleKey> roleByAdminId = adminRoleService.getRoleByAdminId(adminId); List<AdminRefUserRoleKey> roleByAdminId = adminRoleService.getRoleByAdminId(adminId);

View File

@@ -0,0 +1,98 @@
package com.accompany.admin.controller.game;
import com.accompany.admin.controller.BaseController;
import com.accompany.admin.model.AdminUser;
import com.accompany.admin.service.system.AdminPartitionService;
import com.accompany.admin.service.system.AdminUserService;
import com.accompany.business.service.game.ChargeUserXDetailService;
import com.accompany.business.vo.game.ChargeUserXDetailVo;
import com.accompany.common.result.BusiResult;
import com.accompany.common.utils.StringUtils;
import com.accompany.core.exception.AdminServiceException;
import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.support.ExcelTypeEnum;
import com.baomidou.mybatisplus.core.metadata.IPage;
import io.swagger.annotations.ApiImplicitParam;
import io.swagger.annotations.ApiOperation;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.List;
/**
* <p>
* 用户充值等级 前端控制器
* </p>
*
* @author wxf
* @since 2025-06-30
*/
@RestController
@RequestMapping("/chargeUserXDetail")
public class ChargeUserXDetailAdminController extends BaseController {
@Autowired
private AdminUserService adminUserService;
@Autowired
private AdminPartitionService adminPartitionService;
@Autowired
private ChargeUserXDetailService chargeUserXDetailService;
@GetMapping(value = "/list")
public BusiResult<IPage<ChargeUserXDetailVo>> listPage(Long erbanNo, String ip,
String device, Integer identity, Integer pageNo, Integer pageSize) {
List<Integer> allPartitionId = adminPartitionService.getAllPartitionId(getAdminId());
IPage<ChargeUserXDetailVo> ipage = chargeUserXDetailService.listPage(allPartitionId, erbanNo, ip, device, identity, pageNo, pageSize);
return BusiResult.success(ipage);
}
@ApiImplicitParam(paramType = "query", name = "erbanNos", value = "逗号隔开ID", required = false)
@ApiOperation(value = "新增", httpMethod = "POST")
@PostMapping(value = "/save")
public BusiResult<Void> save(String erbanNos, String addReason) {
if (erbanNos == null) {
throw new AdminServiceException(5001, "请填写用户id");
}
AdminUser adminUserVo = adminUserService.getAdminUserById(getAdminId());
String[] split = erbanNos.split(",");
List<Long> erbanNoList = new ArrayList<>();
for (String erbanNo : split) {
erbanNoList.add(Long.parseLong(erbanNo.trim()));
}
chargeUserXDetailService.saveDetail(erbanNoList, addReason, adminUserVo.getId(), adminUserVo.getUsername());
return BusiResult.success();
}
@ApiOperation(value = "删除", httpMethod = "POST")
@PostMapping(value = "/delete")
public BusiResult<Void> delete(Long uid, String removeReason) {
AdminUser adminUser = adminUserService.getAdminUserById(getAdminId());
if (StringUtils.isEmpty(removeReason)) {
throw new AdminServiceException(5001, "请填写删除原因");
}
chargeUserXDetailService.delete(uid, removeReason, adminUser.getId(), adminUser.getUsername());
return BusiResult.success();
}
@ApiOperation(value = "导出", httpMethod = "POST")
@PostMapping("/export")
public void export(Long erbanNo, String ip, String device, Integer identity, HttpServletResponse response) throws IOException {
List<Integer> allPartitionId = adminPartitionService.getAllPartitionId(getAdminId());
IPage<ChargeUserXDetailVo> ipage = chargeUserXDetailService.listPage(allPartitionId, erbanNo, ip, device, identity, -1, -1);
response.setContentType("application/vnd.ms-excel");
response.setCharacterEncoding("utf-8");
// 这里URLEncoder.encode可以防止中文乱码
String excelName = URLEncoder.encode("嫌疑人x用户", StandardCharsets.UTF_8);
response.setHeader("Content-disposition", "attachment;filename=" + excelName + ExcelTypeEnum.XLSX.getValue());
EasyExcel.write(response.getOutputStream(), ChargeUserXDetailVo.class).sheet("嫌疑人x用户").doWrite(ipage.getRecords());
}
}

View File

@@ -1396,6 +1396,8 @@ public class Constant {
public static final String EXTRA_DIAMOND_RATE_CONFIG = "extra_diamond_rate_config"; public static final String EXTRA_DIAMOND_RATE_CONFIG = "extra_diamond_rate_config";
public static final String CP_MIC_SVGA_URL = "cp_mic_svga_url"; public static final String CP_MIC_SVGA_URL = "cp_mic_svga_url";
public static String charge_user_x_gold = "charge_user_x_gold";
} }
public static class WithDrawStatus { public static class WithDrawStatus {

View File

@@ -1470,6 +1470,7 @@ public enum RedisKey {
guild_usd_withdraw_num, //公会薪资提现次数 guild_usd_withdraw_num, //公会薪资提现次数
guild_usd_to_recharge_num,//公会薪资转代理次数 guild_usd_to_recharge_num,//公会薪资转代理次数
charge_user_x_detail,//嫌疑用户
; ;
public String getKey() { public String getKey() {

View File

@@ -4,6 +4,7 @@ import com.accompany.common.redis.RedisKey;
import com.accompany.payment.mapper.ChargeRecordMapperMgr; import com.accompany.payment.mapper.ChargeRecordMapperMgr;
import com.accompany.payment.mapper.UserRechargeLevelMapper; import com.accompany.payment.mapper.UserRechargeLevelMapper;
import com.accompany.payment.model.UserRechargeLevel; import com.accompany.payment.model.UserRechargeLevel;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.redisson.api.RMapCache; import org.redisson.api.RMapCache;
import org.redisson.api.RedissonClient; import org.redisson.api.RedissonClient;
@@ -13,7 +14,9 @@ import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils; import org.springframework.util.StringUtils;
import java.math.BigDecimal; import java.math.BigDecimal;
import java.util.*; import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors; import java.util.stream.Collectors;
@@ -92,4 +95,10 @@ public class UserRechargeLevelService extends ServiceImpl<UserRechargeLevelMappe
public void afterPropertiesSet() throws Exception { public void afterPropertiesSet() throws Exception {
cacheMap = redissonClient.getMapCache(RedisKey.user_recharge_level.getKey()); cacheMap = redissonClient.getMapCache(RedisKey.user_recharge_level.getKey());
} }
public List<UserRechargeLevel> listByZeroTotalGold() {
LambdaQueryWrapper<UserRechargeLevel> queryWrapper = new LambdaQueryWrapper<>();
queryWrapper.eq(UserRechargeLevel::getTotalGold, 0);
return baseMapper.selectList(queryWrapper);
}
} }

View File

@@ -0,0 +1,60 @@
package com.accompany.business.model.game;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import lombok.Data;
import java.io.Serializable;
import java.math.BigDecimal;
import java.util.Date;
/**
* X嫌疑人用户表实体类
*
* @author
* @since 2025-09-26
*/
@Data
public class ChargeUserXDetail implements Serializable {
private static final long serialVersionUID = 1L;
@TableId(value = "id", type = IdType.AUTO)
private Long id;
private Long uid;
/**
* 用户身份 0 待评测 1嫌疑用户 2 充值用户 3后台删除用户
*/
private Integer identity;
/**
* h5小游戏支出
*/
private BigDecimal payGold;
/**
* h5小游戏获得
*/
private BigDecimal winGold;
private String ip;
private String deviceId;
/**
* 是否因为关联被记录0-否1-是
*/
private Integer refStatus;
/**
* 是否后台添加0-否1-是
*/
private Integer adminAdd;
/**
* 标记原因
*/
private String remark;
/**
* 移除原因
*/
private String removeReason;
private Integer adminId;
private Date createTime;
private Date updateTime;
}

View File

@@ -0,0 +1,44 @@
package com.accompany.business.model.game;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import lombok.Data;
import java.io.Serializable;
import java.util.Date;
/**
* 嫌疑人ip,设备记录表实体类
*
* @author
* @since 2025-09-26
*/
@Data
public class ChargeUserXRecord implements Serializable {
private static final long serialVersionUID = 1L;
@TableId(value = "id", type = IdType.AUTO)
private Long id;
private Long uid;
/**
* ip
*/
private String ip;
/**
* 设备
*/
private String deviceId;
/**
* 类型 1ip 2设备
*/
private Integer type;
/**
* 状态 1正常 2删除
*/
private Integer status;
private Date createTime;
private Date updateTime;
}

View File

@@ -0,0 +1,82 @@
package com.accompany.business.vo.game;
import com.alibaba.excel.annotation.ExcelProperty;
import io.swagger.annotations.ApiModelProperty;
import lombok.Getter;
import lombok.Setter;
import java.math.BigDecimal;
/**
* <p>
* 用户充值等级
* </p>
*
* @author wxf
* @since 2025-06-30
*/
@Getter
@Setter
public class ChargeUserXDetailVo {
@ExcelProperty("用户ID")
@ApiModelProperty("用户ID")
private Long erbanNo;
@ExcelProperty("用户等级")
@ApiModelProperty("用户等级")
private String chargeUserLevel;
@ExcelProperty("用户UID")
@ApiModelProperty("用户UID")
private Long uid;
@ExcelProperty("用户昵称")
@ApiModelProperty("用户昵称")
private String nick;
@ExcelProperty("用户国家")
@ApiModelProperty("用户国家")
private String regionName;
@ExcelProperty("投入")
@ApiModelProperty("投入")
private BigDecimal payGold;
/**
* h5小游戏获得
*/
@ExcelProperty("支出")
@ApiModelProperty("支出")
private BigDecimal winGold;
@ExcelProperty("差额")
@ApiModelProperty("差额")
private BigDecimal diff;
@ExcelProperty("ip")
@ApiModelProperty("ip")
private String ip;
@ExcelProperty("设备")
@ApiModelProperty("设备")
private String deviceId;
/**
* 用户身份 0 待评测 1嫌疑用户 2 充值用户 3后台删除用户
*/
@ExcelProperty("当前是否为X身份 1嫌疑用户 2 充值用户 3后台删除用户")
@ApiModelProperty("当前是否为X身份 1嫌疑用户 2 充值用户 3后台删除用户")
private Integer identity;
/**
* 标记原因
*/
@ExcelProperty("成为X身份标记原因")
@ApiModelProperty("成为X身份标记原因")
private String remark;
/**
* 移除原因
*/
@ExcelProperty("取消X身份标记原因")
@ApiModelProperty("取消X身份标记原因")
private String removeReason;
}

View File

@@ -10,4 +10,6 @@ public class GameUserInfoResponseVO {
private Long coin;//玩家当前游戏币 必选 private Long coin;//玩家当前游戏币 必选
private Integer vipLevel; //VIP等级 必选 private Integer vipLevel; //VIP等级 必选
private Double water; private Double water;
//传1代表是特殊用户不传或者其他是正常用户
private Integer prizeLabel;
} }

View File

@@ -0,0 +1,35 @@
package com.accompany.business.mybatismapper.game;
import com.accompany.business.model.game.ChargeUserXDetail;
import com.accompany.business.vo.game.ChargeUserXDetailVo;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;
import java.util.List;
/**
* <p>
* 用户充值等级 Mapper 接口
* </p>
*
* @author wxf
* @since 2025-06-30
*/
@Mapper
public interface ChargeUserXDetailMapper extends BaseMapper<ChargeUserXDetail> {
void updateCharge(@Param("uid") Long uid);
ChargeUserXDetail getRecord(@Param("uid") Long uid);
IPage<ChargeUserXDetailVo> listPage(@Param("page") Page<ChargeUserXDetailVo> page,
@Param("partitionIds") List<Integer> partitionIds,
@Param("erbanNo") Long erbanNo,
@Param("ip") String ip,
@Param("device") String device,
@Param("identity") Integer identity);
}

View File

@@ -0,0 +1,34 @@
package com.accompany.business.mybatismapper.game;
import com.accompany.business.model.game.ChargeUserXRecord;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;
import java.util.List;
/**
* <p>
* 用户充值等级 Mapper 接口
* </p>
*
* @author wxf
* @since 2025-06-30
*/
@Mapper
public interface ChargeUserXRecordMapper extends BaseMapper<ChargeUserXRecord> {
List<String> getLastThirtyXIp(@Param("uid") Long uid);
List<String> getLastThirtyXDevice(@Param("uid") Long uid);
ChargeUserXRecord getRecordByIp(@Param("loginIp") String loginIp);
ChargeUserXRecord deviceId(@Param("deviceId") String deviceId);
void deleteRecord(@Param("uid") Long uid);
IPage<ChargeUserXRecord> listPage(@Param("page") Page<ChargeUserXRecord> page, @Param("uid") Long uid, @Param("type") Integer type);
}

View File

@@ -19,4 +19,7 @@ public interface GameDayStatDataMapper extends BaseMapper<GameDayStatData> {
IPage<GameDataTotalVo> selectGroupDateList(IPage<GameDayStatData> iPage, @Param("channel") String channel, @Param("gameId") String gameId, IPage<GameDataTotalVo> selectGroupDateList(IPage<GameDayStatData> iPage, @Param("channel") String channel, @Param("gameId") String gameId,
@Param("beginTime") Date beginTime, @Param("endTime") Date endTime, @Param("partitionId") Integer partitionId); @Param("beginTime") Date beginTime, @Param("endTime") Date endTime, @Param("partitionId") Integer partitionId);
List<GameDayStatData> statByChannelUid4XRecord(@Param("channel") String channel, @Param("miniWin") Long miniWin);
} }

View File

@@ -0,0 +1,188 @@
package com.accompany.business.service.game;
import com.accompany.business.model.game.ChargeUserXDetail;
import com.accompany.business.model.game.ChargeUserXRecord;
import com.accompany.business.mybatismapper.game.ChargeUserXDetailMapper;
import com.accompany.business.service.AccountLoginRecordService;
import com.accompany.business.service.user.UsersService;
import com.accompany.business.vo.game.ChargeUserXDetailVo;
import com.accompany.common.redis.RedisKey;
import com.accompany.core.exception.AdminServiceException;
import com.accompany.core.model.AccountLoginRecord;
import com.accompany.core.model.Users;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.redisson.api.RMap;
import org.redisson.api.RedissonClient;
import org.redisson.codec.TypedJsonJacksonCodec;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import java.text.MessageFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
/**
* <p>
* 用户充值等级 服务实现类
* </p>
*
* @author wxf
* @since 2025-06-30
*/
@Service
public class ChargeUserXDetailService extends ServiceImpl<ChargeUserXDetailMapper, ChargeUserXDetail> {
@Autowired
private AccountLoginRecordService accountLoginRecordService;
@Autowired
private ChargeUserXRecordService chargeUserXRecordService;
@Autowired
private RedissonClient redissonClient;
@Autowired
private UsersService usersService;
public IPage<ChargeUserXDetailVo> listPage(List<Integer> partitionIds, Long erbanNo, String ip, String device, Integer identity, Integer pageNo, Integer pageSize) {
Page<ChargeUserXDetailVo> page = new Page<>(pageNo, pageSize);
if (CollectionUtils.isEmpty(partitionIds)) {
return page;
}
return this.baseMapper.listPage(page, partitionIds, erbanNo, ip, device, identity);
}
public void saveDetail(List<Long> erbanNos, String addReason, Integer adminId,String username) {
List<Users> usersList = new ArrayList<>();
for (Long erbanNo : erbanNos) {
Users userByErbanNo = usersService.getUserByErbanNo(erbanNo);
if (userByErbanNo == null) {
throw new AdminServiceException(5001, "不存在该用户");
}
usersList.add(userByErbanNo);
}
String remark = "后台添加:[" + username + "]" + addReason;
for (Users users : usersList) {
Long uid = users.getUid();
ChargeUserXDetail record = this.baseMapper.getRecord(uid);
if (record != null) {
if (record.getIdentity() != 1) {
record.setIdentity(1);
record.setRemark(remark);
record.setRemoveReason("");
record.setUpdateTime(new Date());
record.setAdminId(adminId);
record.setAdminAdd(1);
this.updateById(record);
this.delCache(uid);
chargeUserXRecordService.saveRecord(uid);
}
} else {
ChargeUserXDetail chargeUserXDetail = new ChargeUserXDetail();
AccountLoginRecord lastLogin = accountLoginRecordService.getLastLoginRecord(uid);
if (lastLogin != null) {
chargeUserXDetail.setIp(lastLogin.getLoginIp());
chargeUserXDetail.setDeviceId(lastLogin.getDeviceId());
}
chargeUserXDetail.setAdminId(adminId);
chargeUserXDetail.setAdminAdd(1);
chargeUserXDetail.setUid(uid);
chargeUserXDetail.setIdentity(1);
chargeUserXDetail.setRemark(remark);
this.save(chargeUserXDetail);
this.delCache(uid);
chargeUserXRecordService.saveRecord(uid);
}
}
}
public void delete(Long uid, String removeReason, Integer adminId, String username) {
ChargeUserXDetail record = this.baseMapper.getRecord(uid);
record.setIdentity(3);
record.setUpdateTime(new Date());
record.setRemoveReason("后台移除:" + username + ":" + removeReason);
record.setAdminId(adminId);
this.updateById(record);
chargeUserXRecordService.deleteRecord(uid);
this.delCache(uid);
}
public void updateCharge(Long uid) {
ChargeUserXDetail record = this.baseMapper.getRecord(uid);
if (record != null && record.getIdentity() == 1) {
record.setIdentity(2);
record.setRemoveReason("每日搜索:充值");
record.setUpdateTime(new Date());
this.updateById(record);
this.delCache(uid);
//删除记录
chargeUserXRecordService.deleteRecord(uid);
}
}
private void delCache(Long uid) {
detailCache().remove(uid);
}
public ChargeUserXDetail getRecord(Long uid) {
ChargeUserXDetail value = detailCache().get(uid);
if (value != null) {
return value;
}
ChargeUserXDetail chargeUserXDetail = this.baseMapper.getRecord(uid);
if (chargeUserXDetail == null) {
return null;
}
detailCache().put(uid, chargeUserXDetail);
return chargeUserXDetail;
}
public void check(Long uid) {
ChargeUserXDetail chargeUserXDetail = new ChargeUserXDetail();
AccountLoginRecord lastLogin = accountLoginRecordService.getLastLoginRecord(uid);
if (lastLogin != null) {
chargeUserXDetail.setUid(uid);
chargeUserXDetail.setIp(lastLogin.getLoginIp());
chargeUserXDetail.setDeviceId(lastLogin.getDeviceId());
chargeUserXDetail.setIdentity(1);
//进行iP检测
ChargeUserXRecord recordByIp = chargeUserXRecordService.getRecordByIp(lastLogin.getLoginIp());
String remark = "注册关联,关联记录id:{0}";
ChargeUserXRecord recordByDevice = chargeUserXRecordService.getRecordByDevice(lastLogin.getDeviceId());
if (recordByDevice != null) {
chargeUserXDetail.setRemark(MessageFormat.format(remark, recordByDevice.getId()));
this.save(chargeUserXDetail);
this.delCache(uid);
chargeUserXRecordService.saveRecord(uid);
return;
}
if (recordByIp != null) {
chargeUserXDetail.setRemark(MessageFormat.format(remark, recordByIp.getId()));
this.save(chargeUserXDetail);
this.delCache(uid);
chargeUserXRecordService.saveRecord(uid);
}
}
}
public List<ChargeUserXDetail> listExistAutoRecord() {
LambdaQueryWrapper<ChargeUserXDetail> queryWrapper = new LambdaQueryWrapper<>();
queryWrapper.eq(ChargeUserXDetail::getIdentity, 1)
.gt(ChargeUserXDetail::getRefStatus, 0);
return this.baseMapper.selectList(queryWrapper);
}
public RMap<Long, ChargeUserXDetail> detailCache() {
String key = RedisKey.charge_user_x_detail.getKey();
return redissonClient.getMap(key, new TypedJsonJacksonCodec(Long.class, ChargeUserXDetail.class));
}
}

View File

@@ -0,0 +1,71 @@
package com.accompany.business.service.game;
import com.accompany.business.model.game.ChargeUserXRecord;
import com.accompany.business.mybatismapper.game.ChargeUserXRecordMapper;
import com.accompany.business.param.BasePageParams;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import java.util.ArrayList;
import java.util.List;
/**
* <p>
* 用户充值等级 服务实现类
* </p>
*
* @author wxf
* @since 2025-06-30
*/
@Service
public class ChargeUserXRecordService extends ServiceImpl<ChargeUserXRecordMapper, ChargeUserXRecord> {
public IPage<ChargeUserXRecord> listPage(BasePageParams basePageParams, Long uid, Integer type) {
Page<ChargeUserXRecord> page = new Page<>(basePageParams.getPageNo(),basePageParams.getPageSize());
return this.baseMapper.listPage(page,uid, type);
}
public void saveRecord(Long uid) {
List<String> ips = this.baseMapper.getLastThirtyXIp(uid);
if (!CollectionUtils.isEmpty(ips)){
List<ChargeUserXRecord> chargeUserXRecords = new ArrayList<>();
for (String ip : ips) {
ChargeUserXRecord chargeUserXRecord = new ChargeUserXRecord();
chargeUserXRecord.setUid(uid);
chargeUserXRecord.setIp(ip);
chargeUserXRecord.setType(1);
chargeUserXRecords.add(chargeUserXRecord);
}
this.saveBatch(chargeUserXRecords);
}
List<String> devices = this.baseMapper.getLastThirtyXDevice(uid);
if (!CollectionUtils.isEmpty(devices)){
List<ChargeUserXRecord> chargeUserXRecords = new ArrayList<>();
for (String device : devices) {
ChargeUserXRecord chargeUserXRecord = new ChargeUserXRecord();
chargeUserXRecord.setUid(uid);
chargeUserXRecord.setDeviceId(device);
chargeUserXRecord.setType(2);
chargeUserXRecords.add(chargeUserXRecord);
}
this.saveBatch(chargeUserXRecords);
}
}
public ChargeUserXRecord getRecordByIp(String loginIp) {
return this.baseMapper.getRecordByIp(loginIp);
}
public ChargeUserXRecord getRecordByDevice(String deviceId) {
return this.baseMapper.deviceId(deviceId);
}
public void deleteRecord(Long uid) {
this.baseMapper.deleteRecord(uid);
}
}

View File

@@ -0,0 +1,115 @@
package com.accompany.business.service.game;
import com.accompany.business.model.game.ChargeUserXDetail;
import com.accompany.business.model.game.GameDayStatData;
import com.accompany.business.service.AccountLoginRecordService;
import com.accompany.business.service.user.UsersService;
import com.accompany.common.constant.Constant;
import com.accompany.common.constant.GameConstant;
import com.accompany.core.service.SysConfService;
import com.accompany.payment.model.UserRechargeLevel;
import com.accompany.payment.service.UserRechargeLevelService;
import org.apache.commons.collections.CollectionUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.*;
import java.util.stream.Collectors;
/**
* <p>
* 用户充值等级 服务实现类
* </p>
*
* @author wxf
* @since 2025-06-19
*/
@Service
public class ChargeUserXService {
@Autowired
private GameDayStatDataService gameDayStatDataService;
@Autowired
private SysConfService sysConfService;
@Autowired
private UsersService usersService;
@Autowired
private AccountLoginRecordService accountLoginRecordService;
@Autowired
private ChargeUserXDetailService chargeUserXDetailService;
@Autowired
private UserRechargeLevelService rechargeLevelService;
public void updateUserX(Date date) {
List<UserRechargeLevel> zeroChargeList = rechargeLevelService.listByZeroTotalGold();
List<ChargeUserXDetail> chargeUserXDetails = chargeUserXDetailService.listExistAutoRecord();
//无总充值为0的用户
if (CollectionUtils.isEmpty(zeroChargeList)) {
if (CollectionUtils.isNotEmpty(chargeUserXDetails)) {
chargeUserXDetails.stream().forEach(x -> {
x.setIdentity(2);
x.setUpdateTime(date);
});
chargeUserXDetailService.saveOrUpdateBatch(chargeUserXDetails);
chargeUserXDetailService.detailCache().delete();
}
return;
}
String value = sysConfService.getDefaultSysConfValueById(Constant.SysConfId.charge_user_x_gold, "200000");
Map<Long, GameDayStatData> gameDayStatDataMap = gameDayStatDataService.statByChannelUid4XRecord(GameConstant.GameChannel.LEADERCC.name(), Long.valueOf(value));
List<Long> zeroChargeUidList = new ArrayList<>();
List<Long> existXUidList = new ArrayList<>();
if (CollectionUtils.isNotEmpty(zeroChargeList)) {
zeroChargeUidList = zeroChargeList.stream().map(UserRechargeLevel::getUid).toList();
}
Map<Long, ChargeUserXDetail> existXMap = new HashMap<>();
if (CollectionUtils.isNotEmpty(chargeUserXDetails)) {
existXMap = chargeUserXDetails.stream().collect(Collectors.toMap(ChargeUserXDetail::getUid, v -> v));
for (ChargeUserXDetail x : chargeUserXDetails) {
if (zeroChargeUidList.contains(x.getUid())) {
GameDayStatData gameDayStatData = gameDayStatDataMap.get(x.getUid());
if (gameDayStatData != null) {
x.setPayGold(gameDayStatData.getPayGold());
x.setWinGold(gameDayStatData.getWinGold());
x.setUpdateTime(date);
}
continue;
}
x.setIdentity(2);
x.setUpdateTime(date);
}
}
if (CollectionUtils.isNotEmpty(zeroChargeList)) {
for (UserRechargeLevel zeroCharge : zeroChargeList) {
if (existXMap.containsKey(zeroCharge.getUid())) {
continue;
}
}
}
}
public void initChargeUserX() {
}
private void sendMsg() {
}
public void initDetail() {
}
}

View File

@@ -10,6 +10,7 @@ import com.baomidou.mybatisplus.extension.service.IService;
import java.util.Date; import java.util.Date;
import java.util.List; import java.util.List;
import java.util.Map;
/** /**
* 游戏日统计表 服务类 * 游戏日统计表 服务类
@@ -43,4 +44,6 @@ public interface GameDayStatDataService extends IService<GameDayStatData> {
void statDayList(String channel, Date statTime); void statDayList(String channel, Date statTime);
GameUserDataDetailVo userTotalALL(Long erbanNo, String channel, String gameId, String startDate, String endDate, List<Integer> rolePartitionIds); GameUserDataDetailVo userTotalALL(Long erbanNo, String channel, String gameId, String startDate, String endDate, List<Integer> rolePartitionIds);
Map<Long, GameDayStatData> statByChannelUid4XRecord(String channel, Long miniWin);
} }

View File

@@ -4,6 +4,7 @@ import com.accompany.business.config.LeaderccMiniGameConfig;
import com.accompany.business.enums.resource.ResourceCodeEnum; import com.accompany.business.enums.resource.ResourceCodeEnum;
import com.accompany.business.message.GameMsgMessage; import com.accompany.business.message.GameMsgMessage;
import com.accompany.business.model.UserPurse; import com.accompany.business.model.UserPurse;
import com.accompany.business.model.game.ChargeUserXDetail;
import com.accompany.business.model.game.GameFeeRateConfig; import com.accompany.business.model.game.GameFeeRateConfig;
import com.accompany.business.model.game.GameFeeRateUserRechargeLevelConfig; import com.accompany.business.model.game.GameFeeRateUserRechargeLevelConfig;
import com.accompany.business.service.mq.RocketMQService; import com.accompany.business.service.mq.RocketMQService;
@@ -33,10 +34,7 @@ import org.redisson.client.codec.StringCodec;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import java.util.Collections; import java.util.*;
import java.util.Date;
import java.util.List;
import java.util.UUID;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors; import java.util.stream.Collectors;
@@ -71,6 +69,8 @@ public class GameService {
private GameFeeRateUserRechargeLevelConfigService gameFeeRateUserRechargeLevelConfigService; private GameFeeRateUserRechargeLevelConfigService gameFeeRateUserRechargeLevelConfigService;
@Autowired @Autowired
private RocketMQService rocketMQService; private RocketMQService rocketMQService;
@Autowired
private ChargeUserXDetailService chargeUserXDetailService;
public static final String ALL = "All"; public static final String ALL = "All";
@@ -110,6 +110,7 @@ public class GameService {
vo.setNickname(users.getNick()); vo.setNickname(users.getNick());
vo.setUid(param.getUid()); vo.setUid(param.getUid());
vo.setWater(this.getGameFeeRate(uid, param.getGameId())); vo.setWater(this.getGameFeeRate(uid, param.getGameId()));
vo.setPrizeLabel(this.getPrizeLabel(uid));
return vo; return vo;
} }
@@ -287,4 +288,18 @@ public class GameService {
} }
return gameConfigVOS; return gameConfigVOS;
} }
private Integer getPrizeLabel(Long uid) {
ChargeUserXDetail record = chargeUserXDetailService.getRecord(uid);
if (record == null){
return 0;
}
Integer identity = record.getIdentity();
List<Integer> cancelTypes = Arrays.asList(2, 3);
if (record.getIdentity() != null && cancelTypes.contains(record.getIdentity())) {
return -1;
}
return identity;
}
} }

View File

@@ -580,4 +580,13 @@ public class GameDayStatDataServiceImpl extends ServiceImpl<GameDayStatDataMappe
} }
return gameUserDataDetailVo; return gameUserDataDetailVo;
} }
@Override
public Map<Long, GameDayStatData> statByChannelUid4XRecord(String channel, Long miniWin) {
List<GameDayStatData> gameDayStatDatas = baseMapper.statByChannelUid4XRecord(channel, miniWin);
if (CollectionUtils.isEmpty(gameDayStatDatas)) {
return Collections.emptyMap();
}
return gameDayStatDatas.stream().collect(Collectors.toMap(GameDayStatData::getUid, v -> v));
}
} }

View File

@@ -0,0 +1,48 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.accompany.business.mybatismapper.game.ChargeUserXDetailMapper">
<update id="updateCharge">
UPDATE `charge_user_x_detail`
SET `identity` = 2
WHERE `uid` = #{uid};
</update>
<select id="getRecord" resultType="com.accompany.business.model.game.ChargeUserXDetail">
select *
from charge_user_x_detail
where uid = #{uid}
</select>
<select id="listPage" resultType="com.accompany.business.vo.game.ChargeUserXDetailVo">
select cuxd.*,
u.erban_no,
u.nick,
ri.name regionName,
u.partition_id partitionId,
cuxd.win_gold - cuxd.pay_gold diff,
cul.`level` chargeUserLevel
from charge_user_x_detail cuxd
left join users u on cuxd.uid = u.uid
left join user_recharge_level cul on cul.uid = cuxd.uid
left join region_info ri on u.region_id = ri.id
where
<foreach collection="partitionIds" open="u.partition_id in(" separator="," item="pi" close=")">
#{pi}
</foreach>
<if test="erbanNo != null">
and u.erban_no = #{erbanNo}
</if>
<if test="identity != null and identity == 1">
and cuxd.identity = #{identity}
</if>
<if test="identity != null and identity != 1">
and not cuxd.identity = 1
</if>
<if test="ip != null">
and cuxd.uid in (select uid from charge_user_x_record where type = 1 and ip = #{ip})
</if>
<if test="device != null">
and cuxd.uid in (select uid from charge_user_x_record where type = 2 and device_id = #{device})
</if>
order by cuxd.update_time desc
</select>
</mapper>

View File

@@ -0,0 +1,22 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.accompany.business.mybatismapper.game.ChargeUserXRecordMapper">
<update id="deleteRecord">
UPDATE `charge_user_x_record` SET `status` = 2 WHERE `uid` = #{uid};
</update>
<select id="getLastThirtyXIp" resultType="java.lang.String">
select login_ip from account_login_record where uid = #{uid} and create_time >= DATE_SUB(CURRENT_DATE(), INTERVAL 30 DAY) group by login_ip
</select>
<select id="getLastThirtyXDevice" resultType="java.lang.String">
select device_id from account_login_record where uid = #{uid} and create_time >= DATE_SUB(CURRENT_DATE(), INTERVAL 30 DAY) group by device_id
</select>
<select id="deviceId" resultType="com.accompany.business.model.game.ChargeUserXRecord">
select * from charge_user_x_record where type = 2 and device_id = #{deviceId} and status = 1 limit 1
</select>
<select id="getRecordByIp" resultType="com.accompany.business.model.game.ChargeUserXRecord">
select * from charge_user_x_record where type = 1 and ip = #{loginIp} and status = 1 limit 1
</select>
<select id="listPage" resultType="com.accompany.business.model.game.ChargeUserXRecord">
select * from charge_user_x_record where uid = #{uid} and status = 1 and type = #{type}
</select>
</mapper>

View File

@@ -27,4 +27,17 @@
group by stat_date group by stat_date
order by stat_date desc order by stat_date desc
</select> </select>
<select id="statByChannelUid4XRecord" resultType="com.accompany.business.model.game.GameDayStatData">
select uid,
sum(pay_gold) payGold,
sum(win_gold) winGold
from game_day_stat_data
where channel = #{channel}
GROUP BY
uid
HAVING
winGold - payGold > #{miniWin}
</select>
</mapper> </mapper>

View File

@@ -0,0 +1,20 @@
package com.accompany.scheduler.task.game;
import com.accompany.business.service.game.ChargeUserXService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
import java.util.Date;
@Component
public class ChargeUserXTask {
@Autowired
private ChargeUserXService chargeUserXService;
@Scheduled(cron = "0 0 4 * * *")
public void statDayList() {
chargeUserXService.updateUserX(new Date());
}
}

View File

@@ -14,7 +14,7 @@ public class GameDayStatDataTask {
@Autowired @Autowired
private GameDayStatDataService gameDayStatDataService; private GameDayStatDataService gameDayStatDataService;
@Scheduled(cron = "0 0 9 * * *") @Scheduled(cron = "0 0 10 * * *")
public void statDayList() { public void statDayList() {
for (GameConstant.GameChannel gameChannel : GameConstant.GameChannel.values()) { for (GameConstant.GameChannel gameChannel : GameConstant.GameChannel.values()) {
gameDayStatDataService.statDayList(gameChannel.name(), new Date()); gameDayStatDataService.statDayList(gameChannel.name(), new Date());