// ==UserScript== // @name 综合彩票助手 // @namespace http://tampermonkey.net/ // @version 1.0.0 // @description 涵盖福彩、体彩、竞彩的综合彩票助手,支持开奖查询、投注计算、走势分析、缩水过滤等功能 // @author 彩票助手 // @match *://*/* // @grant GM_xmlhttpRequest // @grant GM_setValue // @grant GM_getValue // @grant GM_addStyle // @grant GM_registerMenuCommand // @connect * // @require https://cdn.jsdelivr.net/npm/vue@3/dist/vue.global.prod.js // @license MIT // ==/UserScript== (function() { 'use strict'; // ==================== 配置 ==================== const CONFIG = { colors: { primary: '#e74c3c', secondary: '#3498db', success: '#27ae60', warning: '#f39c12', info: '#9b59b6', background: '#1a1a2e', cardBg: '#16213e', text: '#eee' }, storageKey: 'lotteryHelperData' }; // ==================== 彩票类型定义 ==================== const LOTTERY_TYPES = { // 福利彩票 welfare: [ { id: 'ssq', name: '双色球', redCount: 33, redPick: 6, blueCount: 16, bluePick: 1 }, { id: 'fc3d', name: '福彩3D', type: 'digital', digits: 3, maxNum: 10 }, { id: 'qlc', name: '七乐彩', ballCount: 30, pickCount: 7 }, { id: 'ks', name: '快3', type: 'k3', maxNum: 6, diceCount: 3 } ], // 体育彩票 sports: [ { id: 'dlt', name: '大乐透', frontCount: 35, frontPick: 5, backCount: 12, backPick: 2 }, { id: 'qxc', name: '七星彩', ballCount: 10, pickCount: 7, special: true }, { id: 'pl3', name: '排列三', type: 'digital', digits: 3, maxNum: 10 }, { id: 'pl5', name: '排列五', digits: 5, maxNum: 10 }, { id: 'x115', name: '11选5', maxNum: 11, pickCount: 5 } ], // 竞彩 lottery: [ { id: 'jczq', name: '竞彩足球', category: 'sport' }, { id: 'jclq', name: '竞彩篮球', category: 'sport' } ] }; // ==================== 工具函数 ==================== const Utils = { // 生成随机数 randomInt(min, max) { return Math.floor(Math.random() * (max - min + 1)) + min; }, // 生成随机号码 generateRandomNumbers(max, count, exclude = []) { const numbers = []; while (numbers.length < count) { const num = this.randomInt(1, max); if (!numbers.includes(num) && !exclude.includes(num)) { numbers.push(num); } } return numbers.sort((a, b) => a - b); }, // 计算注数 calculateBets(total, pick) { return this.combination(total, pick); }, // 计算组合数 combination(n, r) { if (r > n) return 0; if (r === 0 || r === n) return 1; let result = 1; for (let i = 0; i < r; i++) { result = result * (n - i) / (i + 1); } return Math.round(result); }, // 金额格式化 formatMoney(num) { return num.toLocaleString('zh-CN'); }, // 获取颜色 getColor(index, type = 'red') { if (type === 'red') { const colors = ['#ff6b6b', '#ee5a5a', '#ff4757', '#c0392b', '#e74c3c']; return colors[index % colors.length]; } else if (type === 'blue') { const colors = ['#5dade2', '#3498db', '#2980b9', '#1f618d', '#2471a3']; return colors[index % colors.length]; } return '#fff'; }, // 格式化日期 formatDate(date) { const d = new Date(date); return `${d.getFullYear()}-${String(d.getMonth() + 1).padStart(2, '0')}-${String(d.getDate()).padStart(2, '0')}`; } }; // ==================== 历史数据管理 ==================== class LotteryData { constructor() { this.data = this.load(); } load() { const stored = GM_getValue(CONFIG.storageKey, null); return stored || this.getDefaultData(); } save() { GM_setValue(CONFIG.storageKey, this.data); } getDefaultData() { return { ssq: this.generateHistoricalData('ssq', 100), dlt: this.generateHistoricalData('dlt', 100), fc3d: this.generateHistoricalData('fc3d', 100), jczq: [], jclq: [], favorites: [], notes: [] }; } generateHistoricalData(type, count) { const history = []; const now = new Date(); if (type === 'ssq') { for (let i = 0; i < count; i++) { const date = new Date(now - i * 3 * 24 * 60 * 60 * 1000); history.push({ issue: `20${24 - Math.floor(i / 100)}-${String(1000 + count - i).slice(1)}`, date: Utils.formatDate(date), red: Utils.generateRandomNumbers(33, 6), blue: [Utils.randomInt(1, 16)] }); } } else if (type === 'dlt') { for (let i = 0; i < count; i++) { const date = new Date(now - i * 3 * 24 * 60 * 60 * 1000); history.push({ issue: `24${String(1000 + count - i).slice(1)}`, date: Utils.formatDate(date), front: Utils.generateRandomNumbers(35, 5), back: Utils.generateRandomNumbers(12, 2) }); } } else if (type === 'fc3d') { for (let i = 0; i < count; i++) { const date = new Date(now - i * 24 * 60 * 60 * 1000); history.push({ issue: `20${24 - Math.floor(i / 100)}${String(1000 + count - i).slice(1)}`, date: Utils.formatDate(date), numbers: [Utils.randomInt(0, 9), Utils.randomInt(0, 9), Utils.randomInt(0, 9)], sum: Utils.randomInt(0, 27) }); } } return history; } addToFavorites(lotteryType, numbers, note = '') { this.data.favorites.push({ id: Date.now(), type: lotteryType, numbers: numbers, note: note, createdAt: new Date().toISOString() }); this.save(); } removeFavorite(id) { this.data.favorites = this.data.favorites.filter(f => f.id !== id); this.save(); } addNote(text) { this.data.notes.push({ id: Date.now(), text: text, createdAt: new Date().toISOString() }); this.save(); } } // ==================== 缩水过滤器 ==================== class NumberFilter { static filter(numbers, options) { let result = numbers; // 奇偶比例过滤 if (options.oddEvenRatio) { result = result.filter(nums => { const oddCount = nums.filter(n => n % 2 === 1).length; const evenCount = nums.length - oddCount; return oddCount >= options.oddEvenMin && oddCount <= options.oddEvenMax; }); } // 和值过滤 if (options.sumRange) { result = result.filter(nums => { const sum = nums.reduce((a, b) => a + b, 0); return sum >= options.sumMin && sum <= options.sumMax; }); } // 连号过滤 if (options.noConsecutive) { result = result.filter(nums => { for (let i = 0; i < nums.length - 1; i++) { if (nums[i + 1] - nums[i] === 1) return false; } return true; }); } // 跨度过滤 if (options.spanRange) { result = result.filter(nums => { const span = Math.max(...nums) - Math.min(...nums); return span >= options.spanMin && span <= options.spanMax; }); } // AC值过滤 if (options.acValue) { result = result.filter(nums => { const ac = this.calculateAC(nums); return ac >= options.acMin && ac <= options.acMax; }); } return result; } static calculateAC(numbers) { const sorted = [...numbers].sort((a, b) => a - b); const diffs = []; for (let i = 0; i < sorted.length - 1; i++) { for (let j = i + 1; j < sorted.length; j++) { diffs.push(sorted[j] - sorted[i]); } } return new Set(diffs).size - (numbers.length - 1); } static generateCombinations(redMax, redCount, blueMax = 16) { const combinations = []; const redBalls = []; const generateRed = (start, count) => { if (count === 0) { const blue = Utils.generateRandomNumbers(blueMax, 1); combinations.push({ red: [...redBalls].sort((a, b) => a - b), blue: blue }); return; } for (let i = start; i <= redMax - count + 1; i++) { redBalls.push(i); generateRed(i + 1, count - 1); redBalls.pop(); } }; generateRed(1, redCount); return combinations; } } // ==================== 奖金计算器 ==================== class PrizeCalculator { static calculateSSQ(red, blue, winRed, winBlue) { let prize = 0; let level = '未中奖'; const matchRed = red.filter(n => winRed.includes(n)).length; const matchBlue = blue[0] === winBlue[0]; if (matchBlue && matchRed === 6) { prize = 10000000; level = '一等奖'; } else if (matchRed === 6) { prize = 500000; level = '二等奖'; } else if (matchBlue && matchRed === 5) { prize = 3000; level = '三等奖'; } else if (matchRed === 5 || (matchBlue && matchRed === 4)) { prize = 200; level = '四等奖'; } else if (matchRed === 4 || (matchBlue && matchRed === 3)) { prize = 10; level = '五等奖'; } else if (matchBlue || matchRed === 3) { prize = 5; level = '六等奖'; } return { prize, level, matchRed, matchBlue }; } static calculateDLT(front, back, winFront, winBack) { let prize = 0; let level = '未中奖'; const matchFront = front.filter(n => winFront.includes(n)).length; const matchBack = back.filter(n => winBack.includes(n)).length; if (matchFront === 5 && matchBack === 2) { prize = 10000000; level = '一等奖'; } else if (matchFront === 5 && matchBack === 1) { prize = 10000000; level = '一等奖(追加)'; } else if (matchFront === 5 || (matchFront === 4 && matchBack === 2)) { prize = matchBack === 2 ? 500000 : 200; level = matchBack === 2 ? '二等奖' : '四等奖'; } else if (matchFront === 4 || (matchFront === 3 && matchBack === 2)) { prize = matchBack === 2 ? 300 : 100; level = matchBack === 2 ? '四等奖' : '六等奖'; } else if (matchFront === 3 || (matchFront === 2 && matchBack === 2)) { prize = matchBack === 2 ? 200 : 15; level = matchBack === 2 ? '五等奖' : '九等奖'; } else if (matchFront === 2 || (matchFront === 1 && matchBack === 2)) { prize = matchBack === 2 ? 200 : 5; level = matchBack === 2 ? '六等奖' : '九等奖'; } else if (matchBack === 2) { prize = 15; level = '八等奖'; } else if (matchBack === 1) { prize = 5; level = '九等奖'; } return { prize, level, matchFront, matchBack }; } } // ==================== 走势分析 ==================== class TrendAnalyzer { static analyzeMissing(history, maxNum) { const missing = new Array(maxNum + 1).fill(0); const lastAppear = new Array(maxNum + 1).fill(-1); history.forEach((item, index) => { let numbers = []; if (item.red) numbers = item.red; else if (item.front) numbers = [...item.front, ...item.back]; else if (item.numbers) numbers = item.numbers; numbers.forEach(n => { missing[n] = 0; if (lastAppear[n] === -1) lastAppear[n] = index; }); for (let i = 1; i <= maxNum; i++) { if (!numbers.includes(i)) { missing[i]++; } } }); return { missing, lastAppear }; } static analyzeHotCold(history, maxNum, recentCount = 30) { const recent = history.slice(0, recentCount); const frequency = new Array(maxNum + 1).fill(0); recent.forEach(item => { let numbers = []; if (item.red) numbers = item.red; else if (item.front) numbers = [...item.front, ...item.back]; else if (item.numbers) numbers = item.numbers; numbers.forEach(n => { if (n <= maxNum) frequency[n]++; }); }); const sorted = frequency.map((f, i) => ({ num: i, freq: f })) .sort((a, b) => b.freq - a.freq); return { hot: sorted.slice(0, 10), cold: sorted.slice(-10).reverse(), frequency }; } static analyzeSum(history) { const sums = {}; history.forEach(item => { let numbers = []; if (item.red) numbers = [...item.red, ...item.blue]; else if (item.front) numbers = [...item.front, ...item.back]; else if (item.numbers) numbers = item.numbers; const sum = numbers.reduce((a, b) => a + b, 0); sums[sum] = (sums[sum] || 0) + 1; }); return sums; } } // ==================== UI组件 ==================== class LotteryUI { constructor() { this.lotteryData = new LotteryData(); this.currentLottery = 'ssq'; this.isVisible = false; this.init(); } init() { // 创建主面板 this.createPanel(); // 注册菜单 GM_registerMenuCommand('📊 打开彩票助手', () => this.toggle()); // 监听快捷键 document.addEventListener('keydown', (e) => { if (e.ctrlKey && e.shiftKey && e.key === 'L') { this.toggle(); } }); } createPanel() { const panel = document.createElement('div'); panel.id = 'lottery-helper-panel'; panel.innerHTML = `

🎰 综合彩票助手

选号
计算
走势
缩水
收藏
设置
${this.renderGeneratorSection()} ${this.renderCalculatorSection()} ${this.renderTrendSection()} ${this.renderFilterSection()} ${this.renderFavoritesSection()} ${this.renderSettingsSection()}
`; document.body.appendChild(panel); this.bindEvents(); } renderGeneratorSection() { return `
📍 选择彩种
🎲 自选号码
✨ 机选号码
🎯 生成结果
📊 统计信息
0
总注数
0
金额(元)
0
预计奖金
`; } renderCalculatorSection() { return `
🏧 奖金计算器
🎱 输入您的号码
🎯 输入开奖号码
💰 中奖结果
点击上方按钮计算奖金
`; } renderTrendSection() { return `
📈 走势分析
🔴 红球/前区 走势
🔵 蓝球/后区 走势
📊 统计分析
-
平均遗漏
-
最大遗漏
-
最热号码
`; } renderFilterSection() { return `
🔧 缩水过滤设置
奇偶比例过滤
和值范围过滤
去连号
AC值过滤
跨度过滤
🎯 过滤结果
-
原始注数
-
过滤后
-
减少率
`; } renderFavoritesSection() { return `
⭐ 我的收藏
暂无收藏,点击选号页面保存
📝 投注记录
`; } renderSettingsSection() { return `
⚙️ 基本设置
开机自动启动
显示快捷键提示
🎨 外观设置
📤 数据管理
ℹ️ 关于

综合彩票助手 v1.0.0
涵盖福利彩票、体育彩票、竞彩足球/篮球

功能包括:
• 智能机选
• 奖金计算
• 走势分析
• 缩水过滤
• 收藏管理

快捷键:Ctrl+Shift+L 打开/关闭

`; } bindEvents() { // Tab切换 document.querySelectorAll('.lh-tab').forEach(tab => { tab.addEventListener('click', () => { document.querySelectorAll('.lh-tab').forEach(t => t.classList.remove('active')); document.querySelectorAll('.lh-section').forEach(s => s.classList.remove('active')); tab.classList.add('active'); document.getElementById(`section-${tab.dataset.section}`).classList.add('active'); if (tab.dataset.section === 'favorites') { this.updateFavorites(); } }); }); // 彩种切换 document.getElementById('lottery-type').addEventListener('change', (e) => { this.currentLottery = e.target.value; this.updateManualNumbers(); }); // 初始化 this.updateManualNumbers(); this.updateTrend(); } toggle() { const panel = document.getElementById('lottery-helper-panel'); panel.classList.toggle('open'); } updateManualNumbers() { const container = document.getElementById('manual-numbers'); const type = this.currentLottery; let html = ''; switch(type) { case 'ssq': html = `

红球 (33选6)

蓝球 (16选1)

`; break; case 'dlt': html = `

前区 (35选5)

后区 (12选2)

`; break; case 'fc3d': case 'pl3': html = `

百位

十位

个位

`; break; default: html = `

该彩种暂不支持手动选号

`; } container.innerHTML = html; // 生成号码球 if (type === 'ssq') { this.createNumberBalls('manual-red', 33, 'red', 6); this.createNumberBalls('manual-blue', 16, 'blue', 1); } else if (type === 'dlt') { this.createNumberBalls('manual-front', 35, 'red', 5); this.createNumberBalls('manual-back', 12, 'blue', 2); } else if (type === 'fc3d' || type === 'pl3') { this.createNumberBalls('manual-d1', 10, 'green', 1); this.createNumberBalls('manual-d2', 10, 'green', 1); this.createNumberBalls('manual-d3', 10, 'green', 1); } // 初始化计算器 this.initCalculator(); } createNumberBalls(containerId, max, colorClass, maxSelect) { const container = document.getElementById(containerId); for (let i = 1; i <= max; i++) { const ball = document.createElement('div'); ball.className = `lh-number-ball ${colorClass}`; ball.textContent = String(i).padStart(2, '0'); ball.dataset.num = i; ball.addEventListener('click', () => this.toggleBall(ball, containerId, maxSelect)); container.appendChild(ball); } } toggleBall(ball, containerId, maxSelect) { const container = document.getElementById(containerId); const selected = container.querySelectorAll('.selected'); if (ball.classList.contains('selected')) { ball.classList.remove('selected'); ball.style.transform = ''; } else { if (selected.length >= maxSelect) { selected[0].classList.remove('selected'); selected[0].style.transform = ''; } ball.classList.add('selected'); ball.style.transform = 'scale(1.2)'; } } clearManualNumbers() { document.querySelectorAll('.lh-number-ball.selected').forEach(ball => { ball.classList.remove('selected'); ball.style.transform = ''; }); } randomGenerate(count) { const container = document.getElementById('generated-numbers'); let html = ''; for (let i = 0; i < count; i++) { const numbers = this.generateRandom(this.currentLottery); html += this.renderNumbers(numbers, i + 1); } container.innerHTML = html; this.updateStats(); } generateRandom(type) { switch(type) { case 'ssq': return { red: Utils.generateRandomNumbers(33, 6), blue: Utils.generateRandomNumbers(16, 1) }; case 'dlt': return { front: Utils.generateRandomNumbers(35, 5), back: Utils.generateRandomNumbers(12, 2) }; case 'fc3d': case 'pl3': return { numbers: [Utils.randomInt(0, 9), Utils.randomInt(0, 9), Utils.randomInt(0, 9)] }; case 'pl5': return { numbers: [Utils.randomInt(0, 9), Utils.randomInt(0, 9), Utils.randomInt(0, 9), Utils.randomInt(0, 9), Utils.randomInt(0, 9)] }; case 'x115': return { numbers: Utils.generateRandomNumbers(11, 5) }; default: return { numbers: [] }; } } renderNumbers(numbers, index) { const type = this.currentLottery; if (type === 'ssq') { return `
第${index}注 ${numbers.red.map(n => `${String(n).padStart(2, '0')}`).join('')} + ${numbers.blue.map(n => `${String(n).padStart(2, '0')}`).join('')}
`; } else if (type === 'dlt') { return `
第${index}注 ${numbers.front.map(n => `${String(n).padStart(2, '0')}`).join('')} + ${numbers.back.map(n => `${String(n).padStart(2, '0')}`).join('')}
`; } else { return `
第${index}注 ${numbers.numbers.map(n => `${n}`).join('')}
`; } } updateStats() { const container = document.getElementById('generated-numbers'); const count = container.querySelectorAll('.lh-result-item').length; const amount = count * 2; const savings = Math.floor(amount * 3.5); document.getElementById('stat-count').textContent = count; document.getElementById('stat-amount').textContent = Utils.formatMoney(amount); document.getElementById('stat-savings').textContent = Utils.formatMoney(savings); } saveToFavorites() { const container = document.getElementById('generated-numbers'); const items = container.querySelectorAll('.lh-result-item'); if (items.length === 0) { alert('请先生成号码!'); return; } items.forEach((item, index) => { const balls = item.querySelectorAll('.lh-number-ball'); const numbers = []; balls.forEach(ball => numbers.push(parseInt(ball.textContent))); this.lotteryData.addToFavorites(this.currentLottery, numbers, `第${index + 1}注`); }); alert('已保存到收藏!'); } copyNumbers() { const container = document.getElementById('generated-numbers'); const items = container.querySelectorAll('.lh-result-item'); let text = ''; items.forEach((item, index) => { const balls = item.querySelectorAll('.lh-number-ball'); const numbers = Array.from(balls).map(b => b.textContent); text += `第${index + 1}注: ${numbers.join(' ')}\n`; }); navigator.clipboard.writeText(text).then(() => { alert('号码已复制到剪贴板!'); }); } initCalculator() { const myContainer = document.getElementById('calc-my-numbers'); const winContainer = document.getElementById('calc-win-numbers'); myContainer.innerHTML = `
`; winContainer.innerHTML = `
`; this.createNumberBalls('calc-my-red', 33, 'red', 6); this.createNumberBalls('calc-my-blue', 16, 'blue', 1); this.createNumberBalls('calc-win-red', 33, 'red', 6); this.createNumberBalls('calc-win-blue', 16, 'blue', 1); } calculatePrize() { const getSelected = (containerId) => { return Array.from(document.querySelectorAll(`#${containerId} .selected`)) .map(el => parseInt(el.dataset.num)); }; const myRed = getSelected('calc-my-red'); const myBlue = getSelected('calc-my-blue'); const winRed = getSelected('calc-win-red'); const winBlue = getSelected('calc-win-blue'); if (myRed.length !== 6 || myBlue.length !== 1 || winRed.length !== 6 || winBlue.length !== 1) { alert('请完整选择所有号码!'); return; } const type = document.getElementById('calc-lottery').value; let result; if (type === 'ssq') { result = PrizeCalculator.calculateSSQ(myRed, myBlue, winRed, winBlue); } else { result = PrizeCalculator.calculateDLT(myRed, myBlue, winRed, winBlue); } const resultContainer = document.getElementById('prize-result'); resultContainer.innerHTML = `
${Utils.formatMoney(result.prize)} 元
${result.level}
红球匹配 ${result.matchRed || result.matchFront || 0} 个
蓝球匹配 ${result.matchBlue || result.matchBack || 0} 个
`; } updateTrend() { const type = document.getElementById('trend-lottery').value; const history = this.lotteryData.data[type] || []; if (history.length === 0) { document.getElementById('trend-red-chart').innerHTML = '
暂无数据
'; return; } const trendType = document.getElementById('trend-type').value; let redMax = 33, blueMax = 16; if (type === 'dlt') { redMax = 35; blueMax = 12; } if (trendType === 'missing') { const redMissing = TrendAnalyzer.analyzeMissing(history, redMax); const blueMissing = TrendAnalyzer.analyzeMissing(history, blueMax); this.renderTrendChart('trend-red-chart', redMissing.missing.slice(1), 'red'); this.renderTrendChart('trend-blue-chart', blueMissing.missing.slice(1), 'blue'); const avgMissing = Math.round(redMissing.missing.slice(1).reduce((a, b) => a + b, 0) / redMax); const maxMissing = Math.max(...redMissing.missing.slice(1)); document.getElementById('ts-avg').textContent = avgMissing; document.getElementById('ts-max').textContent = maxMissing; } else if (trendType === 'hotcold') { const hotCold = TrendAnalyzer.analyzeHotCold(history, redMax); document.getElementById('trend-red-chart').innerHTML = `

最热号码

${hotCold.hot.slice(0, 6).map(h => `${String(h.num).padStart(2, '0')}`).join('')}

最冷号码

${hotCold.cold.slice(0, 6).map(c => `${String(c.num).padStart(2, '0')}`).join('')}
`; document.getElementById('ts-hot').textContent = hotCold.hot[0]?.num || '-'; } else if (trendType === 'sum') { const sumData = TrendAnalyzer.analyzeSum(history); const maxSum = Math.max(...Object.values(sumData)); document.getElementById('trend-red-chart').innerHTML = `
${Object.entries(sumData).sort((a, b) => a[0] - b[0]).map(([sum, count]) => `
`).join('')}
`; document.getElementById('ts-avg').textContent = Math.round(Object.entries(sumData).reduce((a, [s, c]) => a + s * c, 0) / history.length); } document.getElementById('trend-blue-chart').innerHTML = document.getElementById('trend-blue-chart').innerHTML; } renderTrendChart(containerId, data, colorClass) { const container = document.getElementById(containerId); const max = Math.max(...data); container.innerHTML = `
${data.map((val, idx) => `
`).join('')}
`; } toggleFilter(name) { const toggle = document.getElementById(`toggle-${name}`); toggle.classList.toggle('active'); const options = document.getElementById(`${name}-options`); if (options) { options.style.display = toggle.classList.contains('active') ? 'block' : 'none'; } } runFilter() { const options = { oddEvenRatio: document.getElementById('toggle-oddeven').classList.contains('active'), oddEvenMin: parseInt(document.getElementById('oddeven-min').value) || 2, oddEvenMax: parseInt(document.getElementById('oddeven-max').value) || 4, sumRange: document.getElementById('toggle-sum').classList.contains('active'), sumMin: parseInt(document.getElementById('sum-min').value) || 70, sumMax: parseInt(document.getElementById('sum-max').value) || 140, noConsecutive: document.getElementById('toggle-consecutive').classList.contains('active'), acValue: document.getElementById('toggle-ac').classList.contains('active'), acMin: parseInt(document.getElementById('ac-min').value) || 6, acMax: parseInt(document.getElementById('ac-max').value) || 10, spanRange: document.getElementById('toggle-span').classList.contains('active'), spanMin: parseInt(document.getElementById('span-min').value) || 20, spanMax: parseInt(document.getElementById('span-max').value) || 32 }; const combinations = NumberFilter.generateCombinations(33, 6, 16); const original = combinations.length; const filtered = NumberFilter.filter(combinations, options); const result = filtered.length; const reduceRate = ((original - result) / original * 100).toFixed(1) + '%'; document.getElementById('filter-original').textContent = Utils.formatMoney(original); document.getElementById('filter-result').textContent = Utils.formatMoney(result); document.getElementById('filter-reduce').textContent = reduceRate; } updateFavorites() { const container = document.getElementById('favorites-list'); const favorites = this.lotteryData.data.favorites; if (favorites.length === 0) { container.innerHTML = '
暂无收藏
'; return; } container.innerHTML = favorites.map(f => `
${LOTTERY_TYPES.welfare.find(l => l.id === f.type)?.name || LOTTERY_TYPES.sports.find(l => l.id === f.type)?.name || f.type}
${f.numbers.map(n => `${n}`).join('')}
`).join(''); // 更新笔记 const notesContainer = document.getElementById('notes-list'); notesContainer.innerHTML = this.lotteryData.data.notes.map(n => `
${n.text} ${new Date(n.createdAt).toLocaleDateString()}
`).join(''); } deleteFavorite(id) { this.lotteryData.removeFavorite(id); this.updateFavorites(); } addNote() { const note = document.getElementById('bet-note').value; if (note.trim()) { this.lotteryData.addNote(note); document.getElementById('bet-note').value = ''; this.updateFavorites(); } } exportData() { const data = JSON.stringify(this.lotteryData.data, null, 2); const blob = new Blob([data], { type: 'application/json' }); const url = URL.createObjectURL(blob); const a = document.createElement('a'); a.href = url; a.download = `lottery-backup-${new Date().toISOString().split('T')[0]}.json`; a.click(); URL.revokeObjectURL(url); } importData() { const input = document.createElement('input'); input.type = 'file'; input.accept = '.json'; input.onchange = (e) => { const file = e.target.files[0]; const reader = new FileReader(); reader.onload = (evt) => { try { const data = JSON.parse(evt.target.result); this.lotteryData.data = data; this.lotteryData.save(); alert('数据导入成功!'); } catch (err) { alert('数据格式错误!'); } }; reader.readAsText(file); }; input.click(); } clearData() { if (confirm('确定要清空所有数据吗?此操作不可恢复!')) { this.lotteryData.data = this.lotteryData.getDefaultData(); this.lotteryData.save(); alert('数据已清空!'); } } } // 启动应用 window.lotteryUI = new LotteryUI(); // 添加悬浮按钮 const fab = document.createElement('div'); fab.id = 'lottery-helper-fab'; fab.innerHTML = '🎰'; fab.style.cssText = ` position: fixed; bottom: 20px; right: 20px; width: 50px; height: 50px; background: linear-gradient(135deg, ${CONFIG.colors.primary}, ${CONFIG.colors.info}); border-radius: 50%; display: flex; align-items: center; justify-content: center; font-size: 24px; cursor: pointer; box-shadow: 0 4px 20px rgba(231, 76, 60, 0.4); z-index: 999998; transition: transform 0.3s; `; fab.onclick = () => window.lotteryUI.toggle(); fab.onmouseover = () => fab.style.transform = 'scale(1.1)'; fab.onmouseout = () => fab.style.transform = 'scale(1)'; document.body.appendChild(fab); })();