diff --git a/accompany-admin/accompany-admin-service/src/main/java/com/accompany/admin/service/system/AdminUserService.java b/accompany-admin/accompany-admin-service/src/main/java/com/accompany/admin/service/system/AdminUserService.java index 21162d383..3f0dce0e5 100644 --- a/accompany-admin/accompany-admin-service/src/main/java/com/accompany/admin/service/system/AdminUserService.java +++ b/accompany-admin/accompany-admin-service/src/main/java/com/accompany/admin/service/system/AdminUserService.java @@ -402,6 +402,11 @@ public class AdminUserService extends BaseService { return adminUserMapper.selectByExample(example); } + /** + * 特殊方法,不能当通用后台用 + * @param adminId + * @return + */ public AdminUserVo getByAdminId(Integer adminId) { AdminUser adminUserById = this.getAdminUserById(adminId); List roleByAdminId = adminRoleService.getRoleByAdminId(adminId); diff --git a/accompany-admin/accompany-admin-web/src/main/java/com/accompany/admin/controller/game/ChargeUserXDetailAdminController.java b/accompany-admin/accompany-admin-web/src/main/java/com/accompany/admin/controller/game/ChargeUserXDetailAdminController.java new file mode 100644 index 000000000..6a3764b02 --- /dev/null +++ b/accompany-admin/accompany-admin-web/src/main/java/com/accompany/admin/controller/game/ChargeUserXDetailAdminController.java @@ -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; + +/** + *

+ * 用户充值等级 前端控制器 + *

+ * + * @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> listPage(Long erbanNo, String ip, + String device, Integer identity, Integer pageNo, Integer pageSize) { + List allPartitionId = adminPartitionService.getAllPartitionId(getAdminId()); + IPage 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 save(String erbanNos, String addReason) { + if (erbanNos == null) { + throw new AdminServiceException(5001, "请填写用户id"); + } + AdminUser adminUserVo = adminUserService.getAdminUserById(getAdminId()); + + String[] split = erbanNos.split(","); + List 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 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 allPartitionId = adminPartitionService.getAllPartitionId(getAdminId()); + IPage 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()); + } +} diff --git a/accompany-base/accompany-core/src/main/java/com/accompany/common/constant/Constant.java b/accompany-base/accompany-core/src/main/java/com/accompany/common/constant/Constant.java index 26075450b..6e3d79c17 100644 --- a/accompany-base/accompany-core/src/main/java/com/accompany/common/constant/Constant.java +++ b/accompany-base/accompany-core/src/main/java/com/accompany/common/constant/Constant.java @@ -1396,6 +1396,8 @@ public class Constant { 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 String charge_user_x_gold = "charge_user_x_gold"; } public static class WithDrawStatus { diff --git a/accompany-base/accompany-core/src/main/java/com/accompany/common/redis/RedisKey.java b/accompany-base/accompany-core/src/main/java/com/accompany/common/redis/RedisKey.java index 5f9cc923a..c8e02d035 100644 --- a/accompany-base/accompany-core/src/main/java/com/accompany/common/redis/RedisKey.java +++ b/accompany-base/accompany-core/src/main/java/com/accompany/common/redis/RedisKey.java @@ -1470,6 +1470,7 @@ public enum RedisKey { guild_usd_withdraw_num, //公会薪资提现次数 guild_usd_to_recharge_num,//公会薪资转代理次数 + charge_user_x_detail,//嫌疑用户 ; public String getKey() { diff --git a/accompany-base/accompany-payment/accompany-payment-service/src/main/java/com/accompany/payment/service/UserRechargeLevelService.java b/accompany-base/accompany-payment/accompany-payment-service/src/main/java/com/accompany/payment/service/UserRechargeLevelService.java index 31b254de2..cf40ccf98 100644 --- a/accompany-base/accompany-payment/accompany-payment-service/src/main/java/com/accompany/payment/service/UserRechargeLevelService.java +++ b/accompany-base/accompany-payment/accompany-payment-service/src/main/java/com/accompany/payment/service/UserRechargeLevelService.java @@ -4,6 +4,7 @@ import com.accompany.common.redis.RedisKey; import com.accompany.payment.mapper.ChargeRecordMapperMgr; import com.accompany.payment.mapper.UserRechargeLevelMapper; import com.accompany.payment.model.UserRechargeLevel; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; import org.redisson.api.RMapCache; import org.redisson.api.RedissonClient; @@ -13,7 +14,9 @@ import org.springframework.stereotype.Service; import org.springframework.util.StringUtils; 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.stream.Collectors; @@ -92,4 +95,10 @@ public class UserRechargeLevelService extends ServiceImpl listByZeroTotalGold() { + LambdaQueryWrapper queryWrapper = new LambdaQueryWrapper<>(); + queryWrapper.eq(UserRechargeLevel::getTotalGold, 0); + return baseMapper.selectList(queryWrapper); + } } \ No newline at end of file diff --git a/accompany-business/accompany-business-sdk/src/main/java/com/accompany/business/model/game/ChargeUserXDetail.java b/accompany-business/accompany-business-sdk/src/main/java/com/accompany/business/model/game/ChargeUserXDetail.java new file mode 100644 index 000000000..e284729cf --- /dev/null +++ b/accompany-business/accompany-business-sdk/src/main/java/com/accompany/business/model/game/ChargeUserXDetail.java @@ -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; + + +} diff --git a/accompany-business/accompany-business-sdk/src/main/java/com/accompany/business/model/game/ChargeUserXRecord.java b/accompany-business/accompany-business-sdk/src/main/java/com/accompany/business/model/game/ChargeUserXRecord.java new file mode 100644 index 000000000..ca0df2367 --- /dev/null +++ b/accompany-business/accompany-business-sdk/src/main/java/com/accompany/business/model/game/ChargeUserXRecord.java @@ -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; + + +} diff --git a/accompany-business/accompany-business-sdk/src/main/java/com/accompany/business/vo/game/ChargeUserXDetailVo.java b/accompany-business/accompany-business-sdk/src/main/java/com/accompany/business/vo/game/ChargeUserXDetailVo.java new file mode 100644 index 000000000..a28c2724b --- /dev/null +++ b/accompany-business/accompany-business-sdk/src/main/java/com/accompany/business/vo/game/ChargeUserXDetailVo.java @@ -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; + +/** + *

+ * 用户充值等级 + *

+ * + * @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; + +} diff --git a/accompany-business/accompany-business-sdk/src/main/java/com/accompany/business/vo/game/GameUserInfoResponseVO.java b/accompany-business/accompany-business-sdk/src/main/java/com/accompany/business/vo/game/GameUserInfoResponseVO.java index 0c58fe6f4..c6fe8ac6f 100644 --- a/accompany-business/accompany-business-sdk/src/main/java/com/accompany/business/vo/game/GameUserInfoResponseVO.java +++ b/accompany-business/accompany-business-sdk/src/main/java/com/accompany/business/vo/game/GameUserInfoResponseVO.java @@ -10,4 +10,6 @@ public class GameUserInfoResponseVO { private Long coin;//玩家当前游戏币 必选 private Integer vipLevel; //VIP等级 必选 private Double water; + //传1代表是特殊用户,不传或者其他是正常用户 + private Integer prizeLabel; } diff --git a/accompany-business/accompany-business-service/src/main/java/com/accompany/business/mybatismapper/game/ChargeUserXDetailMapper.java b/accompany-business/accompany-business-service/src/main/java/com/accompany/business/mybatismapper/game/ChargeUserXDetailMapper.java new file mode 100644 index 000000000..50d172ab7 --- /dev/null +++ b/accompany-business/accompany-business-service/src/main/java/com/accompany/business/mybatismapper/game/ChargeUserXDetailMapper.java @@ -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; + +/** + *

+ * 用户充值等级 Mapper 接口 + *

+ * + * @author wxf + * @since 2025-06-30 + */ +@Mapper +public interface ChargeUserXDetailMapper extends BaseMapper { + + void updateCharge(@Param("uid") Long uid); + + ChargeUserXDetail getRecord(@Param("uid") Long uid); + + IPage listPage(@Param("page") Page page, + @Param("partitionIds") List partitionIds, + @Param("erbanNo") Long erbanNo, + @Param("ip") String ip, + @Param("device") String device, + @Param("identity") Integer identity); + +} diff --git a/accompany-business/accompany-business-service/src/main/java/com/accompany/business/mybatismapper/game/ChargeUserXRecordMapper.java b/accompany-business/accompany-business-service/src/main/java/com/accompany/business/mybatismapper/game/ChargeUserXRecordMapper.java new file mode 100644 index 000000000..608ab619c --- /dev/null +++ b/accompany-business/accompany-business-service/src/main/java/com/accompany/business/mybatismapper/game/ChargeUserXRecordMapper.java @@ -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; + +/** + *

+ * 用户充值等级 Mapper 接口 + *

+ * + * @author wxf + * @since 2025-06-30 + */ +@Mapper +public interface ChargeUserXRecordMapper extends BaseMapper { + + List getLastThirtyXIp(@Param("uid") Long uid); + + List getLastThirtyXDevice(@Param("uid") Long uid); + + ChargeUserXRecord getRecordByIp(@Param("loginIp") String loginIp); + + ChargeUserXRecord deviceId(@Param("deviceId") String deviceId); + + void deleteRecord(@Param("uid") Long uid); + + IPage listPage(@Param("page") Page page, @Param("uid") Long uid, @Param("type") Integer type); +} diff --git a/accompany-business/accompany-business-service/src/main/java/com/accompany/business/mybatismapper/game/GameDayStatDataMapper.java b/accompany-business/accompany-business-service/src/main/java/com/accompany/business/mybatismapper/game/GameDayStatDataMapper.java index a9cefd9a8..ea193e718 100644 --- a/accompany-business/accompany-business-service/src/main/java/com/accompany/business/mybatismapper/game/GameDayStatDataMapper.java +++ b/accompany-business/accompany-business-service/src/main/java/com/accompany/business/mybatismapper/game/GameDayStatDataMapper.java @@ -19,4 +19,7 @@ public interface GameDayStatDataMapper extends BaseMapper { IPage selectGroupDateList(IPage iPage, @Param("channel") String channel, @Param("gameId") String gameId, @Param("beginTime") Date beginTime, @Param("endTime") Date endTime, @Param("partitionId") Integer partitionId); + + List statByChannelUid4XRecord(@Param("channel") String channel, @Param("miniWin") Long miniWin); + } diff --git a/accompany-business/accompany-business-service/src/main/java/com/accompany/business/service/game/ChargeUserXDetailService.java b/accompany-business/accompany-business-service/src/main/java/com/accompany/business/service/game/ChargeUserXDetailService.java new file mode 100644 index 000000000..ce0418902 --- /dev/null +++ b/accompany-business/accompany-business-service/src/main/java/com/accompany/business/service/game/ChargeUserXDetailService.java @@ -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; + +/** + *

+ * 用户充值等级 服务实现类 + *

+ * + * @author wxf + * @since 2025-06-30 + */ +@Service +public class ChargeUserXDetailService extends ServiceImpl { + @Autowired + private AccountLoginRecordService accountLoginRecordService; + @Autowired + private ChargeUserXRecordService chargeUserXRecordService; + @Autowired + private RedissonClient redissonClient; + @Autowired + private UsersService usersService; + + + public IPage listPage(List partitionIds, Long erbanNo, String ip, String device, Integer identity, Integer pageNo, Integer pageSize) { + Page 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 erbanNos, String addReason, Integer adminId,String username) { + List 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 listExistAutoRecord() { + LambdaQueryWrapper queryWrapper = new LambdaQueryWrapper<>(); + queryWrapper.eq(ChargeUserXDetail::getIdentity, 1) + .gt(ChargeUserXDetail::getRefStatus, 0); + return this.baseMapper.selectList(queryWrapper); + } + + public RMap detailCache() { + String key = RedisKey.charge_user_x_detail.getKey(); + return redissonClient.getMap(key, new TypedJsonJacksonCodec(Long.class, ChargeUserXDetail.class)); + } +} diff --git a/accompany-business/accompany-business-service/src/main/java/com/accompany/business/service/game/ChargeUserXRecordService.java b/accompany-business/accompany-business-service/src/main/java/com/accompany/business/service/game/ChargeUserXRecordService.java new file mode 100644 index 000000000..24d1500fc --- /dev/null +++ b/accompany-business/accompany-business-service/src/main/java/com/accompany/business/service/game/ChargeUserXRecordService.java @@ -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; + +/** + *

+ * 用户充值等级 服务实现类 + *

+ * + * @author wxf + * @since 2025-06-30 + */ +@Service +public class ChargeUserXRecordService extends ServiceImpl { + + public IPage listPage(BasePageParams basePageParams, Long uid, Integer type) { + Page page = new Page<>(basePageParams.getPageNo(),basePageParams.getPageSize()); + return this.baseMapper.listPage(page,uid, type); + } + + public void saveRecord(Long uid) { + List ips = this.baseMapper.getLastThirtyXIp(uid); + if (!CollectionUtils.isEmpty(ips)){ + List 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 devices = this.baseMapper.getLastThirtyXDevice(uid); + if (!CollectionUtils.isEmpty(devices)){ + List 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); + } + + +} diff --git a/accompany-business/accompany-business-service/src/main/java/com/accompany/business/service/game/ChargeUserXService.java b/accompany-business/accompany-business-service/src/main/java/com/accompany/business/service/game/ChargeUserXService.java new file mode 100644 index 000000000..7afb1675e --- /dev/null +++ b/accompany-business/accompany-business-service/src/main/java/com/accompany/business/service/game/ChargeUserXService.java @@ -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; + +/** + *

+ * 用户充值等级 服务实现类 + *

+ * + * @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 zeroChargeList = rechargeLevelService.listByZeroTotalGold(); + List 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 gameDayStatDataMap = gameDayStatDataService.statByChannelUid4XRecord(GameConstant.GameChannel.LEADERCC.name(), Long.valueOf(value)); + + List zeroChargeUidList = new ArrayList<>(); + List existXUidList = new ArrayList<>(); + + if (CollectionUtils.isNotEmpty(zeroChargeList)) { + zeroChargeUidList = zeroChargeList.stream().map(UserRechargeLevel::getUid).toList(); + } + + Map 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() { + + } +} diff --git a/accompany-business/accompany-business-service/src/main/java/com/accompany/business/service/game/GameDayStatDataService.java b/accompany-business/accompany-business-service/src/main/java/com/accompany/business/service/game/GameDayStatDataService.java index 234cdd4a7..b91efcd07 100644 --- a/accompany-business/accompany-business-service/src/main/java/com/accompany/business/service/game/GameDayStatDataService.java +++ b/accompany-business/accompany-business-service/src/main/java/com/accompany/business/service/game/GameDayStatDataService.java @@ -10,6 +10,7 @@ import com.baomidou.mybatisplus.extension.service.IService; import java.util.Date; import java.util.List; +import java.util.Map; /** * 游戏日统计表 服务类 @@ -43,4 +44,6 @@ public interface GameDayStatDataService extends IService { void statDayList(String channel, Date statTime); GameUserDataDetailVo userTotalALL(Long erbanNo, String channel, String gameId, String startDate, String endDate, List rolePartitionIds); + + Map statByChannelUid4XRecord(String channel, Long miniWin); } diff --git a/accompany-business/accompany-business-service/src/main/java/com/accompany/business/service/game/GameService.java b/accompany-business/accompany-business-service/src/main/java/com/accompany/business/service/game/GameService.java index 4f21674ce..d90b3e063 100644 --- a/accompany-business/accompany-business-service/src/main/java/com/accompany/business/service/game/GameService.java +++ b/accompany-business/accompany-business-service/src/main/java/com/accompany/business/service/game/GameService.java @@ -4,6 +4,7 @@ import com.accompany.business.config.LeaderccMiniGameConfig; import com.accompany.business.enums.resource.ResourceCodeEnum; import com.accompany.business.message.GameMsgMessage; 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.GameFeeRateUserRechargeLevelConfig; 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.stereotype.Service; -import java.util.Collections; -import java.util.Date; -import java.util.List; -import java.util.UUID; +import java.util.*; import java.util.concurrent.TimeUnit; import java.util.stream.Collectors; @@ -71,6 +69,8 @@ public class GameService { private GameFeeRateUserRechargeLevelConfigService gameFeeRateUserRechargeLevelConfigService; @Autowired private RocketMQService rocketMQService; + @Autowired + private ChargeUserXDetailService chargeUserXDetailService; public static final String ALL = "All"; @@ -110,6 +110,7 @@ public class GameService { vo.setNickname(users.getNick()); vo.setUid(param.getUid()); vo.setWater(this.getGameFeeRate(uid, param.getGameId())); + vo.setPrizeLabel(this.getPrizeLabel(uid)); return vo; } @@ -287,4 +288,18 @@ public class GameService { } return gameConfigVOS; } + + + private Integer getPrizeLabel(Long uid) { + ChargeUserXDetail record = chargeUserXDetailService.getRecord(uid); + if (record == null){ + return 0; + } + Integer identity = record.getIdentity(); + List cancelTypes = Arrays.asList(2, 3); + if (record.getIdentity() != null && cancelTypes.contains(record.getIdentity())) { + return -1; + } + return identity; + } } diff --git a/accompany-business/accompany-business-service/src/main/java/com/accompany/business/service/game/impl/GameDayStatDataServiceImpl.java b/accompany-business/accompany-business-service/src/main/java/com/accompany/business/service/game/impl/GameDayStatDataServiceImpl.java index 718e0da19..091eeea84 100644 --- a/accompany-business/accompany-business-service/src/main/java/com/accompany/business/service/game/impl/GameDayStatDataServiceImpl.java +++ b/accompany-business/accompany-business-service/src/main/java/com/accompany/business/service/game/impl/GameDayStatDataServiceImpl.java @@ -580,4 +580,13 @@ public class GameDayStatDataServiceImpl extends ServiceImpl statByChannelUid4XRecord(String channel, Long miniWin) { + List gameDayStatDatas = baseMapper.statByChannelUid4XRecord(channel, miniWin); + if (CollectionUtils.isEmpty(gameDayStatDatas)) { + return Collections.emptyMap(); + } + return gameDayStatDatas.stream().collect(Collectors.toMap(GameDayStatData::getUid, v -> v)); + } } diff --git a/accompany-business/accompany-business-service/src/main/resources/accompany/sqlmappers/ChargeUserXDetailMapper.xml b/accompany-business/accompany-business-service/src/main/resources/accompany/sqlmappers/ChargeUserXDetailMapper.xml new file mode 100644 index 000000000..a35b23803 --- /dev/null +++ b/accompany-business/accompany-business-service/src/main/resources/accompany/sqlmappers/ChargeUserXDetailMapper.xml @@ -0,0 +1,48 @@ + + + + + + UPDATE `charge_user_x_detail` + SET `identity` = 2 + WHERE `uid` = #{uid}; + + + + diff --git a/accompany-business/accompany-business-service/src/main/resources/accompany/sqlmappers/ChargeUserXRecordMapper.xml b/accompany-business/accompany-business-service/src/main/resources/accompany/sqlmappers/ChargeUserXRecordMapper.xml new file mode 100644 index 000000000..fb09549e5 --- /dev/null +++ b/accompany-business/accompany-business-service/src/main/resources/accompany/sqlmappers/ChargeUserXRecordMapper.xml @@ -0,0 +1,22 @@ + + + + + UPDATE `charge_user_x_record` SET `status` = 2 WHERE `uid` = #{uid}; + + + + + + + diff --git a/accompany-business/accompany-business-service/src/main/resources/accompany/sqlmappers/GameDayStatDataMapper.xml b/accompany-business/accompany-business-service/src/main/resources/accompany/sqlmappers/GameDayStatDataMapper.xml index 527befaa8..ed8e9c592 100644 --- a/accompany-business/accompany-business-service/src/main/resources/accompany/sqlmappers/GameDayStatDataMapper.xml +++ b/accompany-business/accompany-business-service/src/main/resources/accompany/sqlmappers/GameDayStatDataMapper.xml @@ -27,4 +27,17 @@ group by stat_date order by stat_date desc + + diff --git a/accompany-scheduler/accompany-scheduler-service/src/main/java/com/accompany/scheduler/task/game/ChargeUserXTask.java b/accompany-scheduler/accompany-scheduler-service/src/main/java/com/accompany/scheduler/task/game/ChargeUserXTask.java new file mode 100644 index 000000000..bc4989aeb --- /dev/null +++ b/accompany-scheduler/accompany-scheduler-service/src/main/java/com/accompany/scheduler/task/game/ChargeUserXTask.java @@ -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()); + } +} diff --git a/accompany-scheduler/accompany-scheduler-service/src/main/java/com/accompany/scheduler/task/game/GameDayStatDataTask.java b/accompany-scheduler/accompany-scheduler-service/src/main/java/com/accompany/scheduler/task/game/GameDayStatDataTask.java index 9966a6018..35c2bfb1e 100644 --- a/accompany-scheduler/accompany-scheduler-service/src/main/java/com/accompany/scheduler/task/game/GameDayStatDataTask.java +++ b/accompany-scheduler/accompany-scheduler-service/src/main/java/com/accompany/scheduler/task/game/GameDayStatDataTask.java @@ -14,7 +14,7 @@ public class GameDayStatDataTask { @Autowired private GameDayStatDataService gameDayStatDataService; - @Scheduled(cron = "0 0 9 * * *") + @Scheduled(cron = "0 0 10 * * *") public void statDayList() { for (GameConstant.GameChannel gameChannel : GameConstant.GameChannel.values()) { gameDayStatDataService.statDayList(gameChannel.name(), new Date());