fix(history): 重构特码冷热功能 — 改为弹窗列表展示每期相对于前N期的冷热状态
改为批量查询模式:每期特码相对于它前面N期的出现频率判定冷热 弹窗内以表格形式展示所有期号、特码球、冷热标签、次数、排名 支持调整向前期数(10-100),打开弹窗自动查询
This commit is contained in:
@@ -1,35 +1,35 @@
|
|||||||
---
|
---
|
||||||
description: 在history页面新增特码冷热查询功能 — 选定某一期,向前推算y期,判定该期特码属于冷号还是热号
|
description: 在history页面新增特码冷热列表功能 — 每期特码相对于它前面N期的冷热状态
|
||||||
status: complete
|
status: complete
|
||||||
date: 2026-04-24
|
date: 2026-04-24
|
||||||
---
|
---
|
||||||
|
|
||||||
# Quick Task Summary: 特码冷热查询
|
# Quick Task Summary: 特码冷热列表
|
||||||
|
|
||||||
## What was built
|
## What was built
|
||||||
|
|
||||||
新增「特码冷热查询」功能,允许用户选择任意历史期号,设定向前追溯期数(10-100期),系统自动判定该期特码在追溯范围内属于冷号、温号还是热号。
|
新增「特码冷热列表」功能,以弹窗表格形式展示每一期特码相对于它前面 N 期的冷热状态。
|
||||||
|
|
||||||
|
### 核心逻辑
|
||||||
|
- 对每一期,取它**前面** N 期(不包含自身)的历史数据
|
||||||
|
- 统计这 N 期内 49 个号码各自作为特码的出现次数
|
||||||
|
- 计算平均值(N / 49),对比该期特码的出现次数:
|
||||||
|
- **热号**:出现次数 > 平均值 × 1.5
|
||||||
|
- **冷号**:出现次数 < 平均值 × 0.5
|
||||||
|
- **温号**:介于两者之间
|
||||||
|
|
||||||
## Changes made
|
## Changes made
|
||||||
|
|
||||||
### Backend — Model (`application/admin/model/History.php`)
|
### Model (`application/admin/model/History.php`)
|
||||||
- 新增 `getSpecialHotColdByExpect($expect, $lookback)` 方法
|
- `getSpecialHotColdList($lookback, $limit)` — 批量查询,返回每期的冷热状态数组
|
||||||
- 逻辑:根据指定期号找到该期特码,向前取 lookback 期数据,统计49个号码各自的出现次数
|
|
||||||
- 判定标准:出现次数 > 平均值×1.5 → 热号;< 平均值×0.5 → 冷号;其余为温号
|
|
||||||
- 返回包含:特码值、出现次数、平均值、冷热状态、频率排名、热号Top5、冷号Top5
|
|
||||||
|
|
||||||
### Backend — Controller (`application/admin/controller/History.php`)
|
### Controller (`application/admin/controller/History.php`)
|
||||||
- 新增 `specialHotColdAction()` 接口方法
|
- `specialHotColdAction()` — AJAX 接口,接收 `lookback`(默认30)和 `limit`(默认100)
|
||||||
- 接收 `expect`(期号,必填)和 `lookback`(向前期数,默认30,范围10-100)
|
|
||||||
- 已加入 `noNeedRight` 白名单
|
|
||||||
|
|
||||||
### Frontend — View (`application/admin/view/history/index.html`)
|
### Frontend (`history.js`)
|
||||||
- 在 toolbar 新增「特码冷热」按钮(红色主题,fa-fire 图标)
|
- `showSpecialHotColdDialog()` — 弹窗,包含向前期数输入框 + 查询按钮
|
||||||
|
- `querySpecialHotCold()` — AJAX 请求
|
||||||
### Frontend — JS (`public/assets/js/backend/history.js`)
|
- `renderSpecialHotCold()` — 表格渲染:期号、特码球(带波色)、冷热标签、出现次数、平均次数、频率排名;热号行淡红背景、冷号行淡蓝背景
|
||||||
- 新增 `showSpecialHotColdDialog()` — 弹窗包含:期号下拉选择(加载最近50期)、向前期数输入框、查询按钮
|
|
||||||
- 新增 `querySpecialHotCold()` — AJAX 请求后端
|
|
||||||
- 新增 `renderSpecialHotCold()` — 卡片式渲染结果:大号球显示特码、冷热状态标签、统计数据、热号/冷号Top5球
|
|
||||||
|
|
||||||
## Commit
|
## Commit
|
||||||
`2513bbb`
|
`d4a5c30`
|
||||||
|
|||||||
@@ -237,23 +237,20 @@ class History extends Backend
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 特码冷热查询(指定期号向前y期判定)
|
* 特码冷热列表(每期相对于前N期的冷热状态)
|
||||||
*/
|
*/
|
||||||
public function specialHotColdAction()
|
public function specialHotColdAction()
|
||||||
{
|
{
|
||||||
if ($this->request->isAjax()) {
|
if ($this->request->isAjax()) {
|
||||||
$expect = $this->request->get('expect', '');
|
|
||||||
if (empty($expect)) {
|
|
||||||
$this->error('请输入期号');
|
|
||||||
}
|
|
||||||
$lookback = $this->request->get('lookback', 30, 'intval');
|
$lookback = $this->request->get('lookback', 30, 'intval');
|
||||||
if ($lookback < 10 || $lookback > 100) {
|
if ($lookback < 10 || $lookback > 100) {
|
||||||
$this->error('向前期数范围必须在 10-100 之间');
|
$this->error('向前期数范围必须在 10-100 之间');
|
||||||
}
|
}
|
||||||
$result = $this->model->getSpecialHotColdByExpect($expect, $lookback);
|
$limit = $this->request->get('limit', 100, 'intval');
|
||||||
if ($result === false) {
|
if ($limit < 10 || $limit > 200) {
|
||||||
$this->error('未找到该期号数据');
|
$this->error('查询期数范围必须在 10-200 之间');
|
||||||
}
|
}
|
||||||
|
$result = $this->model->getSpecialHotColdList($lookback, $limit);
|
||||||
$this->success('查询成功', null, $result);
|
$this->success('查询成功', null, $result);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -469,60 +469,89 @@ class History extends Model
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 查询指定期号特码在向前y期范围内的冷热状态
|
* 批量查询所有期号特码相对于前N期的冷热状态
|
||||||
* @param string|int $expect 指定期号
|
|
||||||
* @param int $lookback 向前推算期数
|
* @param int $lookback 向前推算期数
|
||||||
* @return array|false 冷热状态数据,未找到返回false
|
* @param int $limit 查询总期数(从最新往前取)
|
||||||
|
* @return array [{expect, specialNum, count, avgCount, status, rank, totalPeriods}, ...]
|
||||||
*/
|
*/
|
||||||
public function getSpecialHotColdByExpect($expect, $lookback = 30)
|
public function getSpecialHotColdList($lookback = 30, $limit = 100)
|
||||||
{
|
{
|
||||||
// 查询指定期号的数据
|
// 查询最近 $limit 期数据,按时间倒序(最新在前)
|
||||||
$target = $this->where('expect', $expect)->field('expect,num7,openTime')->find();
|
|
||||||
if (!$target) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
$specialNum = (int)$target['num7'];
|
|
||||||
|
|
||||||
// 查询该期往前lookback期的数据(按openTime排序,取目标期之前的lookback条)
|
|
||||||
$history = $this
|
$history = $this
|
||||||
->field('expect,num7,openTime')
|
->field('expect,num7,openTime')
|
||||||
->where('openTime', '<', $target['openTime'])
|
|
||||||
->order('openTime', 'desc')
|
->order('openTime', 'desc')
|
||||||
->limit($lookback)
|
->limit($limit)
|
||||||
->select();
|
->select();
|
||||||
|
|
||||||
$totalPeriods = count($history);
|
if (empty($history)) {
|
||||||
if ($totalPeriods === 0) {
|
return [];
|
||||||
return [
|
|
||||||
'expect' => (string)$expect,
|
|
||||||
'specialNum' => $specialNum,
|
|
||||||
'lookback' => $lookback,
|
|
||||||
'count' => 0,
|
|
||||||
'avgCount' => 0,
|
|
||||||
'status' => 'cold',
|
|
||||||
'rank' => 0,
|
|
||||||
'totalPeriods' => 0,
|
|
||||||
'allStats' => []
|
|
||||||
];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// 统计lookback范围内每个特码的出现次数
|
// 查询更多历史数据用于统计
|
||||||
$count = array_fill(1, 49, 0);
|
$allHistory = $this
|
||||||
|
->field('expect,num7,openTime')
|
||||||
|
->order('openTime', 'desc')
|
||||||
|
->limit($limit + 200)
|
||||||
|
->select();
|
||||||
|
|
||||||
|
// 按openTime排序(确保顺序)
|
||||||
|
$historySorted = [];
|
||||||
foreach ($history as $row) {
|
foreach ($history as $row) {
|
||||||
$num = (int)$row['num7'];
|
$historySorted[] = $row;
|
||||||
|
}
|
||||||
|
$allHistorySorted = [];
|
||||||
|
foreach ($allHistory as $row) {
|
||||||
|
$allHistorySorted[] = $row;
|
||||||
|
}
|
||||||
|
|
||||||
|
$result = [];
|
||||||
|
|
||||||
|
// 对每一期,计算它前面lookback期的冷热状态
|
||||||
|
for ($i = 0; $i < count($historySorted); $i++) {
|
||||||
|
$row = $historySorted[$i];
|
||||||
|
$specialNum = (int)$row['num7'];
|
||||||
|
|
||||||
|
// 找到该期在全量数据中的位置
|
||||||
|
$targetTime = $row['openTime'];
|
||||||
|
$count = array_fill(1, 49, 0);
|
||||||
|
$periodCount = 0;
|
||||||
|
|
||||||
|
// 往前统计lookback期(跳过该期本身)
|
||||||
|
for ($j = 0; $j < count($allHistorySorted); $j++) {
|
||||||
|
$checkRow = $allHistorySorted[$j];
|
||||||
|
$checkTime = $checkRow['openTime'];
|
||||||
|
|
||||||
|
// 只统计比该期更早的数据
|
||||||
|
if ($checkTime >= $targetTime) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($periodCount >= $lookback) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
$num = (int)$checkRow['num7'];
|
||||||
if ($num >= 1 && $num <= 49) {
|
if ($num >= 1 && $num <= 49) {
|
||||||
$count[$num]++;
|
$count[$num]++;
|
||||||
}
|
}
|
||||||
|
$periodCount++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($periodCount === 0) {
|
||||||
|
$result[] = [
|
||||||
|
'expect' => (string)$row['expect'],
|
||||||
|
'specialNum' => $specialNum,
|
||||||
|
'count' => 0,
|
||||||
|
'avgCount' => 0,
|
||||||
|
'status' => 'unknown',
|
||||||
|
'rank' => 0
|
||||||
|
];
|
||||||
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 计算目标特码的出现次数
|
|
||||||
$targetCount = $count[$specialNum];
|
$targetCount = $count[$specialNum];
|
||||||
|
$avgCount = $periodCount / 49;
|
||||||
|
|
||||||
// 计算平均出现次数(49个号码,totalPeriods期)
|
|
||||||
$avgCount = $totalPeriods / 49;
|
|
||||||
|
|
||||||
// 判定冷热
|
|
||||||
$status = 'normal';
|
$status = 'normal';
|
||||||
if ($avgCount > 0) {
|
if ($avgCount > 0) {
|
||||||
if ($targetCount > $avgCount * 1.5) {
|
if ($targetCount > $avgCount * 1.5) {
|
||||||
@@ -532,7 +561,7 @@ class History extends Model
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 计算排名(按出现次数降序)
|
// 计算排名
|
||||||
$sorted = [];
|
$sorted = [];
|
||||||
for ($num = 1; $num <= 49; $num++) {
|
for ($num = 1; $num <= 49; $num++) {
|
||||||
$sorted[] = ['num' => $num, 'count' => $count[$num]];
|
$sorted[] = ['num' => $num, 'count' => $count[$num]];
|
||||||
@@ -549,25 +578,19 @@ class History extends Model
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 构建所有号码的统计(只返回top和bottom用于展示)
|
$result[] = [
|
||||||
$hotNums = array_slice($sorted, 0, 5);
|
'expect' => (string)$row['expect'],
|
||||||
$coldNums = array_slice($sorted, -5);
|
|
||||||
$coldNums = array_reverse($coldNums);
|
|
||||||
|
|
||||||
return [
|
|
||||||
'expect' => (string)$expect,
|
|
||||||
'specialNum' => $specialNum,
|
'specialNum' => $specialNum,
|
||||||
'lookback' => $lookback,
|
|
||||||
'count' => $targetCount,
|
'count' => $targetCount,
|
||||||
'avgCount' => round($avgCount, 2),
|
'avgCount' => round($avgCount, 2),
|
||||||
'status' => $status,
|
'status' => $status,
|
||||||
'rank' => $rank,
|
'rank' => $rank
|
||||||
'totalPeriods' => $totalPeriods,
|
|
||||||
'hotNums' => $hotNums,
|
|
||||||
'coldNums' => $coldNums
|
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return $result;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 特码热力图数据
|
* 特码热力图数据
|
||||||
* @param int $periods 查询最近多少期
|
* @param int $periods 查询最近多少期
|
||||||
|
|||||||
@@ -17,7 +17,6 @@
|
|||||||
<a href="javascript:;" class="btn btn-success btn-sumchart" title="{:__('Sum Chart')}"><i class="fa fa-line-chart"></i> {:__('Sum Chart')}</a>
|
<a href="javascript:;" class="btn btn-success btn-sumchart" title="{:__('Sum Chart')}"><i class="fa fa-line-chart"></i> {:__('Sum Chart')}</a>
|
||||||
<a href="javascript:;" class="btn btn-warning btn-consecutive" title="{:__('Consecutive')}"><i class="fa fa-link"></i> {:__('Consecutive')}</a>
|
<a href="javascript:;" class="btn btn-warning 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-default btn-tailnums" title="{:__('Tail Numbers')}"><i class="fa fa-list-ol"></i> {:__('Tail Numbers')}</a>
|
||||||
<a href="javascript:;" class="btn btn-danger btn-specialhotcold" title="{:__('Special Hot/Cold')}"><i class="fa fa-fire"></i> {:__('Special Hot/Cold')}</a>
|
|
||||||
<!-- <a href="javascript:;" class="btn btn-success btn-dashboard" title="{:__('Dashboard')}"><i class="fa fa-tachometer"></i> {:__('Dashboard')}</a>-->
|
<!-- <a href="javascript:;" class="btn btn-success btn-dashboard" title="{:__('Dashboard')}"><i class="fa fa-tachometer"></i> {:__('Dashboard')}</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>-->
|
<!-- <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>
|
</div>
|
||||||
|
|||||||
@@ -590,67 +590,48 @@ define(['jquery', 'bootstrap', 'backend', 'table', 'form'], function ($, undefin
|
|||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 特码冷热查询(指定期号向前y期判定)
|
* 特码冷热列表(每期相对于前N期的冷热状态)
|
||||||
*/
|
*/
|
||||||
showSpecialHotColdDialog: function () {
|
showSpecialHotColdDialog: function () {
|
||||||
var html = '<div style="padding:20px;">' +
|
var html = '<div style="padding:20px;">' +
|
||||||
'<div class="form-group">' +
|
'<div class="form-group" style="border-bottom:1px solid #eee;padding-bottom:10px;margin-bottom:10px;">' +
|
||||||
' <label>期号:</label>' +
|
|
||||||
' <select id="shc-expect" class="form-control" style="width:200px;display:inline-block;"></select>' +
|
|
||||||
'</div>' +
|
|
||||||
'<div class="form-group">' +
|
|
||||||
' <label>向前期数:</label>' +
|
' <label>向前期数:</label>' +
|
||||||
' <input type="number" id="shc-lookback" class="form-control" value="30" min="10" max="100" style="width:120px;display:inline-block;">' +
|
' <input type="number" id="shc-lookback" class="form-control" value="30" min="10" max="100" style="width:120px;display:inline-block;">' +
|
||||||
' <button class="btn btn-primary" id="btn-shc-query" style="margin-left:10px;"><i class="fa fa-search"></i> ' + __('Query') + '</button>' +
|
' <button class="btn btn-primary" id="btn-shc-query" style="margin-left:10px;"><i class="fa fa-search"></i> ' + __('Query') + '</button>' +
|
||||||
'</div>' +
|
'</div>' +
|
||||||
'<div id="shc-result" style="margin-top:15px;"></div>' +
|
'<div id="shc-result" style="margin-top:10px;max-height:500px;overflow-y:auto;"></div>' +
|
||||||
'</div>';
|
'</div>';
|
||||||
|
|
||||||
Layer.open({
|
Layer.open({
|
||||||
type: 1,
|
type: 1,
|
||||||
title: '特码冷热查询',
|
title: '特码冷热列表',
|
||||||
area: ['650px', '550px'],
|
area: ['650px', '600px'],
|
||||||
content: html,
|
content: html,
|
||||||
shadeClose: true,
|
shadeClose: true,
|
||||||
success: function (layero, index) {
|
success: function (layero, index) {
|
||||||
// 加载最近50期期号供选择
|
|
||||||
$.ajax({
|
|
||||||
url: 'history/specialTrend',
|
|
||||||
type: 'GET',
|
|
||||||
data: {periods: 50},
|
|
||||||
dataType: 'json',
|
|
||||||
success: function (ret) {
|
|
||||||
if (ret.code == 1 && ret.data.expects) {
|
|
||||||
var options = '';
|
|
||||||
for (var i = 0; i < ret.data.expects.length; i++) {
|
|
||||||
options += '<option value="' + ret.data.expects[i] + '">' + ret.data.expects[i] + '</option>';
|
|
||||||
}
|
|
||||||
$('#shc-expect', layero).html(options);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
$('#btn-shc-query', layero).on('click', function () {
|
$('#btn-shc-query', layero).on('click', function () {
|
||||||
var expect = $('#shc-expect', layero).val();
|
|
||||||
var lookback = parseInt($('#shc-lookback', layero).val()) || 30;
|
var lookback = parseInt($('#shc-lookback', layero).val()) || 30;
|
||||||
Controller.api.querySpecialHotCold(expect, lookback, layero);
|
Controller.api.querySpecialHotCold(lookback, layero);
|
||||||
});
|
});
|
||||||
|
// 打开时自动查询
|
||||||
|
var lookback = parseInt($('#shc-lookback', layero).val()) || 30;
|
||||||
|
Controller.api.querySpecialHotCold(lookback, layero);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
querySpecialHotCold: function (expect, lookback, layero) {
|
querySpecialHotCold: function (lookback, layero) {
|
||||||
var $btn = $('#btn-shc-query', layero);
|
var $btn = $('#btn-shc-query', layero);
|
||||||
$btn.prop('disabled', true);
|
$btn.prop('disabled', true);
|
||||||
$('#shc-result', layero).html('<div class="text-center"><i class="fa fa-spinner fa-spin"></i> ' + __('Loading') + '</div>');
|
$('#shc-result', layero).html('<div class="text-center"><i class="fa fa-spinner fa-spin"></i> ' + __('Loading') + '</div>');
|
||||||
$.ajax({
|
$.ajax({
|
||||||
url: 'history/specialHotColdAction',
|
url: 'history/specialHotColdAction',
|
||||||
type: 'GET',
|
type: 'GET',
|
||||||
data: {expect: expect, lookback: lookback},
|
data: {lookback: lookback},
|
||||||
dataType: 'json',
|
dataType: 'json',
|
||||||
success: function (ret) {
|
success: function (ret) {
|
||||||
if (ret.code == 1) {
|
if (ret.code == 1) {
|
||||||
Controller.api.renderSpecialHotCold(ret.data, layero);
|
Controller.api.renderSpecialHotCold(ret.data, lookback, layero);
|
||||||
} else {
|
} else {
|
||||||
$('#shc-result', layero).html('<div class="alert alert-danger">' + (ret.msg || __('Query failed')) + '</div>');
|
$('#shc-result', layero).html('<div class="alert alert-danger">' + (ret.msg || __('Query failed')) + '</div>');
|
||||||
}
|
}
|
||||||
@@ -664,68 +645,56 @@ define(['jquery', 'bootstrap', 'backend', 'table', 'form'], function ($, undefin
|
|||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
renderSpecialHotCold: function (data, layero) {
|
renderSpecialHotCold: function (data, lookback, layero) {
|
||||||
var getColor = function (num) {
|
var getColor = function (num) {
|
||||||
return Controller.api.getColorByNum(num);
|
return Controller.api.getColorByNum(num);
|
||||||
};
|
};
|
||||||
|
|
||||||
var statusConfig = {
|
var statusTag = function (status) {
|
||||||
'hot': {label: '🔥 热号', color: '#e74c3c', bg: '#fce4ec', desc: '出现频率高于平均值的1.5倍'},
|
var map = {
|
||||||
'cold': {label: '❄️ 冷号', color: '#3498db', bg: '#e3f2fd', desc: '出现频率低于平均值的0.5倍'},
|
'hot': '<span style="color:#e74c3c;font-weight:bold;">🔥 热号</span>',
|
||||||
'normal': {label: '➡️ 温号', color: '#f39c12', bg: '#fff8e1', desc: '出现频率在正常范围内'}
|
'cold': '<span style="color:#3498db;font-weight:bold;">❄ 冷号</span>',
|
||||||
|
'normal': '<span style="color:#f39c12;font-weight:bold;">➜ 温号</span>',
|
||||||
|
'unknown': '<span style="color:#999;">数据不足</span>'
|
||||||
|
};
|
||||||
|
return map[status] || '';
|
||||||
};
|
};
|
||||||
|
|
||||||
var cfg = statusConfig[data.status] || statusConfig['normal'];
|
if (!data || data.length === 0) {
|
||||||
|
$('#shc-result', layero).html('<div class="alert alert-info">暂无数据</div>');
|
||||||
var html = '<div style="padding:15px;">';
|
return;
|
||||||
|
|
||||||
// 主信息卡片
|
|
||||||
html += '<div style="padding:20px;border-radius:8px;background:' + cfg.bg + ';margin-bottom:15px;">';
|
|
||||||
html += '<div style="display:flex;align-items:center;justify-content:space-between;">';
|
|
||||||
html += '<div>' +
|
|
||||||
'<div style="font-size:14px;color:#666;">期号 <b>' + data.expect + '</b> 的特码</div>' +
|
|
||||||
'<div style="margin-top:8px;">' +
|
|
||||||
'<span style="display:inline-block;width:48px;height:48px;line-height:48px;text-align:center;border-radius:50%;color:#fff;background-color:' + getColor(data.specialNum) + ';font-size:20px;font-weight:bold;">' + data.specialNum + '</span>' +
|
|
||||||
'</div>' +
|
|
||||||
'</div>';
|
|
||||||
html += '<div style="text-align:right;">' +
|
|
||||||
'<div style="font-size:24px;font-weight:bold;color:' + cfg.color + ';">' + cfg.label + '</div>' +
|
|
||||||
'<div style="font-size:12px;color:#999;margin-top:4px;">' + cfg.desc + '</div>' +
|
|
||||||
'</div>';
|
|
||||||
html += '</div></div>';
|
|
||||||
|
|
||||||
// 统计数据
|
|
||||||
html += '<div style="display:flex;gap:10px;margin-bottom:15px;">';
|
|
||||||
html += '<div style="flex:1;text-align:center;padding:10px;background:#f5f5f5;border-radius:6px;">' +
|
|
||||||
'<div style="font-size:22px;font-weight:bold;">' + data.count + '</div>' +
|
|
||||||
'<div style="font-size:12px;color:#666;">近' + data.lookback + '期出现次数</div></div>';
|
|
||||||
html += '<div style="flex:1;text-align:center;padding:10px;background:#f5f5f5;border-radius:6px;">' +
|
|
||||||
'<div style="font-size:22px;font-weight:bold;">' + data.avgCount + '</div>' +
|
|
||||||
'<div style="font-size:12px;color:#666;">平均出现次数</div></div>';
|
|
||||||
html += '<div style="flex:1;text-align:center;padding:10px;background:#f5f5f5;border-radius:6px;">' +
|
|
||||||
'<div style="font-size:22px;font-weight:bold;">第' + data.rank + '名</div>' +
|
|
||||||
'<div style="font-size:12px;color:#666;">频率排名 (共' + data.totalPeriods + '期)</div></div>';
|
|
||||||
html += '</div>';
|
|
||||||
|
|
||||||
// 热号/冷号参考
|
|
||||||
if (data.hotNums && data.hotNums.length > 0) {
|
|
||||||
html += '<div style="margin-bottom:10px;"><b style="color:#e74c3c;">🔥 热号 Top5</b><div style="display:flex;gap:6px;margin-top:5px;">';
|
|
||||||
for (var i = 0; i < data.hotNums.length; i++) {
|
|
||||||
var item = data.hotNums[i];
|
|
||||||
html += '<span style="display:inline-block;width:32px;height:32px;line-height:32px;text-align:center;border-radius:50%;color:#fff;background-color:' + getColor(item.num) + ';font-weight:bold;font-size:14px;" title="' + item.count + '次">' + item.num + '</span>';
|
|
||||||
}
|
|
||||||
html += '</div></div>';
|
|
||||||
}
|
|
||||||
if (data.coldNums && data.coldNums.length > 0) {
|
|
||||||
html += '<div><b style="color:#3498db;">❄️ 冷号 Top5</b><div style="display:flex;gap:6px;margin-top:5px;">';
|
|
||||||
for (var i = 0; i < data.coldNums.length; i++) {
|
|
||||||
var item = data.coldNums[i];
|
|
||||||
html += '<span style="display:inline-block;width:32px;height:32px;line-height:32px;text-align:center;border-radius:50%;color:#fff;background-color:' + getColor(item.num) + ';font-weight:bold;font-size:14px;" title="' + item.count + '次">' + item.num + '</span>';
|
|
||||||
}
|
|
||||||
html += '</div></div>';
|
|
||||||
}
|
}
|
||||||
|
|
||||||
html += '</div>';
|
var html = '<div style="padding:0 5px;">';
|
||||||
|
html += '<table class="table table-striped table-bordered table-hover" style="font-size:13px;">' +
|
||||||
|
'<thead><tr>' +
|
||||||
|
'<th style="text-align:center;width:120px;">期号</th>' +
|
||||||
|
'<th style="text-align:center;width:60px;">特码</th>' +
|
||||||
|
'<th style="text-align:center;width:80px;">冷热</th>' +
|
||||||
|
'<th style="text-align:center;width:60px;">次数</th>' +
|
||||||
|
'<th style="text-align:center;width:60px;">平均</th>' +
|
||||||
|
'<th style="text-align:center;width:60px;">排名</th>' +
|
||||||
|
'</tr></thead><tbody>';
|
||||||
|
|
||||||
|
for (var i = 0; i < data.length; i++) {
|
||||||
|
var item = data[i];
|
||||||
|
var rowClass = '';
|
||||||
|
if (item.status === 'hot') rowClass = 'style="background:#fff5f5;"';
|
||||||
|
else if (item.status === 'cold') rowClass = 'style="background:#f5f8ff;"';
|
||||||
|
|
||||||
|
html += '<tr ' + rowClass + '>' +
|
||||||
|
'<td style="text-align:center;">' + item.expect + '</td>' +
|
||||||
|
'<td style="text-align:center;">' +
|
||||||
|
'<span style="display:inline-block;width:30px;height:30px;line-height:30px;text-align:center;border-radius:50%;color:#fff;background-color:' + getColor(item.specialNum) + ';font-weight:bold;font-size:14px;">' + item.specialNum + '</span>' +
|
||||||
|
'</td>' +
|
||||||
|
'<td style="text-align:center;">' + statusTag(item.status) + '</td>' +
|
||||||
|
'<td style="text-align:center;">' + item.count + '</td>' +
|
||||||
|
'<td style="text-align:center;">' + item.avgCount + '</td>' +
|
||||||
|
'<td style="text-align:center;">' + item.rank + '</td>' +
|
||||||
|
'</tr>';
|
||||||
|
}
|
||||||
|
|
||||||
|
html += '</tbody></table></div>';
|
||||||
$('#shc-result', layero).html(html);
|
$('#shc-result', layero).html(html);
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user