彩票猪手精推版
This commit is contained in:
File diff suppressed because it is too large
Load Diff
13
src/main/java/com/xy/xyaicpzs/service/D10Service.java
Normal file
13
src/main/java/com/xy/xyaicpzs/service/D10Service.java
Normal file
@@ -0,0 +1,13 @@
|
||||
package com.xy.xyaicpzs.service;
|
||||
|
||||
import com.xy.xyaicpzs.domain.entity.D10;
|
||||
import com.baomidou.mybatisplus.extension.service.IService;
|
||||
|
||||
/**
|
||||
* @author XY003
|
||||
* @description 针对表【d10(d10表)】的数据库操作Service
|
||||
* @createDate 2025-08-21 15:06:10
|
||||
*/
|
||||
public interface D10Service extends IService<D10> {
|
||||
|
||||
}
|
||||
13
src/main/java/com/xy/xyaicpzs/service/D11Service.java
Normal file
13
src/main/java/com/xy/xyaicpzs/service/D11Service.java
Normal file
@@ -0,0 +1,13 @@
|
||||
package com.xy.xyaicpzs.service;
|
||||
|
||||
import com.xy.xyaicpzs.domain.entity.D11;
|
||||
import com.baomidou.mybatisplus.extension.service.IService;
|
||||
|
||||
/**
|
||||
* @author XY003
|
||||
* @description 针对表【d11(d11表)】的数据库操作Service
|
||||
* @createDate 2025-08-21 15:06:10
|
||||
*/
|
||||
public interface D11Service extends IService<D11> {
|
||||
|
||||
}
|
||||
13
src/main/java/com/xy/xyaicpzs/service/D12Service.java
Normal file
13
src/main/java/com/xy/xyaicpzs/service/D12Service.java
Normal file
@@ -0,0 +1,13 @@
|
||||
package com.xy.xyaicpzs.service;
|
||||
|
||||
import com.xy.xyaicpzs.domain.entity.D12;
|
||||
import com.baomidou.mybatisplus.extension.service.IService;
|
||||
|
||||
/**
|
||||
* @author XY003
|
||||
* @description 针对表【d12(d12表)】的数据库操作Service
|
||||
* @createDate 2025-08-21 15:06:10
|
||||
*/
|
||||
public interface D12Service extends IService<D12> {
|
||||
|
||||
}
|
||||
13
src/main/java/com/xy/xyaicpzs/service/D5Service.java
Normal file
13
src/main/java/com/xy/xyaicpzs/service/D5Service.java
Normal file
@@ -0,0 +1,13 @@
|
||||
package com.xy.xyaicpzs.service;
|
||||
|
||||
import com.xy.xyaicpzs.domain.entity.D5;
|
||||
import com.baomidou.mybatisplus.extension.service.IService;
|
||||
|
||||
/**
|
||||
* @author XY003
|
||||
* @description 针对表【d5(d5表)】的数据库操作Service
|
||||
* @createDate 2025-01-26 16:00:00
|
||||
*/
|
||||
public interface D5Service extends IService<D5> {
|
||||
|
||||
}
|
||||
13
src/main/java/com/xy/xyaicpzs/service/D6Service.java
Normal file
13
src/main/java/com/xy/xyaicpzs/service/D6Service.java
Normal file
@@ -0,0 +1,13 @@
|
||||
package com.xy.xyaicpzs.service;
|
||||
|
||||
import com.xy.xyaicpzs.domain.entity.D6;
|
||||
import com.baomidou.mybatisplus.extension.service.IService;
|
||||
|
||||
/**
|
||||
* @author XY003
|
||||
* @description 针对表【d6(d6表)】的数据库操作Service
|
||||
* @createDate 2025-08-21 14:10:22
|
||||
*/
|
||||
public interface D6Service extends IService<D6> {
|
||||
|
||||
}
|
||||
13
src/main/java/com/xy/xyaicpzs/service/D7Service.java
Normal file
13
src/main/java/com/xy/xyaicpzs/service/D7Service.java
Normal file
@@ -0,0 +1,13 @@
|
||||
package com.xy.xyaicpzs.service;
|
||||
|
||||
import com.xy.xyaicpzs.domain.entity.D7;
|
||||
import com.baomidou.mybatisplus.extension.service.IService;
|
||||
|
||||
/**
|
||||
* @author XY003
|
||||
* @description 针对表【d7(d7表)】的数据库操作Service
|
||||
* @createDate 2025-08-21 15:06:10
|
||||
*/
|
||||
public interface D7Service extends IService<D7> {
|
||||
|
||||
}
|
||||
13
src/main/java/com/xy/xyaicpzs/service/D8Service.java
Normal file
13
src/main/java/com/xy/xyaicpzs/service/D8Service.java
Normal file
@@ -0,0 +1,13 @@
|
||||
package com.xy.xyaicpzs.service;
|
||||
|
||||
import com.xy.xyaicpzs.domain.entity.D8;
|
||||
import com.baomidou.mybatisplus.extension.service.IService;
|
||||
|
||||
/**
|
||||
* @author XY003
|
||||
* @description 针对表【d8(d8表)】的数据库操作Service
|
||||
* @createDate 2025-08-21 15:06:10
|
||||
*/
|
||||
public interface D8Service extends IService<D8> {
|
||||
|
||||
}
|
||||
13
src/main/java/com/xy/xyaicpzs/service/D9Service.java
Normal file
13
src/main/java/com/xy/xyaicpzs/service/D9Service.java
Normal file
@@ -0,0 +1,13 @@
|
||||
package com.xy.xyaicpzs.service;
|
||||
|
||||
import com.xy.xyaicpzs.domain.entity.D9;
|
||||
import com.baomidou.mybatisplus.extension.service.IService;
|
||||
|
||||
/**
|
||||
* @author XY003
|
||||
* @description 针对表【d9(d9表)】的数据库操作Service
|
||||
* @createDate 2025-08-21 15:06:10
|
||||
*/
|
||||
public interface D9Service extends IService<D9> {
|
||||
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
package com.xy.xyaicpzs.service;
|
||||
|
||||
import com.xy.xyaicpzs.domain.entity.DltBackendHistory100;
|
||||
import com.baomidou.mybatisplus.extension.service.IService;
|
||||
|
||||
/**
|
||||
* @author XY003
|
||||
* @description 针对表【dlt_backend_history_100(大乐透后区最近100期数据表)】的数据库操作Service
|
||||
* @createDate 2025-08-21 11:35:47
|
||||
*/
|
||||
public interface DltBackendHistory100Service extends IService<DltBackendHistory100> {
|
||||
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
package com.xy.xyaicpzs.service;
|
||||
|
||||
import com.xy.xyaicpzs.domain.entity.DltBackendHistoryAll;
|
||||
import com.baomidou.mybatisplus.extension.service.IService;
|
||||
|
||||
/**
|
||||
* @author XY003
|
||||
* @description 针对表【dlt_backend_history_all(大乐透后区全部历史数据表)】的数据库操作Service
|
||||
* @createDate 2025-08-21 11:35:47
|
||||
*/
|
||||
public interface DltBackendHistoryAllService extends IService<DltBackendHistoryAll> {
|
||||
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
package com.xy.xyaicpzs.service;
|
||||
|
||||
import com.xy.xyaicpzs.domain.entity.DltBackendHistoryTop100;
|
||||
import com.baomidou.mybatisplus.extension.service.IService;
|
||||
|
||||
/**
|
||||
* @author XY003
|
||||
* @description 针对表【dlt_backend_history_top_100(大乐透后区百期数据排行表)】的数据库操作Service
|
||||
* @createDate 2025-08-21 11:35:47
|
||||
*/
|
||||
public interface DltBackendHistoryTop100Service extends IService<DltBackendHistoryTop100> {
|
||||
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
package com.xy.xyaicpzs.service;
|
||||
|
||||
import com.xy.xyaicpzs.domain.entity.DltBackendHistoryTop;
|
||||
import com.baomidou.mybatisplus.extension.service.IService;
|
||||
|
||||
/**
|
||||
* @author XY003
|
||||
* @description 针对表【dlt_backend_history_top(大乐透后区历史数据排行表)】的数据库操作Service
|
||||
* @createDate 2025-08-21 11:35:47
|
||||
*/
|
||||
public interface DltBackendHistoryTopService extends IService<DltBackendHistoryTop> {
|
||||
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
package com.xy.xyaicpzs.service;
|
||||
|
||||
import com.xy.xyaicpzs.domain.vo.BallCombinationAnalysisVO;
|
||||
|
||||
/**
|
||||
* 大乐透组合分析服务接口
|
||||
*/
|
||||
public interface DltCombinationAnalysisService {
|
||||
|
||||
/**
|
||||
* 前区与前区的组合性分析
|
||||
* @param masterBall 主球号码(前区)
|
||||
* @param slaveBall 随球号码(前区)
|
||||
* @return 组合分析结果
|
||||
*/
|
||||
BallCombinationAnalysisVO analyzeFrontFrontCombination(Integer masterBall, Integer slaveBall);
|
||||
|
||||
/**
|
||||
* 前区与后区的组合性分析
|
||||
* @param masterBall 主球号码(前区)
|
||||
* @param slaveBall 随球号码(后区)
|
||||
* @return 组合分析结果
|
||||
*/
|
||||
BallCombinationAnalysisVO analyzeFrontBackCombination(Integer masterBall, Integer slaveBall);
|
||||
|
||||
/**
|
||||
* 后区与后区的组合性分析
|
||||
* @param masterBall 主球号码(后区)
|
||||
* @param slaveBall 随球号码(后区)
|
||||
* @return 组合分析结果
|
||||
*/
|
||||
BallCombinationAnalysisVO analyzeBackBackCombination(Integer masterBall, Integer slaveBall);
|
||||
|
||||
/**
|
||||
* 后区与前区的组合性分析
|
||||
* @param masterBall 主球号码(后区)
|
||||
* @param slaveBall 随球号码(前区)
|
||||
* @return 组合分析结果
|
||||
*/
|
||||
BallCombinationAnalysisVO analyzeBackFrontCombination(Integer masterBall, Integer slaveBall);
|
||||
}
|
||||
@@ -0,0 +1,60 @@
|
||||
package com.xy.xyaicpzs.service;
|
||||
|
||||
import com.xy.xyaicpzs.domain.vo.PrizeEstimateVO;
|
||||
import com.xy.xyaicpzs.domain.vo.RedBallHitRateVO;
|
||||
import com.xy.xyaicpzs.domain.vo.UserPredictStatVO;
|
||||
|
||||
/**
|
||||
* 大乐透数据分析服务接口
|
||||
*/
|
||||
public interface DltDataAnalysisService {
|
||||
|
||||
/**
|
||||
* 处理大乐透待开奖记录,匹配开奖结果
|
||||
* @return 处理的记录数量
|
||||
*/
|
||||
int processPendingDltPredictions();
|
||||
|
||||
/**
|
||||
* 获取用户大乐透预测统计数据
|
||||
* @param userId 用户ID
|
||||
* @return 用户大乐透预测统计数据
|
||||
*/
|
||||
UserPredictStatVO getUserDltPredictStat(Long userId);
|
||||
|
||||
/**
|
||||
* 大乐透奖金统计
|
||||
* @param userId 用户ID
|
||||
* @param predictId 预测记录ID,如果为null则统计所有记录
|
||||
* @return 奖金统计信息
|
||||
*/
|
||||
PrizeEstimateVO getDltPrizeStatistics(Long userId, Long predictId);
|
||||
|
||||
/**
|
||||
* 大乐透前区首球命中率分析
|
||||
* @param userId 用户ID
|
||||
* @return 前区首球命中率统计信息
|
||||
*/
|
||||
RedBallHitRateVO getFrontFirstBallHitRate(Long userId);
|
||||
|
||||
/**
|
||||
* 大乐透前区球号命中率分析
|
||||
* @param userId 用户ID
|
||||
* @return 前区球号命中率统计信息
|
||||
*/
|
||||
RedBallHitRateVO getFrontBallHitRate(Long userId);
|
||||
|
||||
/**
|
||||
* 大乐透后区首球命中率分析
|
||||
* @param userId 用户ID
|
||||
* @return 后区首球命中率统计信息
|
||||
*/
|
||||
RedBallHitRateVO getBackFirstBallHitRate(Long userId);
|
||||
|
||||
/**
|
||||
* 大乐透后区球号命中率分析
|
||||
* @param userId 用户ID
|
||||
* @return 后区球号命中率统计信息
|
||||
*/
|
||||
RedBallHitRateVO getBackBallHitRate(Long userId);
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
package com.xy.xyaicpzs.service;
|
||||
|
||||
import com.xy.xyaicpzs.domain.entity.DltDrawRecord;
|
||||
import com.baomidou.mybatisplus.extension.service.IService;
|
||||
|
||||
/**
|
||||
* @author XY003
|
||||
* @description 针对表【dlt_draw_record(大乐透开奖信息表)】的数据库操作Service
|
||||
* @createDate 2025-08-20 15:55:06
|
||||
*/
|
||||
public interface DltDrawRecordService extends IService<DltDrawRecord> {
|
||||
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
package com.xy.xyaicpzs.service;
|
||||
|
||||
import com.xy.xyaicpzs.domain.entity.DltFrontendHistory100;
|
||||
import com.baomidou.mybatisplus.extension.service.IService;
|
||||
|
||||
/**
|
||||
* @author XY003
|
||||
* @description 针对表【dlt_frontend_history_100(大乐透前区最近100期数据表)】的数据库操作Service
|
||||
* @createDate 2025-08-20 16:24:40
|
||||
*/
|
||||
public interface DltFrontendHistory100Service extends IService<DltFrontendHistory100> {
|
||||
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
package com.xy.xyaicpzs.service;
|
||||
|
||||
import com.xy.xyaicpzs.domain.entity.DltFrontendHistoryAll;
|
||||
import com.baomidou.mybatisplus.extension.service.IService;
|
||||
|
||||
/**
|
||||
* @author XY003
|
||||
* @description 针对表【dlt_frontend_history_all(大乐透前区全部历史数据表)】的数据库操作Service
|
||||
* @createDate 2025-08-20 16:24:40
|
||||
*/
|
||||
public interface DltFrontendHistoryAllService extends IService<DltFrontendHistoryAll> {
|
||||
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
package com.xy.xyaicpzs.service;
|
||||
|
||||
import com.xy.xyaicpzs.domain.entity.DltFrontendHistoryTop100;
|
||||
import com.baomidou.mybatisplus.extension.service.IService;
|
||||
|
||||
/**
|
||||
* @author XY003
|
||||
* @description 针对表【dlt_frontend_history_top_100(大乐透前区百期数据排行表)】的数据库操作Service
|
||||
* @createDate 2025-08-20 16:24:40
|
||||
*/
|
||||
public interface DltFrontendHistoryTop100Service extends IService<DltFrontendHistoryTop100> {
|
||||
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
package com.xy.xyaicpzs.service;
|
||||
|
||||
import com.xy.xyaicpzs.domain.entity.DltFrontendHistoryTop;
|
||||
import com.baomidou.mybatisplus.extension.service.IService;
|
||||
|
||||
/**
|
||||
* @author XY003
|
||||
* @description 针对表【dlt_frontend_history_top(大乐透前区历史数据排行表)】的数据库操作Service
|
||||
* @createDate 2025-08-20 16:24:40
|
||||
*/
|
||||
public interface DltFrontendHistoryTopService extends IService<DltFrontendHistoryTop> {
|
||||
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
package com.xy.xyaicpzs.service;
|
||||
|
||||
import com.xy.xyaicpzs.domain.vo.BallPersistenceAnalysisVO;
|
||||
|
||||
/**
|
||||
* 大乐透持续性分析服务接口
|
||||
*/
|
||||
public interface DltPersistenceAnalysisService {
|
||||
|
||||
/**
|
||||
* 前区与前区的持续性分析
|
||||
* @param masterBall 主球号码(前区)
|
||||
* @param slaveBall 随球号码(前区)
|
||||
* @return 持续性分析结果
|
||||
*/
|
||||
BallPersistenceAnalysisVO analyzeFrontFrontPersistence(Integer masterBall, Integer slaveBall);
|
||||
|
||||
/**
|
||||
* 后区与后区的持续性分析
|
||||
* @param masterBall 主球号码(后区)
|
||||
* @param slaveBall 随球号码(后区)
|
||||
* @return 持续性分析结果
|
||||
*/
|
||||
BallPersistenceAnalysisVO analyzeBackBackPersistence(Integer masterBall, Integer slaveBall);
|
||||
|
||||
/**
|
||||
* 前区与后区的持续性分析
|
||||
* @param masterBall 主球号码(前区)
|
||||
* @param slaveBall 随球号码(后区)
|
||||
* @return 持续性分析结果
|
||||
*/
|
||||
BallPersistenceAnalysisVO analyzeFrontBackPersistence(Integer masterBall, Integer slaveBall);
|
||||
|
||||
/**
|
||||
* 后区与前区的持续性分析
|
||||
* @param masterBall 主球号码(后区)
|
||||
* @param slaveBall 随球号码(前区)
|
||||
* @return 持续性分析结果
|
||||
*/
|
||||
BallPersistenceAnalysisVO analyzeBackFrontPersistence(Integer masterBall, Integer slaveBall);
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
package com.xy.xyaicpzs.service;
|
||||
|
||||
import com.xy.xyaicpzs.domain.entity.DltPredictRecord;
|
||||
import com.baomidou.mybatisplus.extension.service.IService;
|
||||
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author XY003
|
||||
* @description 针对表【dlt_predict_record(大乐透推测记录表)】的数据库操作Service
|
||||
* @createDate 2025-09-08 14:01:12
|
||||
*/
|
||||
public interface DltPredictRecordService extends IService<DltPredictRecord> {
|
||||
|
||||
/**
|
||||
* 创建大乐透预测记录
|
||||
* @param userId 用户ID
|
||||
* @param drawId 开奖期号
|
||||
* @param drawDate 开奖日期
|
||||
* @param frontBalls 5个前区球号码
|
||||
* @param backBalls 2个后区球号码
|
||||
* @return 创建的预测记录
|
||||
*/
|
||||
DltPredictRecord createDltPredictRecord(Long userId, Long drawId, Date drawDate, List<Integer> frontBalls, List<Integer> backBalls);
|
||||
|
||||
/**
|
||||
* 根据用户ID分页获取大乐透预测记录
|
||||
* @param userId 用户ID
|
||||
* @param page 页码,从1开始
|
||||
* @param size 每页大小
|
||||
* @return 用户的大乐透预测记录列表,按预测时间倒序排列
|
||||
*/
|
||||
List<DltPredictRecord> getDltPredictRecordsByUserIdWithPaging(Long userId, Integer page, Integer size);
|
||||
|
||||
/**
|
||||
* 根据用户ID获取大乐透预测记录总数
|
||||
* @param userId 用户ID
|
||||
* @return 用户的大乐透预测记录总数
|
||||
*/
|
||||
Long getDltPredictRecordsCountByUserId(Long userId);
|
||||
|
||||
}
|
||||
@@ -1,9 +1,11 @@
|
||||
package com.xy.xyaicpzs.service;
|
||||
|
||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||
import com.baomidou.mybatisplus.extension.service.IService;
|
||||
import com.xy.xyaicpzs.domain.dto.user.UserPhoneLoginRequest;
|
||||
import com.xy.xyaicpzs.domain.dto.user.UserPhoneRegisterRequest;
|
||||
import com.xy.xyaicpzs.domain.entity.User;
|
||||
import com.xy.xyaicpzs.domain.vo.*;
|
||||
|
||||
import jakarta.servlet.http.HttpServletRequest;
|
||||
|
||||
@@ -96,4 +98,53 @@ public interface UserService extends IService<User> {
|
||||
* @return 加密后的密码
|
||||
*/
|
||||
String encryptPassword(String password);
|
||||
|
||||
// region 统计相关方法
|
||||
|
||||
/**
|
||||
* 根据时间段获取新增用户统计
|
||||
*
|
||||
* @param startDate 开始日期 (格式: yyyy-MM-dd)
|
||||
* @param endDate 结束日期 (格式: yyyy-MM-dd)
|
||||
* @return 新增用户统计数据
|
||||
*/
|
||||
UserStatisticsVO getNewUsersStatistics(String startDate, String endDate);
|
||||
|
||||
/**
|
||||
* 根据时间段获取新增会员统计
|
||||
*
|
||||
* @param startDate 开始日期 (格式: yyyy-MM-dd)
|
||||
* @param endDate 结束日期 (格式: yyyy-MM-dd)
|
||||
* @return 新增会员统计数据
|
||||
*/
|
||||
VipStatisticsVO getNewVipsStatistics(String startDate, String endDate);
|
||||
|
||||
/**
|
||||
* 根据时间段获取用户注册趋势
|
||||
*
|
||||
* @param startDate 开始日期 (格式: yyyy-MM-dd)
|
||||
* @param endDate 结束日期 (格式: yyyy-MM-dd)
|
||||
* @param granularity 时间粒度 (day/week/month)
|
||||
* @return 用户注册趋势数据
|
||||
*/
|
||||
RegistrationTrendVO getRegistrationTrend(String startDate, String endDate, String granularity);
|
||||
|
||||
/**
|
||||
* 获取即将到期的会员列表
|
||||
*
|
||||
* @param days 提前多少天提醒 (默认7天)
|
||||
* @param current 当前页
|
||||
* @param pageSize 页大小
|
||||
* @return 即将到期的会员列表
|
||||
*/
|
||||
Page<UserVO> getExpiringVips(Integer days, Long current, Long pageSize);
|
||||
|
||||
/**
|
||||
* 获取会员状态分布统计
|
||||
*
|
||||
* @return 会员状态分布数据
|
||||
*/
|
||||
VipDistributionVO getVipDistribution();
|
||||
|
||||
// endregion
|
||||
}
|
||||
|
||||
@@ -0,0 +1,22 @@
|
||||
package com.xy.xyaicpzs.service.impl;
|
||||
|
||||
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
||||
import com.xy.xyaicpzs.domain.entity.D10;
|
||||
import com.xy.xyaicpzs.service.D10Service;
|
||||
import com.xy.xyaicpzs.mapper.D10Mapper;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
/**
|
||||
* @author XY003
|
||||
* @description 针对表【d10(d10表)】的数据库操作Service实现
|
||||
* @createDate 2025-08-21 15:06:10
|
||||
*/
|
||||
@Service
|
||||
public class D10ServiceImpl extends ServiceImpl<D10Mapper, D10>
|
||||
implements D10Service{
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,22 @@
|
||||
package com.xy.xyaicpzs.service.impl;
|
||||
|
||||
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
||||
import com.xy.xyaicpzs.domain.entity.D11;
|
||||
import com.xy.xyaicpzs.service.D11Service;
|
||||
import com.xy.xyaicpzs.mapper.D11Mapper;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
/**
|
||||
* @author XY003
|
||||
* @description 针对表【d11(d11表)】的数据库操作Service实现
|
||||
* @createDate 2025-08-21 15:06:10
|
||||
*/
|
||||
@Service
|
||||
public class D11ServiceImpl extends ServiceImpl<D11Mapper, D11>
|
||||
implements D11Service{
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,22 @@
|
||||
package com.xy.xyaicpzs.service.impl;
|
||||
|
||||
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
||||
import com.xy.xyaicpzs.domain.entity.D12;
|
||||
import com.xy.xyaicpzs.service.D12Service;
|
||||
import com.xy.xyaicpzs.mapper.D12Mapper;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
/**
|
||||
* @author XY003
|
||||
* @description 针对表【d12(d12表)】的数据库操作Service实现
|
||||
* @createDate 2025-08-21 15:06:10
|
||||
*/
|
||||
@Service
|
||||
public class D12ServiceImpl extends ServiceImpl<D12Mapper, D12>
|
||||
implements D12Service{
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,17 @@
|
||||
package com.xy.xyaicpzs.service.impl;
|
||||
|
||||
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
||||
import com.xy.xyaicpzs.domain.entity.D5;
|
||||
import com.xy.xyaicpzs.service.D5Service;
|
||||
import com.xy.xyaicpzs.mapper.D5Mapper;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
/**
|
||||
* @author XY003
|
||||
* @description 针对表【d5(d5表)】的数据库操作Service实现
|
||||
* @createDate 2025-01-26 16:00:00
|
||||
*/
|
||||
@Service
|
||||
public class D5ServiceImpl extends ServiceImpl<D5Mapper, D5> implements D5Service {
|
||||
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
package com.xy.xyaicpzs.service.impl;
|
||||
|
||||
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
||||
import com.xy.xyaicpzs.domain.entity.D6;
|
||||
import com.xy.xyaicpzs.service.D6Service;
|
||||
import com.xy.xyaicpzs.mapper.D6Mapper;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
/**
|
||||
* @author XY003
|
||||
* @description 针对表【d6(d6表)】的数据库操作Service实现
|
||||
* @createDate 2025-08-21 14:10:22
|
||||
*/
|
||||
@Service
|
||||
public class D6ServiceImpl extends ServiceImpl<D6Mapper, D6>
|
||||
implements D6Service{
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,22 @@
|
||||
package com.xy.xyaicpzs.service.impl;
|
||||
|
||||
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
||||
import com.xy.xyaicpzs.domain.entity.D7;
|
||||
import com.xy.xyaicpzs.service.D7Service;
|
||||
import com.xy.xyaicpzs.mapper.D7Mapper;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
/**
|
||||
* @author XY003
|
||||
* @description 针对表【d7(d7表)】的数据库操作Service实现
|
||||
* @createDate 2025-08-21 15:06:10
|
||||
*/
|
||||
@Service
|
||||
public class D7ServiceImpl extends ServiceImpl<D7Mapper, D7>
|
||||
implements D7Service{
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,22 @@
|
||||
package com.xy.xyaicpzs.service.impl;
|
||||
|
||||
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
||||
import com.xy.xyaicpzs.domain.entity.D8;
|
||||
import com.xy.xyaicpzs.service.D8Service;
|
||||
import com.xy.xyaicpzs.mapper.D8Mapper;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
/**
|
||||
* @author XY003
|
||||
* @description 针对表【d8(d8表)】的数据库操作Service实现
|
||||
* @createDate 2025-08-21 15:06:10
|
||||
*/
|
||||
@Service
|
||||
public class D8ServiceImpl extends ServiceImpl<D8Mapper, D8>
|
||||
implements D8Service{
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,22 @@
|
||||
package com.xy.xyaicpzs.service.impl;
|
||||
|
||||
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
||||
import com.xy.xyaicpzs.domain.entity.D9;
|
||||
import com.xy.xyaicpzs.service.D9Service;
|
||||
import com.xy.xyaicpzs.mapper.D9Mapper;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
/**
|
||||
* @author XY003
|
||||
* @description 针对表【d9(d9表)】的数据库操作Service实现
|
||||
* @createDate 2025-08-21 15:06:10
|
||||
*/
|
||||
@Service
|
||||
public class D9ServiceImpl extends ServiceImpl<D9Mapper, D9>
|
||||
implements D9Service{
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -34,7 +34,8 @@ public class DataAnalysisServiceImpl implements DataAnalysisService {
|
||||
|
||||
// 查询用户的所有预测记录
|
||||
QueryWrapper<PredictRecord> queryWrapper = new QueryWrapper<>();
|
||||
queryWrapper.eq("userId", userId);
|
||||
queryWrapper.eq("userId", userId)
|
||||
.eq("type", "ssq");
|
||||
List<PredictRecord> predictRecords = predictRecordMapper.selectList(queryWrapper);
|
||||
|
||||
if (predictRecords == null || predictRecords.isEmpty()) {
|
||||
@@ -83,7 +84,8 @@ public class DataAnalysisServiceImpl implements DataAnalysisService {
|
||||
public int processPendingPredictions() {
|
||||
// 查询所有待开奖的预测记录
|
||||
QueryWrapper<PredictRecord> queryWrapper = new QueryWrapper<>();
|
||||
queryWrapper.eq("predictStatus", "待开奖");
|
||||
queryWrapper.eq("predictStatus", "待开奖")
|
||||
.eq("type", "ssq");
|
||||
List<PredictRecord> pendingRecords = predictRecordMapper.selectList(queryWrapper);
|
||||
|
||||
int processedCount = 0;
|
||||
@@ -129,6 +131,9 @@ public class DataAnalysisServiceImpl implements DataAnalysisService {
|
||||
queryWrapper.eq("predictStatus", request.getPredictStatus());
|
||||
}
|
||||
|
||||
// 添加类型筛选条件,只查询双色球类型
|
||||
queryWrapper.eq("type", "ssq");
|
||||
|
||||
// 按预测时间降序排序
|
||||
queryWrapper.orderByDesc("predictTime");
|
||||
|
||||
@@ -147,8 +152,10 @@ public class DataAnalysisServiceImpl implements DataAnalysisService {
|
||||
|
||||
@Override
|
||||
public long getTotalPredictCount() {
|
||||
// 获取全部预测记录数量
|
||||
return predictRecordMapper.selectCount(null);
|
||||
// 获取全部预测记录数量(只统计双色球类型)
|
||||
QueryWrapper<PredictRecord> queryWrapper = new QueryWrapper<>();
|
||||
queryWrapper.eq("type", "ssq");
|
||||
return predictRecordMapper.selectCount(queryWrapper);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -0,0 +1,22 @@
|
||||
package com.xy.xyaicpzs.service.impl;
|
||||
|
||||
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
||||
import com.xy.xyaicpzs.domain.entity.DltBackendHistory100;
|
||||
import com.xy.xyaicpzs.service.DltBackendHistory100Service;
|
||||
import com.xy.xyaicpzs.mapper.DltBackendHistory100Mapper;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
/**
|
||||
* @author XY003
|
||||
* @description 针对表【dlt_backend_history_100(大乐透后区最近100期数据表)】的数据库操作Service实现
|
||||
* @createDate 2025-08-21 11:35:47
|
||||
*/
|
||||
@Service
|
||||
public class DltBackendHistory100ServiceImpl extends ServiceImpl<DltBackendHistory100Mapper, DltBackendHistory100>
|
||||
implements DltBackendHistory100Service{
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,22 @@
|
||||
package com.xy.xyaicpzs.service.impl;
|
||||
|
||||
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
||||
import com.xy.xyaicpzs.domain.entity.DltBackendHistoryAll;
|
||||
import com.xy.xyaicpzs.service.DltBackendHistoryAllService;
|
||||
import com.xy.xyaicpzs.mapper.DltBackendHistoryAllMapper;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
/**
|
||||
* @author XY003
|
||||
* @description 针对表【dlt_backend_history_all(大乐透后区全部历史数据表)】的数据库操作Service实现
|
||||
* @createDate 2025-08-21 11:35:47
|
||||
*/
|
||||
@Service
|
||||
public class DltBackendHistoryAllServiceImpl extends ServiceImpl<DltBackendHistoryAllMapper, DltBackendHistoryAll>
|
||||
implements DltBackendHistoryAllService{
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,22 @@
|
||||
package com.xy.xyaicpzs.service.impl;
|
||||
|
||||
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
||||
import com.xy.xyaicpzs.domain.entity.DltBackendHistoryTop100;
|
||||
import com.xy.xyaicpzs.service.DltBackendHistoryTop100Service;
|
||||
import com.xy.xyaicpzs.mapper.DltBackendHistoryTop100Mapper;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
/**
|
||||
* @author XY003
|
||||
* @description 针对表【dlt_backend_history_top_100(大乐透后区百期数据排行表)】的数据库操作Service实现
|
||||
* @createDate 2025-08-21 11:35:47
|
||||
*/
|
||||
@Service
|
||||
public class DltBackendHistoryTop100ServiceImpl extends ServiceImpl<DltBackendHistoryTop100Mapper, DltBackendHistoryTop100>
|
||||
implements DltBackendHistoryTop100Service{
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,22 @@
|
||||
package com.xy.xyaicpzs.service.impl;
|
||||
|
||||
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
||||
import com.xy.xyaicpzs.domain.entity.DltBackendHistoryTop;
|
||||
import com.xy.xyaicpzs.service.DltBackendHistoryTopService;
|
||||
import com.xy.xyaicpzs.mapper.DltBackendHistoryTopMapper;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
/**
|
||||
* @author XY003
|
||||
* @description 针对表【dlt_backend_history_top(大乐透后区历史数据排行表)】的数据库操作Service实现
|
||||
* @createDate 2025-08-21 11:35:47
|
||||
*/
|
||||
@Service
|
||||
public class DltBackendHistoryTopServiceImpl extends ServiceImpl<DltBackendHistoryTopMapper, DltBackendHistoryTop>
|
||||
implements DltBackendHistoryTopService{
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,251 @@
|
||||
package com.xy.xyaicpzs.service.impl;
|
||||
|
||||
import com.xy.xyaicpzs.domain.entity.DltDrawRecord;
|
||||
import com.xy.xyaicpzs.domain.entity.D5;
|
||||
import com.xy.xyaicpzs.domain.entity.D6;
|
||||
import com.xy.xyaicpzs.domain.entity.D7;
|
||||
import com.xy.xyaicpzs.domain.entity.D8;
|
||||
import com.xy.xyaicpzs.domain.vo.BallCombinationAnalysisVO;
|
||||
import com.xy.xyaicpzs.service.DltCombinationAnalysisService;
|
||||
import com.xy.xyaicpzs.service.DltDrawRecordService;
|
||||
import com.xy.xyaicpzs.service.D5Service;
|
||||
import com.xy.xyaicpzs.service.D6Service;
|
||||
import com.xy.xyaicpzs.service.D7Service;
|
||||
import com.xy.xyaicpzs.service.D8Service;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.util.Comparator;
|
||||
import java.util.List;
|
||||
import java.util.function.Function;
|
||||
|
||||
/**
|
||||
* 大乐透组合分析服务实现类
|
||||
*/
|
||||
@Slf4j
|
||||
@Service
|
||||
public class DltCombinationAnalysisServiceImpl implements DltCombinationAnalysisService {
|
||||
|
||||
@Autowired
|
||||
private D5Service d5Service;
|
||||
|
||||
@Autowired
|
||||
private D6Service d6Service;
|
||||
|
||||
@Autowired
|
||||
private D7Service d7Service;
|
||||
|
||||
@Autowired
|
||||
private D8Service d8Service;
|
||||
|
||||
@Autowired
|
||||
private DltDrawRecordService dltDrawRecordService;
|
||||
|
||||
@Override
|
||||
public BallCombinationAnalysisVO analyzeFrontFrontCombination(Integer masterBall, Integer slaveBall) {
|
||||
// 参数校验
|
||||
validateBallRange(masterBall, 1, 35, "主球(前区)");
|
||||
validateBallRange(slaveBall, 1, 35, "随球(前区)");
|
||||
|
||||
// 查询指定组合记录
|
||||
D5 targetRecord = d5Service.lambdaQuery()
|
||||
.eq(D5::getMasterBallNumber, masterBall)
|
||||
.eq(D5::getSlaveBallNumber, slaveBall)
|
||||
.one();
|
||||
|
||||
if (targetRecord == null) {
|
||||
throw new RuntimeException(String.format("未找到主球(前区)%d和随球(前区)%d的组合记录", masterBall, slaveBall));
|
||||
}
|
||||
|
||||
// 查询主球与所有其他球的组合记录
|
||||
List<D5> allCombinations = d5Service.lambdaQuery()
|
||||
.eq(D5::getMasterBallNumber, masterBall)
|
||||
.ne(D5::getSlaveBallNumber, masterBall) // 排除自身
|
||||
.list();
|
||||
|
||||
if (allCombinations.isEmpty()) {
|
||||
throw new RuntimeException(String.format("未找到主球(前区)%d的组合记录", masterBall));
|
||||
}
|
||||
|
||||
return buildCombinationAnalysisVO(
|
||||
targetRecord.getCoefficient(),
|
||||
allCombinations,
|
||||
D5::getCoefficient,
|
||||
D5::getSlaveBallNumber
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
public BallCombinationAnalysisVO analyzeFrontBackCombination(Integer masterBall, Integer slaveBall) {
|
||||
// 参数校验
|
||||
validateBallRange(masterBall, 1, 35, "主球(前区)");
|
||||
validateBallRange(slaveBall, 1, 12, "随球(后区)");
|
||||
|
||||
// 查询指定组合记录
|
||||
D6 targetRecord = d6Service.lambdaQuery()
|
||||
.eq(D6::getMasterBallNumber, masterBall)
|
||||
.eq(D6::getSlaveBallNumber, slaveBall)
|
||||
.one();
|
||||
|
||||
if (targetRecord == null) {
|
||||
throw new RuntimeException(String.format("未找到主球(前区)%d和随球(后区)%d的组合记录", masterBall, slaveBall));
|
||||
}
|
||||
|
||||
// 查询主球与所有其他球的组合记录
|
||||
List<D6> allCombinations = d6Service.lambdaQuery()
|
||||
.eq(D6::getMasterBallNumber, masterBall)
|
||||
.list();
|
||||
|
||||
if (allCombinations.isEmpty()) {
|
||||
throw new RuntimeException(String.format("未找到主球(前区)%d的组合记录", masterBall));
|
||||
}
|
||||
|
||||
return buildCombinationAnalysisVO(
|
||||
targetRecord.getCoefficient(),
|
||||
allCombinations,
|
||||
D6::getCoefficient,
|
||||
D6::getSlaveBallNumber
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
public BallCombinationAnalysisVO analyzeBackBackCombination(Integer masterBall, Integer slaveBall) {
|
||||
// 参数校验
|
||||
validateBallRange(masterBall, 1, 12, "主球(后区)");
|
||||
validateBallRange(slaveBall, 1, 12, "随球(后区)");
|
||||
|
||||
// 查询指定组合记录
|
||||
D7 targetRecord = d7Service.lambdaQuery()
|
||||
.eq(D7::getMasterBallNumber, masterBall)
|
||||
.eq(D7::getSlaveBallNumber, slaveBall)
|
||||
.one();
|
||||
|
||||
if (targetRecord == null) {
|
||||
throw new RuntimeException(String.format("未找到主球(后区)%d和随球(后区)%d的组合记录", masterBall, slaveBall));
|
||||
}
|
||||
|
||||
// 查询主球与所有其他球的组合记录
|
||||
List<D7> allCombinations = d7Service.lambdaQuery()
|
||||
.eq(D7::getMasterBallNumber, masterBall)
|
||||
.ne(D7::getSlaveBallNumber, masterBall) // 排除自身
|
||||
.list();
|
||||
|
||||
if (allCombinations.isEmpty()) {
|
||||
throw new RuntimeException(String.format("未找到主球(后区)%d的组合记录", masterBall));
|
||||
}
|
||||
|
||||
return buildCombinationAnalysisVO(
|
||||
targetRecord.getCoefficient(),
|
||||
allCombinations,
|
||||
D7::getCoefficient,
|
||||
D7::getSlaveBallNumber
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
public BallCombinationAnalysisVO analyzeBackFrontCombination(Integer masterBall, Integer slaveBall) {
|
||||
// 参数校验
|
||||
validateBallRange(masterBall, 1, 12, "主球(后区)");
|
||||
validateBallRange(slaveBall, 1, 35, "随球(前区)");
|
||||
|
||||
// 查询指定组合记录
|
||||
D8 targetRecord = d8Service.lambdaQuery()
|
||||
.eq(D8::getMasterBallNumber, masterBall)
|
||||
.eq(D8::getSlaveBallNumber, slaveBall)
|
||||
.one();
|
||||
|
||||
if (targetRecord == null) {
|
||||
throw new RuntimeException(String.format("未找到主球(后区)%d和随球(前区)%d的组合记录", masterBall, slaveBall));
|
||||
}
|
||||
|
||||
// 查询主球与所有其他球的组合记录
|
||||
List<D8> allCombinations = d8Service.lambdaQuery()
|
||||
.eq(D8::getMasterBallNumber, masterBall)
|
||||
.list();
|
||||
|
||||
if (allCombinations.isEmpty()) {
|
||||
throw new RuntimeException(String.format("未找到主球(后区)%d的组合记录", masterBall));
|
||||
}
|
||||
|
||||
return buildCombinationAnalysisVO(
|
||||
targetRecord.getCoefficient(),
|
||||
allCombinations,
|
||||
D8::getCoefficient,
|
||||
D8::getSlaveBallNumber
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* 验证球号范围
|
||||
*/
|
||||
private void validateBallRange(Integer ballNumber, int minValue, int maxValue, String ballType) {
|
||||
if (ballNumber == null) {
|
||||
throw new IllegalArgumentException(ballType + "号码不能为空");
|
||||
}
|
||||
if (ballNumber < minValue || ballNumber > maxValue) {
|
||||
throw new IllegalArgumentException(String.format("%s号码必须在%d-%d范围内,错误值:%d",
|
||||
ballType, minValue, maxValue, ballNumber));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 构建组合分析结果VO
|
||||
*/
|
||||
private <T> BallCombinationAnalysisVO buildCombinationAnalysisVO(
|
||||
Double targetCoefficient,
|
||||
List<T> allCombinations,
|
||||
Function<T, Double> coefficientGetter,
|
||||
Function<T, Integer> ballNumberGetter) {
|
||||
|
||||
// 找出系数最高的球号
|
||||
T highest = allCombinations.stream()
|
||||
.max(Comparator.comparing(coefficientGetter))
|
||||
.orElse(null);
|
||||
|
||||
// 找出系数最低的球号
|
||||
T lowest = allCombinations.stream()
|
||||
.min(Comparator.comparing(coefficientGetter))
|
||||
.orElse(null);
|
||||
|
||||
// 计算平均系数
|
||||
double avgCoefficient = allCombinations.stream()
|
||||
.mapToDouble(coefficientGetter::apply)
|
||||
.average()
|
||||
.orElse(0.0);
|
||||
|
||||
// 获取最新开奖期号
|
||||
Long latestDrawId = getLatestDrawId();
|
||||
|
||||
return BallCombinationAnalysisVO.builder()
|
||||
.faceCoefficient(targetCoefficient)
|
||||
.highestBall(highest != null ? ballNumberGetter.apply(highest) : null)
|
||||
.highestCoefficient(highest != null ? coefficientGetter.apply(highest) : null)
|
||||
.lowestBall(lowest != null ? ballNumberGetter.apply(lowest) : null)
|
||||
.lowestCoefficient(lowest != null ? coefficientGetter.apply(lowest) : null)
|
||||
.averageCoefficient(avgCoefficient)
|
||||
.latestDrawId(latestDrawId)
|
||||
.build();
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取最新开奖期号
|
||||
*/
|
||||
private Long getLatestDrawId() {
|
||||
String latestDrawId = dltDrawRecordService.lambdaQuery()
|
||||
.orderByDesc(DltDrawRecord::getDrawId)
|
||||
.last("LIMIT 1")
|
||||
.oneOpt()
|
||||
.map(DltDrawRecord::getDrawId)
|
||||
.orElse(null);
|
||||
|
||||
if (latestDrawId != null) {
|
||||
try {
|
||||
return Long.parseLong(latestDrawId);
|
||||
} catch (NumberFormatException e) {
|
||||
log.warn("开奖期号格式转换失败:{}", latestDrawId);
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,485 @@
|
||||
package com.xy.xyaicpzs.service.impl;
|
||||
|
||||
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
|
||||
import com.xy.xyaicpzs.domain.entity.DltDrawRecord;
|
||||
import com.xy.xyaicpzs.domain.entity.DltPredictRecord;
|
||||
import com.xy.xyaicpzs.mapper.DltDrawRecordMapper;
|
||||
import com.xy.xyaicpzs.mapper.DltPredictRecordMapper;
|
||||
import com.xy.xyaicpzs.domain.vo.PrizeEstimateVO;
|
||||
import com.xy.xyaicpzs.domain.vo.RedBallHitRateVO;
|
||||
import com.xy.xyaicpzs.domain.vo.UserPredictStatVO;
|
||||
import com.xy.xyaicpzs.service.DltDataAnalysisService;
|
||||
import com.xy.xyaicpzs.service.DltDrawRecordService;
|
||||
import com.xy.xyaicpzs.util.DltPrizeCalculator;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.math.RoundingMode;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* 大乐透数据分析服务实现类
|
||||
*/
|
||||
@Slf4j
|
||||
@Service
|
||||
public class DltDataAnalysisServiceImpl implements DltDataAnalysisService {
|
||||
|
||||
@Autowired
|
||||
private DltPredictRecordMapper dltPredictRecordMapper;
|
||||
|
||||
@Autowired
|
||||
private DltDrawRecordMapper dltDrawRecordMapper;
|
||||
|
||||
@Autowired
|
||||
private DltDrawRecordService dltDrawRecordService;
|
||||
|
||||
@Override
|
||||
public int processPendingDltPredictions() {
|
||||
log.info("开始处理大乐透待开奖预测记录");
|
||||
|
||||
// 查询所有待开奖的大乐透预测记录
|
||||
QueryWrapper<DltPredictRecord> queryWrapper = new QueryWrapper<>();
|
||||
queryWrapper.eq("predictStatus", "待开奖");
|
||||
List<DltPredictRecord> pendingRecords = dltPredictRecordMapper.selectList(queryWrapper);
|
||||
|
||||
log.info("找到{}条待开奖的大乐透预测记录", pendingRecords.size());
|
||||
|
||||
int processedCount = 0;
|
||||
|
||||
for (DltPredictRecord record : pendingRecords) {
|
||||
try {
|
||||
// 查询对应期号的开奖结果
|
||||
// 注意:DltDrawRecord的drawId是String类型,DltPredictRecord的drawId是Long类型
|
||||
QueryWrapper<DltDrawRecord> drawQueryWrapper = new QueryWrapper<>();
|
||||
drawQueryWrapper.eq("drawId", String.valueOf(record.getDrawId()));
|
||||
DltDrawRecord drawRecord = dltDrawRecordMapper.selectOne(drawQueryWrapper);
|
||||
|
||||
if (drawRecord != null) {
|
||||
log.debug("处理预测记录ID:{},期号:{}", record.getId(), record.getDrawId());
|
||||
|
||||
// 构建预测号码数组 [前区5个号码, 后区2个号码]
|
||||
Integer[] predictNumbers = {
|
||||
record.getFrontendBall1(),
|
||||
record.getFrontendBall2(),
|
||||
record.getFrontendBall3(),
|
||||
record.getFrontendBall4(),
|
||||
record.getFrontendBall5(),
|
||||
record.getBackendBall1(),
|
||||
record.getBackendBall2()
|
||||
};
|
||||
|
||||
// 构建开奖号码数组 [前区5个号码, 后区2个号码]
|
||||
Integer[] drawNumbers = {
|
||||
drawRecord.getFrontBall1(),
|
||||
drawRecord.getFrontBall2(),
|
||||
drawRecord.getFrontBall3(),
|
||||
drawRecord.getFrontBall4(),
|
||||
drawRecord.getFrontBall5(),
|
||||
drawRecord.getBackBall1(),
|
||||
drawRecord.getBackBall2()
|
||||
};
|
||||
|
||||
// 使用DltPrizeCalculator计算中奖结果
|
||||
DltPrizeCalculator.PrizeResult prizeResult = DltPrizeCalculator.calculatePrize(predictNumbers, drawNumbers);
|
||||
|
||||
// 更新预测记录
|
||||
// 根据中奖结果设置状态
|
||||
if(prizeResult.getPrizeLevel().equals("未中奖")){
|
||||
record.setPredictStatus("未中奖");
|
||||
}else{
|
||||
record.setPredictStatus("已中奖");
|
||||
}
|
||||
record.setPredictResult(prizeResult.getPrizeLevel());
|
||||
record.setBonus(prizeResult.getBonus());
|
||||
|
||||
dltPredictRecordMapper.updateById(record);
|
||||
|
||||
log.debug("预测记录ID:{} 处理完成,中奖等级:{},奖金:{}",
|
||||
record.getId(), prizeResult.getPrizeLevel(), prizeResult.getBonus());
|
||||
|
||||
processedCount++;
|
||||
} else {
|
||||
log.debug("未找到期号{}的开奖记录", record.getDrawId());
|
||||
}
|
||||
} catch (Exception e) {
|
||||
log.error("处理预测记录ID:{} 时发生错误:{}", record.getId(), e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
|
||||
log.info("大乐透待开奖预测记录处理完成,共处理{}条记录", processedCount);
|
||||
return processedCount;
|
||||
}
|
||||
|
||||
@Override
|
||||
public UserPredictStatVO getUserDltPredictStat(Long userId) {
|
||||
log.info("开始获取用户{}的大乐透预测统计数据", userId);
|
||||
|
||||
UserPredictStatVO statVO = new UserPredictStatVO();
|
||||
|
||||
// 查询用户的所有大乐透预测记录
|
||||
QueryWrapper<DltPredictRecord> queryWrapper = new QueryWrapper<>();
|
||||
queryWrapper.eq("userId", userId);
|
||||
List<DltPredictRecord> predictRecords = dltPredictRecordMapper.selectList(queryWrapper);
|
||||
|
||||
if (predictRecords == null || predictRecords.isEmpty()) {
|
||||
log.info("用户{}没有大乐透预测记录", userId);
|
||||
statVO.setUserId(userId);
|
||||
statVO.setPredictCount(0L);
|
||||
statVO.setHitCount(0L);
|
||||
statVO.setPendingCount(0L);
|
||||
statVO.setDrawnCount(0L);
|
||||
statVO.setHitRate(BigDecimal.ZERO);
|
||||
return statVO;
|
||||
}
|
||||
|
||||
// 统计数据
|
||||
long totalPredicts = predictRecords.size();
|
||||
long hitCount = 0L;
|
||||
long pendingCount = 0L;
|
||||
long drawnCount = 0L;
|
||||
|
||||
for (DltPredictRecord record : predictRecords) {
|
||||
if ("待开奖".equals(record.getPredictStatus())) {
|
||||
pendingCount++;
|
||||
} else if ("已开奖".equals(record.getPredictStatus())) {
|
||||
drawnCount++;
|
||||
// 检查是否中奖(除了"未中奖"都算中奖)
|
||||
if (!"未中奖".equals(record.getPredictResult()) &&
|
||||
record.getPredictResult() != null &&
|
||||
!record.getPredictResult().trim().isEmpty()) {
|
||||
hitCount++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 计算命中率
|
||||
BigDecimal hitRate = drawnCount > 0 ?
|
||||
BigDecimal.valueOf(hitCount).divide(BigDecimal.valueOf(drawnCount), 4, RoundingMode.HALF_UP) :
|
||||
BigDecimal.ZERO;
|
||||
|
||||
statVO.setUserId(userId);
|
||||
statVO.setPredictCount(totalPredicts);
|
||||
statVO.setHitCount(hitCount);
|
||||
statVO.setPendingCount(pendingCount);
|
||||
statVO.setDrawnCount(drawnCount);
|
||||
statVO.setHitRate(hitRate);
|
||||
|
||||
log.info("用户{}大乐透预测统计数据:预测次数={},待开奖次数={},已开奖次数={},命中次数={},命中率={}",
|
||||
userId, totalPredicts, pendingCount, drawnCount, hitCount, hitRate);
|
||||
|
||||
return statVO;
|
||||
}
|
||||
|
||||
@Override
|
||||
public PrizeEstimateVO getDltPrizeStatistics(Long userId, Long predictId) {
|
||||
log.info("开始为用户{}进行大乐透奖金统计,predictId={}", userId, predictId);
|
||||
|
||||
// 查询条件
|
||||
QueryWrapper<DltPredictRecord> queryWrapper = new QueryWrapper<>();
|
||||
queryWrapper.eq("userId", userId);
|
||||
// 排除待开奖状态
|
||||
queryWrapper.eq("predictStatus", "已开奖");
|
||||
// 如果指定了预测记录ID,则只查询该记录
|
||||
if (predictId != null) {
|
||||
queryWrapper.eq("id", predictId);
|
||||
}
|
||||
|
||||
// 查询用户的大乐透预测记录
|
||||
List<DltPredictRecord> records = dltPredictRecordMapper.selectList(queryWrapper);
|
||||
|
||||
// 按中奖等级分组统计
|
||||
Map<String, Integer> countByPrizeLevel = new HashMap<>();
|
||||
Map<String, BigDecimal> totalBonusByPrizeLevel = new HashMap<>();
|
||||
|
||||
// 初始化大乐透的所有等级
|
||||
String[] prizeLevels = {"一等奖", "二等奖", "三等奖", "四等奖", "五等奖", "六等奖", "七等奖", "八等奖", "九等奖", "未中奖"};
|
||||
for (String level : prizeLevels) {
|
||||
countByPrizeLevel.put(level, 0);
|
||||
totalBonusByPrizeLevel.put(level, BigDecimal.ZERO);
|
||||
}
|
||||
|
||||
// 统计各等级数量和奖金
|
||||
for (DltPredictRecord record : records) {
|
||||
String prizeLevel = record.getPredictResult();
|
||||
if (prizeLevel == null || prizeLevel.trim().isEmpty()) {
|
||||
prizeLevel = "未中奖";
|
||||
}
|
||||
|
||||
// 更新计数
|
||||
countByPrizeLevel.put(prizeLevel, countByPrizeLevel.getOrDefault(prizeLevel, 0) + 1);
|
||||
|
||||
// 累计奖金
|
||||
if (record.getBonus() != null) {
|
||||
BigDecimal bonus = new BigDecimal(record.getBonus().toString());
|
||||
totalBonusByPrizeLevel.put(prizeLevel,
|
||||
totalBonusByPrizeLevel.getOrDefault(prizeLevel, BigDecimal.ZERO).add(bonus));
|
||||
}
|
||||
}
|
||||
|
||||
// 构建返回结果
|
||||
List<PrizeEstimateVO.PrizeDetailItem> prizeDetails = new ArrayList<>();
|
||||
|
||||
// 按顺序添加各等级的统计结果(从高到低)
|
||||
for (String level : prizeLevels) {
|
||||
// 跳过没有记录的等级
|
||||
if (countByPrizeLevel.get(level) <= 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
int count = countByPrizeLevel.get(level);
|
||||
BigDecimal totalBonus = totalBonusByPrizeLevel.get(level);
|
||||
BigDecimal singlePrize = BigDecimal.ZERO;
|
||||
if (count > 0 && totalBonus.compareTo(BigDecimal.ZERO) > 0) {
|
||||
singlePrize = totalBonus.divide(new BigDecimal(count), 2, RoundingMode.HALF_UP);
|
||||
}
|
||||
|
||||
prizeDetails.add(PrizeEstimateVO.PrizeDetailItem.builder()
|
||||
.prizeLevel(level)
|
||||
.winningCount(count)
|
||||
.singlePrize(singlePrize)
|
||||
.subtotal(totalBonus)
|
||||
.build());
|
||||
}
|
||||
|
||||
// 计算总奖金
|
||||
BigDecimal totalPrize = prizeDetails.stream()
|
||||
.map(PrizeEstimateVO.PrizeDetailItem::getSubtotal)
|
||||
.reduce(BigDecimal.ZERO, BigDecimal::add);
|
||||
|
||||
PrizeEstimateVO result = PrizeEstimateVO.builder()
|
||||
.totalPrize(totalPrize)
|
||||
.prizeDetails(prizeDetails)
|
||||
.build();
|
||||
|
||||
log.info("用户{}的大乐透奖金统计结果:总奖金{},各等级明细数量:{}",
|
||||
userId, totalPrize, prizeDetails.size());
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public RedBallHitRateVO getFrontFirstBallHitRate(Long userId) {
|
||||
log.info("开始统计用户{}的大乐透前区首球命中率", userId);
|
||||
|
||||
// 查询用户的所有预测记录(除了"待开奖"状态的)
|
||||
QueryWrapper<DltPredictRecord> queryWrapper = new QueryWrapper<>();
|
||||
queryWrapper.eq("userId", userId)
|
||||
.eq("predictStatus", "已开奖");
|
||||
|
||||
List<DltPredictRecord> predictRecords = dltPredictRecordMapper.selectList(queryWrapper);
|
||||
|
||||
// 总预测次数
|
||||
int totalCount = predictRecords.size();
|
||||
|
||||
// 统计前区首球命中次数
|
||||
int hitCount = 0;
|
||||
|
||||
for (DltPredictRecord record : predictRecords) {
|
||||
// 获取该预测记录对应的开奖信息
|
||||
DltDrawRecord draw = dltDrawRecordService.lambdaQuery()
|
||||
.eq(DltDrawRecord::getDrawId, String.valueOf(record.getDrawId()))
|
||||
.one();
|
||||
|
||||
if (draw != null && record.getFrontendBall1() != null) {
|
||||
Integer predictedFirstBall = record.getFrontendBall1();
|
||||
List<Integer> drawnFrontBalls = Arrays.asList(
|
||||
draw.getFrontBall1(),
|
||||
draw.getFrontBall2(),
|
||||
draw.getFrontBall3(),
|
||||
draw.getFrontBall4(),
|
||||
draw.getFrontBall5()
|
||||
);
|
||||
// 比较预测的第一个前区球是否在开奖的五个前区球中
|
||||
if (drawnFrontBalls.contains(predictedFirstBall)) {
|
||||
hitCount++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 计算命中率
|
||||
double hitRate = totalCount > 0 ? (double) hitCount / totalCount * 100 : 0;
|
||||
|
||||
RedBallHitRateVO result = RedBallHitRateVO.builder()
|
||||
.totalHitCount(hitCount)
|
||||
.totalPredictedCount(totalCount)
|
||||
.hitRate(hitRate)
|
||||
.build();
|
||||
|
||||
log.info("用户{}的大乐透前区首球命中率统计结果:命中{}次,总计{}次,命中率{}%",
|
||||
userId, hitCount, totalCount, String.format("%.2f", hitRate));
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public RedBallHitRateVO getFrontBallHitRate(Long userId) {
|
||||
log.info("开始统计用户{}的大乐透前区球号命中率", userId);
|
||||
|
||||
// 查询用户的所有预测记录(除了"待开奖"状态的)
|
||||
QueryWrapper<DltPredictRecord> queryWrapper = new QueryWrapper<>();
|
||||
queryWrapper.eq("userId", userId)
|
||||
.eq("predictStatus", "已开奖");
|
||||
|
||||
List<DltPredictRecord> predictRecords = dltPredictRecordMapper.selectList(queryWrapper);
|
||||
|
||||
int totalHitCount = 0;
|
||||
int totalRecords = predictRecords.size();
|
||||
|
||||
for (DltPredictRecord record : predictRecords) {
|
||||
// 获取该预测记录对应的开奖信息
|
||||
DltDrawRecord draw = dltDrawRecordService.lambdaQuery()
|
||||
.eq(DltDrawRecord::getDrawId, String.valueOf(record.getDrawId()))
|
||||
.one();
|
||||
|
||||
if (draw != null) {
|
||||
List<Integer> predictedFrontBalls = Arrays.asList(
|
||||
record.getFrontendBall1(),
|
||||
record.getFrontendBall2(),
|
||||
record.getFrontendBall3(),
|
||||
record.getFrontendBall4(),
|
||||
record.getFrontendBall5()
|
||||
);
|
||||
|
||||
List<Integer> drawnFrontBalls = Arrays.asList(
|
||||
draw.getFrontBall1(),
|
||||
draw.getFrontBall2(),
|
||||
draw.getFrontBall3(),
|
||||
draw.getFrontBall4(),
|
||||
draw.getFrontBall5()
|
||||
);
|
||||
|
||||
// 计算当前记录命中的前区球数
|
||||
for (Integer predictedBall : predictedFrontBalls) {
|
||||
if (predictedBall != null && drawnFrontBalls.contains(predictedBall)) {
|
||||
totalHitCount++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int totalPredictedCount = totalRecords * 5; // 每条记录预测5个前区球
|
||||
double hitRate = (totalPredictedCount > 0) ? ((double) totalHitCount / totalPredictedCount) * 100 : 0;
|
||||
|
||||
RedBallHitRateVO result = RedBallHitRateVO.builder()
|
||||
.totalHitCount(totalHitCount)
|
||||
.totalPredictedCount(totalPredictedCount)
|
||||
.hitRate(hitRate)
|
||||
.build();
|
||||
|
||||
log.info("用户{}的大乐透前区球号命中率统计结果:命中总数{},预测总数{},命中率{}%",
|
||||
userId, totalHitCount, totalPredictedCount, String.format("%.2f", hitRate));
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public RedBallHitRateVO getBackFirstBallHitRate(Long userId) {
|
||||
log.info("开始统计用户{}的大乐透后区首球命中率", userId);
|
||||
|
||||
// 查询用户的所有预测记录(除了"待开奖"状态的)
|
||||
QueryWrapper<DltPredictRecord> queryWrapper = new QueryWrapper<>();
|
||||
queryWrapper.eq("userId", userId)
|
||||
.eq("predictStatus", "已开奖");
|
||||
|
||||
List<DltPredictRecord> predictRecords = dltPredictRecordMapper.selectList(queryWrapper);
|
||||
|
||||
// 总预测次数
|
||||
int totalCount = predictRecords.size();
|
||||
|
||||
// 统计后区首球命中次数
|
||||
int hitCount = 0;
|
||||
|
||||
for (DltPredictRecord record : predictRecords) {
|
||||
// 获取该预测记录对应的开奖信息
|
||||
DltDrawRecord draw = dltDrawRecordService.lambdaQuery()
|
||||
.eq(DltDrawRecord::getDrawId, String.valueOf(record.getDrawId()))
|
||||
.one();
|
||||
|
||||
if (draw != null && record.getBackendBall1() != null) {
|
||||
Integer predictedFirstBackBall = record.getBackendBall1();
|
||||
List<Integer> drawnBackBalls = Arrays.asList(
|
||||
draw.getBackBall1(),
|
||||
draw.getBackBall2()
|
||||
);
|
||||
// 比较预测的第一个后区球是否在开奖的两个后区球中
|
||||
if (drawnBackBalls.contains(predictedFirstBackBall)) {
|
||||
hitCount++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 计算命中率
|
||||
double hitRate = totalCount > 0 ? (double) hitCount / totalCount * 100 : 0;
|
||||
|
||||
RedBallHitRateVO result = RedBallHitRateVO.builder()
|
||||
.totalHitCount(hitCount)
|
||||
.totalPredictedCount(totalCount)
|
||||
.hitRate(hitRate)
|
||||
.build();
|
||||
|
||||
log.info("用户{}的大乐透后区首球命中率统计结果:命中{}次,总计{}次,命中率{}%",
|
||||
userId, hitCount, totalCount, String.format("%.2f", hitRate));
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public RedBallHitRateVO getBackBallHitRate(Long userId) {
|
||||
log.info("开始统计用户{}的大乐透后区球号命中率", userId);
|
||||
|
||||
// 查询用户的所有预测记录(除了"待开奖"状态的)
|
||||
QueryWrapper<DltPredictRecord> queryWrapper = new QueryWrapper<>();
|
||||
queryWrapper.eq("userId", userId)
|
||||
.eq("predictStatus", "已开奖");
|
||||
|
||||
List<DltPredictRecord> predictRecords = dltPredictRecordMapper.selectList(queryWrapper);
|
||||
|
||||
int totalHitCount = 0;
|
||||
int totalRecords = predictRecords.size();
|
||||
|
||||
for (DltPredictRecord record : predictRecords) {
|
||||
// 获取该预测记录对应的开奖信息
|
||||
DltDrawRecord draw = dltDrawRecordService.lambdaQuery()
|
||||
.eq(DltDrawRecord::getDrawId, String.valueOf(record.getDrawId()))
|
||||
.one();
|
||||
|
||||
if (draw != null) {
|
||||
List<Integer> predictedBackBalls = Arrays.asList(
|
||||
record.getBackendBall1(),
|
||||
record.getBackendBall2()
|
||||
);
|
||||
|
||||
List<Integer> drawnBackBalls = Arrays.asList(
|
||||
draw.getBackBall1(),
|
||||
draw.getBackBall2()
|
||||
);
|
||||
|
||||
// 计算当前记录命中的后区球数
|
||||
for (Integer predictedBall : predictedBackBalls) {
|
||||
if (predictedBall != null && drawnBackBalls.contains(predictedBall)) {
|
||||
totalHitCount++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int totalPredictedCount = totalRecords * 2; // 每条记录预测2个后区球
|
||||
double hitRate = (totalPredictedCount > 0) ? ((double) totalHitCount / totalPredictedCount) * 100 : 0;
|
||||
|
||||
RedBallHitRateVO result = RedBallHitRateVO.builder()
|
||||
.totalHitCount(totalHitCount)
|
||||
.totalPredictedCount(totalPredictedCount)
|
||||
.hitRate(hitRate)
|
||||
.build();
|
||||
|
||||
log.info("用户{}的大乐透后区球号命中率统计结果:命中总数{},预测总数{},命中率{}%",
|
||||
userId, totalHitCount, totalPredictedCount, String.format("%.2f", hitRate));
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
package com.xy.xyaicpzs.service.impl;
|
||||
|
||||
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
||||
import com.xy.xyaicpzs.domain.entity.DltDrawRecord;
|
||||
import com.xy.xyaicpzs.service.DltDrawRecordService;
|
||||
import com.xy.xyaicpzs.mapper.DltDrawRecordMapper;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
/**
|
||||
* @author XY003
|
||||
* @description 针对表【dlt_draw_record(大乐透开奖信息表)】的数据库操作Service实现
|
||||
* @createDate 2025-08-20 15:55:06
|
||||
*/
|
||||
@Service
|
||||
public class DltDrawRecordServiceImpl extends ServiceImpl<DltDrawRecordMapper, DltDrawRecord>
|
||||
implements DltDrawRecordService{
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,22 @@
|
||||
package com.xy.xyaicpzs.service.impl;
|
||||
|
||||
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
||||
import com.xy.xyaicpzs.domain.entity.DltFrontendHistory100;
|
||||
import com.xy.xyaicpzs.service.DltFrontendHistory100Service;
|
||||
import com.xy.xyaicpzs.mapper.DltFrontendHistory100Mapper;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
/**
|
||||
* @author XY003
|
||||
* @description 针对表【dlt_frontend_history_100(大乐透前区最近100期数据表)】的数据库操作Service实现
|
||||
* @createDate 2025-08-20 16:24:40
|
||||
*/
|
||||
@Service
|
||||
public class DltFrontendHistory100ServiceImpl extends ServiceImpl<DltFrontendHistory100Mapper, DltFrontendHistory100>
|
||||
implements DltFrontendHistory100Service{
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,22 @@
|
||||
package com.xy.xyaicpzs.service.impl;
|
||||
|
||||
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
||||
import com.xy.xyaicpzs.domain.entity.DltFrontendHistoryAll;
|
||||
import com.xy.xyaicpzs.service.DltFrontendHistoryAllService;
|
||||
import com.xy.xyaicpzs.mapper.DltFrontendHistoryAllMapper;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
/**
|
||||
* @author XY003
|
||||
* @description 针对表【dlt_frontend_history_all(大乐透前区全部历史数据表)】的数据库操作Service实现
|
||||
* @createDate 2025-08-20 16:24:40
|
||||
*/
|
||||
@Service
|
||||
public class DltFrontendHistoryAllServiceImpl extends ServiceImpl<DltFrontendHistoryAllMapper, DltFrontendHistoryAll>
|
||||
implements DltFrontendHistoryAllService{
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,22 @@
|
||||
package com.xy.xyaicpzs.service.impl;
|
||||
|
||||
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
||||
import com.xy.xyaicpzs.domain.entity.DltFrontendHistoryTop100;
|
||||
import com.xy.xyaicpzs.service.DltFrontendHistoryTop100Service;
|
||||
import com.xy.xyaicpzs.mapper.DltFrontendHistoryTop100Mapper;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
/**
|
||||
* @author XY003
|
||||
* @description 针对表【dlt_frontend_history_top_100(大乐透前区百期数据排行表)】的数据库操作Service实现
|
||||
* @createDate 2025-08-20 16:24:40
|
||||
*/
|
||||
@Service
|
||||
public class DltFrontendHistoryTop100ServiceImpl extends ServiceImpl<DltFrontendHistoryTop100Mapper, DltFrontendHistoryTop100>
|
||||
implements DltFrontendHistoryTop100Service{
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,22 @@
|
||||
package com.xy.xyaicpzs.service.impl;
|
||||
|
||||
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
||||
import com.xy.xyaicpzs.domain.entity.DltFrontendHistoryTop;
|
||||
import com.xy.xyaicpzs.service.DltFrontendHistoryTopService;
|
||||
import com.xy.xyaicpzs.mapper.DltFrontendHistoryTopMapper;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
/**
|
||||
* @author XY003
|
||||
* @description 针对表【dlt_frontend_history_top(大乐透前区历史数据排行表)】的数据库操作Service实现
|
||||
* @createDate 2025-08-20 16:24:40
|
||||
*/
|
||||
@Service
|
||||
public class DltFrontendHistoryTopServiceImpl extends ServiceImpl<DltFrontendHistoryTopMapper, DltFrontendHistoryTop>
|
||||
implements DltFrontendHistoryTopService{
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,249 @@
|
||||
package com.xy.xyaicpzs.service.impl;
|
||||
|
||||
import com.xy.xyaicpzs.domain.entity.DltDrawRecord;
|
||||
import com.xy.xyaicpzs.domain.entity.D9;
|
||||
import com.xy.xyaicpzs.domain.entity.D10;
|
||||
import com.xy.xyaicpzs.domain.entity.D11;
|
||||
import com.xy.xyaicpzs.domain.entity.D12;
|
||||
import com.xy.xyaicpzs.domain.vo.BallPersistenceAnalysisVO;
|
||||
import com.xy.xyaicpzs.service.DltPersistenceAnalysisService;
|
||||
import com.xy.xyaicpzs.service.DltDrawRecordService;
|
||||
import com.xy.xyaicpzs.service.D9Service;
|
||||
import com.xy.xyaicpzs.service.D10Service;
|
||||
import com.xy.xyaicpzs.service.D11Service;
|
||||
import com.xy.xyaicpzs.service.D12Service;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.util.Comparator;
|
||||
import java.util.List;
|
||||
import java.util.function.Function;
|
||||
|
||||
/**
|
||||
* 大乐透持续性分析服务实现类
|
||||
*/
|
||||
@Slf4j
|
||||
@Service
|
||||
public class DltPersistenceAnalysisServiceImpl implements DltPersistenceAnalysisService {
|
||||
|
||||
@Autowired
|
||||
private D9Service d9Service;
|
||||
|
||||
@Autowired
|
||||
private D10Service d10Service;
|
||||
|
||||
@Autowired
|
||||
private D11Service d11Service;
|
||||
|
||||
@Autowired
|
||||
private D12Service d12Service;
|
||||
|
||||
@Autowired
|
||||
private DltDrawRecordService dltDrawRecordService;
|
||||
|
||||
@Override
|
||||
public BallPersistenceAnalysisVO analyzeFrontFrontPersistence(Integer masterBall, Integer slaveBall) {
|
||||
// 参数校验
|
||||
validateBallRange(masterBall, 1, 35, "主球(前区)");
|
||||
validateBallRange(slaveBall, 1, 35, "随球(前区)");
|
||||
|
||||
// 查询指定组合记录
|
||||
D9 targetRecord = d9Service.lambdaQuery()
|
||||
.eq(D9::getMasterBallNumber, masterBall)
|
||||
.eq(D9::getSlaveBallNumber, slaveBall)
|
||||
.one();
|
||||
|
||||
if (targetRecord == null) {
|
||||
throw new RuntimeException(String.format("未找到主球(前区)%d和随球(前区)%d的持续性记录", masterBall, slaveBall));
|
||||
}
|
||||
|
||||
// 查询主球与所有其他球的组合记录
|
||||
List<D9> allCombinations = d9Service.lambdaQuery()
|
||||
.eq(D9::getMasterBallNumber, masterBall)
|
||||
.list();
|
||||
|
||||
if (allCombinations.isEmpty()) {
|
||||
throw new RuntimeException(String.format("未找到主球(前区)%d的持续性记录", masterBall));
|
||||
}
|
||||
|
||||
return buildPersistenceAnalysisVO(
|
||||
targetRecord.getCoefficient(),
|
||||
allCombinations,
|
||||
D9::getCoefficient,
|
||||
D9::getSlaveBallNumber
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
public BallPersistenceAnalysisVO analyzeBackBackPersistence(Integer masterBall, Integer slaveBall) {
|
||||
// 参数校验
|
||||
validateBallRange(masterBall, 1, 12, "主球(后区)");
|
||||
validateBallRange(slaveBall, 1, 12, "随球(后区)");
|
||||
|
||||
// 查询指定组合记录
|
||||
D11 targetRecord = d11Service.lambdaQuery()
|
||||
.eq(D11::getMasterBallNumber, masterBall)
|
||||
.eq(D11::getSlaveBallNumber, slaveBall)
|
||||
.one();
|
||||
|
||||
if (targetRecord == null) {
|
||||
throw new RuntimeException(String.format("未找到主球(后区)%d和随球(后区)%d的持续性记录", masterBall, slaveBall));
|
||||
}
|
||||
|
||||
// 查询主球与所有其他球的组合记录
|
||||
List<D11> allCombinations = d11Service.lambdaQuery()
|
||||
.eq(D11::getMasterBallNumber, masterBall)
|
||||
.list();
|
||||
|
||||
if (allCombinations.isEmpty()) {
|
||||
throw new RuntimeException(String.format("未找到主球(后区)%d的持续性记录", masterBall));
|
||||
}
|
||||
|
||||
return buildPersistenceAnalysisVO(
|
||||
targetRecord.getCoefficient(),
|
||||
allCombinations,
|
||||
D11::getCoefficient,
|
||||
D11::getSlaveBallNumber
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
public BallPersistenceAnalysisVO analyzeFrontBackPersistence(Integer masterBall, Integer slaveBall) {
|
||||
// 参数校验
|
||||
validateBallRange(masterBall, 1, 35, "主球(前区)");
|
||||
validateBallRange(slaveBall, 1, 12, "随球(后区)");
|
||||
|
||||
// 查询指定组合记录
|
||||
D10 targetRecord = d10Service.lambdaQuery()
|
||||
.eq(D10::getMasterBallNumber, masterBall)
|
||||
.eq(D10::getSlaveBallNumber, slaveBall)
|
||||
.one();
|
||||
|
||||
if (targetRecord == null) {
|
||||
throw new RuntimeException(String.format("未找到主球(前区)%d和随球(后区)%d的持续性记录", masterBall, slaveBall));
|
||||
}
|
||||
|
||||
// 查询主球与所有其他球的组合记录
|
||||
List<D10> allCombinations = d10Service.lambdaQuery()
|
||||
.eq(D10::getMasterBallNumber, masterBall)
|
||||
.list();
|
||||
|
||||
if (allCombinations.isEmpty()) {
|
||||
throw new RuntimeException(String.format("未找到主球(前区)%d的持续性记录", masterBall));
|
||||
}
|
||||
|
||||
return buildPersistenceAnalysisVO(
|
||||
targetRecord.getCoefficient(),
|
||||
allCombinations,
|
||||
D10::getCoefficient,
|
||||
D10::getSlaveBallNumber
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
public BallPersistenceAnalysisVO analyzeBackFrontPersistence(Integer masterBall, Integer slaveBall) {
|
||||
// 参数校验
|
||||
validateBallRange(masterBall, 1, 12, "主球(后区)");
|
||||
validateBallRange(slaveBall, 1, 35, "随球(前区)");
|
||||
|
||||
// 查询指定组合记录
|
||||
D12 targetRecord = d12Service.lambdaQuery()
|
||||
.eq(D12::getMasterBallNumber, masterBall)
|
||||
.eq(D12::getSlaveBallNumber, slaveBall)
|
||||
.one();
|
||||
|
||||
if (targetRecord == null) {
|
||||
throw new RuntimeException(String.format("未找到主球(后区)%d和随球(前区)%d的持续性记录", masterBall, slaveBall));
|
||||
}
|
||||
|
||||
// 查询主球与所有其他球的组合记录
|
||||
List<D12> allCombinations = d12Service.lambdaQuery()
|
||||
.eq(D12::getMasterBallNumber, masterBall)
|
||||
.list();
|
||||
|
||||
if (allCombinations.isEmpty()) {
|
||||
throw new RuntimeException(String.format("未找到主球(后区)%d的持续性记录", masterBall));
|
||||
}
|
||||
|
||||
return buildPersistenceAnalysisVO(
|
||||
targetRecord.getCoefficient(),
|
||||
allCombinations,
|
||||
D12::getCoefficient,
|
||||
D12::getSlaveBallNumber
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* 验证球号范围
|
||||
*/
|
||||
private void validateBallRange(Integer ballNumber, int minValue, int maxValue, String ballType) {
|
||||
if (ballNumber == null) {
|
||||
throw new IllegalArgumentException(ballType + "号码不能为空");
|
||||
}
|
||||
if (ballNumber < minValue || ballNumber > maxValue) {
|
||||
throw new IllegalArgumentException(String.format("%s号码必须在%d-%d范围内,错误值:%d",
|
||||
ballType, minValue, maxValue, ballNumber));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 构建持续性分析结果VO
|
||||
*/
|
||||
private <T> BallPersistenceAnalysisVO buildPersistenceAnalysisVO(
|
||||
Double targetCoefficient,
|
||||
List<T> allCombinations,
|
||||
Function<T, Double> coefficientGetter,
|
||||
Function<T, Integer> ballNumberGetter) {
|
||||
|
||||
// 找出系数最高的球号
|
||||
T highest = allCombinations.stream()
|
||||
.max(Comparator.comparing(coefficientGetter))
|
||||
.orElse(null);
|
||||
|
||||
// 找出系数最低的球号
|
||||
T lowest = allCombinations.stream()
|
||||
.min(Comparator.comparing(coefficientGetter))
|
||||
.orElse(null);
|
||||
|
||||
// 计算平均系数
|
||||
double avgCoefficient = allCombinations.stream()
|
||||
.mapToDouble(coefficientGetter::apply)
|
||||
.average()
|
||||
.orElse(0.0);
|
||||
|
||||
// 获取最新开奖期号
|
||||
Long latestDrawId = getLatestDrawId();
|
||||
|
||||
return BallPersistenceAnalysisVO.builder()
|
||||
.lineCoefficient(targetCoefficient)
|
||||
.highestBall(highest != null ? ballNumberGetter.apply(highest) : null)
|
||||
.highestCoefficient(highest != null ? coefficientGetter.apply(highest) : null)
|
||||
.lowestBall(lowest != null ? ballNumberGetter.apply(lowest) : null)
|
||||
.lowestCoefficient(lowest != null ? coefficientGetter.apply(lowest) : null)
|
||||
.averageCoefficient(avgCoefficient)
|
||||
.latestDrawId(latestDrawId)
|
||||
.build();
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取最新开奖期号
|
||||
*/
|
||||
private Long getLatestDrawId() {
|
||||
String latestDrawId = dltDrawRecordService.lambdaQuery()
|
||||
.orderByDesc(DltDrawRecord::getDrawId)
|
||||
.last("LIMIT 1")
|
||||
.oneOpt()
|
||||
.map(DltDrawRecord::getDrawId)
|
||||
.orElse(null);
|
||||
|
||||
if (latestDrawId != null) {
|
||||
try {
|
||||
return Long.parseLong(latestDrawId);
|
||||
} catch (NumberFormatException e) {
|
||||
log.warn("开奖期号格式转换失败:{}", latestDrawId);
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,75 @@
|
||||
package com.xy.xyaicpzs.service.impl;
|
||||
|
||||
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
|
||||
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
||||
import com.xy.xyaicpzs.domain.entity.DltPredictRecord;
|
||||
import com.xy.xyaicpzs.service.DltPredictRecordService;
|
||||
import com.xy.xyaicpzs.mapper.DltPredictRecordMapper;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author XY003
|
||||
* @description 针对表【dlt_predict_record(大乐透推测记录表)】的数据库操作Service实现
|
||||
* @createDate 2025-09-08 14:01:12
|
||||
*/
|
||||
@Service
|
||||
public class DltPredictRecordServiceImpl extends ServiceImpl<DltPredictRecordMapper, DltPredictRecord>
|
||||
implements DltPredictRecordService{
|
||||
|
||||
@Override
|
||||
public DltPredictRecord createDltPredictRecord(Long userId, Long drawId, Date drawDate, List<Integer> frontBalls, List<Integer> backBalls) {
|
||||
DltPredictRecord predictRecord = new DltPredictRecord();
|
||||
predictRecord.setUserId(userId);
|
||||
predictRecord.setDrawId(drawId);
|
||||
predictRecord.setDrawDate(drawDate);
|
||||
predictRecord.setPredictTime(new Date());
|
||||
|
||||
// 设置前区球号码(5个)
|
||||
if (frontBalls != null && frontBalls.size() >= 5) {
|
||||
predictRecord.setFrontendBall1(frontBalls.get(0));
|
||||
predictRecord.setFrontendBall2(frontBalls.get(1));
|
||||
predictRecord.setFrontendBall3(frontBalls.get(2));
|
||||
predictRecord.setFrontendBall4(frontBalls.get(3));
|
||||
predictRecord.setFrontendBall5(frontBalls.get(4));
|
||||
}
|
||||
|
||||
// 设置后区球号码(2个)
|
||||
if (backBalls != null && backBalls.size() >= 2) {
|
||||
predictRecord.setBackendBall1(backBalls.get(0));
|
||||
predictRecord.setBackendBall2(backBalls.get(1));
|
||||
}
|
||||
|
||||
// 默认状态为待开奖
|
||||
predictRecord.setPredictStatus("待开奖");
|
||||
|
||||
save(predictRecord);
|
||||
return predictRecord;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<DltPredictRecord> getDltPredictRecordsByUserIdWithPaging(Long userId, Integer page, Integer size) {
|
||||
QueryWrapper<DltPredictRecord> queryWrapper = new QueryWrapper<>();
|
||||
queryWrapper.eq("userId", userId).orderByDesc("predictTime");
|
||||
|
||||
// 计算偏移量
|
||||
int offset = (page - 1) * size;
|
||||
queryWrapper.last("LIMIT " + offset + ", " + size);
|
||||
|
||||
return list(queryWrapper);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Long getDltPredictRecordsCountByUserId(Long userId) {
|
||||
QueryWrapper<DltPredictRecord> queryWrapper = new QueryWrapper<>();
|
||||
queryWrapper.eq("userId", userId);
|
||||
return count(queryWrapper);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -44,6 +44,7 @@ public class PredictRecordServiceImpl extends ServiceImpl<PredictRecordMapper, P
|
||||
|
||||
// 默认状态为待开奖
|
||||
predictRecord.setPredictStatus("待开奖");
|
||||
predictRecord.setType("ssq");
|
||||
|
||||
save(predictRecord);
|
||||
return predictRecord;
|
||||
|
||||
@@ -1,26 +1,28 @@
|
||||
package com.xy.xyaicpzs.service.impl;
|
||||
|
||||
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
|
||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
||||
import com.xy.xyaicpzs.common.ErrorCode;
|
||||
import com.xy.xyaicpzs.constant.UserConstant;
|
||||
import com.xy.xyaicpzs.domain.dto.user.UserPhoneLoginRequest;
|
||||
import com.xy.xyaicpzs.domain.dto.user.UserPhoneRegisterRequest;
|
||||
import com.xy.xyaicpzs.domain.entity.User;
|
||||
import com.xy.xyaicpzs.domain.vo.*;
|
||||
import com.xy.xyaicpzs.exception.BusinessException;
|
||||
import com.xy.xyaicpzs.mapper.UserMapper;
|
||||
import com.xy.xyaicpzs.service.SmsService;
|
||||
import com.xy.xyaicpzs.service.UserService;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.springframework.beans.BeanUtils;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.util.DigestUtils;
|
||||
|
||||
import jakarta.servlet.http.HttpServletRequest;
|
||||
import java.util.Date;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
import java.util.*;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* @author XY003
|
||||
@@ -329,4 +331,239 @@ public class UserServiceImpl extends ServiceImpl<UserMapper, User>
|
||||
}
|
||||
return DigestUtils.md5DigestAsHex((SALT + password).getBytes());
|
||||
}
|
||||
|
||||
// region 统计相关方法实现
|
||||
|
||||
@Override
|
||||
public UserStatisticsVO getNewUsersStatistics(String startDate, String endDate) {
|
||||
try {
|
||||
// 构建查询条件
|
||||
QueryWrapper<User> queryWrapper = new QueryWrapper<>();
|
||||
queryWrapper.between("createTime", startDate + " 00:00:00", endDate + " 23:59:59");
|
||||
|
||||
// 获取新增用户总数
|
||||
long totalNewUsers = this.count(queryWrapper);
|
||||
|
||||
// 获取新增用户列表(最近20个)
|
||||
queryWrapper.orderByDesc("createTime");
|
||||
queryWrapper.last("LIMIT 20");
|
||||
List<User> recentUsers = this.list(queryWrapper);
|
||||
List<UserVO> recentUserVOs = recentUsers.stream().map(user -> {
|
||||
UserVO userVO = new UserVO();
|
||||
BeanUtils.copyProperties(user, userVO);
|
||||
return userVO;
|
||||
}).collect(Collectors.toList());
|
||||
|
||||
return UserStatisticsVO.builder()
|
||||
.totalNewUsers(totalNewUsers)
|
||||
.startDate(startDate)
|
||||
.endDate(endDate)
|
||||
.recentUsers(recentUserVOs)
|
||||
.build();
|
||||
|
||||
} catch (Exception e) {
|
||||
log.error("获取新增用户统计失败:{}", e.getMessage());
|
||||
throw new BusinessException(ErrorCode.SYSTEM_ERROR, "获取统计数据失败");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public VipStatisticsVO getNewVipsStatistics(String startDate, String endDate) {
|
||||
try {
|
||||
// 构建查询条件 - 新增会员(isVip != 0 且在时间范围内)
|
||||
QueryWrapper<User> queryWrapper = new QueryWrapper<>();
|
||||
queryWrapper.ne("isVip", 0);
|
||||
queryWrapper.between("createTime", startDate + " 00:00:00", endDate + " 23:59:59");
|
||||
|
||||
// 获取新增会员总数
|
||||
long totalNewVips = this.count(queryWrapper);
|
||||
|
||||
// 获取新增会员列表(最近20个)
|
||||
queryWrapper.orderByDesc("createTime");
|
||||
queryWrapper.last("LIMIT 20");
|
||||
List<User> recentVips = this.list(queryWrapper);
|
||||
List<UserVO> recentVipVOs = recentVips.stream().map(user -> {
|
||||
UserVO userVO = new UserVO();
|
||||
BeanUtils.copyProperties(user, userVO);
|
||||
return userVO;
|
||||
}).collect(Collectors.toList());
|
||||
|
||||
// 计算会员转化率(该时间段内新增会员 / 新增用户总数)
|
||||
QueryWrapper<User> allUsersWrapper = new QueryWrapper<>();
|
||||
allUsersWrapper.between("createTime", startDate + " 00:00:00", endDate + " 23:59:59");
|
||||
long totalNewUsers = this.count(allUsersWrapper);
|
||||
|
||||
double conversionRate = totalNewUsers > 0 ? (double) totalNewVips / totalNewUsers * 100 : 0.0;
|
||||
|
||||
return VipStatisticsVO.builder()
|
||||
.totalNewVips(totalNewVips)
|
||||
.totalNewUsers(totalNewUsers)
|
||||
.conversionRate(Math.round(conversionRate * 100.0) / 100.0)
|
||||
.startDate(startDate)
|
||||
.endDate(endDate)
|
||||
.recentVips(recentVipVOs)
|
||||
.build();
|
||||
|
||||
} catch (Exception e) {
|
||||
log.error("获取新增会员统计失败:{}", e.getMessage());
|
||||
throw new BusinessException(ErrorCode.SYSTEM_ERROR, "获取统计数据失败");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public RegistrationTrendVO getRegistrationTrend(String startDate, String endDate, String granularity) {
|
||||
try {
|
||||
// 这里简化处理,实际应该使用SQL的GROUP BY和DATE_FORMAT函数
|
||||
// 由于MyBatis-Plus的限制,我们先获取所有数据然后在Java中分组
|
||||
QueryWrapper<User> queryWrapper = new QueryWrapper<>();
|
||||
queryWrapper.between("createTime", startDate + " 00:00:00", endDate + " 23:59:59");
|
||||
queryWrapper.orderByAsc("createTime");
|
||||
List<User> users = this.list(queryWrapper);
|
||||
|
||||
Map<String, Long> trendData = new HashMap<>();
|
||||
Map<String, Long> vipTrendData = new HashMap<>();
|
||||
|
||||
// 在Java中按指定粒度分组统计
|
||||
for (User user : users) {
|
||||
String key = formatDateByGranularity(user.getCreateTime(), granularity);
|
||||
trendData.put(key, trendData.getOrDefault(key, 0L) + 1);
|
||||
|
||||
// 同时统计会员趋势
|
||||
if (user.getIsVip() != null && user.getIsVip() != 0) {
|
||||
vipTrendData.put(key, vipTrendData.getOrDefault(key, 0L) + 1);
|
||||
}
|
||||
}
|
||||
|
||||
return RegistrationTrendVO.builder()
|
||||
.startDate(startDate)
|
||||
.endDate(endDate)
|
||||
.granularity(granularity)
|
||||
.userTrend(trendData)
|
||||
.vipTrend(vipTrendData)
|
||||
.totalUsers(users.size())
|
||||
.totalVips(users.stream().mapToLong(u -> u.getIsVip() != null && u.getIsVip() != 0 ? 1 : 0).sum())
|
||||
.build();
|
||||
|
||||
} catch (Exception e) {
|
||||
log.error("获取用户注册趋势失败:{}", e.getMessage());
|
||||
throw new BusinessException(ErrorCode.SYSTEM_ERROR, "获取趋势数据失败");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Page<UserVO> getExpiringVips(Integer days, Long current, Long pageSize) {
|
||||
try {
|
||||
// 计算目标日期范围
|
||||
Date now = new Date();
|
||||
Date futureDate = new Date(now.getTime() + days * 24 * 60 * 60 * 1000L);
|
||||
|
||||
// 构建查询条件
|
||||
QueryWrapper<User> queryWrapper = new QueryWrapper<>();
|
||||
queryWrapper.ne("isVip", 0); // 是会员
|
||||
queryWrapper.isNotNull("vipExpire"); // 有到期时间
|
||||
queryWrapper.between("vipExpire", now, futureDate); // 在即将到期的时间范围内
|
||||
queryWrapper.orderByAsc("vipExpire"); // 按到期时间升序
|
||||
|
||||
Page<User> userPage = this.page(new Page<>(current, pageSize), queryWrapper);
|
||||
|
||||
// 转换为UserVO
|
||||
Page<UserVO> userVOPage = new Page<>(userPage.getCurrent(), userPage.getSize(), userPage.getTotal());
|
||||
List<UserVO> userVOList = userPage.getRecords().stream().map(user -> {
|
||||
UserVO userVO = new UserVO();
|
||||
BeanUtils.copyProperties(user, userVO);
|
||||
return userVO;
|
||||
}).collect(Collectors.toList());
|
||||
userVOPage.setRecords(userVOList);
|
||||
|
||||
return userVOPage;
|
||||
|
||||
} catch (Exception e) {
|
||||
log.error("获取即将到期会员失败:{}", e.getMessage());
|
||||
throw new BusinessException(ErrorCode.SYSTEM_ERROR, "获取数据失败");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public VipDistributionVO getVipDistribution() {
|
||||
try {
|
||||
Date now = new Date();
|
||||
|
||||
// 总用户数
|
||||
long totalUsers = this.count();
|
||||
|
||||
// 普通用户数(isVip = 0 或 null)
|
||||
QueryWrapper<User> normalWrapper = new QueryWrapper<>();
|
||||
normalWrapper.and(wrapper -> wrapper.eq("isVip", 0).or().isNull("isVip"));
|
||||
long normalUsers = this.count(normalWrapper);
|
||||
|
||||
// 有效会员数(isVip != 0 且 vipExpire > now)
|
||||
QueryWrapper<User> activeVipWrapper = new QueryWrapper<>();
|
||||
activeVipWrapper.ne("isVip", 0)
|
||||
.and(wrapper -> wrapper.isNull("vipExpire").or().gt("vipExpire", now));
|
||||
long activeVips = this.count(activeVipWrapper);
|
||||
|
||||
// 过期会员数(isVip != 0 且 vipExpire <= now)
|
||||
QueryWrapper<User> expiredVipWrapper = new QueryWrapper<>();
|
||||
expiredVipWrapper.ne("isVip", 0)
|
||||
.isNotNull("vipExpire")
|
||||
.le("vipExpire", now);
|
||||
long expiredVips = this.count(expiredVipWrapper);
|
||||
|
||||
// 即将到期会员数(7天内到期)
|
||||
Date sevenDaysLater = new Date(now.getTime() + 7 * 24 * 60 * 60 * 1000L);
|
||||
QueryWrapper<User> soonExpireWrapper = new QueryWrapper<>();
|
||||
soonExpireWrapper.ne("isVip", 0)
|
||||
.between("vipExpire", now, sevenDaysLater);
|
||||
long soonExpireVips = this.count(soonExpireWrapper);
|
||||
|
||||
// 计算百分比
|
||||
double normalPercentage = totalUsers > 0 ? (double) normalUsers / totalUsers * 100 : 0;
|
||||
double activeVipPercentage = totalUsers > 0 ? (double) activeVips / totalUsers * 100 : 0;
|
||||
double expiredVipPercentage = totalUsers > 0 ? (double) expiredVips / totalUsers * 100 : 0;
|
||||
|
||||
return VipDistributionVO.builder()
|
||||
.totalUsers(totalUsers)
|
||||
.normalUsers(normalUsers)
|
||||
.normalPercentage(Math.round(normalPercentage * 100.0) / 100.0)
|
||||
.activeVips(activeVips)
|
||||
.activeVipPercentage(Math.round(activeVipPercentage * 100.0) / 100.0)
|
||||
.expiredVips(expiredVips)
|
||||
.expiredVipPercentage(Math.round(expiredVipPercentage * 100.0) / 100.0)
|
||||
.soonExpireVips(soonExpireVips)
|
||||
.statisticsTime(now)
|
||||
.build();
|
||||
|
||||
} catch (Exception e) {
|
||||
log.error("获取会员分布统计失败:{}", e.getMessage());
|
||||
throw new BusinessException(ErrorCode.SYSTEM_ERROR, "获取统计数据失败");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据时间粒度格式化日期
|
||||
*/
|
||||
private String formatDateByGranularity(Date date, String granularity) {
|
||||
if (date == null) return "";
|
||||
|
||||
java.time.LocalDateTime localDateTime = date.toInstant().atZone(java.time.ZoneId.systemDefault()).toLocalDateTime();
|
||||
java.time.format.DateTimeFormatter formatter;
|
||||
|
||||
switch (granularity) {
|
||||
case "week":
|
||||
// 获取年份和周数
|
||||
int year = localDateTime.getYear();
|
||||
int week = localDateTime.get(java.time.temporal.WeekFields.of(java.util.Locale.getDefault()).weekOfYear());
|
||||
return year + "-W" + String.format("%02d", week);
|
||||
case "month":
|
||||
formatter = java.time.format.DateTimeFormatter.ofPattern("yyyy-MM");
|
||||
break;
|
||||
default:
|
||||
formatter = java.time.format.DateTimeFormatter.ofPattern("yyyy-MM-dd");
|
||||
break;
|
||||
}
|
||||
|
||||
return localDateTime.format(formatter);
|
||||
}
|
||||
|
||||
// endregion
|
||||
}
|
||||
Reference in New Issue
Block a user