feat(dashboard): 添加后台仪表板功能并优化数据分析
- 新增 dashboard.js 文件实现前端图表展示功能 - 添加彩球渲染和颜色映射功能 - 实现数据加载和渲染逻辑 - 添加多种统计图表包括冷热号码、比例分析、生肖排名等 - 重构区域转移动态数据方法 - 更新区域到区域颜色转移概率计算逻辑 - 优化转移概率数据结构和显示方式 - 添加热力图和各种统计图表的响应式支持
This commit is contained in:
@@ -467,7 +467,7 @@ class History extends Model
|
|||||||
'heatmap' => $this->getSpecialHeatmap($periods),
|
'heatmap' => $this->getSpecialHeatmap($periods),
|
||||||
'zonetransition' => $this->getZoneTransition($periods),
|
'zonetransition' => $this->getZoneTransition($periods),
|
||||||
'colorwavetransition' => $this->getColorWaveTransition($periods),
|
'colorwavetransition' => $this->getColorWaveTransition($periods),
|
||||||
'zonetocolortransition' => $this->getZoneToColorTransition($periods)
|
'zonetocolortransition' => $this->getZoneToZoneColor($periods)
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -797,12 +797,12 @@ class History extends Model
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 区域→波色交叉转移概率
|
* 区域→区域转移矩阵,单元格内显示波色概率
|
||||||
* 统计上一期特码所在数字区域后,下一期特码波色(红/蓝/绿)的分布概率
|
* 统计上一期特码所在区域后,下一期特码在各区域的分布,以及每个区域内的波色占比
|
||||||
* @param int $periods 查询最近多少期
|
* @param int $periods 查询最近多少期
|
||||||
* @return array {zones: [], colors: [], matrix: [], probabilities: [], row_totals: [], total_transitions: int}
|
* @return array {zones: [], matrix: [[zone_count]], color_probs: [[{red, blue, green}]]}
|
||||||
*/
|
*/
|
||||||
public function getZoneToColorTransition($periods = 100)
|
public function getZoneToZoneColor($periods = 100)
|
||||||
{
|
{
|
||||||
$history = $this
|
$history = $this
|
||||||
->field('expect,num7,openTime')
|
->field('expect,num7,openTime')
|
||||||
@@ -811,7 +811,7 @@ class History extends Model
|
|||||||
->select();
|
->select();
|
||||||
|
|
||||||
if (empty($history) || count($history) < 2) {
|
if (empty($history) || count($history) < 2) {
|
||||||
return ['zones' => ['1-10','11-20','21-30','31-40','41-49'], 'colors' => ['红波','蓝波','绿波'], 'matrix' => [], 'probabilities' => [], 'row_totals' => [], 'total_transitions' => 0];
|
return ['zones' => ['1-10','11-20','21-30','31-40','41-49'], 'matrix' => [], 'color_probs' => []];
|
||||||
}
|
}
|
||||||
|
|
||||||
$history = array_reverse($history);
|
$history = array_reverse($history);
|
||||||
@@ -819,9 +819,13 @@ class History extends Model
|
|||||||
$colorMap = $num_model->column('color', 'num');
|
$colorMap = $num_model->column('color', 'num');
|
||||||
|
|
||||||
$zoneLabels = ['1-10', '11-20', '21-30', '31-40', '41-49'];
|
$zoneLabels = ['1-10', '11-20', '21-30', '31-40', '41-49'];
|
||||||
$colorLabels = ['红波', '蓝波', '绿波'];
|
$matrix = array_fill(0, 5, array_fill(0, 5, 0));
|
||||||
$matrix = array_fill(0, 5, array_fill(0, 3, 0));
|
$colorCounts = [];
|
||||||
$rowTotals = array_fill(0, 5, 0);
|
for ($i = 0; $i < 5; $i++) {
|
||||||
|
for ($j = 0; $j < 5; $j++) {
|
||||||
|
$colorCounts[$i][$j] = ['red' => 0, 'blue' => 0, 'green' => 0];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
$getZone = function ($num) {
|
$getZone = function ($num) {
|
||||||
if ($num <= 10) return 0;
|
if ($num <= 10) return 0;
|
||||||
@@ -831,43 +835,38 @@ class History extends Model
|
|||||||
return 4;
|
return 4;
|
||||||
};
|
};
|
||||||
|
|
||||||
$getColorIdx = function ($num) use ($colorMap) {
|
|
||||||
$color = $colorMap[$num] ?? '';
|
|
||||||
if (strpos($color, '红') !== false) return 0;
|
|
||||||
if (strpos($color, '蓝') !== false) return 1;
|
|
||||||
if (strpos($color, '绿') !== false) return 2;
|
|
||||||
return -1;
|
|
||||||
};
|
|
||||||
|
|
||||||
$totalTransitions = 0;
|
|
||||||
for ($i = 0; $i < count($history) - 1; $i++) {
|
for ($i = 0; $i < count($history) - 1; $i++) {
|
||||||
$currentNum = (int)$history[$i]['num7'];
|
$currentNum = (int)$history[$i]['num7'];
|
||||||
$nextNum = (int)$history[$i + 1]['num7'];
|
$nextNum = (int)$history[$i + 1]['num7'];
|
||||||
$from = $getZone($currentNum);
|
$from = $getZone($currentNum);
|
||||||
$to = $getColorIdx($nextNum);
|
$to = $getZone($nextNum);
|
||||||
if ($to < 0) continue;
|
$color = $colorMap[$nextNum] ?? '';
|
||||||
|
|
||||||
$matrix[$from][$to]++;
|
$matrix[$from][$to]++;
|
||||||
$rowTotals[$from]++;
|
if (strpos($color, '红') !== false) $colorCounts[$from][$to]['red']++;
|
||||||
$totalTransitions++;
|
elseif (strpos($color, '蓝') !== false) $colorCounts[$from][$to]['blue']++;
|
||||||
|
elseif (strpos($color, '绿') !== false) $colorCounts[$from][$to]['green']++;
|
||||||
}
|
}
|
||||||
|
|
||||||
$probabilities = array_fill(0, 5, array_fill(0, 3, 0));
|
// 计算每个单元格波色概率
|
||||||
|
$colorProbs = array_fill(0, 5, array_fill(0, 5, ['red' => 0, 'blue' => 0, 'green' => 0]));
|
||||||
for ($i = 0; $i < 5; $i++) {
|
for ($i = 0; $i < 5; $i++) {
|
||||||
if ($rowTotals[$i] > 0) {
|
for ($j = 0; $j < 5; $j++) {
|
||||||
for ($j = 0; $j < 3; $j++) {
|
$total = $matrix[$i][$j];
|
||||||
$probabilities[$i][$j] = round($matrix[$i][$j] / $rowTotals[$i] * 100, 1);
|
if ($total > 0) {
|
||||||
|
$colorProbs[$i][$j] = [
|
||||||
|
'red' => round($colorCounts[$i][$j]['red'] / $total * 100, 1),
|
||||||
|
'blue' => round($colorCounts[$i][$j]['blue'] / $total * 100, 1),
|
||||||
|
'green' => round($colorCounts[$i][$j]['green'] / $total * 100, 1),
|
||||||
|
];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return [
|
return [
|
||||||
'zones' => $zoneLabels,
|
'zones' => $zoneLabels,
|
||||||
'colors' => $colorLabels,
|
|
||||||
'matrix' => $matrix,
|
'matrix' => $matrix,
|
||||||
'probabilities' => $probabilities,
|
'color_probs' => $colorProbs
|
||||||
'row_totals' => $rowTotals,
|
|
||||||
'total_transitions' => $totalTransitions
|
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -131,24 +131,23 @@ define(['jquery'], function ($) {
|
|||||||
html += '</tbody></table></div>';
|
html += '</tbody></table></div>';
|
||||||
}
|
}
|
||||||
html += '</div>';
|
html += '</div>';
|
||||||
// 下方:区域→波色交叉转移
|
// 下方:区域→区域转移矩阵,单元格内显示波色概率
|
||||||
var ztc = data.zonetocolortransition;
|
var ztc = data.zonetocolortransition;
|
||||||
if (ztc && ztc.matrix && ztc.matrix.length > 0) {
|
if (ztc && ztc.matrix && ztc.matrix.length > 0) {
|
||||||
html += '<div style="margin-top:20px;font-size:12px;color:#999;margin-bottom:8px;">区域→波色交叉转移(共 ' + ztc.total_transitions + ' 次)</div>';
|
html += '<div style="margin-top:20px;font-size:12px;color:#999;margin-bottom:8px;">区域→区域转移矩阵(单元格内为波色概率)</div>';
|
||||||
html += '<table class="table table-bordered table-condensed text-center" style="max-width:500px;margin:0 auto;"><thead><tr><th style="width:80px;position:relative;"><div style="width:100%;height:35px;border-bottom:1px solid #e5e5e5;position:relative;"><span style="position:absolute;top:2px;right:5px;font-size:12px;">波色</span><span style="position:absolute;bottom:2px;left:5px;font-size:12px;">特码</span></div></th>';
|
html += '<table class="table table-bordered table-condensed text-center" style="max-width:600px;margin:0 auto;"><thead><tr><th style="width:80px;position:relative;"><div style="width:100%;height:35px;border-bottom:1px solid #e5e5e5;position:relative;"><span style="position:absolute;top:2px;right:5px;font-size:12px;">区域</span><span style="position:absolute;bottom:2px;left:5px;font-size:12px;">特码</span></div></th>';
|
||||||
var cwColors2 = ['#e74c3c', '#3498db', '#2ecc71'];
|
for (var z = 0; z < ztc.zones.length; z++) {
|
||||||
for (var z = 0; z < ztc.colors.length; z++) {
|
html += '<th>' + ztc.zones[z] + '</th>';
|
||||||
html += '<th><span style="color:' + cwColors2[z] + '">' + ztc.colors[z] + '</span></th>';
|
|
||||||
}
|
}
|
||||||
html += '</tr></thead><tbody>';
|
html += '</tr></thead><tbody>';
|
||||||
for (var r = 0; r < 5; r++) {
|
for (var r = 0; r < 5; r++) {
|
||||||
html += '<tr><td style="font-weight:bold;">' + ztc.zones[r] + '</td>';
|
html += '<tr><td style="font-weight:bold;">' + ztc.zones[r] + '</td>';
|
||||||
for (var c = 0; c < 3; c++) {
|
for (var c = 0; c < 5; c++) {
|
||||||
var pct = ztc.probabilities[r][c];
|
|
||||||
var cnt = ztc.matrix[r][c];
|
var cnt = ztc.matrix[r][c];
|
||||||
var bg = pct > 40 ? cwColors2[c] : pct > 20 ? cwColors2[c] + 'cc' : pct > 0 ? '#95a5a6' : '#f5f5f5';
|
var cp = ztc.color_probs[r][c];
|
||||||
var txt = pct > 20 ? '#fff' : '#333';
|
var bg = cnt > 0 ? '#fafafa' : '#fff';
|
||||||
html += '<td style="background-color:' + bg + ';color:' + txt + ';">' + cnt + '次<br>' + pct + '%</td>';
|
var txt = (cp.red > 40 || cp.blue > 40 || cp.green > 40) ? '#fff' : '#333';
|
||||||
|
html += '<td style="background-color:' + bg + ';color:' + txt + ';"><span style="color:#e74c3c;">红' + cp.red + '%</span><br><span style="color:#3498db;">蓝' + cp.blue + '%</span><br><span style="color:#2ecc71;">绿' + cp.green + '%</span><br><span style="font-size:11px;color:#000;">(' + cnt + '次)</span></td>';
|
||||||
}
|
}
|
||||||
html += '</tr>';
|
html += '</tr>';
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user