feat(11-03): 前端展示置信度和扩展回测指标

- 新增置信度评估展示区域(V2和V3版本)
- 添加整体置信度和各排名置信度卡片展示
- 添加数据不足时的警告提示(confidence.data_warning)
- 扩展回测指标:NDCG@5、MRR、命中分布柱状图
- 添加回测数据警告提示(backtest.data_warning)
- 显示转移概率阶数(analysis.transition_order)
- 预测号码卡片中显示置信度等级和百分比(V3版本)
This commit is contained in:
2026-05-01 15:25:11 +08:00
parent 27915b0ecb
commit cb3ca055ee
+440
View File
@@ -102,6 +102,11 @@ define(['jquery', 'bootstrap', 'backend', 'table', 'form'], function ($, undefin
$(document).off('click', '.btn-numberfilter').on('click', '.btn-numberfilter', function () { $(document).off('click', '.btn-numberfilter').on('click', '.btn-numberfilter', function () {
Controller.api.showNumberFilterDialog(); Controller.api.showNumberFilterDialog();
}); });
// 预测号码按钮事件
$(document).off('click', '.btn-predict').on('click', '.btn-predict', function () {
Controller.api.showPredictDialog();
});
}, },
add: function () { add: function () {
Controller.api.bindevent(); Controller.api.bindevent();
@@ -1520,6 +1525,441 @@ define(['jquery', 'bootstrap', 'backend', 'table', 'form'], function ($, undefin
html += '</div>'; html += '</div>';
$('#dash-result', layero).html(html); $('#dash-result', layero).html(html);
},
/**
* 预测号码弹窗
*/
showPredictDialog: function () {
var html = '<div style="padding:20px;">' +
'<div style="margin-bottom:15px;background:#fff3cd;border:1px solid #ffc107;padding:10px;border-radius:6px;">' +
' <div style="font-size:13px;font-weight:bold;color:#856404;margin-bottom:8px;"><i class="fa fa-lightbulb-o"></i> 预测算法说明</div>' +
' <div style="font-size:12px;color:#666;">' +
' <b>V1版本</b>:基于转移概率分析(区域、生肖、尾号、首号、波色转移 + 冷热系数)<br>' +
' <b>V2版本</b>:基于统计回归分析(遗漏回归、频率回归、区域平衡、波色平衡等)+ 历史回测验证<br>' +
' <b>V3版本(推荐)</b>:多维度综合预测,新增转移概率(马尔可夫链)、单双规律、大小规律、走势方向分析' +
' </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="v2"> V2(统计回归)</label>' +
' <label class="radio-inline"><input type="radio" name="predict-version" value="v1"> V1(转移概率)</label>' +
'</div>' +
'<div class="form-group" style="border-bottom:1px solid #eee;padding-bottom:10px;margin-bottom:10px;">' +
' <label style="margin-right:10px;">验证期号:</label>' +
' <input type="text" id="predict-target" class="form-control" placeholder="输入期号验证历史预测(可选)" style="width:180px;display:inline-block;">' +
' <span style="font-size:11px;color:#999;margin-left:5px;">留空则预测下一期</span>' +
'</div>' +
'<div class="form-group" style="border-bottom:1px solid #eee;padding-bottom:10px;margin-bottom:10px;">' +
' <label style="margin-right:10px;">统计期数:</label>' +
' <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>' +
// 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>' +
' <div style="display:flex;flex-wrap:wrap;gap:10px;font-size:12px;">' +
' <div>遗漏回归: <input type="number" class="predict-weight-v3" data-key="omit_regression" value="0.20" min="0" max="1" step="0.05" style="width:60px;"></div>' +
' <div>频率回归: <input type="number" class="predict-weight-v3" data-key="freq_regression" value="0.15" min="0" max="1" step="0.05" style="width:60px;"></div>' +
' <div>转移概率: <input type="number" class="predict-weight-v3" data-key="transition_prob" value="0.20" min="0" max="1" step="0.05" style="width:60px;"></div>' +
' <div>单双平衡: <input type="number" class="predict-weight-v3" data-key="oddeven_balance" value="0.10" min="0" max="1" step="0.05" style="width:60px;"></div>' +
' <div>大小平衡: <input type="number" class="predict-weight-v3" data-key="bigsmall_balance" value="0.10" min="0" max="1" step="0.05" style="width:60px;"></div>' +
' <div>走势方向: <input type="number" class="predict-weight-v3" data-key="trend_direction" value="0.15" min="0" max="1" step="0.05" style="width:60px;"></div>' +
' <div>区域平衡: <input type="number" class="predict-weight-v3" data-key="zone_balance" value="0.05" min="0" max="1" step="0.05" style="width:60px;"></div>' +
' <div>波色平衡: <input type="number" class="predict-weight-v3" data-key="color_balance" value="0.05" min="0" max="1" step="0.05" style="width:60px;"></div>' +
' </div>' +
'</div>' +
// V2权重配置
'<div id="predict-v2-weights" style="display:none;border-bottom:1px solid #eee;padding-bottom:10px;margin-bottom:10px;">' +
' <label style="margin-right:10px;">V2权重配置:</label>' +
' <div style="display:flex;flex-wrap:wrap;gap:10px;font-size:12px;">' +
' <div>遗漏回归: <input type="number" class="predict-weight-v2" data-key="omit_regression" value="0.30" min="0" max="1" step="0.05" style="width:60px;"></div>' +
' <div>频率回归: <input type="number" class="predict-weight-v2" data-key="freq_regression" value="0.25" min="0" max="1" step="0.05" style="width:60px;"></div>' +
' <div>近期趋势: <input type="number" class="predict-weight-v2" data-key="recent_trend" value="0.20" min="0" max="1" step="0.05" style="width:60px;"></div>' +
' <div>区域平衡: <input type="number" class="predict-weight-v2" data-key="zone_balance" value="0.10" min="0" max="1" step="0.05" style="width:60px;"></div>' +
' <div>波色平衡: <input type="number" class="predict-weight-v2" data-key="color_balance" value="0.08" min="0" max="1" step="0.05" style="width:60px;"></div>' +
' <div>统计显著性: <input type="number" class="predict-weight-v2" data-key="stat_significance" value="0.07" min="0" max="1" step="0.05" style="width:60px;"></div>' +
' </div>' +
'</div>' +
// V1权重配置
'<div id="predict-v1-weights" style="display:none;border-bottom:1px solid #eee;padding-bottom:10px;margin-bottom:10px;">' +
' <label style="margin-right:10px;">V1权重配置:</label>' +
' <div style="display:flex;flex-wrap:wrap;gap:10px;font-size:12px;">' +
' <div>区域: <input type="number" class="predict-weight" data-key="zone" value="0.25" min="0" max="1" step="0.05" style="width:60px;"></div>' +
' <div>生肖: <input type="number" class="predict-weight" data-key="zodiac" value="0.20" min="0" max="1" step="0.05" style="width:60px;"></div>' +
' <div>尾号: <input type="number" class="predict-weight" data-key="tail" value="0.20" min="0" max="1" step="0.05" style="width:60px;"></div>' +
' <div>首号: <input type="number" class="predict-weight" data-key="head" value="0.15" min="0" max="1" step="0.05" style="width:60px;"></div>' +
' <div>波色: <input type="number" class="predict-weight" data-key="color" value="0.10" min="0" max="1" step="0.05" style="width:60px;"></div>' +
' <div>冷热: <input type="number" class="predict-weight" data-key="hotcold" value="0.10" min="0" max="1" step="0.05" style="width:60px;"></div>' +
' </div>' +
'</div>' +
'<div style="text-align:center;margin-bottom:15px;">' +
' <button class="btn btn-primary" id="btn-predict-query"><i class="fa fa-magic"></i> 开始预测</button>' +
'</div>' +
'<div id="predict-result" style="margin-top:15px;"></div>' +
'</div>';
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('<div class="text-center"><i class="fa fa-spinner fa-spin"></i> 正在分析历史数据...</div>');
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('<div class="alert alert-danger">' + (ret.msg || '预测失败') + '</div>');
}
},
error: function () {
$('#predict-result', layero).html('<div class="alert alert-danger">预测请求失败</div>');
},
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('<div class="alert alert-info">暂无预测结果</div>');
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 = '<div style="padding:10px;">';
// 基准期号标题
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')) {
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>';
// 数据警告提示(数据不足时显示)
if (confidence.data_warning) {
html += '<div style="font-size:11px;color:#d32f2f;background:#ffebee;padding:6px;border-radius:4px;margin-bottom:8px;"><i class="fa fa-exclamation-triangle"></i> ' + confidence.data_warning + '</div>';
}
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>';
// 各排名置信度(使用得分集中度维度)
if (confidence.confidence_scores && confidence.confidence_scores.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');
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>';
}
html += '</div>';
}
html += '</div></div>';
}
// 回测验证结果(V2和V3版本)
if (backtest && (version === 'v2' || version === 'v3')) {
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>';
// 回测数据警告提示
if (backtest.data_warning) {
html += '<div style="font-size:11px;color:#d32f2f;background:#ffebee;padding:6px;border-radius:4px;margin-bottom:8px;"><i class="fa fa-exclamation-triangle"></i> ' + backtest.data_warning + '</div>';
}
html += '<div style="display:flex;gap:15px;flex-wrap:wrap;">';
html += '<div style="text-align:center;padding:8px;"><div style="font-size:22px;font-weight:bold;color:#2196f3;">' + backtest.hit_rate + '%</div><div style="font-size:11px;color:#666;">命中率(Top5</div></div>';
html += '<div style="text-align:center;padding:8px;"><div style="font-size:22px;font-weight:bold;color:#4caf50;">' + backtest.total_hits + '/' + backtest.total_tests + '</div><div style="font-size:11px;color:#666;">命中次数</div></div>';
html += '<div style="text-align:center;padding:8px;"><div style="font-size:22px;font-weight:bold;color:#ff9800;">' + (backtest.avg_rank || '—') + '</div><div style="font-size:11px;color:#666;">平均排名</div></div>';
// 新增指标:NDCG@5 和 MRR(百分比展示)
if (backtest.ndcg_5 !== undefined) {
html += '<div style="text-align:center;padding:8px;"><div style="font-size:22px;font-weight:bold;color:#9c27b0;">' + (backtest.ndcg_5 * 100).toFixed(1) + '%</div><div style="font-size:11px;color:#666;">NDCG@5</div></div>';
}
if (backtest.mrr !== undefined) {
html += '<div style="text-align:center;padding:8px;"><div style="font-size:22px;font-weight:bold;color:#00bcd4;">' + (backtest.mrr * 100).toFixed(1) + '%</div><div style="font-size:11px;color:#666;">MRR</div></div>';
}
// 转移概率阶数显示(来自analysis.transition_order字段)
if (analysis && analysis.transition_order !== undefined) {
html += '<div style="text-align:center;padding:8px;"><div style="font-size:22px;font-weight:bold;color:#607d8b;">' + analysis.transition_order + '阶</div><div style="font-size:11px;color:#666;">转移概率</div></div>';
}
html += '</div>';
// 命中分布柱状图(使用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 += '<div style="margin-top:10px;font-size:11px;color:#666;">命中分布(各排名命中次数):</div>';
html += '<div style="display:flex;gap:8px;align-items:flex-end;height:60px;margin-top:5px;padding:5px;background:#f5f5f5;border-radius:4px;">';
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 += '<div style="text-align:center;min-width:50px;">';
html += '<div style="height:' + barHeight + 'px;background:' + barColor + ';border-radius:2px 2px 0 0;width:35px;margin:0 auto;"></div>';
html += '<div style="font-size:10px;color:#666;margin-top:2px;">#' + r + '</div>';
html += '<div style="font-size:11px;color:#333;font-weight:bold;">' + hitCount + '</div>';
html += '</div>';
}
html += '</div>';
}
// 回测详情
if (backtest.details && backtest.details.length > 0) {
html += '<div style="margin-top:10px;font-size:11px;color:#666;">最近' + backtest.details.length + '期验证详情:</div>';
html += '<div style="margin-top:5px;max-height:300px;overflow-y:auto;">';
for (var i = 0; i < backtest.details.length; i++) {
var bd = backtest.details[i];
var hitTag = bd.hit ? '<span style="color:#4caf50;">✓</span>' : '<span style="color:#f44336;">✗</span>';
html += '<div style="font-size:11px;padding:3px 0;border-bottom:1px dashed #eee;">期号' + bd.expect + ': 实际<b>' + bd.actual + '</b> ' + hitTag + ' 预测[' + bd.predictions.join(',') + ']</div>';
}
html += '</div>';
}
html += '</div>';
}
// V3版本特有的分析信息
if (version === 'v3' && analysis) {
html += '<div style="background:#f3e5f5;border:1px solid #9c27b0;border-radius:6px;padding:10px;margin-bottom:15px;font-size:12px;">';
html += '<div style="font-weight:bold;color:#7b1fa2;margin-bottom:8px;"><i class="fa fa-chart-bar"></i> V3多维度分析</div>';
// 单双统计
if (analysis.oddeven_stats) {
var oe = analysis.oddeven_stats;
html += '<div style="margin-bottom:5px;"><b>单双规律:</b> 单号' + 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 += '</div>';
}
// 大小统计
if (analysis.bigsmall_stats) {
var bs = analysis.bigsmall_stats;
html += '<div style="margin-bottom:5px;"><b>大小规律:</b> 大号' + 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 += '</div>';
}
// 走势方向
if (analysis.trend_direction) {
var td = analysis.trend_direction;
var trendNames = { 'ascending': '上升(号码减小)', 'descending': '下降(号码增大)', 'jump': '跳跃震荡' };
html += '<div style="margin-bottom:5px;"><b>走势方向:</b> ' + trendNames[td.trend_type];
html += ' | 强度' + (td.trend_strength * 100).toFixed(0) + '% | 平均变化' + td.avg_change + '</div>';
}
// 上期属性
html += '<div><b>上期属性:</b> 区域[' + (analysis.last_zone || '') + '] 尾数[' + (analysis.last_tail || '') + '] 首号[' + (analysis.last_head || '') + ']</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;">';
html += '<b>遗漏值统计:</b> 平均遗漏 ' + (analysis.omit_stats.avg || 0).toFixed(1) + ' 期 | 最大遗漏 ' + (analysis.omit_stats.max || 0) + ' 期 | 期望频率 ' + analysis.expected_freq + '';
html += '</div>';
}
// 命中结果(验证模式下显示)
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 += '<div style="background:' + hitBgColor + ';border:2px solid ' + hitBorderColor + ';border-radius:6px;padding:12px;margin-bottom:15px;">';
html += '<div style="font-size:14px;font-weight:bold;color:' + hitTitleColor + ';margin-bottom:8px;">';
if (hitInfo.hit) {
html += '<i class="fa fa-check-circle"></i> 预测命中!排名第 ' + hitInfo.rank + ' 位';
} else {
html += '<i class="fa fa-times-circle"></i> 未命中(实际号码不在预测Top' + predictions.length + '中)';
}
html += '</div>';
html += '<div style="display:flex;align-items:center;gap:15px;">';
html += '<div style="font-size:12px;">期号 <b>' + hitInfo.actual_expect + '</b> 实际开奖:</div>';
html += '<span style="display:inline-block;width:40px;height:40px;line-height:40px;text-align:center;border-radius:50%;color:#fff;background-color:' + actualColorHex + ';font-weight:bold;font-size:18px;">' + hitInfo.actual_num + '</span>';
html += '<div style="font-size:12px;">' + hitInfo.actual_animal + ' / ' + hitInfo.actual_color + '</div>';
html += '</div></div>';
}
// 预测号码列表
var topCount = predictions.length;
html += '<div style="background:#e8f5e9;border:1px solid #4caf50;border-radius:6px;padding:12px;margin-bottom:15px;">';
html += '<div style="font-size:13px;font-weight:bold;color:#2e7d32;margin-bottom:10px;"><i class="fa fa-bullseye"></i> 预测推荐号码(Top ' + topCount + '</div>';
html += '<div style="display:flex;flex-wrap:wrap;gap:10px;">';
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 ? '<span style="position:absolute;top:-5px;right:-5px;background:#f39c12;color:#fff;font-size:10px;padding:2px 4px;border-radius:50%;">' + (i + 1) + '</span>' : '';
// 根据版本显示不同的详情信息
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 = '<div style="font-size:9px;color:#999;line-height:1.3;">';
detailInfo += '遗漏:' + omitInfo + '期 | ';
detailInfo += '转移:' + transScore + ' | ';
detailInfo += (p.detail.is_odd ? '单' : '双') + ':' + oddevenScore + ' | ';
detailInfo += (p.detail.is_big ? '大' : '小') + ':' + bigsmallScore;
detailInfo += '</div>';
} else if (version === 'v2') {
var omitInfo = p.detail.omit || 0;
detailInfo = '<div style="font-size:9px;color:#999;">遗漏:' + omitInfo + '期</div>';
}
}
html += '<div style="text-align:center;background:' + cardBg + ';border:' + cardBorder + ';padding:8px;border-radius:8px;min-width:80px;position:relative;box-shadow:0 1px 3px rgba(0,0,0,0.1);">' + rankBadge;
html += '<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;font-size:16px;">' + p.num + '</span>';
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; });
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>';
}
}
html += detailInfo;
html += '</div>';
}
html += '</div></div>';
html += '</div>';
$('#predict-result', layero).html(html);
} }
} }
}; };