diff --git a/application/admin/controller/History.php b/application/admin/controller/History.php index 7b19a59..286cf77 100644 --- a/application/admin/controller/History.php +++ b/application/admin/controller/History.php @@ -22,7 +22,7 @@ class History extends Backend * 无需额外权限检查的方法(但仍在 admin 模块内,需要 admin 登录) * @var array */ - protected $noNeedRight = ['missingNum', 'trendData', 'hotColdNumbers', 'colorWaveAnalysis', 'zodiacAnalysis', 'oddEvenAnalysis', 'bigSmallAnalysis', 'specialTrend', 'consecutiveNumbers', 'tailNumbers', 'dashboard', 'specialHeatmap', 'specialHotColdAction']; + protected $noNeedRight = ['missingNum', 'trendData', 'hotColdNumbers', 'colorWaveAnalysis', 'zodiacAnalysis', 'oddEvenAnalysis', 'bigSmallAnalysis', 'specialTrend', 'consecutiveNumbers', 'tailNumbers', 'dashboard', 'specialHeatmap', 'specialHotColdAction', 'zoneTransition']; public function _initialize() { @@ -313,5 +313,20 @@ class History extends Backend } } + /** + * 区域转移概率统计 + */ + 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); + } + } + } diff --git a/application/admin/model/History.php b/application/admin/model/History.php index a146e93..15b5b55 100644 --- a/application/admin/model/History.php +++ b/application/admin/model/History.php @@ -464,7 +464,8 @@ class History extends Model 'bigsmall' => $this->getBigSmallAnalysis($periods, 'special'), 'special' => $this->getSpecialTrend($periods), 'tailnumbers' => $this->getTailNumbers($periods, 'special'), - 'heatmap' => $this->getSpecialHeatmap($periods) + 'heatmap' => $this->getSpecialHeatmap($periods), + 'zonetransition' => $this->getZoneTransition($periods) ]; } @@ -662,6 +663,69 @@ class History extends Model return ['hot' => $hot, 'cold' => $cold, 'warm' => $warm]; } + /** + * 区域转移概率统计 + * 将1-49分为5个区域,统计特码从一个区域转移到另一个区域的概率 + * 区域1: 1-10, 区域2: 11-20, 区域3: 21-30, 区域4: 31-40, 区域5: 41-49 + * @param int $periods 查询最近多少期 + * @return array {zones: [], matrix: [], probabilities: [], total_transitions: int} + */ + public function getZoneTransition($periods = 100) + { + $history = $this + ->field('expect,num7,openTime') + ->order('openTime', 'asc') + ->limit($periods) + ->select(); + + if (empty($history) || count($history) < 2) { + return ['zones' => ['1-10','11-20','21-30','31-40','41-49'], 'matrix' => [], 'probabilities' => [], 'total_transitions' => 0]; + } + + $zoneLabels = ['1-10', '11-20', '21-30', '31-40', '41-49']; + $matrix = array_fill(0, 5, array_fill(0, 5, 0)); + $rowTotals = array_fill(0, 5, 0); + + $getZone = function ($num) { + if ($num <= 10) return 0; + if ($num <= 20) return 1; + if ($num <= 30) return 2; + if ($num <= 40) return 3; + return 4; + }; + + $totalTransitions = 0; + for ($i = 0; $i < count($history) - 1; $i++) { + $currentNum = (int)$history[$i]['num7']; + $nextNum = (int)$history[$i + 1]['num7']; + if ($currentNum < 1 || $currentNum > 49 || $nextNum < 1 || $nextNum > 49) continue; + + $from = $getZone($currentNum); + $to = $getZone($nextNum); + $matrix[$from][$to]++; + $rowTotals[$from]++; + $totalTransitions++; + } + + // 计算概率矩阵 + $probabilities = array_fill(0, 5, array_fill(0, 5, 0)); + for ($i = 0; $i < 5; $i++) { + if ($rowTotals[$i] > 0) { + for ($j = 0; $j < 5; $j++) { + $probabilities[$i][$j] = round($matrix[$i][$j] / $rowTotals[$i] * 100, 1); + } + } + } + + return [ + 'zones' => $zoneLabels, + 'matrix' => $matrix, + 'probabilities' => $probabilities, + 'row_totals' => $rowTotals, + 'total_transitions' => $totalTransitions + ]; + } + /** * 特码热力图数据 * @param int $periods 查询最近多少期 diff --git a/public/assets/js/backend/dashboard.js b/public/assets/js/backend/dashboard.js index efb6bea..e2bdb04 100644 --- a/public/assets/js/backend/dashboard.js +++ b/public/assets/js/backend/dashboard.js @@ -40,6 +40,7 @@ define(['jquery'], function ($) { function render(data) { var hc = data.hotcold, cw = data.colorwave, zo = data.zodiac; var oe = data.oddeven, bs = data.bigsmall, sp = data.special, tn = data.tailnumbers; + var zt = data.zonetransition; var html = ''; @@ -88,6 +89,28 @@ define(['jquery'], function ($) { var hm = data.heatmap; html += '

🎨 特码热力图

X轴:期号(从左往右,从远到近) | Y轴:号码1-49 | 颜色:号码波色
'; + // 区域转移概率 + if (zt && zt.matrix && zt.matrix.length > 0) { + html += '

🔄 区域转移概率

当前共 ' + zt.total_transitions + ' 次区域转移 | 行=上一期特码所在区域,列=下一期特码所在区域
'; + html += ''; + for (var z = 0; z < zt.zones.length; z++) { + html += ''; + } + html += ''; + for (var r = 0; r < 5; r++) { + html += ''; + for (var c = 0; c < 5; c++) { + var pct = zt.probabilities[r][c]; + var cnt = zt.matrix[r][c]; + var bg = pct > 30 ? '#e74c3c' : pct > 20 ? '#f39c12' : pct > 10 ? '#3498db' : pct > 0 ? '#95a5a6' : '#f5f5f5'; + var txt = pct > 10 ? '#fff' : '#333'; + html += ''; + } + html += ''; + } + html += '
区域→' + zt.zones[z] + '
' + zt.zones[r] + '' + cnt + '次
' + pct + '%
'; + } + $('#dash-content').html(html); // 波色饼图