Files
amlhc/application/admin/controller/History.php
T
916117771 919fbbc148 feat(admin): 新增尾首概率分析弹窗
在history页面工具栏添加"尾首概率"按钮,弹窗显示:
- 下一期尾数与前一期尾数相同的概率
- 下一期首位与前一期首位相同的概率
支持切换统计期数(30/50/100/200期)
2026-05-02 15:36:00 +08:00

576 lines
20 KiB
PHP

<?php
namespace app\admin\controller;
use app\common\controller\Backend;
/**
*
*
* @icon fa fa-circle-o
*/
class History extends Backend
{
/**
* History模型对象
* @var \app\admin\model\History
*/
protected $model = null;
/**
* 无需额外权限检查的方法(但仍在 admin 模块内,需要 admin 登录)
* @var array
*/
protected $noNeedRight = ['missingNum', 'trendData', 'hotColdNumbers', 'colorWaveAnalysis', 'zodiacAnalysis', 'oddEvenAnalysis', 'bigSmallAnalysis', 'specialTrend', 'consecutiveNumbers', 'tailNumbers', 'dashboard', 'specialHeatmap', 'specialHotColdAction', 'zoneTransition', 'colorWaveTransition', 'zoneToColorTransition', 'zodiacTransition', 'tailNumberTransition', 'headNumberTransition', 'tailHeadProb', 'predict', 'predictV2', 'predictV3', 'optimizeWeights', 'predictByNormalRelation'];
public function _initialize()
{
parent::_initialize();
$this->model = new \app\admin\model\History;
}
/**
* 查看开奖记录(支持按每月日号筛选)
*/
public function index()
{
$this->request->filter(['strip_tags', 'trim']);
if (false === $this->request->isAjax()) {
return $this->view->fetch();
}
if ($this->request->request('keyField')) {
return $this->selectpage();
}
// search_day 在 filter JSON 里,先提取出来再移除
$filterStr = $this->request->get('filter', '[]', 'trim');
$opStr = $this->request->get('op', '[]', 'trim');
$filter = json_decode($filterStr, true) ?: [];
$op = json_decode($opStr, true) ?: [];
$searchDay = isset($filter['search_day']) ? $filter['search_day'] : '';
unset($filter['search_day'], $op['search_day']);
// 写回 Request 对象
$ref = new \ReflectionProperty($this->request, 'get');
$ref->setAccessible(true);
$getData = $ref->getValue($this->request);
if (is_array($getData)) {
$getData['filter'] = json_encode($filter);
$getData['op'] = json_encode($op);
$ref->setValue($this->request, $getData);
}
[$where, $sort, $order, $offset, $limit] = $this->buildparams();
$list = $this->model->where($where);
// 按每月日号筛选
if ($searchDay !== '' && is_numeric($searchDay)) {
$day = intval($searchDay);
if ($day >= 1 && $day <= 31) {
$list = $list->whereRaw('DAY(openTime) = ?', [$day]);
}
}
$query = $list->order($sort, $order)->paginate($limit);
$result = ['total' => $query->total(), 'rows' => $query->items()];
return json($result);
}
/**
* 查询遗漏号码
* @return void
*/
public function missingNum()
{
if ($this->request->isAjax()) {
$periods = $this->request->get('periods', 10, 'intval');
if ($periods < 1 || $periods > 100) {
$this->error('期数范围必须在 1-100 之间');
}
$type = $this->request->get('type', 'all');
if (!in_array($type, ['all', 'special'])) {
$this->error('查询类型不正确');
}
$result = $this->model->getMissingNumbers($periods, $type);
$this->success('查询成功', null, $result);
}
}
/**
* 获取走势图数据
* @return void
*/
public function trendData()
{
if ($this->request->isAjax()) {
$periods = $this->request->get('periods', 30, 'intval');
if ($periods < 10 || $periods > 100) {
$this->error('期数范围必须在 10-100 之间');
}
$type = $this->request->get('type', 'all');
if (!in_array($type, ['all', 'special'])) {
$this->error('查询类型不正确');
}
$result = $this->model->getTrendData($periods, $type);
$this->success('查询成功', null, $result);
}
}
/**
* 获取冷热号码
* @return void
*/
public function hotColdNumbers()
{
if ($this->request->isAjax()) {
$periods = $this->request->get('periods', 30, 'intval');
if ($periods < 10 || $periods > 100) {
$this->error('期数范围必须在 10-100 之间');
}
$type = $this->request->get('type', 'all');
if (!in_array($type, ['all', 'special'])) {
$this->error('查询类型不正确');
}
$result = $this->model->getHotColdNumbers($periods, $type);
$this->success('查询成功', null, $result);
}
}
/**
* 波色分析
*/
public function colorWaveAnalysis()
{
if ($this->request->isAjax()) {
$periods = $this->request->get('periods', 30, 'intval');
if ($periods < 10 || $periods > 100) {
$this->error('期数范围必须在 10-100 之间');
}
$type = $this->request->get('type', 'all');
if (!in_array($type, ['all', 'special'])) {
$this->error('查询类型不正确');
}
$result = $this->model->getColorWaveAnalysis($periods, $type);
$this->success('查询成功', null, $result);
}
}
/**
* 生肖分析
*/
public function zodiacAnalysis()
{
if ($this->request->isAjax()) {
$periods = $this->request->get('periods', 30, 'intval');
if ($periods < 10 || $periods > 100) {
$this->error('期数范围必须在 10-100 之间');
}
$type = $this->request->get('type', 'all');
if (!in_array($type, ['all', 'special'])) {
$this->error('查询类型不正确');
}
$result = $this->model->getZodiacAnalysis($periods, $type);
$this->success('查询成功', null, $result);
}
}
/**
* 奇偶分析
*/
public function oddEvenAnalysis()
{
if ($this->request->isAjax()) {
$periods = $this->request->get('periods', 30, 'intval');
if ($periods < 10 || $periods > 100) {
$this->error('期数范围必须在 10-100 之间');
}
$type = $this->request->get('type', 'all');
if (!in_array($type, ['all', 'special'])) {
$this->error('查询类型不正确');
}
$result = $this->model->getOddEvenAnalysis($periods, $type);
$this->success('查询成功', null, $result);
}
}
/**
* 大小分析
*/
public function bigSmallAnalysis()
{
if ($this->request->isAjax()) {
$periods = $this->request->get('periods', 30, 'intval');
if ($periods < 10 || $periods > 100) {
$this->error('期数范围必须在 10-100 之间');
}
$type = $this->request->get('type', 'all');
if (!in_array($type, ['all', 'special'])) {
$this->error('查询类型不正确');
}
$result = $this->model->getBigSmallAnalysis($periods, $type);
$this->success('查询成功', null, $result);
}
}
/**
* 特码走势
*/
public function specialTrend()
{
if ($this->request->isAjax()) {
$periods = $this->request->get('periods', 30, 'intval');
if ($periods < 10 || $periods > 100) {
$this->error('期数范围必须在 10-100 之间');
}
$result = $this->model->getSpecialTrend($periods);
$this->success('查询成功', null, $result);
}
}
/**
* 连号分析
*/
public function consecutiveNumbers()
{
if ($this->request->isAjax()) {
$periods = $this->request->get('periods', 30, 'intval');
if ($periods < 10 || $periods > 100) {
$this->error('期数范围必须在 10-100 之间');
}
$result = $this->model->getConsecutiveNumbers($periods);
$this->success('查询成功', null, $result);
}
}
/**
* 尾数分析
*/
public function tailNumbers()
{
if ($this->request->isAjax()) {
$periods = $this->request->get('periods', 30, 'intval');
if ($periods < 10 || $periods > 100) {
$this->error('期数范围必须在 10-100 之间');
}
$type = $this->request->get('type', 'all');
if (!in_array($type, ['all', 'special'])) {
$this->error('查询类型不正确');
}
$result = $this->model->getTailNumbers($periods, $type);
$this->success('查询成功', null, $result);
}
}
/**
* 综合统计面板
*/
public function dashboard()
{
if ($this->request->isAjax()) {
$periods = $this->request->get('periods', 30, 'intval');
if ($periods < 10 || $periods > 100) {
$this->error('期数范围必须在 10-100 之间');
}
$type = $this->request->get('type', 'all');
if (!in_array($type, ['all', 'special'])) {
$this->error('查询类型不正确');
}
$result = $this->model->getDashboardData($periods, $type);
$this->success('查询成功', null, $result);
}
}
/**
* 特码冷热列表(每期相对于前N期的冷热状态)
*/
public function specialHotColdAction()
{
if ($this->request->isAjax()) {
$lookback = $this->request->get('lookback', 30, 'intval');
if ($lookback < 10 || $lookback > 100) {
$this->error('向前期数范围必须在 10-100 之间');
}
$limit = $this->request->get('limit', 100, 'intval');
if ($limit < 10 || $limit > 200) {
$this->error('查询期数范围必须在 10-200 之间');
}
$result = $this->model->getSpecialHotColdList($lookback, $limit);
$this->success('查询成功', null, $result);
}
}
/**
* 特码热力图
*/
public function specialHeatmap()
{
if ($this->request->isAjax()) {
$periods = $this->request->get('periods', 30, 'intval');
if ($periods < 10 || $periods > 100) {
$this->error('期数范围必须在 10-100 之间');
}
$result = $this->model->getSpecialHeatmap($periods);
$this->success('查询成功', null, $result);
}
}
/**
* 区域转移概率统计
*/
public function zoneTransition()
{
if ($this->request->isAjax()) {
$periods = $this->request->get('periods', 100, 'intval');
if ($periods < 10 || $periods > 500) {
$this->error('期数范围必须在 10-500 之间');
}
$result = $this->model->getZoneTransition($periods);
$this->success('查询成功', null, $result);
}
}
/**
* 波色转移概率统计
*/
public function colorWaveTransition()
{
if ($this->request->isAjax()) {
$periods = $this->request->get('periods', 100, 'intval');
if ($periods < 10 || $periods > 500) {
$this->error('期数范围必须在 10-500 之间');
}
$result = $this->model->getColorWaveTransition($periods);
$this->success('查询成功', null, $result);
}
}
/**
* 生肖转移概率统计
*/
public function zodiacTransition()
{
if ($this->request->isAjax()) {
$periods = $this->request->get('periods', 100, 'intval');
if ($periods < 10 || $periods > 500) {
$this->error('期数范围必须在 10-500 之间');
}
$result = $this->model->getZodiacTransition($periods);
$this->success('查询成功', null, $result);
}
}
/**
* 尾号转移概率统计
*/
public function tailNumberTransition()
{
if ($this->request->isAjax()) {
$periods = $this->request->get('periods', 100, 'intval');
if ($periods < 10 || $periods > 500) {
$this->error('期数范围必须在 10-500 之间');
}
$result = $this->model->getTailNumberTransition($periods);
$this->success('查询成功', null, $result);
}
}
/**
* 首号转移概率统计
*/
public function headNumberTransition()
{
if ($this->request->isAjax()) {
$periods = $this->request->get('periods', 100, 'intval');
if ($periods < 10 || $periods > 500) {
$this->error('期数范围必须在 10-500 之间');
}
$result = $this->model->getHeadNumberTransition($periods);
$this->success('查询成功', null, $result);
}
}
/**
* 尾首概率分析
*/
public function tailHeadProb()
{
if ($this->request->isAjax()) {
$periods = $this->request->get('periods', 100, 'intval');
$result = $this->model->getTailHeadProbability($periods);
$this->success('查询成功', null, $result);
}
}
/**
* 综合预测号码
* 基于历史多维度转移概率分析,给出号码预测建议
*/
public function predict()
{
if ($this->request->isAjax()) {
$periods = $this->request->get('periods', 100, 'intval');
if ($periods < 10 || $periods > 500) {
$this->error('期数范围必须在 10-500 之间');
}
// 权重配置(可选)
$weights = [];
$weightStr = $this->request->get('weights', '', 'trim');
if ($weightStr) {
$weightsArr = json_decode($weightStr, true);
if (is_array($weightsArr)) {
$weights = $weightsArr;
}
}
// 目标期号(可选,用于验证历史预测成功率)
$targetExpect = $this->request->get('target_expect', '', 'trim');
$result = $this->model->getPrediction($periods, $weights, $targetExpect);
if (isset($result['error'])) {
$this->error($result['error']);
}
$this->success('查询成功', null, $result);
}
}
/**
* 改进版智能预测算法
* 基于统计回归分析,包含遗漏回归、频率回归、区域平衡等多维度评分
*/
public function predictV2()
{
if ($this->request->isAjax()) {
$periods = $this->request->get('periods', 200, 'intval');
if ($periods < 30 || $periods > 500) {
$this->error('期数范围必须在 30-500 之间');
}
// 权重配置(可选)
$weights = [];
$weightStr = $this->request->get('weights', '', 'trim');
if ($weightStr) {
$weightsArr = json_decode($weightStr, true);
if (is_array($weightsArr)) {
$weights = $weightsArr;
}
}
// 目标期号(可选,用于验证历史预测成功率)
$targetExpect = $this->request->get('target_expect', '', 'trim');
// 回测期数(可选)
$backtestCount = $this->request->get('backtest', 50, 'intval');
if ($backtestCount < 10 || $backtestCount > 100) {
$backtestCount = 50;
}
$result = $this->model->getPredictionV2($periods, $weights, $targetExpect, false, $backtestCount);
if (isset($result['error'])) {
$this->error($result['error']);
}
$this->success('查询成功', null, $result);
}
}
/**
* 多维度综合预测算法 V3
* 新增维度:转移概率(马尔可夫链)、单双规律、大小规律、走势方向分析
*/
public function predictV3()
{
if ($this->request->isAjax()) {
$periods = $this->request->get('periods', 200, 'intval');
if ($periods < 30 || $periods > 500) {
$this->error('期数范围必须在 30-500 之间');
}
// 权重配置(可选)
$weights = [];
$weightStr = $this->request->get('weights', '', 'trim');
if ($weightStr) {
$weightsArr = json_decode($weightStr, true);
if (is_array($weightsArr)) {
$weights = $weightsArr;
}
}
// 目标期号(可选,用于验证历史预测成功率)
$targetExpect = $this->request->get('target_expect', '', 'trim');
// 回测期数(可选)
$backtestCount = $this->request->get('backtest', 50, 'intval');
if ($backtestCount < 10 || $backtestCount > 100) {
$backtestCount = 50;
}
$result = $this->model->getPredictionV3($periods, $weights, $targetExpect, false, $backtestCount);
if (isset($result['error'])) {
$this->error($result['error']);
}
$this->success('查询成功', null, $result);
}
}
/**
* 权重网格搜索优化接口
* 执行多权重配置回测,返回最优权重组合
*
* 参数说明:
* - periods: 统计期数,范围50-500,默认200
* - backtest: 回测期数,范围10-100,默认30
* - timeout: 超时秒数,范围10-120,默认60
*
* 返回说明:
* - best_weights: 最优权重配置
* - best_hit_rate: 最优配置命中率
* - all_results: 所有配置测试结果
* - timed_out: 是否超时中断
*/
public function optimizeWeights()
{
if ($this->request->isAjax()) {
// 参数验证
$periods = $this->request->get('periods', 200, 'intval');
if ($periods < 50 || $periods > 500) {
$this->error('期数范围必须在 50-500 之间');
}
$backtestCount = $this->request->get('backtest', 30, 'intval');
if ($backtestCount < 10 || $backtestCount > 100) {
$backtestCount = 30; // 使用默认值而非报错
}
$timeoutSeconds = $this->request->get('timeout', 60, 'intval');
if ($timeoutSeconds < 10 || $timeoutSeconds > 120) {
$timeoutSeconds = 60; // 使用默认值
}
// 执行优化
$result = $this->model->_optimizeWeightsGridSearch($periods, $backtestCount, $timeoutSeconds);
// 超时警告提示
$message = '优化完成';
if ($result['timed_out']) {
$message = '优化超时中断,已完成' . count($result['all_results']) . '种配置测试';
}
$this->success($message, null, $result);
}
}
/**
* 基于正码关联规律的特码预测
* 核心规律:
* - 波色重复规律:90.67%特码波色与正码中某号码波色相同
* - 距离规律:94.13%特码与最近正码距离<=10
* - 区间覆盖规律:74.13%特码落在正码覆盖的区间
* - 正码范围规律:70.67%特码在正码min-max之间
*/
public function predictByNormalRelation()
{
if ($this->request->isAjax()) {
$periods = $this->request->get('periods', 100, 'intval');
if ($periods < 30 || $periods > 500) {
$periods = 100;
}
$targetExpect = $this->request->get('target_expect', '', 'trim');
$result = $this->model->getPredictionByNormalRelation($periods, $targetExpect);
if (isset($result['error'])) {
$this->error($result['error']);
}
$this->success('查询成功', null, $result);
}
}
}