define(['jquery'], function ($) { var Controller = { index: function () { var getColor = function (color) { if (!color || color === '—') return '#95a5a6'; if (color.indexOf('红') !== -1) return '#e74c3c'; if (color.indexOf('蓝') !== -1) return '#3498db'; if (color.indexOf('绿') !== -1) return '#2ecc71'; return '#95a5a6'; }; var ball = function (num, color) { return '' + num + ''; }; function loadData() { var periods = parseInt($('#dash-periods').val()) || 30; if (periods < 10) periods = 10; if (periods > 100) periods = 100; $('#dash-content').html('

' + __('Loading') + '
'); $.ajax({ url: 'history/dashboard', type: 'GET', data: {periods: periods}, dataType: 'json', success: function (ret) { if (ret.code != 1) { $('#dash-content').html('
' + (ret.msg || '加载失败') + '
'); return; } render(ret.data); }, error: function () { $('#dash-content').html('
请求失败,请重试
'); } }); } function render(data) { var hc = data.hotcold, cw = data.colorwave, zo = data.zodiac; var oe = data.oddeven, bs = data.bigsmall, sp = data.special, tn = data.tailnumbers; var zt = data.zonetransition; var html = ''; // 热号:按次数降序取前5名 var hotAll = hc.all.slice().sort(function (a, b) { return b.count - a.count; }); var hotTop5 = hotAll.slice(0, 5); // 冷号:按次数升序取前5名,第5名有并列则全部包含 var coldAll = hc.all.slice().sort(function (a, b) { return a.count - b.count; }); var coldList = coldAll.slice(0, 5); if (coldList.length >= 5) { var threshold = coldList[4].count; var rest = coldAll.slice(5); for (var k = 0; k < rest.length; k++) { if (rest[k].count === threshold) coldList.push(rest[k]); else break; } } html += '

🔥❄️ 冷热号码

'; html += '
热号 Top 5
'; html += '
'; for (var i = 0; i < hotTop5.length; i++) { html += '' + ball(hotTop5[i].num, hotTop5[i].color) + '
' + hotTop5[i].count + '次
'; } html += '
'; html += '
冷号
'; html += '
'; for (var i = 0; i < coldList.length; i++) { html += '' + ball(coldList[i].num, coldList[i].color) + '
' + coldList[i].count + '次
'; } html += '
'; html += '

📊 比例分析

'; html += '
'; html += '
'; html += '
'; html += '
'; html += '

⭐ 生肖排名

'; html += '

📈 特码走势

'; html += '

🔢 尾数频率

'; // 区域转移概率 + 波色转移概率 if (zt && zt.matrix && zt.matrix.length > 0) { var cwt = data.colorwavetransition; html += '

🔄 转移概率

'; // 左侧:区域转移 html += '
区域转移(共 ' + zt.total_transitions + ' 次)
'; html += ''; for (var z = 0; z < zt.zones.length; z++) { html += ''; } html += ''; for (var r = 0; r < 5; r++) { html += ''; for (var c = 0; c < 5; c++) { var pct = zt.probabilities[r][c]; var cnt = zt.matrix[r][c]; var bg = pct > 30 ? '#e74c3c' : pct > 20 ? '#f39c12' : pct > 10 ? '#3498db' : pct > 0 ? '#95a5a6' : '#f5f5f5'; var txt = pct > 10 ? '#fff' : '#333'; html += ''; } html += ''; } html += '
区域特码
' + zt.zones[z] + '
' + zt.zones[r] + '' + cnt + '次
' + pct + '%
'; // 右侧:波色转移 if (cwt && cwt.matrix && cwt.matrix.length > 0) { html += '
波色转移(共 ' + cwt.total_transitions + ' 次)
'; html += ''; for (var z = 0; z < cwt.colors.length; z++) { html += ''; } html += ''; var cwColors = ['#e74c3c', '#3498db', '#2ecc71']; for (var r = 0; r < 3; r++) { html += ''; for (var c = 0; c < 3; c++) { var pct = cwt.probabilities[r][c]; var cnt = cwt.matrix[r][c]; var bg = pct > 40 ? cwColors[r] : pct > 20 ? cwColors[c] : pct > 0 ? '#95a5a6' : '#f5f5f5'; var txt = pct > 20 ? '#fff' : '#333'; html += ''; } html += ''; } html += '
区域特码
' + cwt.colors[z] + '
' + cwt.colors[r] + '' + cnt + '次
' + pct + '%
'; } html += '
'; // 下方:区域→区域转移矩阵,单元格内显示波色概率 var ztc = data.zonetocolortransition; if (ztc && ztc.matrix && ztc.matrix.length > 0) { html += '
区域→区域转移矩阵(单元格内为波色概率)
'; html += ''; for (var z = 0; z < ztc.zones.length; z++) { html += ''; } html += ''; for (var r = 0; r < 5; r++) { html += ''; for (var c = 0; c < 5; c++) { var cnt = ztc.matrix[r][c]; var cp = ztc.color_probs[r][c]; var bg = cnt > 0 ? '#fafafa' : '#fff'; var txt = (cp.red > 40 || cp.blue > 40 || cp.green > 40) ? '#fff' : '#333'; html += ''; } html += ''; } html += '
区域特码
' + ztc.zones[z] + '
' + ztc.zones[r] + '红' + cp.red + '%
蓝' + cp.blue + '%
绿' + cp.green + '%
(' + cnt + '次)
'; } html += '
'; } // 热力图部分 var hm = data.heatmap; html += '

🎨 特码热力图

X轴:期号(从左往右,从远到近) | Y轴:号码1-49 | 颜色:号码波色
'; $('#dash-content').html(html); // 波色饼图 if (typeof echarts !== 'undefined') { var cwDom = document.getElementById('colorwave-chart'); if (cwDom) { var cwChart = echarts.init(cwDom); cwChart.setOption({ tooltip: {trigger: 'item', formatter: '{b}: {c} ({d}%)'}, series: [{ type: 'pie', radius: '60%', data: [ {value: cw.red, name: '红波', itemStyle: {color: '#e74c3c'}}, {value: cw.blue, name: '蓝波', itemStyle: {color: '#3498db'}}, {value: cw.green, name: '绿波', itemStyle: {color: '#2ecc71'}} ], label: {show: true, formatter: '{b}\n{d}%'}, emphasis: {itemStyle: {shadowBlur: 10, shadowOffsetX: 0, shadowColor: 'rgba(0,0,0,0.5)'}} }], grid: {top: 0, bottom: 0} }); $(window).on('resize', function(){ cwChart.resize(); }); } // 奇偶饼图 var oeDom = document.getElementById('oddeven-chart'); if (oeDom) { var oeChart = echarts.init(oeDom); oeChart.setOption({ tooltip: {trigger: 'item', formatter: '{b}: {c} ({d}%)'}, series: [{ type: 'pie', radius: '60%', data: [ {value: oe.odd, name: '奇数', itemStyle: {color: '#e74c3c'}}, {value: oe.even, name: '偶数', itemStyle: {color: '#3498db'}} ], label: {show: true, formatter: '{b}\n{d}%'}, emphasis: {itemStyle: {shadowBlur: 10, shadowOffsetX: 0, shadowColor: 'rgba(0,0,0,0.5)'}} }], grid: {top: 0, bottom: 0} }); $(window).on('resize', function(){ oeChart.resize(); }); } // 大小饼图 var bsDom = document.getElementById('bigsmall-chart'); if (bsDom) { var bsChart = echarts.init(bsDom); bsChart.setOption({ tooltip: {trigger: 'item', formatter: '{b}: {c} ({d}%)'}, series: [{ type: 'pie', radius: '60%', data: [ {value: bs.big, name: '大数', itemStyle: {color: '#f39c12'}}, {value: bs.small, name: '小数', itemStyle: {color: '#2ecc71'}} ], label: {show: true, formatter: '{b}\n{d}%'}, emphasis: {itemStyle: {shadowBlur: 10, shadowOffsetX: 0, shadowColor: 'rgba(0,0,0,0.5)'}} }], grid: {top: 0, bottom: 0} }); $(window).on('resize', function(){ bsChart.resize(); }); } } // 生肖柱状图 if (typeof echarts !== 'undefined' && zo.list && zo.list.length > 0) { var zDom = document.getElementById('zodiac-chart'); if (zDom) { var zChart = echarts.init(zDom); zChart.setOption({ tooltip: {trigger: 'axis', axisPointer: {type: 'shadow'}}, grid: {left: 50, right: 20, bottom: 30, top: 10}, xAxis: {type: 'category', data: zo.list.map(function(z){return z.animal;})}, yAxis: {type: 'value', splitNumber: 3}, series: [{type: 'bar', data: zo.list.map(function(z){return z.count;}), itemStyle: {color: '#626c91'}, label: {show: true, position: 'top', fontSize: 12, color: '#333'}}] }); $(window).on('resize', function(){ zChart.resize(); }); } } // 特码走势 if (typeof echarts !== 'undefined' && sp.expects && sp.expects.length > 0) { var chartDom = document.getElementById('special-chart'); if (chartDom) { var chart = echarts.init(chartDom); var colorMap = {'红': '#e74c3c', '蓝': '#3498db', '绿': '#2ecc71'}; var itemColors = sp.colors.map(function(c) { if (c.indexOf('红') !== -1) return colorMap['红']; if (c.indexOf('蓝') !== -1) return colorMap['蓝']; if (c.indexOf('绿') !== -1) return colorMap['绿']; return '#95a5a6'; }); chart.setOption({ tooltip: {trigger: 'axis', formatter: function(p) { return '期号: ' + p[0].axisValue + '
特码: ' + p[0].data + ''; }}, xAxis: {type: 'category', data: sp.expects, axisLabel: {rotate: 45, fontSize: 10}}, yAxis: {type: 'value', min: 0, max: 50}, series: [{type: 'line', data: sp.specials, smooth: true, symbolSize: 8, itemStyle: {color: function(p) { return itemColors[p.dataIndex]; }}, areaStyle: {color: 'rgba(52,152,219,0.05)'}}], grid: {left: 50, right: 20, bottom: 50, top: 20} }); $(window).on('resize', function () { chart.resize(); }); } } // 尾数柱状图 if (typeof echarts !== 'undefined' && tn.all && tn.all.length > 0) { var tDom = document.getElementById('tail-chart'); if (tDom) { var tChart = echarts.init(tDom); var sorted = tn.all.slice().sort(function(a,b){return a.tail - b.tail;}); tChart.setOption({ tooltip: {trigger: 'axis', axisPointer: {type: 'shadow'}}, grid: {left: 50, right: 20, bottom: 30, top: 10}, xAxis: {type: 'category', data: sorted.map(function(t){return t.tail;})}, yAxis: {type: 'value', splitNumber: 3}, series: [{type: 'bar', data: sorted.map(function(t){return t.count;}), itemStyle: {color: '#23b7e5'}, label: {show: true, position: 'top', fontSize: 12, color: '#333'}}] }); $(window).on('resize', function(){ tChart.resize(); }); } } // 特码热力图 if (typeof echarts !== 'undefined' && hm && hm.expects && hm.expects.length > 0) { var hmDom = document.getElementById('heatmap-chart'); if (hmDom) { var hmChart = echarts.init(hmDom); // 构建完整的热力图数据矩阵(每期每号码) var hmData = []; for (var x = 0; x < hm.expects.length; x++) { for (var y = 0; y < 49; y++) { // 检查该期是否有该号码作为特码 var found = false; for (var i = 0; i < hm.heatmap.length; i++) { if (hm.heatmap[i][0] === x && hm.heatmap[i][1] === y) { found = true; break; } } hmData.push([x, y, found ? 1 : 0]); } } hmChart.setOption({ tooltip: { position: 'top', formatter: function(p) { var periodIdx = p.data[0]; var num = p.data[1] + 1; var val = p.data[2]; return '期号: ' + hm.expects[periodIdx] + '
号码: ' + num + '
状态: ' + (val === 1 ? '已开出' : '未开出'); } }, grid: {left: 80, right: 30, bottom: 60, top: 30}, xAxis: { type: 'category', data: hm.expects, axisLabel: {rotate: 45, fontSize: 10, interval: 0}, splitArea: {show: true} }, yAxis: { type: 'category', data: hm.nums, axisLabel: {fontSize: 10}, splitArea: {show: true} }, visualMap: { min: 0, max: 1, show: false, inRange: { color: ['#f0f0f0', '#e74c3c'] } }, series: [{ type: 'heatmap', data: hmData, label: {show: false}, itemStyle: { color: function(p) { // 未开出显示浅灰,开出显示该号码的波色 if (p.data[2] === 0) return '#f5f5f5'; var numIdx = p.data[1]; return hm.colors[numIdx] || '#95a5a6'; } }, emphasis: { itemStyle: {shadowBlur: 10, shadowColor: 'rgba(0,0,0,0.5)'} } }] }); $(window).on('resize', function(){ hmChart.resize(); }); } } } $('#btn-dash-refresh').on('click', loadData); loadData(); } }; return Controller; });