feat(phase-4 to 10): add all remaining analysis features - color wave, zodiac, odd/even, big/small, sum, consecutive, tail numbers
This commit is contained in:
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -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' => '尾数分析',
|
||||
];
|
||||
|
||||
@@ -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];
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -10,6 +10,13 @@
|
||||
<a href="javascript:;" class="btn btn-warning btn-missingnum" title="{:__('Missing Number Analysis')}"><i class="fa fa-search"></i> {:__('Missing Number Analysis')}</a>
|
||||
<a href="javascript:;" class="btn btn-info btn-trend" title="{:__('Trend Chart')}"><i class="fa fa-area-chart"></i> {:__('Trend Chart')}</a>
|
||||
<a href="javascript:;" class="btn btn-danger btn-hotcold" title="{:__('Hot/Cold Analysis')}"><i class="fa fa-fire"></i> {:__('Hot/Cold Analysis')}</a>
|
||||
<a href="javascript:;" class="btn btn-success btn-colorwave" title="{:__('Color Wave')}"><i class="fa fa-paint-brush"></i> {:__('Color Wave')}</a>
|
||||
<a href="javascript:;" class="btn btn-purple btn-zodiac" title="{:__('Zodiac')}"><i class="fa fa-star"></i> {:__('Zodiac')}</a>
|
||||
<a href="javascript:;" class="btn btn-warning btn-oddeven" title="{:__('Odd/Even')}"><i class="fa fa-balance-scale"></i> {:__('Odd/Even')}</a>
|
||||
<a href="javascript:;" class="btn btn-info btn-bigsmall" title="{:__('Big/Small')}"><i class="fa fa-arrows-h"></i> {:__('Big/Small')}</a>
|
||||
<a href="javascript:;" class="btn btn-primary btn-sumchart" title="{:__('Sum Chart')}"><i class="fa fa-line-chart"></i> {:__('Sum Chart')}</a>
|
||||
<a href="javascript:;" class="btn btn-dark btn-consecutive" title="{:__('Consecutive')}"><i class="fa fa-link"></i> {:__('Consecutive')}</a>
|
||||
<a href="javascript:;" class="btn btn-default btn-tailnums" title="{:__('Tail Numbers')}"><i class="fa fa-list-ol"></i> {:__('Tail Numbers')}</a>
|
||||
<!-- <a href="javascript:;" class="btn btn-success btn-add {:$auth->check('history/add')?'':'hide'}" title="{:__('Add')}" ><i class="fa fa-plus"></i> {:__('Add')}</a>-->
|
||||
</div>
|
||||
<table id="table" class="table table-striped table-bordered table-hover table-nowrap"
|
||||
|
||||
Reference in New Issue
Block a user