From 9881f75e593d58d8b798b243d72dd2f3dea1cea5 Mon Sep 17 00:00:00 2001 From: leon <916117771@qq.com> Date: Fri, 24 Apr 2026 20:06:37 +0800 Subject: [PATCH] =?UTF-8?q?fix(history):=20=E9=87=8D=E6=9E=84=E7=89=B9?= =?UTF-8?q?=E7=A0=81=E5=86=B7=E7=83=AD=E5=8A=9F=E8=83=BD=20=E2=80=94=20?= =?UTF-8?q?=E6=94=B9=E4=B8=BA=E5=BC=B9=E7=AA=97=E5=88=97=E8=A1=A8=E5=B1=95?= =?UTF-8?q?=E7=A4=BA=E6=AF=8F=E6=9C=9F=E7=9B=B8=E5=AF=B9=E4=BA=8E=E5=89=8D?= =?UTF-8?q?N=E6=9C=9F=E7=9A=84=E5=86=B7=E7=83=AD=E7=8A=B6=E6=80=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 改为批量查询模式:每期特码相对于它前面N期的出现频率判定冷热 弹窗内以表格形式展示所有期号、特码球、冷热标签、次数、排名 支持调整向前期数(10-100),打开弹窗自动查询 --- .../260424-roj-SUMMARY.md | 40 ++-- application/admin/controller/History.php | 13 +- application/admin/model/History.php | 193 ++++++++++-------- application/admin/view/history/index.html | 1 - public/assets/js/backend/history.js | 139 +++++-------- 5 files changed, 187 insertions(+), 199 deletions(-) diff --git a/.planning/quick/260424-roj-history-y/260424-roj-SUMMARY.md b/.planning/quick/260424-roj-history-y/260424-roj-SUMMARY.md index d462d6f..a9b7bac 100644 --- a/.planning/quick/260424-roj-history-y/260424-roj-SUMMARY.md +++ b/.planning/quick/260424-roj-history-y/260424-roj-SUMMARY.md @@ -1,35 +1,35 @@ --- -description: 在history页面新增特码冷热查询功能 — 选定某一期,向前推算y期,判定该期特码属于冷号还是热号 +description: 在history页面新增特码冷热列表功能 — 每期特码相对于它前面N期的冷热状态 status: complete date: 2026-04-24 --- -# Quick Task Summary: 特码冷热查询 +# Quick Task Summary: 特码冷热列表 ## What was built -新增「特码冷热查询」功能,允许用户选择任意历史期号,设定向前追溯期数(10-100期),系统自动判定该期特码在追溯范围内属于冷号、温号还是热号。 +新增「特码冷热列表」功能,以弹窗表格形式展示每一期特码相对于它前面 N 期的冷热状态。 + +### 核心逻辑 +- 对每一期,取它**前面** N 期(不包含自身)的历史数据 +- 统计这 N 期内 49 个号码各自作为特码的出现次数 +- 计算平均值(N / 49),对比该期特码的出现次数: + - **热号**:出现次数 > 平均值 × 1.5 + - **冷号**:出现次数 < 平均值 × 0.5 + - **温号**:介于两者之间 ## Changes made -### Backend — Model (`application/admin/model/History.php`) -- 新增 `getSpecialHotColdByExpect($expect, $lookback)` 方法 -- 逻辑:根据指定期号找到该期特码,向前取 lookback 期数据,统计49个号码各自的出现次数 -- 判定标准:出现次数 > 平均值×1.5 → 热号;< 平均值×0.5 → 冷号;其余为温号 -- 返回包含:特码值、出现次数、平均值、冷热状态、频率排名、热号Top5、冷号Top5 +### Model (`application/admin/model/History.php`) +- `getSpecialHotColdList($lookback, $limit)` — 批量查询,返回每期的冷热状态数组 -### Backend — Controller (`application/admin/controller/History.php`) -- 新增 `specialHotColdAction()` 接口方法 -- 接收 `expect`(期号,必填)和 `lookback`(向前期数,默认30,范围10-100) -- 已加入 `noNeedRight` 白名单 +### Controller (`application/admin/controller/History.php`) +- `specialHotColdAction()` — AJAX 接口,接收 `lookback`(默认30)和 `limit`(默认100) -### Frontend — View (`application/admin/view/history/index.html`) -- 在 toolbar 新增「特码冷热」按钮(红色主题,fa-fire 图标) - -### Frontend — JS (`public/assets/js/backend/history.js`) -- 新增 `showSpecialHotColdDialog()` — 弹窗包含:期号下拉选择(加载最近50期)、向前期数输入框、查询按钮 -- 新增 `querySpecialHotCold()` — AJAX 请求后端 -- 新增 `renderSpecialHotCold()` — 卡片式渲染结果:大号球显示特码、冷热状态标签、统计数据、热号/冷号Top5球 +### Frontend (`history.js`) +- `showSpecialHotColdDialog()` — 弹窗,包含向前期数输入框 + 查询按钮 +- `querySpecialHotCold()` — AJAX 请求 +- `renderSpecialHotCold()` — 表格渲染:期号、特码球(带波色)、冷热标签、出现次数、平均次数、频率排名;热号行淡红背景、冷号行淡蓝背景 ## Commit -`2513bbb` +`d4a5c30` diff --git a/application/admin/controller/History.php b/application/admin/controller/History.php index 9bd44dd..6e0705b 100644 --- a/application/admin/controller/History.php +++ b/application/admin/controller/History.php @@ -237,23 +237,20 @@ class History extends Backend } /** - * 特码冷热查询(指定期号向前y期判定) + * 特码冷热列表(每期相对于前N期的冷热状态) */ public function specialHotColdAction() { if ($this->request->isAjax()) { - $expect = $this->request->get('expect', ''); - if (empty($expect)) { - $this->error('请输入期号'); - } $lookback = $this->request->get('lookback', 30, 'intval'); if ($lookback < 10 || $lookback > 100) { $this->error('向前期数范围必须在 10-100 之间'); } - $result = $this->model->getSpecialHotColdByExpect($expect, $lookback); - if ($result === false) { - $this->error('未找到该期号数据'); + $limit = $this->request->get('limit', 100, 'intval'); + if ($limit < 10 || $limit > 200) { + $this->error('查询期数范围必须在 10-200 之间'); } + $result = $this->model->getSpecialHotColdList($lookback, $limit); $this->success('查询成功', null, $result); } } diff --git a/application/admin/model/History.php b/application/admin/model/History.php index ebeffdb..b39dd6d 100644 --- a/application/admin/model/History.php +++ b/application/admin/model/History.php @@ -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; } /** diff --git a/application/admin/view/history/index.html b/application/admin/view/history/index.html index b2c275d..8754be8 100644 --- a/application/admin/view/history/index.html +++ b/application/admin/view/history/index.html @@ -17,7 +17,6 @@ {:__('Sum Chart')} {:__('Consecutive')} {:__('Tail Numbers')} - {:__('Special Hot/Cold')} diff --git a/public/assets/js/backend/history.js b/public/assets/js/backend/history.js index 8dad69f..bf18dc6 100644 --- a/public/assets/js/backend/history.js +++ b/public/assets/js/backend/history.js @@ -590,67 +590,48 @@ define(['jquery', 'bootstrap', 'backend', 'table', 'form'], function ($, undefin }, /** - * 特码冷热查询(指定期号向前y期判定) + * 特码冷热列表(每期相对于前N期的冷热状态) */ showSpecialHotColdDialog: function () { var html = '
| 期号 | ' + + '特码 | ' + + '冷热 | ' + + '次数 | ' + + '平均 | ' + + '排名 | ' + + '
|---|---|---|---|---|---|
| ' + item.expect + ' | ' + + '' + + '' + item.specialNum + '' + + ' | ' + + '' + statusTag(item.status) + ' | ' + + '' + item.count + ' | ' + + '' + item.avgCount + ' | ' + + '' + item.rank + ' | ' + + '