package com.xy.xyaicpzs.controller; import com.xy.xyaicpzs.common.ErrorCode; import com.xy.xyaicpzs.common.ResultUtils; import com.xy.xyaicpzs.common.response.ApiResponse; import com.xy.xyaicpzs.domain.entity.LotteryDraws; import com.xy.xyaicpzs.domain.entity.PredictRecord; import com.xy.xyaicpzs.service.BallAnalysisService; import com.xy.xyaicpzs.service.LotteryDrawsService; import com.xy.xyaicpzs.service.PredictRecordService; import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.Parameter; import io.swagger.v3.oas.annotations.tags.Tag; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.format.annotation.DateTimeFormat; import org.springframework.web.bind.annotation.*; import java.util.Arrays; import java.util.Date; import java.util.List; /** * 球号分析控制器 * 提供球号分析算法的API接口 */ @Slf4j @RestController @RequestMapping("/ball-analysis") @Tag(name = "球号分析", description = "球号分析算法API") public class BallAnalysisController { @Autowired private BallAnalysisService ballAnalysisService; @Autowired private LotteryDrawsService lotteryDrawsService; @Autowired private PredictRecordService predictRecordService; @GetMapping("/predict-records/{userId}") @Operation(summary = "获取用户推测记录", description = "根据用户ID获取该用户的所有推测记录,按推测时间倒序排列") public ApiResponse> getPredictRecordsByUserId( @Parameter(description = "用户ID,例如:1001", required = true) @PathVariable Long userId , HttpServletRequest request) { User loginUser = userService.getLoginUser(request); if (loginUser == null){ return ResultUtils.error(ErrorCode.NOT_LOGIN_ERROR, "用户未登录"); } try { log.info("接收到获取用户推测记录请求:用户ID={}", userId); // 调用服务获取用户推测记录 List result = predictRecordService.getPredictRecordsByUserId(userId); log.info("获取用户推测记录完成,用户ID:{},返回{}条记录", userId, result.size()); return ResultUtils.success(result); } catch (Exception e) { log.error("获取用户推测记录失败:{}", e.getMessage(), e); return ResultUtils.error(ErrorCode.SYSTEM_ERROR, "获取用户推测记录失败:" + e.getMessage()); } } /** * 获取近期开奖信息 * @param limit 获取条数,可选参数,默认15条 * @return 近期开奖信息列表 */ @GetMapping("/recent-draws") @Operation(summary = "获取近期开奖信息", description = "获取最近的开奖信息,默认返回15条,按开奖期号倒序排列") public ApiResponse> getRecentDraws( @Parameter(description = "获取条数,默认15条", required = false) @RequestParam(required = false, defaultValue = "15") Integer limit) { try { log.info("接收到获取近期开奖信息请求:条数={}", limit); // 调用服务获取近期开奖信息 List result = lotteryDrawsService.getRecentDraws(limit); log.info("获取近期开奖信息完成,返回{}条记录", result.size()); return ResultUtils.success(result); } catch (Exception e) { log.error("获取近期开奖信息失败:{}", e.getMessage(), e); return ResultUtils.error(ErrorCode.SYSTEM_ERROR, "获取近期开奖信息失败:" + e.getMessage()); } } /** * 根据日期范围查询开奖信息 * @param startDate 开始日期(可选,格式:yyyy-MM-dd) * @param endDate 结束日期(可选,格式:yyyy-MM-dd) * @return 开奖信息列表 */ @GetMapping("/query-draws") @Operation(summary = "按日期范围查询开奖信息", description = "根据日期范围查询开奖信息,支持单边日期查询") public ApiResponse> queryDraws( @Parameter(description = "开始日期,格式:yyyy-MM-dd,例如:2025-01-01", required = false) @RequestParam(required = false) @DateTimeFormat(pattern = "yyyy-MM-dd") Date startDate, @Parameter(description = "结束日期,格式:yyyy-MM-dd,例如:2025-01-31", required = false) @RequestParam(required = false) @DateTimeFormat(pattern = "yyyy-MM-dd") Date endDate) { try { log.info("接收到按日期范围查询开奖信息请求:开始日期={},结束日期={}", startDate, endDate); // 日期范围验证 if (startDate != null && endDate != null && startDate.after(endDate)) { return ResultUtils.error(ErrorCode.PARAMS_ERROR, "开始日期不能晚于结束日期"); } // 调用服务按日期范围查询开奖信息 List result = lotteryDrawsService.getByDateRange(startDate, endDate); log.info("按日期范围查询开奖信息完成,返回{}条记录", result.size()); return ResultUtils.success(result); } catch (Exception e) { log.error("按日期范围查询开奖信息失败:{}", e.getMessage(), e); return ResultUtils.error(ErrorCode.SYSTEM_ERROR, "查询开奖信息失败:" + e.getMessage()); } } /** * 根据期号精准查询单条开奖信息 * @param drawId 开奖期号 * @return 开奖信息 */ @GetMapping("/draw/{drawId}") @Operation(summary = "根据期号查询开奖信息", description = "根据期号精准查询单条开奖信息") public ApiResponse getDrawById( @Parameter(description = "开奖期号,例如:2025056", required = true) @PathVariable Long drawId) { try { log.info("接收到根据期号查询开奖信息请求:期号={}", drawId); // 调用服务查询开奖信息 LotteryDraws result = lotteryDrawsService.getByDrawId(drawId); if (result == null) { log.warn("未找到期号为{}的开奖信息", drawId); return ResultUtils.error(ErrorCode.NOT_FOUND_ERROR, "未找到期号为" + drawId + "的开奖信息"); } log.info("根据期号查询开奖信息完成:{}", result.getDrawId()); return ResultUtils.success(result); } catch (Exception e) { log.error("根据期号查询开奖信息失败:{}", e.getMessage(), e); return ResultUtils.error(ErrorCode.SYSTEM_ERROR, "查询开奖信息失败:" + e.getMessage()); } } /** * 创建推测记录 * @param userId 用户ID * @param drawId 开奖期号 * @param drawDate 开奖日期 * @param redBalls 6个红球号码,用逗号分隔 * @param blueBall 蓝球号码 * @return 创建的推测记录 */ @PostMapping("/create-predict") @Operation(summary = "创建推测记录", description = "向predict_record表插入一条推测记录数据") public ApiResponse createPredictRecord( @Parameter(description = "用户ID,例如:1001", required = true) @RequestParam Long userId, @Parameter(description = "开奖期号,例如:2025056", required = true) @RequestParam Long drawId, @Parameter(description = "开奖日期,格式:yyyy-MM-dd", required = true) @RequestParam @DateTimeFormat(pattern = "yyyy-MM-dd") Date drawDate, @Parameter(description = "6个红球号码,用逗号分隔,例如:1,5,12,18,25,33", required = true) @RequestParam String redBalls, @Parameter(description = "蓝球号码,例如:8", required = true) @RequestParam Integer blueBall) { try { log.info("接收到创建推测记录请求:用户ID={},期号={},开奖日期={},红球={},蓝球={}", userId, drawId, drawDate, redBalls, blueBall); // 解析红球号码 List redBallList = parseRedBalls(redBalls, 6, "红球"); // 调用服务创建推测记录 PredictRecord result = predictRecordService.createPredictRecord(userId, drawId, drawDate, redBallList, blueBall); log.info("创建推测记录完成,用户ID:{},记录ID:{}", userId, result.getId()); return ResultUtils.success(result); } catch (Exception e) { log.error("创建推测记录失败:{}", e.getMessage(), e); return ResultUtils.error(ErrorCode.SYSTEM_ERROR, "创建推测记录失败:" + e.getMessage()); } } /** * 球号分析算法 * @param level 高位/中位/低位标识 (H/M/L) * @param redBalls 6个红球号码,用逗号分隔 * @param blueBall 蓝球号码 * @return 分析结果:出现频率最高的前11位数字 */ @PostMapping("/analyze") @Operation(summary = "首球算法", description = "根据输入的级别、红球和蓝球,分析出现频率最高的前11位数字") public ApiResponse> analyzeBalls( @Parameter(description = "级别:H(高位)/M(中位)/L(低位)", required = true) @RequestParam String level, @Parameter(description = "6个红球号码,用逗号分隔,例如:1,5,12,18,25,33", required = true) @RequestParam String redBalls, @Parameter(description = "蓝球号码,例如:8", required = true) @RequestParam Integer blueBall) { try { log.info("接收到球号分析请求:级别={},红球={},蓝球={}", level, redBalls, blueBall); // 解析红球号码 List redBallList = parseRedBalls(redBalls, 6, "红球"); // 调用分析服务 List result = ballAnalysisService.analyzeBalls(level, redBallList, blueBall); log.info("球号分析完成,结果:{}", result); return ResultUtils.success(result); } catch (Exception e) { log.error("球号分析失败:{}", e.getMessage(), e); return ResultUtils.error(ErrorCode.SYSTEM_ERROR, "球号分析失败:" + e.getMessage()); } } /** * 跟随球号分析算法 * @param level 高位/中位/低位标识 (H/M/L) * @param firstThreeRedBalls 前3个红球号码,用逗号分隔 * @param lastSixRedBalls 后6个红球号码,用逗号分隔 * @param blueBall 蓝球号码 * @return 分析结果:出现频率最高的前8位数字 */ @PostMapping("/fallow") @Operation(summary = "跟随球号分析算法", description = "根据输入的级别、前3个红球、后6个红球和蓝球,分析出现频率最高的前8位数字") public ApiResponse> fallowBallAnalysis( @Parameter(description = "级别:H(高位)/M(中位)/L(低位)", required = true) @RequestParam String level, @Parameter(description = "前3个红球号码,用逗号分隔,例如:7,24,27", required = true) @RequestParam String firstThreeRedBalls, @Parameter(description = "后6个红球号码,用逗号分隔,例如:21,10,5,15,23,28", required = true) @RequestParam String lastSixRedBalls, @Parameter(description = "蓝球号码,例如:16", required = true) @RequestParam Integer blueBall) { try { log.info("接收到跟随球号分析请求:级别={},前3个红球={},后6个红球={},蓝球={}", level, firstThreeRedBalls, lastSixRedBalls, blueBall); // 解析红球号码 List firstThreeRedBallList = parseRedBalls(firstThreeRedBalls, 3, "前3个红球"); List lastSixRedBallList = parseRedBalls(lastSixRedBalls, 6, "后6个红球"); // 调用分析服务 List result = ballAnalysisService.fallowBallAnalysis(level, firstThreeRedBallList, lastSixRedBallList, blueBall); log.info("跟随球号分析完成,结果:{}", result); return ResultUtils.success(result); } catch (Exception e) { log.error("跟随球号分析失败:{}", e.getMessage(), e); return ResultUtils.error(ErrorCode.SYSTEM_ERROR, "跟随球号分析失败:" + e.getMessage()); } } /** * 解析红球号码字符串 */ private List parseRedBalls(String redBalls, int expectedCount, String ballType) { if (redBalls == null || redBalls.trim().isEmpty()) { throw new IllegalArgumentException(ballType + "号码不能为空"); } try { String[] parts = redBalls.split(","); if (parts.length != expectedCount) { throw new IllegalArgumentException(ballType + "数量必须为" + expectedCount + "个,实际:" + parts.length); } List result = Arrays.stream(parts) .map(String::trim) .map(Integer::parseInt) .collect(java.util.stream.Collectors.toList()); // 验证红球号码范围 for (Integer ball : result) { if (ball < 1 || ball > 33) { throw new IllegalArgumentException(ballType + "号码必须在1-33范围内,错误值:" + ball); } } return result; } catch (NumberFormatException e) { throw new IllegalArgumentException(ballType + "号码格式错误,请使用逗号分隔的数字"); } } /** * 蓝球分析算法 * @param level 高位/中位/低位标识 (H/M/L) * @param predictedRedBalls 6个推测红球号码,用逗号分隔 * @param predictedBlueBalls 2个推测蓝球号码,用逗号分隔 * @param lastRedBalls 6个上期红球号码,用逗号分隔 * @param lastBlueBall 上期蓝球号码 * @return 分析结果:频率最高的前4个蓝球号码 */ @PostMapping("/blue-ball") @Operation(summary = "蓝球分析算法", description = "根据输入的级别、推测红球、推测蓝球、上期红球和上期蓝球,分析出频率最高的前4个蓝球号码") public ApiResponse> blueBallAnalysis( @Parameter(description = "级别:H(高位)/M(中位)/L(低位)", required = true) @RequestParam String level, @Parameter(description = "6个推测红球号码,用逗号分隔,例如:26,20,18,32,10,14", required = true) @RequestParam String predictedRedBalls, @Parameter(description = "2个推测蓝球号码,用逗号分隔,例如:5,8", required = true) @RequestParam String predictedBlueBalls, @Parameter(description = "6个上期红球号码,用逗号分隔,例如:7,24,27,21,10,5", required = true) @RequestParam String lastRedBalls, @Parameter(description = "上期蓝球号码,例如:16", required = true) @RequestParam Integer lastBlueBall) { try { log.info("接收到蓝球分析请求:级别={},推测红球={},推测蓝球={},上期红球={},上期蓝球={}", level, predictedRedBalls, predictedBlueBalls, lastRedBalls, lastBlueBall); // 解析球号 List predictedRedBallList = parseRedBalls(predictedRedBalls, 6, "推测红球"); List predictedBlueBallList = parseBlueBalls(predictedBlueBalls, 2, "推测蓝球"); List lastRedBallList = parseRedBalls(lastRedBalls, 6, "上期红球"); // 调用分析服务 List result = ballAnalysisService.blueBallAnalysis( level, predictedRedBallList, predictedBlueBallList, lastRedBallList, lastBlueBall); log.info("蓝球分析完成,结果:{}", result); return ResultUtils.success(result); } catch (Exception e) { log.error("蓝球分析失败:{}", e.getMessage(), e); return ResultUtils.error(ErrorCode.SYSTEM_ERROR, "蓝球分析失败:" + e.getMessage()); } } /** * 解析蓝球号码字符串 */ private List parseBlueBalls(String blueBalls, int expectedCount, String ballType) { if (blueBalls == null || blueBalls.trim().isEmpty()) { throw new IllegalArgumentException(ballType + "号码不能为空"); } try { String[] parts = blueBalls.split(","); if (parts.length != expectedCount) { throw new IllegalArgumentException(ballType + "数量必须为" + expectedCount + "个,实际:" + parts.length); } List result = Arrays.stream(parts) .map(String::trim) .map(Integer::parseInt) .collect(java.util.stream.Collectors.toList()); // 验证蓝球号码范围 for (Integer ball : result) { if (ball < 1 || ball > 16) { throw new IllegalArgumentException(ballType + "号码必须在1-16范围内,错误值:" + ball); } } return result; } catch (NumberFormatException e) { throw new IllegalArgumentException(ballType + "号码格式错误,请使用逗号分隔的数字"); } } }