fix(history): 重构特码冷热功能 — 改为弹窗列表展示每期相对于前N期的冷热状态
改为批量查询模式:每期特码相对于它前面N期的出现频率判定冷热 弹窗内以表格形式展示所有期号、特码球、冷热标签、次数、排名 支持调整向前期数(10-100),打开弹窗自动查询
This commit is contained in:
@@ -469,103 +469,126 @@ class History extends Model
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询指定期号特码在向前y期范围内的冷热状态
|
||||
* @param string|int $expect 指定期号
|
||||
* 批量查询所有期号特码相对于前N期的冷热状态
|
||||
* @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)
|
||||
{
|
||||
// 查询指定期号的数据
|
||||
$target = $this->where('expect', $expect)->field('expect,num7,openTime')->find();
|
||||
if (!$target) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$specialNum = (int)$target['num7'];
|
||||
|
||||
// 查询该期往前lookback期的数据(按openTime排序,取目标期之前的lookback条)
|
||||
// 查询最近 $limit 期数据,按时间倒序(最新在前)
|
||||
$history = $this
|
||||
->field('expect,num7,openTime')
|
||||
->where('openTime', '<', $target['openTime'])
|
||||
->order('openTime', 'desc')
|
||||
->limit($lookback)
|
||||
->limit($limit)
|
||||
->select();
|
||||
|
||||
$totalPeriods = count($history);
|
||||
if ($totalPeriods === 0) {
|
||||
return [
|
||||
'expect' => (string)$expect,
|
||||
if (empty($history)) {
|
||||
return [];
|
||||
}
|
||||
|
||||
// 查询更多历史数据用于统计
|
||||
$allHistory = $this
|
||||
->field('expect,num7,openTime')
|
||||
->order('openTime', 'desc')
|
||||
->limit($limit + 200)
|
||||
->select();
|
||||
|
||||
// 按openTime排序(确保顺序)
|
||||
$historySorted = [];
|
||||
foreach ($history as $row) {
|
||||
$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) {
|
||||
$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];
|
||||
$avgCount = $periodCount / 49;
|
||||
|
||||
$status = 'normal';
|
||||
if ($avgCount > 0) {
|
||||
if ($targetCount > $avgCount * 1.5) {
|
||||
$status = 'hot';
|
||||
} elseif ($targetCount < $avgCount * 0.5) {
|
||||
$status = 'cold';
|
||||
}
|
||||
}
|
||||
|
||||
// 计算排名
|
||||
$sorted = [];
|
||||
for ($num = 1; $num <= 49; $num++) {
|
||||
$sorted[] = ['num' => $num, 'count' => $count[$num]];
|
||||
}
|
||||
usort($sorted, function ($a, $b) {
|
||||
return $b['count'] - $a['count'];
|
||||
});
|
||||
|
||||
$rank = 0;
|
||||
foreach ($sorted as $idx => $item) {
|
||||
if ($item['num'] === $specialNum) {
|
||||
$rank = $idx + 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
$result[] = [
|
||||
'expect' => (string)$row['expect'],
|
||||
'specialNum' => $specialNum,
|
||||
'lookback' => $lookback,
|
||||
'count' => 0,
|
||||
'avgCount' => 0,
|
||||
'status' => 'cold',
|
||||
'rank' => 0,
|
||||
'totalPeriods' => 0,
|
||||
'allStats' => []
|
||||
'count' => $targetCount,
|
||||
'avgCount' => round($avgCount, 2),
|
||||
'status' => $status,
|
||||
'rank' => $rank
|
||||
];
|
||||
}
|
||||
|
||||
// 统计lookback范围内每个特码的出现次数
|
||||
$count = array_fill(1, 49, 0);
|
||||
foreach ($history as $row) {
|
||||
$num = (int)$row['num7'];
|
||||
if ($num >= 1 && $num <= 49) {
|
||||
$count[$num]++;
|
||||
}
|
||||
}
|
||||
|
||||
// 计算目标特码的出现次数
|
||||
$targetCount = $count[$specialNum];
|
||||
|
||||
// 计算平均出现次数(49个号码,totalPeriods期)
|
||||
$avgCount = $totalPeriods / 49;
|
||||
|
||||
// 判定冷热
|
||||
$status = 'normal';
|
||||
if ($avgCount > 0) {
|
||||
if ($targetCount > $avgCount * 1.5) {
|
||||
$status = 'hot';
|
||||
} elseif ($targetCount < $avgCount * 0.5) {
|
||||
$status = 'cold';
|
||||
}
|
||||
}
|
||||
|
||||
// 计算排名(按出现次数降序)
|
||||
$sorted = [];
|
||||
for ($num = 1; $num <= 49; $num++) {
|
||||
$sorted[] = ['num' => $num, 'count' => $count[$num]];
|
||||
}
|
||||
usort($sorted, function ($a, $b) {
|
||||
return $b['count'] - $a['count'];
|
||||
});
|
||||
|
||||
$rank = 0;
|
||||
foreach ($sorted as $idx => $item) {
|
||||
if ($item['num'] === $specialNum) {
|
||||
$rank = $idx + 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// 构建所有号码的统计(只返回top和bottom用于展示)
|
||||
$hotNums = array_slice($sorted, 0, 5);
|
||||
$coldNums = array_slice($sorted, -5);
|
||||
$coldNums = array_reverse($coldNums);
|
||||
|
||||
return [
|
||||
'expect' => (string)$expect,
|
||||
'specialNum' => $specialNum,
|
||||
'lookback' => $lookback,
|
||||
'count' => $targetCount,
|
||||
'avgCount' => round($avgCount, 2),
|
||||
'status' => $status,
|
||||
'rank' => $rank,
|
||||
'totalPeriods' => $totalPeriods,
|
||||
'hotNums' => $hotNums,
|
||||
'coldNums' => $coldNums
|
||||
];
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
Reference in New Issue
Block a user