feat(history): 新增历史记录页面功能

- 实现历史记录表格展示功能,包含开奖期号、号码及时间等字段
- 添加号码球样式显示,支持颜色和生肖标识展示
- 集成遗漏号码分析功能,可查询号码遗漏情况
- 实现走势图分析功能,使用ECharts展示号码趋势
- 添加冷热分析功能,统计号码热度排行
- 实现波色、生肖、奇偶、大小等多维度分析工具
- 集成和值分析、连号分析、尾数分析等功能
- 添加特码冷热列表展示功能
- 实现综合统计面板功能
- 集成筛号器功能,支持多种筛选条件
- 添加号码预测和正码关联预测功能
- 实现尾首概率分析功能
- 集成颜色和生肖映射加载机制
This commit is contained in:
2026-05-03 23:42:58 +08:00
parent 182d322b4e
commit d92cf6cfbc
15 changed files with 1276 additions and 42 deletions
+153 -27
View File
@@ -770,6 +770,11 @@ define(['jquery', 'bootstrap', 'backend', 'table', 'form'], function ($, undefin
'</div>' +
'<div id="nf-tail-list" style="margin-bottom:15px;display:flex;flex-wrap:wrap;gap:6px;"></div>' +
'<div style="margin-bottom:15px;">' +
' <label>首位数筛选:</label>' +
' <button class="btn btn-xs btn-primary btn-nf-add-head"><i class="fa fa-plus"></i> 新增</button>' +
'</div>' +
'<div id="nf-head-list" style="margin-bottom:15px;display:flex;flex-wrap:wrap;gap:6px;"></div>' +
'<div style="margin-bottom:15px;">' +
' <label style="margin-right:10px;">生肖:</label>' +
' <div id="nf-zodiac" style="display:inline-flex;gap:6px;flex-wrap:wrap;">' +
' <button class="btn btn-default btn-xs nf-zodiac" data-zodiac="鼠">鼠</button>' +
@@ -847,6 +852,21 @@ define(['jquery', 'bootstrap', 'backend', 'table', 'form'], function ($, undefin
Controller.api.applyNumberFilters(layero, blockedNums);
});
// 新增首位数
$('.btn-nf-add-head', layero).on('click', function () {
Controller.api.addHeadRow(layero, 0);
Controller.api.applyNumberFilters(layero, blockedNums);
});
// 首位数输入 & 删除事件委托
$('#nf-head-list', layero).on('input change', '.nf-head-select', function () {
Controller.api.applyNumberFilters(layero, blockedNums);
});
$('#nf-head-list', layero).on('click', '.nf-head-del', function () {
$(this).closest('.nf-head-row').remove();
Controller.api.applyNumberFilters(layero, blockedNums);
});
// 生肖按钮点击
$('.nf-zodiac', layero).on('click', function () {
var $btn = $(this);
@@ -896,6 +916,7 @@ define(['jquery', 'bootstrap', 'backend', 'table', 'form'], function ($, undefin
$('.btn-nf-reset', layero).on('click', function () {
blockedNums = [];
$('#nf-tail-list', layero).html('');
$('#nf-head-list', layero).html('');
$('.nf-zodiac', layero).removeClass('btn-gray').addClass('btn-default');
$('.nf-color-btn', layero).removeClass('btn-gray').addClass('btn-default');
$('.nf-parity', layero).removeClass('btn-gray').addClass('btn-default');
@@ -922,6 +943,22 @@ define(['jquery', 'bootstrap', 'backend', 'table', 'form'], function ($, undefin
$('#nf-tail-list', layero).append(html);
},
/**
* 新增一行首位数筛选
*/
addHeadRow: function (layero, value) {
var rowId = 'nf-head-' + Date.now() + Math.random().toString(36).substr(2, 5);
var opts = '<option value="">首号</option>';
for (var h = 0; h <= 4; h++) {
opts += '<option value="' + h + '"' + (h === value ? ' selected' : '') + '>' + h + '</option>';
}
var html = '<div class="nf-head-row" id="' + rowId + '" style="display:inline-flex;align-items:center;gap:4px;">' +
' <select class="form-control nf-head-select" style="width:80px;display:inline-block;">' + opts + '</select>' +
' <button class="btn btn-xs btn-danger nf-head-del"><i class="fa fa-times"></i></button>' +
'</div>';
$('#nf-head-list', layero).append(html);
},
/**
* 新增一行区间筛选
*/
@@ -953,7 +990,7 @@ define(['jquery', 'bootstrap', 'backend', 'table', 'form'], function ($, undefin
if (colorRaw.indexOf('红') !== -1) colorLabel = '红';
else if (colorRaw.indexOf('蓝') !== -1) colorLabel = '蓝';
else if (colorRaw.indexOf('绿') !== -1) colorLabel = '绿';
html += '<div class="nf-number" data-num="' + num + '" data-color="' + colorLabel + '" data-animal="' + animal + '" data-tail="' + (num % 10) + '" data-parity="' + (num % 2 === 1 ? '单' : '双') + '" style="text-align:center;background:#f9f9f9;padding:6px 4px;border-radius:6px;min-width:60px;transition:opacity 0.2s;cursor:pointer;" title="点击屏蔽/恢复">' +
html += '<div class="nf-number" data-num="' + num + '" data-color="' + colorLabel + '" data-animal="' + animal + '" data-tail="' + (num % 10) + '" data-head="' + Math.floor(num / 10) + '" data-parity="' + (num % 2 === 1 ? '单' : '双') + '" style="text-align:center;background:#f9f9f9;padding:6px 4px;border-radius:6px;min-width:60px;transition:opacity 0.2s;cursor:pointer;" title="点击屏蔽/恢复">' +
'<span style="display:inline-block;width:36px;height:36px;line-height:36px;text-align:center;border-radius:50%;color:#fff;background-color:' + colorHex + ';font-weight:bold;">' + num + '</span>' +
'<div style="font-size:10px;color:#666;line-height:1.2;">' + animal + '</div>' +
'</div>';
@@ -976,6 +1013,14 @@ define(['jquery', 'bootstrap', 'backend', 'table', 'form'], function ($, undefin
excludedTails.push(parseInt(val));
}
});
// 收集所有选中的首位数
var excludedHeads = [];
$('.nf-head-select', layero).each(function () {
var val = $(this).val();
if (val !== '' && excludedHeads.indexOf(parseInt(val)) === -1) {
excludedHeads.push(parseInt(val));
}
});
// 收集被点击(置灰)的生肖
var excludedZodiacs = [];
$('.nf-zodiac.btn-gray', layero).each(function () {
@@ -1005,6 +1050,7 @@ define(['jquery', 'bootstrap', 'backend', 'table', 'form'], function ($, undefin
var $num = $(this);
var num = parseInt($num.data('num'));
var tail = $num.data('tail');
var head = $num.data('head');
var animal = $num.data('animal');
var color = $num.data('color');
@@ -1016,6 +1062,10 @@ define(['jquery', 'bootstrap', 'backend', 'table', 'form'], function ($, undefin
if (excludedTails.length > 0 && excludedTails.indexOf(tail) !== -1) {
hidden = true;
}
// 首位数筛选:选中多个首位数,任一命中即屏蔽
if (excludedHeads.length > 0 && excludedHeads.indexOf(head) !== -1) {
hidden = true;
}
// 单双筛选:选中单或双,匹配则屏蔽
if (excludedParities.indexOf(parity) !== -1) {
hidden = true;
@@ -1547,12 +1597,14 @@ define(['jquery', 'bootstrap', 'backend', 'table', 'form'], function ($, undefin
' <div style="font-size:12px;color:#666;">' +
' <b>V1版本</b>:基于转移概率分析(区域、生肖、尾号、首号、波色转移 + 冷热系数)<br>' +
' <b>V2版本</b>:基于统计回归分析(遗漏回归、频率回归、区域平衡、波色平衡等)+ 历史回测验证<br>' +
' <b>V3版本(推荐)</b>:多维度综合预测,新增转移概率(马尔可夫链)、单双规律、大小规律、走势方向分析' +
' <b>V3版本</b>:多维度综合预测,新增转移概率(马尔可夫链)、单双规律、大小规律、走势方向分析<br>' +
' <b>V4版本(推荐)</b>:贝叶斯集成学习,6大子模型融合(EWMA频率/号码转移/遗漏CDF/形态匹配/周期检测/属性平衡)' +
' </div>' +
'</div>' +
'<div class="form-group" style="border-bottom:1px solid #eee;padding-bottom:10px;margin-bottom:10px;">' +
' <label style="margin-right:10px;">算法版本:</label>' +
' <label class="radio-inline" style="margin-right:15px;"><input type="radio" name="predict-version" value="v3" checked> <b>V3</b>多维度综合</label>' +
' <label class="radio-inline" style="margin-right:15px;"><input type="radio" name="predict-version" value="v4" checked> <b>V4</b>贝叶斯集成·推荐</label>' +
' <label class="radio-inline" style="margin-right:15px;"><input type="radio" name="predict-version" value="v3"> <b>V3</b>(多维度综合)</label>' +
' <label class="radio-inline" style="margin-right:15px;"><input type="radio" name="predict-version" value="v2"> V2(统计回归)</label>' +
' <label class="radio-inline"><input type="radio" name="predict-version" value="v1"> V1(转移概率)</label>' +
'</div>' +
@@ -1566,6 +1618,18 @@ define(['jquery', 'bootstrap', 'backend', 'table', 'form'], function ($, undefin
' <input type="number" id="predict-periods" class="form-control" value="200" min="30" max="500" style="width:120px;display:inline-block;">' +
' <span style="font-size:11px;color:#999;margin-left:5px;">建议200期以上</span>' +
'</div>' +
// V4权重配置
'<div id="predict-v4-weights" style="border-bottom:1px solid #eee;padding-bottom:10px;margin-bottom:10px;">' +
' <label style="margin-right:10px;">V4子模型权重:</label>' +
' <div style="display:flex;flex-wrap:wrap;gap:10px;font-size:12px;">' +
' <div>EWMA频率: <input type="number" class="predict-weight-v4" data-key="freq_ewma" value="0.20" min="0" max="1" step="0.02" style="width:60px;"></div>' +
' <div>号码转移: <input type="number" class="predict-weight-v4" data-key="markov_number" value="0.22" min="0" max="1" step="0.02" style="width:60px;"></div>' +
' <div>遗漏CDF: <input type="number" class="predict-weight-v4" data-key="omit_empirical" value="0.17" min="0" max="1" step="0.02" style="width:60px;"></div>' +
' <div>形态匹配: <input type="number" class="predict-weight-v4" data-key="pattern_match" value="0.18" min="0" max="1" step="0.02" style="width:60px;"></div>' +
' <div>周期检测: <input type="number" class="predict-weight-v4" data-key="cyclical" value="0.09" min="0" max="1" step="0.02" style="width:60px;"></div>' +
' <div>属性平衡: <input type="number" class="predict-weight-v4" data-key="attr_balance" value="0.14" min="0" max="1" step="0.02" style="width:60px;"></div>' +
' </div>' +
'</div>' +
// V3权重配置
'<div id="predict-v3-weights" style="border-bottom:1px solid #eee;padding-bottom:10px;margin-bottom:10px;">' +
' <label style="margin-right:10px;">V3权重配置:</label>' +
@@ -1620,10 +1684,14 @@ define(['jquery', 'bootstrap', 'backend', 'table', 'form'], function ($, undefin
// 切换版本时显示对应权重配置
$('input[name="predict-version"]', layero).on('change', function () {
var val = $(this).val();
$('#predict-v4-weights', layero).hide();
$('#predict-v3-weights', layero).hide();
$('#predict-v2-weights', layero).hide();
$('#predict-v1-weights', layero).hide();
if (val === 'v3') {
if (val === 'v4') {
$('#predict-v4-weights', layero).show();
$('#predict-periods', layero).val(200);
} else if (val === 'v3') {
$('#predict-v3-weights', layero).show();
$('#predict-periods', layero).val(200);
} else if (val === 'v2') {
@@ -1655,7 +1723,13 @@ define(['jquery', 'bootstrap', 'backend', 'table', 'form'], function ($, undefin
var weights = {};
// 根据版本获取权重
if (version === 'v3') {
if (version === 'v4') {
$('.predict-weight-v4', layero).each(function () {
var key = $(this).data('key');
var val = parseFloat($(this).val()) || 0;
weights[key] = val;
});
} else if (version === 'v3') {
$('.predict-weight-v3', layero).each(function () {
var key = $(this).data('key');
var val = parseFloat($(this).val()) || 0;
@@ -1677,7 +1751,9 @@ define(['jquery', 'bootstrap', 'backend', 'table', 'form'], function ($, undefin
// 根据版本选择URL
var url = 'history/predict';
if (version === 'v3') {
if (version === 'v4') {
url = 'history/predictV4';
} else if (version === 'v3') {
url = 'history/predictV3';
} else if (version === 'v2') {
url = 'history/predictV2';
@@ -1730,7 +1806,8 @@ define(['jquery', 'bootstrap', 'backend', 'table', 'form'], function ($, undefin
var versionNames = {
'v1': 'V1(转移概率)',
'v2': 'V2(统计回归)',
'v3': 'V3(多维度综合)'
'v3': 'V3(多维度综合)',
'v4': 'V4(贝叶斯集成)'
};
var html = '<div style="padding:10px;">';
@@ -1739,7 +1816,7 @@ define(['jquery', 'bootstrap', 'backend', 'table', 'form'], function ($, undefin
html += '<div style="font-size:12px;color:#666;margin-bottom:10px;">基于期号 <b>' + lastExpect + '</b>(特码 ' + lastSpecial + ')进行预测 | 算法版本: <b>' + versionNames[version] + '</b></div>';
// 置信度评估展示(V2和V3版本)
if (confidence && (version === 'v2' || version === 'v3')) {
if (confidence && (version === 'v2' || version === 'v3' || version === 'v4')) {
html += '<div style="background:#fff8e1;border:1px solid #ffb300;border-radius:6px;padding:12px;margin-bottom:15px;">';
html += '<div style="font-size:13px;font-weight:bold;color:#ff8f00;margin-bottom:8px;"><i class="fa fa-star-half-o"></i> 预测置信度评估</div>';
@@ -1749,19 +1826,23 @@ define(['jquery', 'bootstrap', 'backend', 'table', 'form'], function ($, undefin
}
html += '<div style="display:flex;gap:20px;align-items:center;">';
html += '<div style="text-align:center;"><div style="font-size:24px;font-weight:bold;color:#ff8f00;">' + confidence.overall_confidence + '%</div><div style="font-size:12px;color:#666;">整体置信度</div></div>';
// 整体置信度(兼容 V3/V4 不同字段名)
var overallConf = confidence.overall_confidence || confidence.overall_score || 0;
html += '<div style="text-align:center;"><div style="font-size:24px;font-weight:bold;color:#ff8f00;">' + overallConf + '%</div><div style="font-size:12px;color:#666;">整体置信度</div></div>';
// 各排名置信度(使用得分集中度维度)
if (confidence.confidence_scores && confidence.confidence_scores.length > 0) {
// V4 格式: confidence.items V3 格式: confidence.confidence_scores
var confItems = confidence.items || confidence.confidence_scores || [];
if (confItems.length > 0) {
html += '<div style="display:flex;gap:8px;">';
for (var i = 0; i < confidence.confidence_scores.length; i++) {
var cs = confidence.confidence_scores[i];
// 阈值定义:>=70%高(绿)、50-70%中(橙)、<50%低(红)
var confLevel = cs.confidence >= 70 ? '高' : (cs.confidence >= 50 ? '中' : '低');
var confColor = cs.confidence >= 70 ? '#4caf50' : (cs.confidence >= 50 ? '#ff9800' : '#f44336');
for (var i = 0; i < confItems.length; i++) {
var cs = confItems[i];
var csConf = cs.confidence || cs.score || 0;
var csRank = cs.rank || (i + 1);
var confLevel = csConf >= 70 ? '' : (csConf >= 50 ? '' : '');
var confColor = csConf >= 70 ? '#4caf50' : (csConf >= 50 ? '#ff9800' : '#f44336');
html += '<div style="text-align:center;padding:5px;background:#fff;border-radius:4px;">';
html += '<div style="font-size:14px;font-weight:bold;color:' + confColor + ';">' + cs.confidence + '%</div>';
html += '<div style="font-size:10px;color:#999;">#' + cs.rank + '</div>';
html += '<div style="font-size:14px;font-weight:bold;color:' + confColor + ';">' + csConf + '%</div>';
html += '<div style="font-size:10px;color:#999;">#' + csRank + '</div>';
html += '</div>';
}
html += '</div>';
@@ -1770,7 +1851,7 @@ define(['jquery', 'bootstrap', 'backend', 'table', 'form'], function ($, undefin
}
// 回测验证结果(V2和V3版本)
if (backtest && (version === 'v2' || version === 'v3')) {
if (backtest && (version === 'v2' || version === 'v3' || version === 'v4')) {
html += '<div style="background:#e3f2fd;border:1px solid #2196f3;border-radius:6px;padding:12px;margin-bottom:15px;">';
html += '<div style="font-size:13px;font-weight:bold;color:#1565c0;margin-bottom:8px;"><i class="fa fa-chart-line"></i> 历史回测验证(最近' + backtest.total_tests + '期)</div>';
@@ -1880,6 +1961,40 @@ define(['jquery', 'bootstrap', 'backend', 'table', 'form'], function ($, undefin
html += '</div>';
}
// V4版本特有的分析信息
if (version === 'v4' && analysis) {
html += '<div style="background:#e8eaf6;border:1px solid #3f51b5;border-radius:6px;padding:10px;margin-bottom:15px;font-size:12px;">';
html += '<div style="font-weight:bold;color:#283593;margin-bottom:8px;"><i class="fa fa-cubes"></i> V4贝叶斯集成分析</div>';
html += '<div style="margin-bottom:5px;"><b>算法:</b> ' + (analysis.algorithm || 'Bayesian Ensemble') + '</div>';
html += '<div style="margin-bottom:5px;"><b>半衰期:</b> ' + (analysis.half_life || 50) + '期 | <b>历史数据:</b> ' + (analysis.history_count || 0) + '期</div>';
if (analysis.weights_adaptive) {
html += '<div style="margin-bottom:5px;color:#2e7d32;"><b>自适应权重:</b> 已启用(基于滚动回测性能调整)</div>';
}
if (analysis.pattern_match_info) {
var pmi = analysis.pattern_match_info;
html += '<div style="margin-bottom:5px;"><b>形态匹配:</b> 匹配' + pmi.matched_segments + '个历史片段 | 最佳相似度 ' + (pmi.best_similarity * 100).toFixed(1) + '%</div>';
}
if (analysis.cyclical_detected) {
var cyc = analysis.cyclical_detected;
html += '<div style="margin-bottom:5px;"><b>周期检测:</b> ' + (cyc.has_cyclical ? '发现' + cyc.significant_count + '个号码有显著周期性' : '无明显周期信号') + '</div>';
}
// 显示权重分布
if (analysis.weights) {
html += '<div style="margin-top:8px;"><b>子模型权重分布:</b></div>';
html += '<div style="display:flex;flex-wrap:wrap;gap:5px;margin-top:4px;">';
var wNames = {
'freq_ewma': 'EWMA频率', 'markov_number': '号码转移', 'omit_empirical': '遗漏CDF',
'pattern_match': '形态匹配', 'cyclical': '周期检测', 'attr_balance': '属性平衡'
};
for (var wk in analysis.weights) {
var wv = (analysis.weights[wk] * 100).toFixed(1);
html += '<span style="background:#e0e0e0;padding:2px 6px;border-radius:3px;font-size:11px;">' + (wNames[wk] || wk) + ': <b>' + wv + '%</b></span>';
}
html += '</div>';
}
html += '</div>';
}
// 遗漏统计信息(V2和V3版本)
if (analysis.omit_stats && (version === 'v2' || version === 'v3')) {
html += '<div style="background:#fce4ec;border:1px solid #e91e63;border-radius:6px;padding:10px;margin-bottom:15px;font-size:12px;">';
@@ -1928,7 +2043,14 @@ define(['jquery', 'bootstrap', 'backend', 'table', 'form'], function ($, undefin
// 根据版本显示不同的详情信息
var detailInfo = '';
if (p.detail) {
if (version === 'v3') {
if (version === 'v4') {
// V4版本显示子模型概率和属性
var omitCount = p.detail.omit_count || 0;
detailInfo = '<div style="font-size:9px;color:#999;line-height:1.3;">';
detailInfo += '遗漏:' + omitCount + '期 | ';
detailInfo += (p.detail.is_odd ? '单' : '双') + '/' + (p.detail.is_big ? '大' : '小');
detailInfo += '</div>';
} else if (version === 'v3') {
// V3版本显示更多维度信息
var omitInfo = p.detail.omit || 0;
var transScore = p.detail.trans_score || 0;
@@ -1952,14 +2074,18 @@ define(['jquery', 'bootstrap', 'backend', 'table', 'form'], function ($, undefin
html += '<div style="font-size:10px;color:#666;line-height:1.2;margin-top:2px;">' + animal + '</div>';
html += '<div style="font-size:11px;color:#2e7d32;font-weight:bold;">得分:' + p.score + '</div>';
// 显示置信度(V3版本)
if (version === 'v3' && confidence && confidence.confidence_scores) {
var csForNum = confidence.confidence_scores.find(function(c) { return c.num === p.num; });
// 显示置信度(V3和V4版本)
if ((version === 'v3' || version === 'v4') && confidence) {
var confItemsV4 = confidence.confidence_scores || confidence.items || [];
var csForNum = null;
for (var ci = 0; ci < confItemsV4.length; ci++) {
if (confItemsV4[ci].num === p.num) { csForNum = confItemsV4[ci]; break; }
}
if (csForNum) {
// 阈值定义:>=70%高(绿)、50-70%中(橙)、<50%低(红)
var confLevel = csForNum.confidence >= 70 ? '高' : (csForNum.confidence >= 50 ? '中' : '低');
var confColor = csForNum.confidence >= 70 ? '#4caf50' : (csForNum.confidence >= 50 ? '#ff9800' : '#f44336');
html += '<div style="font-size:10px;"><span style="color:' + confColor + ';font-weight:bold;">置信度:' + confLevel + '</span> <span style="color:#666;">(' + csForNum.confidence + '%)</span></div>';
var csValue = csForNum.confidence || csForNum.score || 0;
var confLevel = csValue >= 70 ? '高' : (csValue >= 50 ? '中' : '低');
var confColor = csValue >= 70 ? '#4caf50' : (csValue >= 50 ? '#ff9800' : '#f44336');
html += '<div style="font-size:10px;"><span style="color:' + confColor + ';font-weight:bold;">置信度:' + confLevel + '</span> <span style="color:#666;">(' + csValue + '%)</span></div>';
}
}