define(['jquery', 'bootstrap', 'backend', 'table', 'form'], function ($, undefined, Backend, Table, Form) {
var Controller = {
index: function () {
Table.api.init({
extend: {
index_url: 'history/index' + location.search,
add_url: 'history/add',
edit_url: 'history/edit',
del_url: 'history/del',
multi_url: 'history/multi',
import_url: 'history/import',
table: 'history',
}
});
var table = $("#table");
// 从后端获取颜色和生肖映射
Controller.api.loadColorMap(function () {
Controller.api.loadAnimalMap(function () {
table.bootstrapTable({
url: $.fn.bootstrapTable.defaults.extend.index_url,
pk: 'expect',
sortName: 'expect',
columns: [
[
{checkbox: true},
{field: 'expect', title: __('Expect')},
{field: 'num1', title: __('Num1'), formatter: Controller.api.formatter.numBall},
{field: 'num2', title: __('Num2'), formatter: Controller.api.formatter.numBall},
{field: 'num3', title: __('Num3'), formatter: Controller.api.formatter.numBall},
{field: 'num4', title: __('Num4'), formatter: Controller.api.formatter.numBall},
{field: 'num5', title: __('Num5'), formatter: Controller.api.formatter.numBall},
{field: 'num6', title: __('Num6'), formatter: Controller.api.formatter.numBall},
{field: 'num7', title: __('Num7'), formatter: Controller.api.formatter.numBall},
{field: 'openTime', title: __('OpenTime'), operate:'RANGE', addclass:'datetimerange', autocomplete:false},
{field: 'search_day', title: '每月日号', visible: false, searchable: true, operate: '=', style: 'width:80px;', extend: 'min="1" max="31" placeholder="1-31"'}
]
]
});
Table.api.bindevent(table);
});
});
// 遗漏号码按钮事件
$(document).off('click', '.btn-missingnum').on('click', '.btn-missingnum', function () {
Controller.api.showMissingNumDialog();
});
// 走势图按钮事件
$(document).off('click', '.btn-trend').on('click', '.btn-trend', function () {
Controller.api.showTrendDialog();
});
// 冷热分析按钮事件
$(document).off('click', '.btn-hotcold').on('click', '.btn-hotcold', function () {
Controller.api.showHotColdDialog();
});
// 波色分析按钮事件
$(document).off('click', '.btn-colorwave').on('click', '.btn-colorwave', function () {
Controller.api.showAnalysisDialog('colorWave');
});
// 生肖分析按钮事件
$(document).off('click', '.btn-zodiac').on('click', '.btn-zodiac', function () {
Controller.api.showAnalysisDialog('zodiac');
});
// 奇偶分析按钮事件
$(document).off('click', '.btn-oddeven').on('click', '.btn-oddeven', function () {
Controller.api.showAnalysisDialog('oddEven');
});
// 大小分析按钮事件
$(document).off('click', '.btn-bigsmall').on('click', '.btn-bigsmall', function () {
Controller.api.showAnalysisDialog('bigSmall');
});
// 和值分析按钮事件
$(document).off('click', '.btn-sumchart').on('click', '.btn-sumchart', function () {
Controller.api.showSumDialog();
});
// 连号分析按钮事件
$(document).off('click', '.btn-consecutive').on('click', '.btn-consecutive', function () {
Controller.api.showConsecutiveDialog();
});
// 尾数分析按钮事件
$(document).off('click', '.btn-tailnums').on('click', '.btn-tailnums', function () {
Controller.api.showAnalysisDialog('tailNumbers');
});
// 特码冷热按钮事件
$(document).off('click', '.btn-specialhotcold').on('click', '.btn-specialhotcold', function () {
Controller.api.showSpecialHotColdDialog();
});
// 综合统计面板按钮事件
$(document).off('click', '.btn-dashboard').on('click', '.btn-dashboard', function () {
Controller.api.showDashboard();
});
// 筛号器按钮事件
$(document).off('click', '.btn-numberfilter').on('click', '.btn-numberfilter', function () {
Controller.api.showNumberFilterDialog();
});
// 预测号码按钮事件
$(document).off('click', '.btn-predict').on('click', '.btn-predict', function () {
Controller.api.showPredictDialog();
});
},
add: function () {
Controller.api.bindevent();
},
edit: function () {
Controller.api.bindevent();
},
api: {
colorMap: {},
colorMapLoaded: false,
animalMap: {},
animalMapLoaded: false,
/**
* 从后端加载颜色映射并缓存
*/
loadColorMap: function (callback) {
if (Controller.api.colorMapLoaded) {
callback();
return;
}
$.ajax({
url: 'num/getColorMap',
type: 'GET',
dataType: 'json',
success: function (ret) {
if (ret.code == 1) {
Controller.api.colorMap = ret.msg;
}
Controller.api.colorMapLoaded = true;
callback();
}
});
},
/**
* 从后端加载生肖映射并缓存
*/
loadAnimalMap: function (callback) {
if (Controller.api.animalMapLoaded) {
callback();
return;
}
$.ajax({
url: 'num/getAnimalMap',
type: 'GET',
dataType: 'json',
success: function (ret) {
if (ret.code == 1) {
Controller.api.animalMap = ret.msg;
}
Controller.api.animalMapLoaded = true;
callback();
}
});
},
/**
* 根据数字从映射表中获取生肖
*/
getAnimalByNum: function (num) {
return Controller.api.animalMap[num] || '';
},
/**
* 根据数字从映射表中获取颜色
*/
getColorByNum: function (num) {
var color = Controller.api.colorMap[num];
if (!color) return '#95a5a6';
// 后端返回中文波色,前端映射为CSS颜色
if (color.indexOf('红') !== -1) return '#e74c3c';
if (color.indexOf('蓝') !== -1) return '#3498db';
if (color.indexOf('绿') !== -1) return '#2ecc71';
return '#95a5a6';
},
formatter: {
numBall: function (value, row, index) {
if (value === null || value === undefined || value === '') return '';
var num = parseInt(value);
var color = Controller.api.getColorByNum(num);
var animal = Controller.api.getAnimalByNum(num);
var html = '
' +
'
' + value + ' ';
if (animal) {
html += '
' + animal + '
';
}
html += '
';
return html;
}
},
/**
* 显示冷热分析弹窗
*/
showHotColdDialog: function () {
var html = '';
Layer.open({
type: 1,
title: __('Hot/Cold Analysis'),
area: ['700px', '600px'],
content: html,
shadeClose: true,
success: function (layero, index) {
$('#btn-hc-query', layero).on('click', function () {
var periods = parseInt($('#hc-periods', layero).val()) || 30;
var type = $('input[name="hc-type"]:checked', layero).val();
Controller.api.queryHotCold(periods, type, layero);
});
$('input[name="hc-type"]', layero).on('change', function () {
var periods = parseInt($('#hc-periods', layero).val()) || 30;
Controller.api.queryHotCold(periods, $(this).val(), layero);
});
}
});
},
queryHotCold: function (periods, type, layero) {
var $btn = $('#btn-hc-query', layero);
$btn.prop('disabled', true);
$('#hc-result', layero).html(' ' + __('Loading') + '
');
$.ajax({
url: 'history/hotColdNumbers',
type: 'GET',
data: {periods: periods, type: type},
dataType: 'json',
success: function (ret) {
if (ret.code == 1) {
Controller.api.renderHotCold(ret.data, layero);
} else {
$('#hc-result', layero).html('' + (ret.msg || __('Query failed')) + '
');
}
},
error: function () {
$('#hc-result', layero).html('' + __('Query failed') + '
');
},
complete: function () {
$btn.prop('disabled', false);
}
});
},
renderHotCold: function (data, layero) {
var getColor = function (num) {
var color = data.all.find(function (item) { return item.num === num; });
if (!color || !color.color) return '#95a5a6';
if (color.color.indexOf('红') !== -1) return '#e74c3c';
if (color.color.indexOf('蓝') !== -1) return '#3498db';
if (color.color.indexOf('绿') !== -1) return '#2ecc71';
return '#95a5a6';
};
var getAnimal = function (num) {
var item = data.all.find(function (item) { return item.num === num; });
return item ? (item.animal || '') : '';
};
var renderSection = function (title, items, icon) {
var html = '' + icon + ' ' + title + ' ';
html += '
';
for (var i = 0; i < items.length; i++) {
var item = items[i];
var color = getColor(item.num);
var animal = getAnimal(item.num);
html += '
' +
'
' + item.num + ' ' +
'
' + (animal ? animal + ' ' : '') + '' + item.count + ' (' + item.percent + '%)
' +
'
';
}
html += '
';
return html;
};
var html = '' +
renderSection('热号 Top 10', data.hot, '🔥 ') +
renderSection('冷号 Top 10', data.cold, '❄ ') +
'
';
$('#hc-result', layero).html(html);
},
/**
* 显示走势图弹窗
*/
showTrendDialog: function () {
var html = '';
Layer.open({
type: 1,
title: __('Trend Chart'),
area: ['90%', '80%'],
content: html,
shadeClose: false,
maxmin: true,
success: function (layero, index) {
$('#btn-trend-query', layero).on('click', function () {
var periods = parseInt($('#trend-periods', layero).val()) || 30;
var type = $('input[name="trend-type"]:checked', layero).val();
Controller.api.queryTrend(periods, type, layero);
});
$('input[name="trend-type"]', layero).on('change', function () {
var periods = parseInt($('#trend-periods', layero).val()) || 30;
Controller.api.queryTrend(periods, $(this).val(), layero);
});
}
});
},
/**
* 查询走势图
*/
queryTrend: function (periods, type, layero) {
var $btn = $('#btn-trend-query', layero);
$btn.prop('disabled', true);
$('#trend-result', layero).html(' ' + __('Loading') + '
');
$.ajax({
url: 'history/trendData',
type: 'GET',
data: {periods: periods, type: type},
dataType: 'json',
success: function (ret) {
if (ret.code == 1) {
Controller.api.renderTrend(ret.data, type, layero);
} else {
$('#trend-result', layero).html('' + (ret.msg || __('Query failed')) + '
');
}
},
error: function () {
$('#trend-result', layero).html('' + __('Query failed') + '
');
},
complete: function () {
$btn.prop('disabled', false);
}
});
},
/**
* 渲染走势图(ECharts 折线图)
*/
renderTrend: function (data, type, layero) {
var expects = data.expects;
var rows = data.data;
var colorMap = data.colorMap;
if (!expects || expects.length === 0) {
$('#trend-result', layero).html('' + __('No data available') + '
');
return;
}
var getColor = function (num) {
var color = colorMap[num];
if (!color) return '#95a5a6';
if (color.indexOf('红') !== -1) return '#e74c3c';
if (color.indexOf('蓝') !== -1) return '#3498db';
if (color.indexOf('绿') !== -1) return '#2ecc71';
return '#95a5a6';
};
$('#trend-result', layero).html('
');
var chartDom = document.getElementById('trend-chart');
var myChart = echarts.init(chartDom);
var series = [];
if (type === 'special') {
series = [{
name: '特码',
type: 'line',
data: rows.map(function (r) { return r.num7; }),
smooth: false,
symbol: 'circle',
symbolSize: 8,
lineStyle: { width: 2 },
itemStyle: {
color: function (params) {
var num = params.data;
return getColor(num);
}
},
label: {
show: true,
position: 'top',
fontSize: 11,
color: '#333'
}
}];
} else {
var numFields = [];
for (var c = 1; c <= 7; c++) {
numFields.push('num' + c);
}
var colors = ['#e74c3c', '#3498db', '#2ecc71', '#f39c12', '#9b59b6', '#1abc9c', '#e67e22'];
for (var f = 0; f < numFields.length; f++) {
(function (idx) {
series.push({
name: '第' + (idx + 1) + '码',
type: 'line',
data: rows.map(function (r) { return r[numFields[idx]]; }),
smooth: false,
symbol: 'circle',
symbolSize: 6,
lineStyle: { width: 2 },
itemStyle: { color: colors[idx] },
label: {
show: true,
position: 'top',
fontSize: 10,
color: '#333'
}
});
})(f);
}
}
var option = {
title: { text: type === 'special' ? '特码走势' : '全部号码走势', left: 'center', textStyle: { fontSize: 14 } },
tooltip: { trigger: 'axis', formatter: function (params) {
var tip = '期号: ' + params[0].axisValueLabel + ' ';
for (var i = 0; i < params.length; i++) {
tip += params[i].seriesName + ': ' + params[i].data + ' ';
}
return tip;
}},
legend: { bottom: 10, data: series.map(function (s) { return s.name; }) },
grid: { left: 40, right: 20, bottom: 50, top: 40 },
xAxis: { type: 'category', data: expects, axisLabel: { rotate: 45, fontSize: 10 } },
yAxis: { type: 'value', min: 0, max: 50, splitLine: { show: true, lineStyle: { type: 'dashed' } } },
dataZoom: [{ type: 'slider', bottom: 30, height: 20, start: 0, end: 100 }],
series: series
};
myChart.setOption(option);
window.addEventListener('resize', function () { myChart.resize(); });
},
/**
* 显示遗漏号码分析弹窗
*/
showMissingNumDialog: function () {
var html = '';
Layer.open({
type: 1,
title: __('Missing Number Analysis'),
area: ['650px', '550px'],
content: html,
shadeClose: true,
success: function (layero, index) {
// 绑定查询按钮事件
$('#btn-missing-query', layero).on('click', function () {
var periods = parseInt($('#missing-periods', layero).val()) || 10;
var type = $('input[name="missing-type"]:checked', layero).val();
Controller.api.queryMissingNum(periods, type, layero);
});
// 切换类型时自动查询
$('input[name="missing-type"]', layero).on('change', function () {
var periods = parseInt($('#missing-periods', layero).val()) || 10;
Controller.api.queryMissingNum(periods, $(this).val(), layero);
});
}
});
},
/**
* 查询遗漏号码
*/
queryMissingNum: function (periods, type, layero) {
// 确保颜色映射已加载
if (!Controller.api.colorMapLoaded) {
Controller.api.loadColorMap(function () {
Controller.api._doQueryMissingNum(periods, type, layero);
});
} else {
Controller.api._doQueryMissingNum(periods, type, layero);
}
},
/**
* 执行遗漏号码查询(内部方法)
*/
_doQueryMissingNum: function (periods, type, layero) {
var $btn = $('#btn-missing-query', layero);
$btn.prop('disabled', true);
$('#missing-result', layero).html(' ' + __('Loading') + '
');
$.ajax({
url: 'history/missingNum',
type: 'GET',
data: {periods: periods, type: type},
dataType: 'json',
success: function (ret) {
if (ret.code == 1) {
Controller.api.renderMissingNum(ret.data, periods, layero);
} else {
$('#missing-result', layero).html('' + (ret.msg || __('Query failed')) + '
');
}
},
error: function () {
$('#missing-result', layero).html('' + __('Query failed') + '
');
},
complete: function () {
$btn.prop('disabled', false);
}
});
},
/**
* 渲染遗漏号码结果
*/
renderMissingNum: function (data, periods, layero) {
if (!data || data.length === 0) {
$('#missing-result', layero).html('' + __('No missing numbers found') + '
');
return;
}
var container = $('
');
for (var i = 0; i < data.length; i++) {
var color = Controller.api.getColorByNum(data[i].num);
var animal = Controller.api.getAnimalByNum(data[i].num);
var $item = $('
');
var $ball = $(' ').css({
'display': 'inline-block',
'width': '48px',
'height': '48px',
'line-height': '48px',
'text-align': 'center',
'border-radius': '50%',
'color': '#fff',
'background-color': color,
'font-weight': 'bold',
'font-size': '18px'
}).text(data[i].num);
var $content = $('
').append($ball);
if (animal) {
$content.append($('
').text(animal));
}
$content.append($('
').text(
__('Missing') + ' ' + data[i].omit + ' ' + __('periods')
));
$item.append($content);
container.append($item);
}
$('#missing-result', layero).html('').append(container);
},
/**
* 特码冷热列表(每期相对于前N期的冷热状态)
*/
showSpecialHotColdDialog: function () {
var html = '' +
'
' +
' 向前期数: ' +
' ' +
' ' + __('Query') + ' ' +
'
' +
'
' +
'
';
Layer.open({
type: 1,
title: '特码冷热列表',
area: ['650px', '600px'],
content: html,
shadeClose: true,
success: function (layero, index) {
$('#btn-shc-query', layero).on('click', function () {
var lookback = parseInt($('#shc-lookback', layero).val()) || 30;
Controller.api.querySpecialHotCold(lookback, layero);
});
// 打开时自动查询
var lookback = parseInt($('#shc-lookback', layero).val()) || 30;
Controller.api.querySpecialHotCold(lookback, layero);
}
});
},
querySpecialHotCold: function (lookback, layero) {
var $btn = $('#btn-shc-query', layero);
$btn.prop('disabled', true);
$('#shc-result', layero).html(' ' + __('Loading') + '
');
$.ajax({
url: 'history/specialHotColdAction',
type: 'GET',
data: {lookback: lookback},
dataType: 'json',
success: function (ret) {
if (ret.code == 1) {
Controller.api.renderSpecialHotCold(ret.data, lookback, layero);
} else {
$('#shc-result', layero).html('' + (ret.msg || __('Query failed')) + '
');
}
},
error: function () {
$('#shc-result', layero).html('' + __('Query failed') + '
');
},
complete: function () {
$btn.prop('disabled', false);
}
});
},
renderSpecialHotCold: function (data, lookback, layero) {
var getColor = function (num) {
return Controller.api.getColorByNum(num);
};
var statusTag = function (status) {
var map = {
'hot': '🔥 热号 ',
'cold': '❄ 冷号 ',
'normal': '➜ 温号 ',
'unknown': '数据不足 '
};
return map[status] || '';
};
// 新接口返回 {list: [...], current: {hot: [], cold: [], warm: []}}
var listData = data.list || data;
var current = data.current || null;
if (!listData || listData.length === 0) {
$('#shc-result', layero).html('暂无数据
');
return;
}
var html = '';
// 当前冷热号汇总区域
if (current && (current.hot.length > 0 || current.cold.length > 0)) {
var renderNumBall = function (item) {
var color = getColor(item.num);
return '
' + item.num + ' ';
};
html += '
';
html += '
当前热号
';
html += '
';
for (var h = 0; h < current.hot.length; h++) {
html += renderNumBall(current.hot[h]);
}
if (current.hot.length === 0) {
html += '暂无热号 ';
}
html += '
';
html += '
';
html += '
当前冷号
';
html += '
';
for (var c = 0; c < current.cold.length; c++) {
html += renderNumBall(current.cold[c]);
}
if (current.cold.length === 0) {
html += '暂无冷号 ';
}
html += '
';
html += '
';
}
// 历史记录表格
html += '
' +
'' +
'期号 ' +
'特码 ' +
'冷热 ' +
'次数 ' +
'平均 ' +
'排名 ' +
' ';
for (var i = 0; i < listData.length; i++) {
var item = listData[i];
var rowClass = '';
if (item.status === 'hot') rowClass = 'style="background:#fff5f5;"';
else if (item.status === 'cold') rowClass = 'style="background:#f5f8ff;"';
html += '' +
'' + item.expect + ' ' +
'' +
'' + item.specialNum + ' ' +
' ' +
'' + statusTag(item.status) + ' ' +
'' + item.count + ' ' +
'' + item.avgCount + ' ' +
'' + item.rank + ' ' +
' ';
}
html += '
';
$('#shc-result', layero).html(html);
},
/**
* 筛号器弹窗
*/
showNumberFilterDialog: function () {
var html = '' +
'' +
'
' +
'
' +
' 尾号筛选: ' +
' 新增 ' +
'
' +
'
重置' +
'
' +
'
' +
'
' +
'
生肖: ' +
'
' +
' 鼠 ' +
' 牛 ' +
' 虎 ' +
' 兔 ' +
' 龙 ' +
' 蛇 ' +
' 马 ' +
' 羊 ' +
' 猴 ' +
' 鸡 ' +
' 狗 ' +
' 猪 ' +
'
' +
'
' +
'
' +
'
波色: ' +
'
' +
' 红波 ' +
' 蓝波 ' +
' 绿波 ' +
'
' +
'
' +
'
' +
' 单双: ' +
' 单 ' +
' 双 ' +
'
' +
'
' +
' 区间: ' +
' 新增 ' +
'
' +
'
' +
'
' +
'
';
Layer.open({
type: 1,
title: '筛号器',
area: ['700px', '600px'],
content: html,
shadeClose: true,
success: function (layero, index) {
// 手动屏蔽的号码列表
var blockedNums = [];
// 渲染号码网格
Controller.api.renderNumberFilterGrid(layero);
// 号码点击屏蔽
$('#nf-numbers', layero).on('click', '.nf-number', function () {
var num = parseInt($(this).data('num'));
var idx = blockedNums.indexOf(num);
if (idx === -1) {
blockedNums.push(num);
} else {
blockedNums.splice(idx, 1);
}
Controller.api.applyNumberFilters(layero, blockedNums);
});
// 新增尾号
$('.btn-nf-add-tail', layero).on('click', function () {
Controller.api.addTailRow(layero, 0);
Controller.api.applyNumberFilters(layero, blockedNums);
});
// 尾号输入 & 删除事件委托
$('#nf-tail-list', layero).on('input change', '.nf-tail-select', function () {
Controller.api.applyNumberFilters(layero, blockedNums);
});
$('#nf-tail-list', layero).on('click', '.nf-tail-del', function () {
$(this).closest('.nf-tail-row').remove();
Controller.api.applyNumberFilters(layero, blockedNums);
});
// 生肖按钮点击
$('.nf-zodiac', layero).on('click', function () {
var $btn = $(this);
$btn.toggleClass('btn-default').toggleClass('btn-gray');
Controller.api.applyNumberFilters(layero, blockedNums);
});
// 波色按钮点击
$('.nf-color-btn', layero).on('click', function () {
var $btn = $(this);
$btn.toggleClass('btn-default').toggleClass('btn-gray');
Controller.api.applyNumberFilters(layero, blockedNums);
});
// 单双按钮点击
$('.nf-parity', layero).on('click', function () {
var $btn = $(this);
$btn.toggleClass('btn-default').toggleClass('btn-gray');
Controller.api.applyNumberFilters(layero, blockedNums);
});
// 新增区间
$('.btn-nf-add-range', layero).on('click', function () {
Controller.api.addRangeRow(layero, 1, 49, 'include');
Controller.api.applyNumberFilters(layero, blockedNums);
});
// 区间输入 & 删除事件委托
$('#nf-range-list', layero).on('input change', '.nf-range-min, .nf-range-max', function () {
Controller.api.applyNumberFilters(layero, blockedNums);
});
$('#nf-range-list', layero).on('click', '.nf-range-mode', function () {
var $btn = $(this);
if ($btn.hasClass('btn-info')) {
$btn.removeClass('btn-info').addClass('btn-default');
} else {
$btn.removeClass('btn-default').addClass('btn-info');
}
Controller.api.applyNumberFilters(layero, blockedNums);
});
$('#nf-range-list', layero).on('click', '.nf-range-del', function () {
$(this).closest('.nf-range-row').remove();
Controller.api.applyNumberFilters(layero, blockedNums);
});
// 重置按钮
$('.btn-nf-reset', layero).on('click', function () {
blockedNums = [];
$('#nf-tail-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');
$('#nf-range-list', layero).html('');
Controller.api.applyNumberFilters(layero, blockedNums);
});
}
});
},
/**
* 新增一行尾号筛选
*/
addTailRow: function (layero, value) {
var rowId = 'nf-tail-' + Date.now() + Math.random().toString(36).substr(2, 5);
var opts = '尾号 ';
for (var t = 0; t <= 9; t++) {
opts += '' + t + ' ';
}
var html = '' +
' ' + opts + ' ' +
' ' +
'
';
$('#nf-tail-list', layero).append(html);
},
/**
* 新增一行区间筛选
*/
addRangeRow: function (layero, min, max, mode) {
var rowId = 'nf-range-' + Date.now();
var isInclude = mode === 'include';
var html = '' +
' ' + (isInclude ? '在区间' : '排除') + ' ' +
' ' +
' — ' +
' ' +
' ' + (isInclude ? '在区间' : '排除区间') + ' ' +
' ' +
'
';
$('#nf-range-list', layero).append(html);
},
/**
* 渲染筛号器号码网格
*/
renderNumberFilterGrid: function (layero) {
var colorMap = Controller.api.colorMap;
var html = '';
for (var num = 1; num <= 49; num++) {
var colorHex = Controller.api.getColorByNum(num);
var colorRaw = colorMap[num] || '';
var animal = Controller.api.getAnimalByNum(num);
var colorLabel = '';
if (colorRaw.indexOf('红') !== -1) colorLabel = '红';
else if (colorRaw.indexOf('蓝') !== -1) colorLabel = '蓝';
else if (colorRaw.indexOf('绿') !== -1) colorLabel = '绿';
html += '' +
'
' + num + ' ' +
'
' + animal + '
' +
'
';
}
$('#nf-numbers', layero).html(html);
},
/**
* 应用筛号器过滤条件
* @param {object} layero Layer弹窗对象
* @param {Array} blockedNums 手动屏蔽的号码列表
*/
applyNumberFilters: function (layero, blockedNums) {
blockedNums = blockedNums || [];
// 收集所有选中的尾号
var excludedTails = [];
$('.nf-tail-select', layero).each(function () {
var val = $(this).val();
if (val !== '' && excludedTails.indexOf(parseInt(val)) === -1) {
excludedTails.push(parseInt(val));
}
});
// 收集被点击(置灰)的生肖
var excludedZodiacs = [];
$('.nf-zodiac.btn-gray', layero).each(function () {
excludedZodiacs.push($(this).data('zodiac'));
});
// 收集被点击(置灰)的波色
var excludedColors = [];
$('.nf-color-btn.btn-gray', layero).each(function () {
excludedColors.push($(this).data('color'));
});
// 收集被点击(置灰)的单双
var excludedParities = [];
$('.nf-parity.btn-gray', layero).each(function () {
excludedParities.push($(this).data('parity'));
});
// 收集所有区间
var ranges = [];
$('.nf-range-row', layero).each(function () {
var $row = $(this);
var min = parseInt($row.find('.nf-range-min').val()) || 1;
var max = parseInt($row.find('.nf-range-max').val()) || 49;
var mode = $row.find('.nf-range-mode').hasClass('btn-info') ? 'include' : 'exclude';
ranges.push({min: min, max: max, mode: mode});
});
$('.nf-number', layero).each(function () {
var $num = $(this);
var num = parseInt($num.data('num'));
var tail = $num.data('tail');
var animal = $num.data('animal');
var color = $num.data('color');
var parity = $num.data('parity');
var hidden = false;
// 尾号筛选:选中多个尾号,任一命中即屏蔽
if (excludedTails.length > 0 && excludedTails.indexOf(tail) !== -1) {
hidden = true;
}
// 单双筛选:选中单或双,匹配则屏蔽
if (excludedParities.indexOf(parity) !== -1) {
hidden = true;
}
// 区间筛选:在区间=白名单(OR)、排除区间=黑名单(OR)
if (!hidden) {
var includeRanges = [];
var excludeRanges = [];
for (var r = 0; r < ranges.length; r++) {
if (ranges[r].mode === 'include') {
includeRanges.push(ranges[r]);
} else {
excludeRanges.push(ranges[r]);
}
}
// 黑名单:任一排除区间命中则屏蔽
for (var r = 0; r < excludeRanges.length; r++) {
if (num >= excludeRanges[r].min && num <= excludeRanges[r].max) {
hidden = true;
break;
}
}
// 白名单:有在区间规则时,号码不在任一区间则屏蔽
if (!hidden && includeRanges.length > 0) {
var inAnyInclude = false;
for (var r = 0; r < includeRanges.length; r++) {
if (num >= includeRanges[r].min && num <= includeRanges[r].max) {
inAnyInclude = true;
break;
}
}
if (!inAnyInclude) {
hidden = true;
}
}
}
// 排除的生肖
if (excludedZodiacs.indexOf(animal) !== -1) {
hidden = true;
}
// 排除的波色
if (excludedColors.indexOf(color) !== -1) {
hidden = true;
}
// 手动屏蔽的号码
if (blockedNums.indexOf(num) !== -1) {
hidden = true;
}
if (hidden) {
$num.css('opacity', '0.25').css('filter', 'grayscale(100%)');
} else {
$num.css('opacity', '1').css('filter', 'none');
}
});
},
bindevent: function () {
Form.api.bindevent($("form[role=form]"));
},
/**
* 通用分析弹窗(波色、生肖、奇偶、大小、尾数)
*/
showAnalysisDialog: function (type) {
var titles = {
colorWave: __('Color Wave'),
zodiac: __('Zodiac'),
oddEven: __('Odd/Even'),
bigSmall: __('Big/Small'),
tailNumbers: __('Tail Numbers')
};
var endpoints = {
colorWave: 'history/colorWaveAnalysis',
zodiac: 'history/zodiacAnalysis',
oddEven: 'history/oddEvenAnalysis',
bigSmall: 'history/bigSmallAnalysis',
tailNumbers: 'history/tailNumbers'
};
var hasType = ['colorWave', 'zodiac', 'oddEven', 'bigSmall', 'tailNumbers'].indexOf(type) !== -1;
var html = '';
Layer.open({
type: 1,
title: titles[type] || type,
area: ['650px', '550px'],
content: html,
shadeClose: true,
success: function (layero, index) {
$('#btn-analysis-' + type, layero).on('click', function () {
var periods = parseInt($('#analysis-periods-' + type, layero).val()) || 30;
var tp = hasType ? $('input[name="analysis-type-' + type + '"]:checked', layero).val() : 'all';
Controller.api.queryAnalysis(periods, tp, type, endpoints[type], layero);
});
if (hasType) {
$('input[name="analysis-type-' + type + '"]', layero).on('change', function () {
var periods = parseInt($('#analysis-periods-' + type, layero).val()) || 30;
Controller.api.queryAnalysis(periods, $(this).val(), type, endpoints[type], layero);
});
}
}
});
},
queryAnalysis: function (periods, type, analysisType, endpoint, layero) {
var $btn = $('#btn-analysis-' + analysisType, layero);
$btn.prop('disabled', true);
$('#analysis-result-' + analysisType, layero).html(' ' + __('Loading') + '
');
$.ajax({
url: endpoint,
type: 'GET',
data: {periods: periods, type: type},
dataType: 'json',
success: function (ret) {
if (ret.code == 1) {
var renderMap = {
colorWave: 'renderColorWaveAnalysis',
zodiac: 'renderZodiacAnalysis',
oddEven: 'renderOddEvenAnalysis',
bigSmall: 'renderBigSmallAnalysis',
tailNumbers: 'renderTailNumbers'
};
var renderFn = renderMap[analysisType];
if (renderFn && typeof Controller.api[renderFn] === 'function') {
Controller.api[renderFn](ret.data, layero);
} else {
$('#analysis-result-' + analysisType, layero).html('渲染方法不存在: ' + renderFn + '
');
}
} else {
$('#analysis-result-' + analysisType, layero).html('' + (ret.msg || __('Query failed')) + '
');
}
},
error: function () {
$('#analysis-result-' + analysisType, layero).html('' + __('Query failed') + '
');
},
complete: function () {
$btn.prop('disabled', false);
}
});
},
renderColorWaveAnalysis: function (data, layero) {
var html = '';
var items = [
{label: '红波', value: data.red, pct: data.red_pct, color: '#e74c3c'},
{label: '蓝波', value: data.blue, pct: data.blue_pct, color: '#3498db'},
{label: '绿波', value: data.green, pct: data.green_pct, color: '#2ecc71'}
];
for (var i = 0; i < items.length; i++) {
var item = items[i];
html += '
' +
'
' + item.value + '
' +
'
' + item.label + '
' +
'
' + item.pct + '%
' +
'
';
}
html += '
总计: ' + data.total + ' 个号码
';
$('#analysis-result-colorWave', layero).html(html);
},
renderZodiacAnalysis: function (data, layero) {
var html = '';
for (var i = 0; i < data.list.length; i++) {
var item = data.list[i];
html += '
' +
'
' + item.animal + '
' +
'
' + item.count + ' (' + item.percent + '%)
' +
'
';
}
html += '
';
$('#analysis-result-zodiac', layero).html(html);
},
renderOddEvenAnalysis: function (data, layero) {
var html = '';
html += '
' +
'
' + data.odd + '
' +
'
奇数
' +
'
' + data.odd_pct + '%
';
html += '
' +
'
' + data.even + '
' +
'
偶数
' +
'
' + data.even_pct + '%
';
html += '
';
$('#analysis-result-oddEven', layero).html(html);
},
renderBigSmallAnalysis: function (data, layero) {
var html = '';
html += '
' +
'
' + data.big + '
' +
'
大数(25-49)
' +
'
' + data.big_pct + '%
';
html += '
' +
'
' + data.small + '
' +
'
小数(1-24)
' +
'
' + data.small_pct + '%
';
html += '
';
$('#analysis-result-bigSmall', layero).html(html);
},
renderTailNumbers: function (data, layero) {
var html = '';
for (var i = 0; i < data.all.length; i++) {
var item = data.all[i];
html += '
' +
'
' + item.tail + '
' +
'
' + item.count + ' (' + item.percent + '%)
';
}
html += '
';
$('#analysis-result-tailNumbers', layero).html(html);
},
/**
* 和值分析弹窗
*/
showSumDialog: function () {
var html = '' +
'
' +
' ' + __('Query Periods') + ': ' +
' ' +
' ' + __('Query') + ' ' +
'
' +
'
' +
'
';
Layer.open({
type: 1,
title: __('Sum Chart'),
area: ['750px', '400px'],
content: html,
shadeClose: true,
success: function (layero, index) {
$('#btn-sum-query', layero).on('click', function () {
var periods = parseInt($('#sum-periods', layero).val()) || 30;
Controller.api.querySum(periods, layero);
});
}
});
},
querySum: function (periods, layero) {
var $btn = $('#btn-sum-query', layero);
$btn.prop('disabled', true);
$('#sum-result', layero).html(' ' + __('Loading') + '
');
$.ajax({
url: 'history/sumAnalysis',
type: 'GET',
data: {periods: periods},
dataType: 'json',
success: function (ret) {
if (ret.code == 1) {
Controller.api.renderSum(ret.data, layero);
} else {
$('#sum-result', layero).html('' + (ret.msg || __('Query failed')) + '
');
}
},
error: function () {
$('#sum-result', layero).html('' + __('Query failed') + '
');
},
complete: function () {
$btn.prop('disabled', false);
}
});
},
renderSum: function (data, layero) {
var html = '';
html += '
';
html += '
';
html += '
';
html += '
';
$('#sum-result', layero).html(html);
var chartDom = document.getElementById('sum-chart');
if (chartDom && typeof echarts !== 'undefined') {
var myChart = echarts.init(chartDom);
myChart.setOption({
xAxis: {type: 'category', data: data.expects, axisLabel: {rotate: 45, fontSize: 10}},
yAxis: {type: 'value'},
series: [{type: 'line', data: data.sums, smooth: true, itemStyle: {color: '#3498db'}, areaStyle: {color: 'rgba(52,152,219,0.1)'}}],
grid: {left: 40, right: 20, bottom: 40, top: 20}
});
}
},
/**
* 连号分析弹窗
*/
showConsecutiveDialog: function () {
var html = '' +
'
' +
' ' + __('Query Periods') + ': ' +
' ' +
' ' + __('Query') + ' ' +
'
' +
'
' +
'
';
Layer.open({
type: 1,
title: __('Consecutive'),
area: ['600px', '500px'],
content: html,
shadeClose: true,
success: function (layero, index) {
$('#btn-consecutive-query', layero).on('click', function () {
var periods = parseInt($('#consecutive-periods', layero).val()) || 30;
Controller.api.queryConsecutive(periods, layero);
});
}
});
},
queryConsecutive: function (periods, layero) {
var $btn = $('#btn-consecutive-query', layero);
$btn.prop('disabled', true);
$('#consecutive-result', layero).html(' ' + __('Loading') + '
');
$.ajax({
url: 'history/consecutiveNumbers',
type: 'GET',
data: {periods: periods},
dataType: 'json',
success: function (ret) {
if (ret.code == 1) {
Controller.api.renderConsecutive(ret.data, layero);
} else {
$('#consecutive-result', layero).html('' + (ret.msg || __('Query failed')) + '
');
}
},
error: function () {
$('#consecutive-result', layero).html('' + __('Query failed') + '
');
},
complete: function () {
$btn.prop('disabled', false);
}
});
},
renderConsecutive: function (data, layero) {
var html = '';
html += '
连号对 ';
html += '
';
var pairs = data.pairs;
if (pairs && Object.keys(pairs).length > 0) {
for (var pair in pairs) {
html += '
' + pair + ' ×' + pairs[pair] + '
';
}
} else {
html += '
暂无连号数据
';
}
html += '
三连号 ';
html += '
';
var triples = data.triples;
if (triples && Object.keys(triples).length > 0) {
for (var triple in triples) {
html += '
' + triple + ' ×' + triples[triple] + '
';
}
} else {
html += '
暂无三连号数据
';
}
html += '
';
$('#consecutive-result', layero).html(html);
},
/**
* 综合统计面板
*/
showDashboard: function () {
var html = '' +
'
' +
' ' + __('Query Periods') + ': ' +
' ' +
' ' + __('Query') + ' ' +
'
' +
'
' +
'
';
Layer.open({
type: 1,
title: __('Dashboard'),
area: ['90%', '90%'],
content: html,
shadeClose: false,
maxmin: true,
success: function (layero, index) {
$('#btn-dash-query', layero).on('click', function () {
var periods = parseInt($('#dash-periods', layero).val()) || 30;
Controller.api.queryDashboard(periods, layero);
});
}
});
},
queryDashboard: function (periods, layero) {
var $btn = $('#btn-dash-query', layero);
$btn.prop('disabled', true);
$('#dash-result', layero).html(' ' + __('Loading') + '
');
$.ajax({
url: 'history/dashboard',
type: 'GET',
data: {periods: periods},
dataType: 'json',
success: function (ret) {
if (ret.code == 1) {
Controller.api.renderDashboard(ret.data, layero);
} else {
$('#dash-result', layero).html('' + (ret.msg || __('Query failed')) + '
');
}
},
error: function () {
$('#dash-result', layero).html('' + __('Query failed') + '
');
},
complete: function () {
$btn.prop('disabled', false);
}
});
},
renderDashboard: function (data, layero) {
var getColor = function (color) {
if (!color) return '#95a5a6';
if (color.indexOf('红') !== -1) return '#e74c3c';
if (color.indexOf('蓝') !== -1) return '#3498db';
if (color.indexOf('绿') !== -1) return '#2ecc71';
return '#95a5a6';
};
var hc = data.hotcold;
var cw = data.colorwave;
var zo = data.zodiac;
var oe = data.oddeven;
var bs = data.bigsmall;
var sm = data.sum;
var tn = data.tailnumbers;
var ballHtml = function (item) {
return '' + item.num + ' ' + item.count + '
';
};
var html = '';
// 冷热号码
html += '
🔥❄️ 冷热号码 ';
html += '
热号 Top5 ';
for (var i = 0; i < 5; i++) html += ballHtml(hc.hot[i]);
html += '
冷号 Top5 ';
for (var i = 0; i < 5; i++) html += ballHtml(hc.cold[i]);
html += '
';
// 波色分析
html += '
🎨 波色比例 ';
html += '
';
html += '
' + cw.red + '
红波 ' + cw.red_pct + '%
';
html += '
' + cw.blue + '
蓝波 ' + cw.blue_pct + '%
';
html += '
' + cw.green + '
绿波 ' + cw.green_pct + '%
';
html += '
';
// 生肖分析
html += '
⭐ 生肖排名 ';
html += '
';
for (var i = 0; i < Math.min(zo.list.length, 12); i++) {
var z = zo.list[i];
html += '
' + z.animal + '
' + z.count + ' (' + z.percent + '%)
';
}
html += '
';
// 奇偶分析
html += '
⚖️ 奇偶分析 ';
html += '
';
html += '
' + oe.odd + ' (' + oe.odd_pct + '%)
奇数
';
html += '
' + oe.even + ' (' + oe.even_pct + '%)
偶数
';
html += '
';
// 大小分析
html += '
📊 大小分析 ';
html += '
';
html += '
' + bs.big + ' (' + bs.big_pct + '%)
大数(25-49)
';
html += '
' + bs.small + ' (' + bs.small_pct + '%)
小数(1-24)
';
html += '
';
// 和值
html += '
📈 和值统计 ';
html += '
';
html += '
';
html += '
';
html += '
';
html += '
';
// 尾数
html += '
🔢 尾数频率 ';
html += '
';
for (var i = 0; i < tn.all.length; i++) {
var t = tn.all[i];
html += '
' + t.tail + '
' + t.count + ' (' + t.percent + '%)
';
}
html += '
';
html += '
';
$('#dash-result', layero).html(html);
},
/**
* 预测号码弹窗
*/
showPredictDialog: function () {
var html = '' +
'
' +
'
预测算法说明
' +
'
' +
' V1版本 :基于转移概率分析(区域、生肖、尾号、首号、波色转移 + 冷热系数) ' +
' V2版本 :基于统计回归分析(遗漏回归、频率回归、区域平衡、波色平衡等)+ 历史回测验证 ' +
' V3版本(推荐) :多维度综合预测,新增转移概率(马尔可夫链)、单双规律、大小规律、走势方向分析' +
'
' +
'
' +
'
' +
' 算法版本: ' +
' V3 (多维度综合) ' +
' V2(统计回归) ' +
' V1(转移概率) ' +
'
' +
'
' +
' 验证期号: ' +
' ' +
' 留空则预测下一期 ' +
'
' +
'
' +
' 统计期数: ' +
' ' +
' 建议200期以上 ' +
'
' +
// V3权重配置
'
' +
// V2权重配置
'
' +
// V1权重配置
'
' +
'
' +
' 开始预测 ' +
'
' +
'
' +
'
';
Layer.open({
type: 1,
title: '🎯 智能预测号码',
area: ['850px', '750px'],
content: html,
shadeClose: true,
success: function (layero, index) {
// 切换版本时显示对应权重配置
$('input[name="predict-version"]', layero).on('change', function () {
var val = $(this).val();
$('#predict-v3-weights', layero).hide();
$('#predict-v2-weights', layero).hide();
$('#predict-v1-weights', layero).hide();
if (val === 'v3') {
$('#predict-v3-weights', layero).show();
$('#predict-periods', layero).val(200);
} else if (val === 'v2') {
$('#predict-v2-weights', layero).show();
$('#predict-periods', layero).val(200);
} else {
$('#predict-v1-weights', layero).show();
$('#predict-periods', layero).val(100);
}
});
$('#btn-predict-query', layero).on('click', function () {
Controller.api.queryPredict(layero);
});
}
});
},
/**
* 查询预测结果
*/
queryPredict: function (layero) {
var $btn = $('#btn-predict-query', layero);
$btn.prop('disabled', true);
$('#predict-result', layero).html(' 正在分析历史数据...
');
var version = $('input[name="predict-version"]:checked', layero).val();
var periods = parseInt($('#predict-periods', layero).val()) || 200;
var targetExpect = $('#predict-target', layero).val().trim();
var weights = {};
// 根据版本获取权重
if (version === 'v3') {
$('.predict-weight-v3', layero).each(function () {
var key = $(this).data('key');
var val = parseFloat($(this).val()) || 0;
weights[key] = val;
});
} else if (version === 'v2') {
$('.predict-weight-v2', layero).each(function () {
var key = $(this).data('key');
var val = parseFloat($(this).val()) || 0;
weights[key] = val;
});
} else {
$('.predict-weight', layero).each(function () {
var key = $(this).data('key');
var val = parseFloat($(this).val()) || 0;
weights[key] = val;
});
}
// 根据版本选择URL
var url = 'history/predict';
if (version === 'v3') {
url = 'history/predictV3';
} else if (version === 'v2') {
url = 'history/predictV2';
}
$.ajax({
url: url,
type: 'GET',
data: { periods: periods, weights: JSON.stringify(weights), target_expect: targetExpect },
dataType: 'json',
success: function (ret) {
if (ret.code == 1) {
Controller.api.renderPredict(ret.data, layero, version);
} else {
$('#predict-result', layero).html('' + (ret.msg || '预测失败') + '
');
}
},
error: function () {
$('#predict-result', layero).html('预测请求失败
');
},
complete: function () {
$btn.prop('disabled', false);
}
});
},
/**
* 渲染预测结果
*/
renderPredict: function (data, layero, version) {
var predictions = data.predictions || [];
var analysis = data.analysis || {};
var hitInfo = data.hit_info || null;
var actualResult = data.actual_result || null;
var backtest = data.backtest || null;
var confidence = data.confidence || null;
if (predictions.length === 0) {
$('#predict-result', layero).html('暂无预测结果
');
return;
}
// 上期特码信息
var lastSpecial = analysis.last_special || 0;
var lastExpect = analysis.last_expect || '';
var lastColor = Controller.api.getColorByNum(lastSpecial);
var lastAnimal = Controller.api.getAnimalByNum(lastSpecial);
// 版本名称映射
var versionNames = {
'v1': 'V1(转移概率)',
'v2': 'V2(统计回归)',
'v3': 'V3(多维度综合)'
};
var html = '';
// 基准期号标题
html += '
基于期号 ' + lastExpect + ' (特码 ' + lastSpecial + ')进行预测 | 算法版本: ' + versionNames[version] + '
';
// 置信度评估展示(V2和V3版本)
if (confidence && (version === 'v2' || version === 'v3')) {
html += '
';
html += '
预测置信度评估
';
// 数据警告提示(数据不足时显示)
if (confidence.data_warning) {
html += '
' + confidence.data_warning + '
';
}
html += '
';
html += '
' + confidence.overall_confidence + '%
整体置信度
';
// 各排名置信度(使用得分集中度维度)
if (confidence.confidence_scores && confidence.confidence_scores.length > 0) {
html += '
';
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');
html += '
';
html += '
' + cs.confidence + '%
';
html += '
#' + cs.rank + '
';
html += '
';
}
html += '
';
}
html += '
';
}
// 回测验证结果(V2和V3版本)
if (backtest && (version === 'v2' || version === 'v3')) {
html += '
';
html += '
历史回测验证(最近' + backtest.total_tests + '期)
';
// 回测数据警告提示
if (backtest.data_warning) {
html += '
' + backtest.data_warning + '
';
}
html += '
';
html += '
' + backtest.hit_rate + '%
命中率(Top5)
';
html += '
' + backtest.total_hits + '/' + backtest.total_tests + '
命中次数
';
html += '
' + (backtest.avg_rank || '—') + '
平均排名
';
// 新增指标:NDCG@5 和 MRR(百分比展示)
if (backtest.ndcg_5 !== undefined) {
html += '
' + (backtest.ndcg_5 * 100).toFixed(1) + '%
NDCG@5
';
}
if (backtest.mrr !== undefined) {
html += '
' + (backtest.mrr * 100).toFixed(1) + '%
MRR
';
}
// 转移概率阶数显示(来自analysis.transition_order字段)
if (analysis && analysis.transition_order !== undefined) {
html += '
' + analysis.transition_order + '阶
转移概率
';
}
html += '
';
// 命中分布柱状图(使用rank_1..rank_5键名)
if (backtest.hit_distribution && Object.keys(backtest.hit_distribution).length > 0) {
var distribution = backtest.hit_distribution;
var maxHit = 0;
// 找最大值用于计算柱状图高度比例
for (var r = 1; r <= 5; r++) {
var key = 'rank_' + r;
if (distribution[key] > maxHit) {
maxHit = distribution[key];
}
}
html += '
命中分布(各排名命中次数):
';
html += '
';
for (var r = 1; r <= 5; r++) {
var key = 'rank_' + r;
var hitCount = distribution[key] || 0;
var barHeight = maxHit > 0 ? (hitCount / maxHit * 45) : 0;
var barColor = hitCount > 0 ? '#4caf50' : '#e0e0e0';
html += '
';
html += '
';
html += '
#' + r + '
';
html += '
' + hitCount + '
';
html += '
';
}
html += '
';
}
// 回测详情
if (backtest.details && backtest.details.length > 0) {
html += '
最近' + backtest.details.length + '期验证详情:
';
html += '
';
for (var i = 0; i < backtest.details.length; i++) {
var bd = backtest.details[i];
var hitTag = bd.hit ? '
✓ ' : '
✗ ';
html += '
期号' + bd.expect + ': 实际' + bd.actual + ' ' + hitTag + ' 预测[' + bd.predictions.join(',') + ']
';
}
html += '
';
}
html += '
';
}
// V3版本特有的分析信息
if (version === 'v3' && analysis) {
html += '
';
html += '
V3多维度分析
';
// 单双统计
if (analysis.oddeven_stats) {
var oe = analysis.oddeven_stats;
html += '
单双规律: 单号' + oe.odd_pct + '% / 双号' + oe.even_pct + '%';
if (oe.recent_streak >= 2) {
html += ' | 近期连续' + (oe.recent_type === 'odd' ? '单号' : '双号') + oe.recent_streak + '期';
html += '(平均连续' + (oe.recent_type === 'odd' ? oe.avg_odd_streak : oe.avg_even_streak) + '期)';
}
html += '
';
}
// 大小统计
if (analysis.bigsmall_stats) {
var bs = analysis.bigsmall_stats;
html += '
大小规律: 大号' + bs.big_pct + '% / 小号' + bs.small_pct + '%';
if (bs.recent_streak >= 2) {
html += ' | 近期连续' + (bs.recent_type === 'big' ? '大号' : '小号') + bs.recent_streak + '期';
html += '(平均连续' + (bs.recent_type === 'big' ? bs.avg_big_streak : bs.avg_small_streak) + '期)';
}
html += '
';
}
// 走势方向
if (analysis.trend_direction) {
var td = analysis.trend_direction;
var trendNames = { 'ascending': '上升(号码减小)', 'descending': '下降(号码增大)', 'jump': '跳跃震荡' };
html += '
走势方向: ' + trendNames[td.trend_type];
html += ' | 强度' + (td.trend_strength * 100).toFixed(0) + '% | 平均变化' + td.avg_change + '
';
}
// 上期属性
html += '
上期属性: 区域[' + (analysis.last_zone || '') + '] 尾数[' + (analysis.last_tail || '') + '] 首号[' + (analysis.last_head || '') + ']
';
html += '
';
}
// 遗漏统计信息(V2和V3版本)
if (analysis.omit_stats && (version === 'v2' || version === 'v3')) {
html += '
';
html += '遗漏值统计: 平均遗漏 ' + (analysis.omit_stats.avg || 0).toFixed(1) + ' 期 | 最大遗漏 ' + (analysis.omit_stats.max || 0) + ' 期 | 期望频率 ' + analysis.expected_freq + '';
html += '
';
}
// 命中结果(验证模式下显示)
if (hitInfo && actualResult) {
var hitBgColor = hitInfo.hit ? '#d4edda' : '#f8d7da';
var hitBorderColor = hitInfo.hit ? '#28a745' : '#dc3545';
var hitTitleColor = hitInfo.hit ? '#155724' : '#721c24';
var actualColorHex = Controller.api.getColorByNum(hitInfo.actual_num);
html += '
';
html += '
';
if (hitInfo.hit) {
html += ' 预测命中!排名第 ' + hitInfo.rank + ' 位';
} else {
html += ' 未命中(实际号码不在预测Top' + predictions.length + '中)';
}
html += '
';
html += '
';
html += '
期号 ' + hitInfo.actual_expect + ' 实际开奖:
';
html += '
' + hitInfo.actual_num + ' ';
html += '
' + hitInfo.actual_animal + ' / ' + hitInfo.actual_color + '
';
html += '
';
}
// 预测号码列表
var topCount = predictions.length;
html += '
';
html += '
预测推荐号码(Top ' + topCount + ')
';
html += '
';
for (var i = 0; i < predictions.length; i++) {
var p = predictions[i];
var colorHex = Controller.api.getColorByNum(p.num);
var animal = Controller.api.getAnimalByNum(p.num);
// 验证模式下,命中号码高亮
var isHit = hitInfo && hitInfo.hit && p.num === hitInfo.actual_num;
var cardBg = isHit ? '#fffacd' : '#fff';
var cardBorder = isHit ? '2px solid #f39c12' : 'none';
var rankBadge = i < 3 ? '
' + (i + 1) + ' ' : '';
// 根据版本显示不同的详情信息
var detailInfo = '';
if (p.detail) {
if (version === 'v3') {
// V3版本显示更多维度信息
var omitInfo = p.detail.omit || 0;
var transScore = p.detail.trans_score || 0;
var oddevenScore = p.detail.oddeven_score || 0;
var bigsmallScore = p.detail.bigsmall_score || 0;
var trendScore = p.detail.trend_score || 0;
detailInfo = '
';
detailInfo += '遗漏:' + omitInfo + '期 | ';
detailInfo += '转移:' + transScore + ' | ';
detailInfo += (p.detail.is_odd ? '单' : '双') + ':' + oddevenScore + ' | ';
detailInfo += (p.detail.is_big ? '大' : '小') + ':' + bigsmallScore;
detailInfo += '
';
} else if (version === 'v2') {
var omitInfo = p.detail.omit || 0;
detailInfo = '
遗漏:' + omitInfo + '期
';
}
}
html += '
' + rankBadge;
html += '
' + p.num + ' ';
html += '
' + animal + '
';
html += '
得分:' + p.score + '
';
// 显示置信度(V3版本)
if (version === 'v3' && confidence && confidence.confidence_scores) {
var csForNum = confidence.confidence_scores.find(function(c) { return c.num === p.num; });
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 += '
置信度:' + confLevel + ' (' + csForNum.confidence + '%)
';
}
}
html += detailInfo;
html += '
';
}
html += '
';
html += '
';
$('#predict-result', layero).html(html);
}
}
};
return Controller;
});