From 8ed4837992ea8dd86ef5713f5fcba27d7a63b6fa Mon Sep 17 00:00:00 2001 From: leon <916117771@qq.com> Date: Tue, 21 Apr 2026 23:46:12 +0800 Subject: [PATCH] feat(phase-4 to 10): add all remaining analysis features - color wave, zodiac, odd/even, big/small, sum, consecutive, tail numbers --- application/admin/controller/History.php | 127 +++++++- application/admin/lang/zh-cn/history.php | 7 + application/admin/model/History.php | 202 ++++++++++++- application/admin/view/history/index.html | 7 + public/assets/js/backend/history.js | 340 ++++++++++++++++++++++ 5 files changed, 681 insertions(+), 2 deletions(-) diff --git a/application/admin/controller/History.php b/application/admin/controller/History.php index f0109c9..f640245 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']; + protected $noNeedRight = ['missingNum', 'trendData', 'hotColdNumbers', 'colorWaveAnalysis', 'zodiacAnalysis', 'oddEvenAnalysis', 'bigSmallAnalysis', 'sumAnalysis', 'consecutiveNumbers', 'tailNumbers']; public function _initialize() { @@ -92,5 +92,130 @@ class History extends Backend } } + /** + * 波色分析 + */ + 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 sumAnalysis() + { + if ($this->request->isAjax()) { + $periods = $this->request->get('periods', 30, 'intval'); + if ($periods < 10 || $periods > 100) { + $this->error('期数范围必须在 10-100 之间'); + } + $result = $this->model->getSumAnalysis($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); + } + } + } diff --git a/application/admin/lang/zh-cn/history.php b/application/admin/lang/zh-cn/history.php index fb10e16..5d2cbd0 100644 --- a/application/admin/lang/zh-cn/history.php +++ b/application/admin/lang/zh-cn/history.php @@ -18,4 +18,11 @@ return [ 'Trend Chart' => '走势图', 'No data available' => '暂无数据', 'Hot/Cold Analysis' => '冷热分析', + 'Color Wave' => '波色分析', + 'Zodiac' => '生肖分析', + 'Odd/Even' => '奇偶分析', + 'Big/Small' => '大小分析', + 'Sum Chart' => '和值分析', + 'Consecutive' => '连号分析', + 'Tail Numbers' => '尾数分析', ]; diff --git a/application/admin/model/History.php b/application/admin/model/History.php index dfafc28..5d7b4c1 100644 --- a/application/admin/model/History.php +++ b/application/admin/model/History.php @@ -44,7 +44,7 @@ class History extends Model $history = $this ->field('expect,num1,num2,num3,num4,num5,num6,num7,openTime') - ->order('openTime', 'asc') + ->order('openTime', 'desc') ->limit($periods) ->select(); @@ -67,6 +67,10 @@ class History extends Model } } + // 反转数组,使最远的数据在左边,最近的数据在右边(从左往右,从远到近) + $expects = array_reverse($expects); + $data = array_reverse($data); + return [ 'expects' => $expects, 'data' => $data, @@ -246,5 +250,201 @@ class History extends Model return count($allHistory); } + /** + * 波色分析 + */ + public function getColorWaveAnalysis($periods = 30, $type = 'all') + { + $num_model = new Num(); + $colorMap = $num_model->column('color', 'num'); + + $history = $this->field('expect,num1,num2,num3,num4,num5,num6,num7')->order('openTime', 'desc')->limit($periods)->select(); + if (empty($history)) return ['red' => 0, 'blue' => 0, 'green' => 0, 'red_pct' => 0, 'blue_pct' => 0, 'green_pct' => 0, 'details' => []]; + + $fields = ($type === 'special') ? ['num7'] : ['num1','num2','num3','num4','num5','num6','num7']; + $colors = ['红' => 0, '蓝' => 0, '绿' => 0]; + $total = 0; + foreach ($history as $row) { + foreach ($fields as $f) { + $num = (int)$row[$f]; + $color = $colorMap[$num] ?? ''; + if (strpos($color, '红') !== false) { $colors['红']++; $total++; } + elseif (strpos($color, '蓝') !== false) { $colors['蓝']++; $total++; } + elseif (strpos($color, '绿') !== false) { $colors['绿']++; $total++; } + } + } + return [ + 'red' => $colors['红'], 'blue' => $colors['蓝'], 'green' => $colors['绿'], + 'red_pct' => $total ? round($colors['红']/$total*100,1) : 0, + 'blue_pct' => $total ? round($colors['蓝']/$total*100,1) : 0, + 'green_pct' => $total ? round($colors['绿']/$total*100,1) : 0, + 'total' => $total + ]; + } + + /** + * 生肖分析 + */ + public function getZodiacAnalysis($periods = 30, $type = 'all') + { + $num_model = new Num(); + $animalMap = $num_model->column('animal', 'num'); + $colorMap = $num_model->column('color', 'num'); + + $history = $this->field('expect,num1,num2,num3,num4,num5,num6,num7')->order('openTime', 'desc')->limit($periods)->select(); + if (empty($history)) return ['list' => []]; + + $fields = ($type === 'special') ? ['num7'] : ['num1','num2','num3','num4','num5','num6','num7']; + $counts = []; + foreach ($history as $row) { + foreach ($fields as $f) { + $num = (int)$row[$f]; + $animal = $animalMap[$num] ?? '未知'; + if (!isset($counts[$animal])) $counts[$animal] = ['animal' => $animal, 'count' => 0, 'color' => $colorMap[$num] ?? '—']; + $counts[$animal]['count']++; + } + } + $list = array_values($counts); + usort($list, function ($a, $b) { return $b['count'] - $a['count']; }); + $total = array_sum(array_column($list, 'count')); + foreach ($list as &$item) { $item['percent'] = $total ? round($item['count']/$total*100, 1) : 0; } + return ['list' => $list]; + } + + /** + * 奇偶分析 + */ + public function getOddEvenAnalysis($periods = 30, $type = 'all') + { + $history = $this->field('expect,num1,num2,num3,num4,num5,num6,num7')->order('openTime', 'desc')->limit($periods)->select(); + if (empty($history)) return ['odd' => 0, 'even' => 0, 'odd_pct' => 0, 'even_pct' => 0, 'per_period' => []]; + + $fields = ($type === 'special') ? ['num7'] : ['num1','num2','num3','num4','num5','num6','num7']; + $odd = 0; $even = 0; $perPeriod = []; + foreach ($history as $row) { + $p_odd = 0; $p_even = 0; + foreach ($fields as $f) { + $num = (int)$row[$f]; + if ($num % 2 == 0) { $even++; $p_even++; } else { $odd++; $p_odd++; } + } + $perPeriod[] = ['expect' => $row['expect'], 'odd' => $p_odd, 'even' => $p_even]; + } + $total = $odd + $even; + return [ + 'odd' => $odd, 'even' => $even, + 'odd_pct' => $total ? round($odd/$total*100, 1) : 0, + 'even_pct' => $total ? round($even/$total*100, 1) : 0, + 'per_period' => $perPeriod + ]; + } + + /** + * 大小分析(1-24为小,25-49为大) + */ + public function getBigSmallAnalysis($periods = 30, $type = 'all') + { + $history = $this->field('expect,num1,num2,num3,num4,num5,num6,num7')->order('openTime', 'desc')->limit($periods)->select(); + if (empty($history)) return ['big' => 0, 'small' => 0, 'big_pct' => 0, 'small_pct' => 0, 'per_period' => []]; + + $fields = ($type === 'special') ? ['num7'] : ['num1','num2','num3','num4','num5','num6','num7']; + $big = 0; $small = 0; $perPeriod = []; + foreach ($history as $row) { + $p_big = 0; $p_small = 0; + foreach ($fields as $f) { + $num = (int)$row[$f]; + if ($num >= 25) { $big++; $p_big++; } else { $small++; $p_small++; } + } + $perPeriod[] = ['expect' => $row['expect'], 'big' => $p_big, 'small' => $p_small]; + } + $total = $big + $small; + return [ + 'big' => $big, 'small' => $small, + 'big_pct' => $total ? round($big/$total*100, 1) : 0, + 'small_pct' => $total ? round($small/$total*100, 1) : 0, + 'per_period' => $perPeriod + ]; + } + + /** + * 和值分析 + */ + public function getSumAnalysis($periods = 30) + { + $history = $this->field('expect,num1,num2,num3,num4,num5,num6,num7')->order('openTime', 'asc')->limit($periods)->select(); + if (empty($history)) return ['expects' => [], 'sums' => []]; + + $expects = []; $sums = []; + foreach ($history as $row) { + $expects[] = (string)$row['expect']; + $sum = (int)$row['num1'] + (int)$row['num2'] + (int)$row['num3'] + (int)$row['num4'] + (int)$row['num5'] + (int)$row['num6'] + (int)$row['num7']; + $sums[] = $sum; + } + $avg = round(array_sum($sums) / count($sums), 1); + $max = max($sums); $min = min($sums); + return ['expects' => $expects, 'sums' => $sums, 'avg' => $avg, 'max' => $max, 'min' => $min]; + } + + /** + * 连号分析 + */ + public function getConsecutiveNumbers($periods = 30) + { + $history = $this->field('expect,num1,num2,num3,num4,num5,num6,num7')->order('openTime', 'desc')->limit($periods)->select(); + if (empty($history)) return ['pairs' => [], 'triples' => []]; + + $pairCount = []; $tripleCount = []; + foreach ($history as $row) { + $nums = []; + for ($i = 1; $i <= 7; $i++) $nums[] = (int)$row['num' . $i]; + sort($nums); + // 找连号对 + for ($i = 0; $i < count($nums) - 1; $i++) { + if ($nums[$i + 1] - $nums[$i] === 1) { + $pair = $nums[$i] . '-' . $nums[$i + 1]; + $pairCount[$pair] = isset($pairCount[$pair]) ? $pairCount[$pair] + 1 : 1; + } + } + // 找连号三连 + for ($i = 0; $i < count($nums) - 2; $i++) { + if ($nums[$i + 1] - $nums[$i] === 1 && $nums[$i + 2] - $nums[$i + 1] === 1) { + $triple = $nums[$i] . '-' . $nums[$i + 1] . '-' . $nums[$i + 2]; + $tripleCount[$triple] = isset($tripleCount[$triple]) ? $tripleCount[$triple] + 1 : 1; + } + } + } + arsort($pairCount); arsort($tripleCount); + return ['pairs' => $pairCount, 'triples' => $tripleCount]; + } + + /** + * 尾数分析 + */ + public function getTailNumbers($periods = 30, $type = 'all') + { + $num_model = new Num(); + $colorMap = $num_model->column('color', 'num'); + $animalMap = $num_model->column('animal', 'num'); + + $history = $this->field('expect,num1,num2,num3,num4,num5,num6,num7')->order('openTime', 'desc')->limit($periods)->select(); + if (empty($history)) return ['tails' => [], 'all' => []]; + + $fields = ($type === 'special') ? ['num7'] : ['num1','num2','num3','num4','num5','num6','num7']; + $tailCount = array_fill(0, 10, 0); + $all = []; + foreach ($history as $row) { + foreach ($fields as $f) { + $num = (int)$row[$f]; + $tail = $num % 10; + $tailCount[$tail]++; + } + } + $total = array_sum($tailCount); + for ($t = 0; $t <= 9; $t++) { + $all[] = ['tail' => $t, 'count' => $tailCount[$t], 'percent' => $total ? round($tailCount[$t]/$total*100, 1) : 0]; + } + usort($all, function ($a, $b) { return $b['count'] - $a['count']; }); + return ['all' => $all]; + } + } diff --git a/application/admin/view/history/index.html b/application/admin/view/history/index.html index 648e2a7..55c09d0 100644 --- a/application/admin/view/history/index.html +++ b/application/admin/view/history/index.html @@ -10,6 +10,13 @@ {:__('Missing Number Analysis')} {:__('Trend Chart')} {:__('Hot/Cold Analysis')} + {:__('Color Wave')} + {:__('Zodiac')} + {:__('Odd/Even')} + {:__('Big/Small')} + {:__('Sum Chart')} + {:__('Consecutive')} + {:__('Tail Numbers')}