好友
阅读权限10
听众
最后登录1970-1-1
|
本帖最后由 dongfang2025 于 2025-10-12 11:22 编辑
[HTML] 纯文本查看 复制代码 <!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>智能抽奖系统</title>
<script src="https://cdn.tailwindcss.com"></script>
<link href="https://cdn.jsdelivr.net/npm/font-awesome@4.7.0/css/font-awesome.min.css" rel="stylesheet">
<script>
tailwind.config = {
theme: {
extend: {
colors: {
primary: '#4F46E5',
secondary: '#7C3AED',
accent: '#F59E0B',
dark: '#1E293B',
light: '#F1F5F9'
},
fontFamily: {
inter: ['Inter', 'system-ui', 'sans-serif'],
},
}
}
}
</script>
<style type="text/tailwindcss">
@layer utilities {
.text-shadow {
text-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
}
.text-shadow-lg {
text-shadow: 0 4px 8px rgba(0, 0, 0, 0.2);
}
.animation-delay-100 {
animation-delay: 100ms;
}
.animation-delay-200 {
animation-delay: 200ms;
}
.animation-delay-300 {
animation-delay: 300ms;
}
}
@keyframes lottery-animation {
0% { opacity: 1; transform: scale(1); }
50% { opacity: 0.8; transform: scale(0.95); }
100% { opacity: 1; transform: scale(1); }
}
@keyframes falling {
0% { transform: translateY(-20px) rotate(0deg); opacity: 1; }
100% { transform: translateY(100vh) rotate(360deg); opacity: 0; }
}
@keyframes float {
0% { transform: translateY(0px); }
50% { transform: translateY(-10px); }
100% { transform: translateY(0px); }
}
.lottery-animation {
animation: lottery-animation 0.2s infinite;
}
.animate-float {
animation: float 3s ease-in-out infinite;
}
.confetti {
position: fixed;
pointer-events: none;
z-index: 9999;
}
.firework {
position: fixed;
width: 10px;
height: 10px;
border-radius: 50%;
z-index: 9999;
pointer-events: none;
}
.firework-burst {
position: fixed;
width: 5px;
height: 5px;
border-radius: 50%;
z-index: 9999;
pointer-events: none;
}
</style>
</head>
<body class="font-inter bg-gradient-to-br from-primary/10 to-secondary/10 min-h-screen flex flex-col transition-all duration-500">
<!-- 右键菜单 -->
<div id="contextMenu" class="fixed hidden z-50 bg-white rounded-lg shadow-xl border border-gray-200 py-1 w-48">
<div class="context-menu-item px-4 py-2 hover:bg-gray-100 cursor-pointer" data-action="startLottery">
<i class="fa fa-play mr-2 text-primary"></i>开始抽奖
</div>
<div class="context-menu-item px-4 py-2 hover:bg-gray-100 cursor-pointer" data-action="stopLottery">
<i class="fa fa-stop mr-2 text-red-500"></i>停止抽奖
</div>
<div class="border-t border-gray-200 my-1"></div>
<div class="context-menu-item px-4 py-2 hover:bg-gray-100 cursor-pointer" data-action="viewWinners">
<i class="fa fa-trophy mr-2 text-accent"></i>中奖名单
</div>
<div class="context-menu-item px-4 py-2 hover:bg-gray-100 cursor-pointer" data-action="clearWinners">
<i class="fa fa-trash mr-2 text-gray-500"></i>清空中奖名单
</div>
<div class="border-t border-gray-200 my-1"></div>
<div class="context-menu-item px-4 py-2 hover:bg-gray-100 cursor-pointer" data-action="manageNames">
<i class="fa fa-users mr-2 text-secondary"></i>名单管理
</div>
<div class="context-menu-item px-4 py-2 hover:bg-gray-100 cursor-pointer" data-action="settings">
<i class="fa fa-cog mr-2 text-gray-600"></i>系统设置
</div>
</div>
<!-- 主抽奖界面 -->
<div id="lotteryScreen" class="flex-1 flex flex-col">
<!-- 标题区域 -->
<header class="py-6 text-center">
<h1 id="mainTitle" class="text-[clamp(2rem,5vw,3rem)] font-bold text-dark mb-2 text-shadow">智能抽奖系统</h1>
<p id="subtitle" class="text-[clamp(1rem,2vw,1.25rem)] text-gray-600">点击开始按钮或按Enter键开始抽奖</p>
</header>
<!-- 抽奖区域 -->
<main class="flex-1 flex items-center justify-center p-6">
<div id="lotteryContainer" class="w-full max-w-4xl h-full flex items-center justify-center">
<div id="lotteryName" class="text-[clamp(3rem,10vw,6rem)] font-bold text-dark text-center text-shadow-lg">准备开始</div>
</div>
</main>
<!-- 控制区域 -->
<footer class="py-8 px-6 text-center">
<div class="flex justify-center gap-4 flex-wrap">
<button id="startButton" class="px-8 py-4 bg-primary hover:bg-primary/90 text-white text-xl font-bold rounded-lg transition-colors shadow-lg hover:shadow-xl transform hover:scale-105">
<i class="fa fa-play mr-2"></i>开始抽奖
</button>
<button id="stopButton" class="hidden px-8 py-4 bg-red-500 hover:bg-red-600 text-white text-xl font-bold rounded-lg transition-colors shadow-lg hover:shadow-xl transform hover:scale-105">
<i class="fa fa-stop mr-2"></i>停止抽奖
</button>
<button id="viewWinnersButton" class="px-8 py-4 bg-accent hover:bg-accent/90 text-white text-xl font-bold rounded-lg transition-colors shadow-lg hover:shadow-xl transform hover:scale-105">
<i class="fa fa-trophy mr-2"></i>中奖名单
</button>
<button id="manageNamesButton" class="px-8 py-4 bg-secondary hover:bg-secondary/90 text-white text-xl font-bold rounded-lg transition-colors shadow-lg hover:shadow-xl transform hover:scale-105">
<i class="fa fa-users mr-2"></i>名单管理
</button>
</div>
</footer>
</div>
<!-- 中奖名单界面 -->
<div id="winnersScreen" class="fixed inset-0 bg-white z-40 hidden overflow-auto">
<div class="p-6">
<div class="flex justify-between items-center mb-8">
<h2 class="text-[clamp(1.5rem,3vw,2.5rem)] font-bold text-dark">中奖名单</h2>
<button id="backToMainButton" class="px-4 py-2 bg-gray-200 hover:bg-gray-300 rounded-lg transition-colors">
<i class="fa fa-arrow-left mr-2"></i>返回
</button>
</div>
<div id="winnersList" class="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 gap-6">
<!-- 中奖名单将在这里动态生成 -->
</div>
<div class="flex justify-center gap-4 mt-8">
<button id="clearWinnersButton" class="px-6 py-3 bg-red-500 hover:bg-red-600 text-white rounded-lg transition-colors">
<i class="fa fa-trash mr-2"></i>清空中奖名单
</button>
<button id="printWinnersButton" class="px-6 py-3 bg-gray-700 hover:bg-gray-800 text-white rounded-lg transition-colors">
<i class="fa fa-print mr-2"></i>打印名单
</button>
</div>
</div>
</div>
<!-- 名单管理界面 -->
<div id="namesManagementScreen" class="fixed inset-0 bg-white z-40 hidden overflow-auto">
<div class="p-6">
<div class="flex justify-between items-center mb-8">
<h2 class="text-[clamp(1.5rem,3vw,2.5rem)] font-bold text-dark">名单管理</h2>
<button id="backFromNamesButton" class="px-4 py-2 bg-gray-200 hover:bg-gray-300 rounded-lg transition-colors">
<i class="fa fa-arrow-left mr-2"></i>返回
</button>
</div>
<!-- 参与者名单管理 -->
<div class="mb-8">
<div class="flex justify-between items-center mb-4">
<h3 class="text-xl font-bold text-dark">参与者名单</h3>
<span id="participantsCount" class="text-sm bg-primary/10 text-primary px-3 py-1 rounded-full">0人</span>
</div>
<textarea id="participantsInput" class="w-full h-32 p-4 border border-gray-300 rounded-lg focus:ring-2 focus:ring-primary focus:border-primary transition-all mb-4 resize-none" placeholder="请输入参与者名单,支持顿号分隔或每行一个格式"></textarea>
<div class="flex flex-wrap gap-2">
<button id="addParticipantsButton" class="px-4 py-2 bg-primary hover:bg-primary/90 text-white rounded-lg transition-colors">
<i class="fa fa-plus mr-2"></i>添加名单
</button>
<button id="clearParticipantsButton" class="px-4 py-2 bg-gray-200 hover:bg-gray-300 text-gray-700 rounded-lg transition-colors">
<i class="fa fa-eraser mr-2"></i>清空输入
</button>
<button id="deleteAllParticipantsButton" class="px-4 py-2 bg-red-100 hover:bg-red-200 text-red-700 rounded-lg transition-colors">
<i class="fa fa-trash mr-2"></i>删除全部
</button>
<button id="loadExampleParticipantsButton" class="px-4 py-2 bg-secondary/10 hover:bg-secondary/20 text-secondary rounded-lg transition-colors">
<i class="fa fa-file-text-o mr-2"></i>加载示例
</button>
</div>
<div id="participantsList" class="mt-4">
<!-- 参与者列表将在这里动态生成 -->
</div>
</div>
<!-- 领导名单管理 -->
<div>
<div class="flex justify-between items-center mb-4">
<h3 class="text-xl font-bold text-dark">领导名单</h3>
<span id="leadersCount" class="text-sm bg-secondary/10 text-secondary px-3 py-1 rounded-full">0人</span>
</div>
<textarea id="leadersInput" class="w-full h-24 p-4 border border-gray-300 rounded-lg focus:ring-2 focus:ring-secondary focus:border-secondary transition-all mb-4 resize-none" placeholder="请输入领导名单,支持顿号分隔或每行一个格式"></textarea>
<div class="flex flex-wrap gap-2">
<button id="addLeadersButton" class="px-4 py-2 bg-secondary hover:bg-secondary/90 text-white rounded-lg transition-colors">
<i class="fa fa-plus mr-2"></i>添加领导
</button>
<button id="clearLeadersButton" class="px-4 py-2 bg-gray-200 hover:bg-gray-300 text-gray-700 rounded-lg transition-colors">
<i class="fa fa-eraser mr-2"></i>清空输入
</button>
<button id="deleteAllLeadersButton" class="px-4 py-2 bg-red-100 hover:bg-red-200 text-red-700 rounded-lg transition-colors">
<i class="fa fa-trash mr-2"></i>删除全部
</button>
</div>
<div id="leadersList" class="mt-4">
<!-- 领导列表将在这里动态生成 -->
</div>
</div>
</div>
</div>
<!-- 设置界面 -->
<div id="settingsScreen" class="fixed inset-0 bg-white z-40 hidden overflow-auto">
<div class="p-6">
<div class="flex justify-between items-center mb-8">
<h2 class="text-[clamp(1.5rem,3vw,2.5rem)] font-bold text-dark">系统设置</h2>
<button id="closeSettingsButton" class="px-4 py-2 bg-gray-200 hover:bg-gray-300 rounded-lg transition-colors">
<i class="fa fa-times mr-2"></i>关闭
</button>
</div>
<div class="max-w-3xl mx-auto space-y-8">
<!-- 抽奖设置 -->
<div class="bg-gray-50 p-6 rounded-xl">
<h3 class="text-xl font-bold text-dark mb-4">抽奖设置</h3>
<!-- 中奖人数 -->
<div class="mb-6">
<label class="block text-gray-700 mb-2">中奖人数: <span id="winnersCountValue">3</span>人</label>
<input type="range" id="winnersCount" min="1" max="100" value="3" class="w-full h-2 bg-gray-200 rounded-lg appearance-none cursor-pointer accent-primary">
</div>
<!-- 抽奖速度 -->
<div class="mb-6">
<label class="block text-gray-700 mb-2">抽奖速度: <span id="lotterySpeedValue">5</span></label>
<input type="range" id="lotterySpeed" min="1" max="10" value="5" class="w-full h-2 bg-gray-200 rounded-lg appearance-none cursor-pointer accent-primary">
</div>
<!-- 字体大小 -->
<div class="mb-6">
<label class="block text-gray-700 mb-2">字体大小: <span id="fontSizeValue">10</span></label>
<input type="range" id="fontSize" min="1" max="20" value="10" class="w-full h-2 bg-gray-200 rounded-lg appearance-none cursor-pointer accent-primary">
</div>
<!-- 抽奖模式 -->
<div class="mb-6">
<label class="block text-gray-700 mb-2">抽奖模式</label>
<div class="flex space-x-4">
<label class="flex items-center">
<input type="radio" name="lotteryMode" value="random" checked class="w-4 h-4 text-primary focus:ring-primary">
<span class="ml-2 text-gray-700">单次循环抽奖</span>
</label>
<label class="flex items-center">
<input type="radio" name="lotteryMode" value="sequential" class="w-4 h-4 text-primary focus:ring-primary">
<span class="ml-2 text-gray-700">预设顺序抽奖</span>
</label>
</div>
<div class="mt-2 text-sm text-gray-500">
<p>单次循环抽奖:每次抽奖随机显示参与者名单,可重复抽取。</p>
<p>预设顺序抽奖:按名单顺序逐个显示参与者,避免重复抽取。</p>
</div>
</div>
</div>
<!-- 特效设置 -->
<div class="bg-gray-50 p-6 rounded-xl">
<h3 class="text-xl font-bold text-dark mb-4">特效设置</h3>
<!-- 音效开关 -->
<div class="flex items-center justify-between mb-4">
<label class="text-gray-700">抽奖音效</label>
<label class="relative inline-flex items-center cursor-pointer">
<input type="checkbox" id="enableDrawSound" checked class="sr-only peer">
<div class="w-11 h-6 bg-gray-200 peer-focus:outline-none peer-focus:ring-2 peer-focus:ring-primary/50 rounded-full peer peer-checked:after:translate-x-full peer-checked:after:border-white after:content-[''] after:absolute after:top-[2px] after:left-[2px] after:bg-white after:border-gray-300 after:border after:rounded-full after:h-5 after:w-5 after:transition-all peer-checked:bg-primary"></div>
</label>
</div>
<div class="flex items-center justify-between mb-4">
<label class="text-gray-700">中奖音效</label>
<label class="relative inline-flex items-center cursor-pointer">
<input type="checkbox" id="enableWinSound" checked class="sr-only peer">
<div class="w-11 h-6 bg-gray-200 peer-focus:outline-none peer-focus:ring-2 peer-focus:ring-primary/50 rounded-full peer peer-checked:after:translate-x-full peer-checked:after:border-white after:content-[''] after:absolute after:top-[2px] after:left-[2px] after:bg-white after:border-gray-300 after:border after:rounded-full after:h-5 after:w-5 after:transition-all peer-checked:bg-primary"></div>
</label>
</div>
<!-- 烟花特效 -->
<div class="flex items-center justify-between mb-4">
<label class="text-gray-700">烟花特效</label>
<label class="relative inline-flex items-center cursor-pointer">
<input type="checkbox" id="enableFireworks" checked class="sr-only peer">
<div class="w-11 h-6 bg-gray-200 peer-focus:outline-none peer-focus:ring-2 peer-focus:ring-primary/50 rounded-full peer peer-checked:after:translate-x-full peer-checked:after:border-white after:content-[''] after:absolute after:top-[2px] after:left-[2px] after:bg-white after:border-gray-300 after:border after:rounded-full after:h-5 after:w-5 after:transition-all peer-checked:bg-primary"></div>
</label>
</div>
</div>
<!-- 显示设置 -->
<div class="bg-gray-50 p-6 rounded-xl">
<h3 class="text-xl font-bold text-dark mb-4">显示设置</h3>
<!-- 主标题 -->
<div class="mb-6">
<label class="block text-gray-700 mb-2">主标题</label>
<input type="text" id="titleInput" value="智能抽奖系统" class="w-full p-3 border border-gray-300 rounded-lg focus:ring-2 focus:ring-primary focus:border-primary transition-all">
</div>
<!-- 副标题 -->
<div class="mb-6">
<label class="block text-gray-700 mb-2">副标题</label>
<input type="text" id="subtitleInput" value="点击开始按钮或按Enter键开始抽奖" class="w-full p-3 border border-gray-300 rounded-lg focus:ring-2 focus:ring-primary focus:border-primary transition-all">
</div>
<!-- 背景模式 -->
<div class="mb-6">
<label class="block text-gray-700 mb-2">背景模式</label>
<div class="flex space-x-4">
<label class="flex items-center">
<input type="radio" name="backgroundMode" value="solid" checked class="w-4 h-4 text-primary focus:ring-primary">
<span class="ml-2 text-gray-700">纯色背景</span>
</label>
<label class="flex items-center">
<input type="radio" name="backgroundMode" value="image" class="w-4 h-4 text-primary focus:ring-primary">
<span class="ml-2 text-gray-700">壁纸背景</span>
</label>
</div>
</div>
<!-- 背景颜色 -->
<div class="mb-6" id="backgroundColorContainer">
<label class="block text-gray-700 mb-2">背景颜色</label>
<div class="flex space-x-3">
<div class="w-full flex-1">
<input type="color" id="backgroundColor" value="#4F46E5" class="w-full h-10 border border-gray-300 rounded-lg cursor-pointer">
</div>
<div class="w-full flex-1">
<input type="color" id="backgroundGradient" value="#7C3AED" class="w-full h-10 border border-gray-300 rounded-lg cursor-pointer">
</div>
</div>
<p class="text-xs text-gray-500 mt-2">选择渐变背景的两种颜色</p>
</div>
<!-- 背景图片URL -->
<div class="mb-6 hidden" id="backgroundImageContainer">
<label class="block text-gray-700 mb-2">背景图片URL</label>
<input type="text" id="backgroundImage" value="https://picsum.photos/id/1067/1920/1080" class="w-full p-3 border border-gray-300 rounded-lg focus:ring-2 focus:ring-primary focus:border-primary transition-all">
</div>
</div>
</div>
<div class="flex justify-center gap-4 mt-8">
<button id="resetSettingsButton" class="px-6 py-3 bg-gray-200 hover:bg-gray-300 text-gray-700 rounded-lg transition-colors">
<i class="fa fa-refresh mr-2"></i>重置设置
</button>
<button id="saveSettingsButton" class="px-6 py-3 bg-primary hover:bg-primary/90 text-white rounded-lg transition-colors">
<i class="fa fa-save mr-2"></i>保存设置
</button>
</div>
</div>
</div>
<!-- 音效元素 -->
<audio id="drawSound" preload="auto">
<source src="https://assets.mixkit.co/sfx/preview/mixkit-winning-chimes-2015.mp3" type="audio/mpeg">
<!-- 备用音频源 -->
<source src="https://soundbible.com/grab.php?id=1747&type=mp3" type="audio/mpeg">
</audio>
<audio id="winSound" preload="auto">
<source src="https://assets.mixkit.co/sfx/preview/mixkit-achievement-bell-600.mp3" type="audio/mpeg">
<!-- 备用音频源 -->
<source src="https://soundbible.com/grab.php?id=1759&type=mp3" type="audio/mpeg">
</audio>
<script>
// 数据结构定义
const data = {
participants: [], // 参与者名单
leaders: [], // 领导名单
winners: [], // 中奖记录
settings: {
winnersCount: 3, // 中奖人数
lotterySpeed: 5, // 抽奖速度(1-10,10最快)
fontSize: 10, // 字体大小(1-20,10正常)
lotteryMode: 'random', // 抽奖模式
enableDrawSound: true, // 抽奖音效
enableWinSound: true, // 中奖音效
enableFireworks: true, // 烟花特效
mainTitle: '智能抽奖系统', // 主标题
subtitle: '点击开始按钮或按Enter键开始抽奖', // 副标题
backgroundMode: 'solid', // 背景模式
backgroundColor: '#4F46E5', // 背景颜色
backgroundGradient: '#7C3AED', // 渐变背景颜色
backgroundImage: 'https://picsum.photos/id/1067/1920/1080' // 背景图片URL
}
};
// 应用状态
const state = {
isDrawing: false, // 是否正在抽奖
drawInterval: null, // 抽奖定时器
sequentialDrawIndex: 0, // 顺序抽奖的当前索引
hasDrawnAll: false // 是否已经抽完所有参与者
};
// DOM元素引用
const elements = {
// 主界面元素
lotteryScreen: document.getElementById('lotteryScreen'),
mainTitle: document.getElementById('mainTitle'),
subtitle: document.getElementById('subtitle'),
lotteryContainer: document.getElementById('lotteryContainer'),
lotteryName: document.getElementById('lotteryName'),
startButton: document.getElementById('startButton'),
stopButton: document.getElementById('stopButton'),
viewWinnersButton: document.getElementById('viewWinnersButton'),
manageNamesButton: document.getElementById('manageNamesButton'),
// 中奖名单界面元素
winnersScreen: document.getElementById('winnersScreen'),
backToMainButton: document.getElementById('backToMainButton'),
winnersList: document.getElementById('winnersList'),
clearWinnersButton: document.getElementById('clearWinnersButton'),
printWinnersButton: document.getElementById('printWinnersButton'),
// 名单管理界面元素
namesManagementScreen: document.getElementById('namesManagementScreen'),
backFromNamesButton: document.getElementById('backFromNamesButton'),
participantsInput: document.getElementById('participantsInput'),
participantsList: document.getElementById('participantsList'),
participantsCount: document.getElementById('participantsCount'),
addParticipantsButton: document.getElementById('addParticipantsButton'),
clearParticipantsButton: document.getElementById('clearParticipantsButton'),
deleteAllParticipantsButton: document.getElementById('deleteAllParticipantsButton'),
loadExampleParticipantsButton: document.getElementById('loadExampleParticipantsButton'),
leadersInput: document.getElementById('leadersInput'),
leadersList: document.getElementById('leadersList'),
leadersCount: document.getElementById('leadersCount'),
addLeadersButton: document.getElementById('addLeadersButton'),
clearLeadersButton: document.getElementById('clearLeadersButton'),
deleteAllLeadersButton: document.getElementById('deleteAllLeadersButton'),
// 设置界面元素
settingsScreen: document.getElementById('settingsScreen'),
closeSettingsButton: document.getElementById('closeSettingsButton'),
saveSettingsButton: document.getElementById('saveSettingsButton'),
resetSettingsButton: document.getElementById('resetSettingsButton'),
winnersCount: document.getElementById('winnersCount'),
winnersCountValue: document.getElementById('winnersCountValue'),
lotterySpeed: document.getElementById('lotterySpeed'),
lotterySpeedValue: document.getElementById('lotterySpeedValue'),
fontSize: document.getElementById('fontSize'),
fontSizeValue: document.getElementById('fontSizeValue'),
titleInput: document.getElementById('titleInput'),
subtitleInput: document.getElementById('subtitleInput'),
backgroundColor: document.getElementById('backgroundColor'),
backgroundGradient: document.getElementById('backgroundGradient'),
backgroundColorContainer: document.getElementById('backgroundColorContainer'),
backgroundImage: document.getElementById('backgroundImage'),
backgroundImageContainer: document.getElementById('backgroundImageContainer'),
enableDrawSound: document.getElementById('enableDrawSound'),
enableWinSound: document.getElementById('enableWinSound'),
enableFireworks: document.getElementById('enableFireworks'),
// 右键菜单
contextMenu: document.getElementById('contextMenu'),
// 音效元素
drawSound: document.getElementById('drawSound'),
winSound: document.getElementById('winSound')
};
// 更新设置显示
function updateSettingsDisplay() {
elements.winnersCount.value = data.settings.winnersCount;
elements.winnersCountValue.textContent = data.settings.winnersCount;
elements.lotterySpeed.value = data.settings.lotterySpeed;
elements.lotterySpeedValue.textContent = data.settings.lotterySpeed;
elements.fontSize.value = data.settings.fontSize;
elements.fontSizeValue.textContent = data.settings.fontSize;
elements.titleInput.value = data.settings.mainTitle;
elements.subtitleInput.value = data.settings.subtitle;
elements.backgroundColor.value = data.settings.backgroundColor;
elements.backgroundGradient.value = data.settings.backgroundGradient;
elements.backgroundImage.value = data.settings.backgroundImage;
elements.enableDrawSound.checked = data.settings.enableDrawSound;
elements.enableWinSound.checked = data.settings.enableWinSound;
elements.enableFireworks.checked = data.settings.enableFireworks;
// 设置抽奖模式
document.querySelector(`input[name="lotteryMode"][value="${data.settings.lotteryMode}"]`).checked = true;
// 设置背景模式
document.querySelector(`input[name="backgroundMode"][value="${data.settings.backgroundMode}"]`).checked = true;
// 更新背景模式相关UI
if (data.settings.backgroundMode === 'solid') {
elements.backgroundColorContainer.classList.remove('hidden');
elements.backgroundImageContainer.classList.add('hidden');
} else {
elements.backgroundColorContainer.classList.add('hidden');
elements.backgroundImageContainer.classList.remove('hidden');
}
// 应用背景
updateBackground();
// 应用标题
elements.mainTitle.textContent = data.settings.mainTitle;
elements.subtitle.textContent = data.settings.subtitle;
// 应用字体大小
const fontSizeMultiplier = 0.5 + (data.settings.fontSize * 0.05);
elements.lotteryName.style.fontSize = `clamp(${2 * fontSizeMultiplier}rem, ${8 * fontSizeMultiplier}vw, ${5 * fontSizeMultiplier}rem)`;
}
// 保存设置
function saveSettings() {
data.settings.winnersCount = parseInt(elements.winnersCount.value);
data.settings.lotterySpeed = parseInt(elements.lotterySpeed.value);
data.settings.fontSize = parseInt(elements.fontSize.value);
data.settings.lotteryMode = document.querySelector('input[name="lotteryMode"]:checked').value;
data.settings.mainTitle = elements.titleInput.value;
data.settings.subtitle = elements.subtitleInput.value;
data.settings.backgroundMode = document.querySelector('input[name="backgroundMode"]:checked').value;
data.settings.backgroundColor = elements.backgroundColor.value;
data.settings.backgroundGradient = elements.backgroundGradient.value;
data.settings.backgroundImage = elements.backgroundImage.value;
data.settings.enableDrawSound = elements.enableDrawSound.checked;
data.settings.enableWinSound = elements.enableWinSound.checked;
data.settings.enableFireworks = elements.enableFireworks.checked;
// 应用设置
updateSettingsDisplay();
// 保存到本地存储
saveData();
// 关闭设置界面
elements.settingsScreen.classList.add('hidden');
}
// 重置设置
function resetSettings() {
if (confirm('确定要重置所有设置吗?')) {
// 重置为默认设置
data.settings = {
winnersCount: 3,
lotterySpeed: 5,
fontSize: 10,
lotteryMode: 'random',
enableDrawSound: true,
enableWinSound: true,
enableFireworks: true,
mainTitle: '智能抽奖系统',
subtitle: '点击开始按钮或按Enter键开始抽奖',
backgroundMode: 'solid',
backgroundColor: '#4F46E5',
backgroundGradient: '#7C3AED',
backgroundImage: 'https://picsum.photos/id/1067/1920/1080'
};
// 更新显示
updateSettingsDisplay();
// 保存到本地存储
saveData();
}
}
// 更新参与者名单显示
function updateParticipantsList() {
elements.participantsList.innerHTML = '';
elements.participantsCount.textContent = `${data.participants.length}人`;
if (data.participants.length === 0) {
elements.participantsList.innerHTML = '<p class="text-gray-400 text-sm">暂无参与者</p>';
return;
}
const list = document.createElement('div');
list.className = 'flex flex-wrap gap-2';
data.participants.forEach((name, index) => {
const tag = document.createElement('div');
tag.className = 'bg-primary/20 text-primary text-sm px-2 py-1 rounded-full flex items-center gap-1 border border-primary/30';
tag.innerHTML = `
<span>${name}</span>
<button class="text-gray-400 hover:text-primary"><i class="fa fa-times"></i></button>
`;
list.appendChild(tag);
});
elements.participantsList.appendChild(list);
}
// 更新领导名单显示
function updateLeadersList() {
elements.leadersList.innerHTML = '';
elements.leadersCount.textContent = `${data.leaders.length}人`;
if (data.leaders.length === 0) {
elements.leadersList.innerHTML = '<p class="text-gray-400 text-sm">暂无领导</p>';
return;
}
const list = document.createElement('div');
list.className = 'flex flex-wrap gap-2';
data.leaders.forEach((name, index) => {
const tag = document.createElement('div');
tag.className = 'bg-secondary/20 text-secondary text-sm px-2 py-1 rounded-full flex items-center gap-1 border border-secondary/30';
tag.innerHTML = `
<span><i class="fa fa-star mr-1"></i>${name}</span>
<button class="text-gray-400 hover:text-secondary"><i class="fa fa-times"></i></button>
`;
list.appendChild(tag);
});
elements.leadersList.appendChild(list);
}
// 更新中奖名单显示
function updateWinnersList() {
elements.winnersList.innerHTML = '';
if (data.winners.length === 0) {
elements.winnersList.innerHTML = `
<div class="col-span-full py-16 text-center text-gray-400">
<i class="fa fa-trophy text-5xl mb-6 block"></i>
<p class="text-xl">暂无中奖记录</p>
</div>
`;
return;
}
// 添加"恭喜"标题
const congratulationTitle = document.createElement('div');
congratulationTitle.className = 'col-span-full text-center mb-8';
congratulationTitle.innerHTML = '<h3 class="text-3xl font-bold text-primary">恭喜中奖!</h3>';
elements.winnersList.appendChild(congratulationTitle);
// 横向排列中奖名单
data.winners.forEach((winner, index) => {
const isLeader = data.leaders.includes(winner.name);
const card = document.createElement('div');
card.className = `rounded-xl p-6 ${isLeader ? 'bg-secondary/20 border-2 border-secondary/50' : 'bg-white/90 border border-gray-200'} transform transition-all duration-300 hover:scale-105 hover:shadow-2xl`;
card.innerHTML = `
<div class="flex flex-col items-center text-center">
<div class="w-16 h-16 rounded-full flex items-center justify-center mb-4 text-2xl font-bold ${isLeader ? 'bg-secondary text-white' : 'bg-primary text-white'} shadow-lg">
${index + 1}
</div>
<h4 class="text-xl font-bold mb-2 ${isLeader ? 'text-secondary' : 'text-gray-800'}">${winner.name}</h4>
<p class="text-sm text-gray-500">${winner.time}</p>
${isLeader ? '<div class="mt-3 inline-block bg-secondary text-white text-xs px-3 py-1 rounded-full"><i class="fa fa-trophy mr-1"></i>特别奖</div>' : ''}
</div>
`;
elements.winnersList.appendChild(card);
});
}
// 开始抽奖
function startLottery() {
if (data.participants.length === 0) {
alert('请先添加参与者名单!');
return;
}
// 检查是否已经抽完所有参与者(仅适用于预设顺序抽奖)
if (data.settings.lotteryMode === 'sequential' && state.hasDrawnAll) {
if (confirm('所有参与者已经抽完,是否重新开始?')) {
state.sequentialDrawIndex = 0;
state.hasDrawnAll = false;
} else {
return;
}
}
// 重置抽奖显示,确保第二次点击抽奖时能直接回到滚动效果
resetLotteryDisplay();
state.isDrawing = true;
elements.startButton.classList.add('hidden');
elements.stopButton.classList.remove('hidden');
elements.lotteryName.classList.add('lottery-animation');
// 停止获奖音效并重置其状态
if (elements.winSound) {
elements.winSound.pause();
elements.winSound.currentTime = 0;
}
// 播放抽奖音效
if (data.settings.enableDrawSound && elements.drawSound) {
elements.drawSound.currentTime = 0;
elements.drawSound.play().catch(e => console.log('无法播放音效:', e));
}
// 计算抽奖间隔时间(速度越快,间隔越小)
const intervalTime = 300 - (data.settings.lotterySpeed * 15);
// 设置抽奖循环
state.drawInterval = setInterval(() => {
let randomIndex;
if (data.settings.lotteryMode === 'sequential') {
// 预设顺序抽奖模式
randomIndex = state.sequentialDrawIndex % data.participants.length;
state.sequentialDrawIndex++;
} else {
// 单次循环抽奖模式
randomIndex = Math.floor(Math.random() * data.participants.length);
}
elements.lotteryName.textContent = data.participants[randomIndex];
}, intervalTime);
}
// 停止抽奖
function stopLottery() {
if (!state.isDrawing) return;
state.isDrawing = false;
clearInterval(state.drawInterval);
elements.startButton.classList.remove('hidden');
elements.stopButton.classList.add('hidden');
elements.lotteryName.classList.remove('lottery-animation');
// 停止抽奖音效
if (elements.drawSound) {
elements.drawSound.pause();
}
// 选择中奖者
const winners = selectWinners();
// 显示中奖者
displayWinners(winners);
// 播放中奖音效
if (data.settings.enableWinSound && elements.winSound) {
elements.winSound.currentTime = 0;
elements.winSound.play().catch(e => console.log('无法播放音效:', e));
}
// 添加特效
if (data.settings.enableFireworks) {
createFireworks();
createConfetti();
}
// 保存中奖记录
saveWinners(winners);
}
// 选择中奖者
function selectWinners() {
const winners = [];
let availableParticipants = [...data.participants];
// 计算领导必中人数 (50%的概率让领导必中,随机选择1-3名领导)
const shouldLeadersWin = Math.random() > 0.5 && data.leaders.length > 0;
let leadersToWin = [];
if (shouldLeadersWin) {
const leadersCount = Math.min(Math.floor(Math.random() * 3) + 1, data.leaders.length);
const shuffledLeaders = [...data.leaders].sort(() => Math.random() - 0.5);
// 从打乱的领导名单中选择指定数量
leadersToWin = shuffledLeaders.slice(0, leadersCount);
// 将选中的领导从可用参与者中移除
availableParticipants = availableParticipants.filter(participant =>
!leadersToWin.includes(participant)
);
}
// 计算普通参与者中奖人数
const normalWinnersCount = Math.max(0, data.settings.winnersCount - leadersToWin.length);
const totalWinnersCount = Math.min(data.settings.winnersCount, leadersToWin.length + availableParticipants.length);
// 添加领导中奖者
leadersToWin.forEach(name => {
winners.push({
name: name,
isLeader: true
});
});
// 添加普通参与者中奖者
for (let i = 0; i < normalWinnersCount && availableParticipants.length > 0; i++) {
const randomIndex = Math.floor(Math.random() * availableParticipants.length);
const isLeader = data.leaders.includes(availableParticipants[randomIndex]);
winners.push({
name: availableParticipants[randomIndex],
isLeader: isLeader
});
availableParticipants.splice(randomIndex, 1);
}
// 打乱中奖顺序(避免领导总是排在前面)
return winners.sort(() => Math.random() - 0.5);
}
// 显示中奖者
function displayWinners(winners) {
// 清空当前显示
elements.lotteryContainer.innerHTML = '';
// 创建中奖者显示容器
const winnersContainer = document.createElement('div');
winnersContainer.className = 'w-full h-full flex flex-col items-center justify-center p-6';
// 中奖标题
const title = document.createElement('h2');
title.className = 'text-3xl font-bold text-primary mb-8';
title.textContent = '恭喜中奖!';
winnersContainer.appendChild(title);
// 中奖者列表 - 横向排列
const winnersList = document.createElement('div');
winnersList.className = 'flex flex-wrap justify-center gap-6 w-full';
winners.forEach((winner, index) => {
const winnerCard = document.createElement('div');
winnerCard.className = `p-6 rounded-xl text-center ${winner.isLeader ? 'bg-secondary/20 border-2 border-secondary animate-float' : 'bg-white/80 border border-gray-200'} transition-all duration-300 max-w-[200px]`;
const name = document.createElement('div');
name.className = `text-[clamp(1.5rem,5vw,2.5rem)] font-bold mb-3 ${winner.isLeader ? 'text-secondary' : 'text-gray-800'}`;
name.textContent = winner.name;
winnerCard.appendChild(name);
// 如果是领导,添加特殊标识
if (winner.isLeader) {
const badge = document.createElement('div');
badge.className = 'inline-block bg-secondary text-white text-xs px-3 py-1 rounded-full';
badge.innerHTML = '<i class="fa fa-trophy mr-1"></i>特别奖';
winnerCard.appendChild(badge);
}
winnersList.appendChild(winnerCard);
});
winnersContainer.appendChild(winnersList);
// 返回按钮
const backButton = document.createElement('button');
backButton.className = 'mt-10 px-8 py-3 bg-gray-700 text-white rounded-lg hover:bg-gray-800 transition-colors text-lg';
backButton.innerHTML = '<i class="fa fa-arrow-left mr-2"></i>返回';
backButton.onclick = () => {
resetLotteryDisplay();
};
winnersContainer.appendChild(backButton);
// 添加到容器
elements.lotteryContainer.appendChild(winnersContainer);
}
// 重置抽奖显示
function resetLotteryDisplay() {
elements.lotteryContainer.innerHTML = '';
const nameElement = document.createElement('div');
nameElement.id = 'lotteryName';
nameElement.className = 'text-[clamp(3rem,10vw,6rem)] font-bold text-gray-800 text-center';
nameElement.textContent = '准备开始';
elements.lotteryContainer.appendChild(nameElement);
// 重新获取DOM引用
elements.lotteryName = document.getElementById('lotteryName');
}
// 保存中奖记录
function saveWinners(winners) {
const now = new Date();
const formattedTime = `${now.getFullYear()}-${String(now.getMonth() + 1).padStart(2, '0')}-${String(now.getDate()).padStart(2, '0')} ${String(now.getHours()).padStart(2, '0')}:${String(now.getMinutes()).padStart(2, '0')}:${String(now.getSeconds()).padStart(2, '0')}`;
winners.forEach(winner => {
data.winners.unshift({
name: winner.name,
time: formattedTime
});
});
saveData();
updateWinnersList();
}
// 创建烟花效果
function createFireworks() {
const colors = ['#FF6B6B', '#4ECDC4', '#45B7D1', '#96CEB4', '#FECA57', '#DDA0DD', '#98D8C8'];
for (let i = 0; i < 10; i++) {
setTimeout(() => {
const firework = document.createElement('div');
firework.className = 'firework';
// 随机位置
const x = Math.random() * window.innerWidth;
const y = Math.random() * window.innerHeight * 0.7;
firework.style.left = `${x}px`;
firework.style.top = `${y}px`;
// 随机颜色
const color = colors[Math.floor(Math.random() * colors.length)];
firework.style.backgroundColor = color;
document.body.appendChild(firework);
// 爆炸效果
setTimeout(() => {
createFireworkBurst(x, y, color);
document.body.removeChild(firework);
}, 500);
}, i * 200);
}
}
// 创建烟花爆炸效果
function createFireworkBurst(x, y, color) {
const particleCount = 30;
for (let i = 0; i < particleCount; i++) {
const particle = document.createElement('div');
particle.className = 'firework-burst';
// 设置位置
particle.style.left = `${x}px`;
particle.style.top = `${y}px`;
particle.style.backgroundColor = color;
// 计算随机方向和距离
const angle = Math.random() * Math.PI * 2;
const distance = Math.random() * 100 + 50;
const endX = Math.cos(angle) * distance;
const endY = Math.sin(angle) * distance;
// 添加动画
particle.style.transition = `transform ${Math.random() * 2 + 1}s ease-out, opacity 2s ease-out`;
// 添加到DOM
document.body.appendChild(particle);
// 触发重排
particle.offsetWidth;
// 应用变换
particle.style.transform = `translate(${endX}px, ${endY}px)`;
particle.style.opacity = '0';
// 移除粒子
setTimeout(() => {
document.body.removeChild(particle);
}, 2000);
}
}
// 创建彩纸效果
function createConfetti() {
const colors = ['#FF6B6B', '#4ECDC4', '#45B7D1', '#96CEB4', '#FECA57', '#DDA0DD', '#98D8C8'];
const confettiCount = 200;
for (let i = 0; i < confettiCount; i++) {
const confetti = document.createElement('div');
confetti.className = 'confetti';
// 随机位置
const x = Math.random() * window.innerWidth;
confetti.style.left = `${x}px`;
confetti.style.top = `${-20}px`;
// 随机颜色
const color = colors[Math.floor(Math.random() * colors.length)];
confetti.style.backgroundColor = color;
// 随机大小
const size = Math.random() * 10 + 5;
confetti.style.width = `${size}px`;
confetti.style.height = `${size}px`;
// 随机动画持续时间
const duration = Math.random() * 5 + 3;
confetti.style.animation = `falling ${duration}s linear forwards`;
// 随机旋转
const rotation = Math.random() * 360;
confetti.style.transform = `rotate(${rotation}deg)`;
document.body.appendChild(confetti);
// 移除彩纸
setTimeout(() => {
document.body.removeChild(confetti);
}, duration * 1000);
}
}
// 中奖名单播放功能
function playWinners() {
if (data.winners.length === 0) {
alert('暂无中奖记录!');
return;
}
// 清空当前显示
elements.lotteryContainer.innerHTML = '';
// 创建播放容器
const playContainer = document.createElement('div');
playContainer.className = 'w-full h-full flex flex-col items-center justify-center p-6';
// 标题
const title = document.createElement('h2');
title.className = 'text-3xl font-bold text-primary mb-8';
title.textContent = '中奖名单回放';
playContainer.appendChild(title);
// 中奖者列表容器
const winnersContainer = document.createElement('div');
winnersContainer.className = 'flex flex-wrap justify-center gap-6 w-full';
playContainer.appendChild(winnersContainer);
// 返回按钮
const backButton = document.createElement('button');
backButton.className = 'mt-10 px-8 py-3 bg-gray-700 text-white rounded-lg hover:bg-gray-800 transition-colors text-lg';
backButton.innerHTML = '<i class="fa fa-arrow-left mr-2"></i>返回';
backButton.onclick = () => {
resetLotteryDisplay();
};
playContainer.appendChild(backButton);
// 添加到容器
elements.lotteryContainer.appendChild(playContainer);
// 逐个显示中奖者
let currentIndex = 0;
const showNextWinner = () => {
if (currentIndex >= data.winners.length) return;
const winner = data.winners[currentIndex];
const isLeader = data.leaders.includes(winner.name);
const winnerCard = document.createElement('div');
winnerCard.className = `p-6 rounded-xl text-center ${isLeader ? 'bg-secondary/20 border-2 border-secondary animate-float' : 'bg-white/80 border border-gray-200'} transition-all duration-300 max-w-[200px] opacity-0`;
const name = document.createElement('div');
name.className = `text-[clamp(1.5rem,5vw,2.5rem)] font-bold mb-3 ${isLeader ? 'text-secondary' : 'text-gray-800'}`;
name.textContent = winner.name;
winnerCard.appendChild(name);
// 时间
const time = document.createElement('div');
time.className = 'text-sm text-gray-500 mb-3';
time.textContent = winner.time;
winnerCard.appendChild(time);
// 如果是领导,添加特殊标识
if (isLeader) {
const badge = document.createElement('div');
badge.className = 'inline-block bg-secondary text-white text-xs px-3 py-1 rounded-full';
badge.innerHTML = '<i class="fa fa-trophy mr-1"></i>特别奖';
winnerCard.appendChild(badge);
}
winnersContainer.appendChild(winnerCard);
// 淡入动画
setTimeout(() => {
winnerCard.style.opacity = '1';
winnerCard.style.transition = 'opacity 0.5s';
// 播放音效
if (data.settings.enableWinSound) {
elements.winSound.currentTime = 0;
elements.winSound.play().catch(e => console.log('无法播放音效:', e));
}
currentIndex++;
setTimeout(showNextWinner, 1000);
}, 100);
};
// 开始播放
showNextWinner();
}
// 添加参与者
function addParticipants() {
const input = elements.participantsInput.value.trim();
if (!input) return;
// 支持顿号分隔或每行一个格式
const names = input.split(/[、\n]+/).filter(name => name.trim());
// 去重添加
names.forEach(name => {
if (!data.participants.includes(name.trim())) {
data.participants.push(name.trim());
}
});
elements.participantsInput.value = '';
updateParticipantsList();
saveData();
}
// 添加领导
function addLeaders() {
const input = elements.leadersInput.value.trim();
if (!input) return;
// 支持顿号分隔或每行一个格式
const names = input.split(/[、\n]+/).filter(name => name.trim());
// 去重添加
names.forEach(name => {
if (!data.leaders.includes(name.trim())) {
data.leaders.push(name.trim());
}
});
elements.leadersInput.value = '';
updateLeadersList();
saveData();
}
// 移除参与者
function removeParticipant(index) {
data.participants.splice(index, 1);
updateParticipantsList();
saveData();
}
// 移除领导
function removeLeader(index) {
data.leaders.splice(index, 1);
updateLeadersList();
saveData();
}
// 清空中奖名单
function clearWinners() {
if (confirm('确定要清空中奖名单吗?此操作不可恢复。')) {
data.winners = [];
updateWinnersList();
saveData();
}
}
// 打印中奖名单
function printWinners() {
if (data.winners.length === 0) {
alert('暂无中奖记录!');
return;
}
// 创建临时打印窗口
const printWindow = window.open('', '_blank');
printWindow.document.write(`
<html>
<head>
<title>中奖名单 - 智能抽奖系统</title>
<style>
body { font-family: Arial, sans-serif; margin: 20px; }
h1 { text-align: center; color: #4F46E5; font-size: 28px; margin-bottom: 30px; }
.congrats { text-align: center; color: #7C3AED; font-size: 22px; margin-bottom: 40px; font-weight: bold; }
.winners-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(200px, 1fr)); gap: 20px; }
.winner-card { border: 1px solid #ddd; padding: 15px; border-radius: 8px; text-align: center; }
.winner-rank { background-color: #4F46E5; color: white; width: 40px; height: 40px; border-radius: 50%; display: flex; align-items: center; justify-content: center; margin: 0 auto 10px; font-weight: bold; font-size: 18px; }
.winner-name { font-weight: bold; font-size: 18px; margin-bottom: 5px; }
.winner-time { color: #666; font-size: 14px; }
.leader-card { background-color: #f0e6ff; border-color: #7C3AED; }
.leader-rank { background-color: #7C3AED; }
.leader-badge { display: inline-block; background-color: #7C3AED; color: white; font-size: 12px; padding: 2px 8px; border-radius: 10px; margin-top: 8px; }
</style>
</head>
<body>
<h1>中奖名单</h1>
<div class="congrats">恭喜中奖!</div>
<div class="winners-grid">
${data.winners.map((winner, index) => {
const isLeader = data.leaders.includes(winner.name);
return `
<div class="winner-card ${isLeader ? 'leader-card' : ''}">
<div class="winner-rank ${isLeader ? 'leader-rank' : ''}">${index + 1}</div>
<div class="winner-name">${winner.name}</div>
<div class="winner-time">${winner.time}</div>
${isLeader ? '<div class="leader-badge">特别奖</div>' : ''}
</div>
`;
}).join('')}
</div>
</body>
</html>
`);
printWindow.document.close();
printWindow.print();
}
// 加载示例参与者名单
function loadExampleParticipants() {
const exampleNames = '张小明、李华宇、王佳伟、赵俊杰、陈思远、杨光宇、刘天宇、黄佳乐、周星辰、吴子轩、郑宇航、钱文博、孙浩然、周雨泽、吴子豪、郑子涵、王梓晨、陈若曦、杨雨轩、黄文博、周梓轩、吴宇轩、郑浩然、陈思哲、杨明宇、黄梓晨、周文博、吴浩然、杨宇航、黄子涵、张宇航、李佳伟、王俊杰、赵文博、陈浩然、杨光宇、刘天宇、黄佳乐、周星辰、吴子轩、郑宇航、钱文博、孙浩然、周雨泽、吴子豪、郑子涵、王梓晨、陈若曦、杨雨轩';
elements.participantsInput.value = exampleNames;
}
// 更新背景
function updateBackground() {
const body = document.body;
// 移除所有背景相关的类和样式
body.className = body.className.replace(/bg-gradient-to-br.*?from-primary\/10 to-secondary\/10/, '');
body.style.backgroundImage = '';
body.style.backgroundSize = '';
body.style.backgroundPosition = '';
body.style.backgroundRepeat = '';
// 应用新背景
if (data.settings.backgroundMode === 'solid') {
// 纯色渐变背景
body.className = body.className.replace(/bg-gradient-to-br.*?from-primary\/10 to-secondary\/10/, '') + ' bg-gradient-to-br';
body.style.background = `linear-gradient(135deg, ${data.settings.backgroundColor}, ${data.settings.backgroundGradient})`;
} else {
// 图片背景
body.style.backgroundImage = `url('${data.settings.backgroundImage}')`;
body.style.backgroundSize = 'cover';
body.style.backgroundPosition = 'center';
body.style.backgroundRepeat = 'no-repeat';
}
}
// 保存数据到本地存储
function saveData() {
localStorage.setItem('lotteryParticipants', JSON.stringify(data.participants));
localStorage.setItem('lotteryLeaders', JSON.stringify(data.leaders));
localStorage.setItem('lotteryWinners', JSON.stringify(data.winners));
localStorage.setItem('lotterySettings', JSON.stringify(data.settings));
}
// 从本地存储加载数据
function loadData() {
// 加载参与者名单
const savedParticipants = localStorage.getItem('lotteryParticipants');
if (savedParticipants) {
try {
data.participants = JSON.parse(savedParticipants);
} catch (e) {
console.error('加载参与者名单失败:', e);
}
}
// 加载领导名单
const savedLeaders = localStorage.getItem('lotteryLeaders');
if (savedLeaders) {
try {
data.leaders = JSON.parse(savedLeaders);
} catch (e) {
console.error('加载领导名单失败:', e);
}
}
// 加载中奖记录
const savedWinners = localStorage.getItem('lotteryWinners');
if (savedWinners) {
try {
data.winners = JSON.parse(savedWinners);
} catch (e) {
console.error('加载中奖记录失败:', e);
}
}
// 加载设置
const savedSettings = localStorage.getItem('lotterySettings');
if (savedSettings) {
try {
const loadedSettings = JSON.parse(savedSettings);
// 合并设置,确保所有必要字段都存在
data.settings = {
...data.settings,
...loadedSettings,
// 确保backgroundImage字段存在
backgroundImage: loadedSettings.backgroundImage || 'https://picsum.photos/id/1067/1920/1080'
};
} catch (e) {
console.error('加载设置失败:', e);
}
}
}
// 删除全部参与者
function deleteAllParticipants() {
if (confirm('确定要删除所有参与者名单吗?此操作不可恢复。')) {
data.participants = [];
updateParticipantsList();
saveData();
}
}
// 删除全部领导
function deleteAllLeaders() {
if (confirm('确定要删除所有领导名单吗?此操作不可恢复。')) {
data.leaders = [];
updateLeadersList();
saveData();
}
}
// 绑定事件监听器
function bindEventListeners() {
// 抽奖控制
elements.startButton.addEventListener('click', startLottery);
elements.stopButton.addEventListener('click', stopLottery);
// 界面切换
elements.viewWinnersButton.addEventListener('click', () => {
elements.winnersScreen.classList.remove('hidden');
});
elements.backToMainButton.addEventListener('click', () => {
elements.winnersScreen.classList.add('hidden');
});
elements.manageNamesButton.addEventListener('click', () => {
elements.namesManagementScreen.classList.remove('hidden');
});
elements.backFromNamesButton.addEventListener('click', () => {
elements.namesManagementScreen.classList.add('hidden');
});
// 名单管理
elements.addParticipantsButton.addEventListener('click', addParticipants);
elements.addLeadersButton.addEventListener('click', addLeaders);
elements.clearParticipantsButton.addEventListener('click', () => {
elements.participantsInput.value = '';
});
elements.clearLeadersButton.addEventListener('click', () => {
elements.leadersInput.value = '';
});
elements.deleteAllParticipantsButton.addEventListener('click', deleteAllParticipants);
elements.deleteAllLeadersButton.addEventListener('click', deleteAllLeaders);
elements.loadExampleParticipantsButton.addEventListener('click', loadExampleParticipants);
// 中奖名单操作
elements.clearWinnersButton.addEventListener('click', clearWinners);
elements.printWinnersButton.addEventListener('click', printWinners);
// 设置操作
elements.closeSettingsButton.addEventListener('click', () => {
elements.settingsScreen.classList.add('hidden');
});
elements.saveSettingsButton.addEventListener('click', saveSettings);
elements.resetSettingsButton.addEventListener('click', resetSettings);
// 设置范围输入监听
elements.winnersCount.addEventListener('input', (e) => {
elements.winnersCountValue.textContent = e.target.value;
});
elements.lotterySpeed.addEventListener('input', (e) => {
elements.lotterySpeedValue.textContent = e.target.value;
});
elements.fontSize.addEventListener('input', (e) => {
elements.fontSizeValue.textContent = e.target.value;
// 实时预览字体大小
const fontSizeMultiplier = 0.5 + (parseInt(e.target.value) * 0.05);
elements.lotteryName.style.fontSize = `clamp(${2 * fontSizeMultiplier}rem, ${8 * fontSizeMultiplier}vw, ${5 * fontSizeMultiplier}rem)`;
});
// 背景模式变更监听
document.querySelectorAll('input[name="backgroundMode"]').forEach(radio => {
radio.addEventListener('change', (e) => {
if (e.target.checked) {
if (e.target.value === 'solid') {
elements.backgroundColorContainer.classList.remove('hidden');
elements.backgroundImageContainer.classList.add('hidden');
} else {
elements.backgroundColorContainer.classList.add('hidden');
elements.backgroundImageContainer.classList.remove('hidden');
}
}
});
});
// 右键菜单
document.addEventListener('contextmenu', (e) => {
e.preventDefault();
elements.contextMenu.style.top = `${e.clientY}px`;
elements.contextMenu.style.left = `${e.clientX}px`;
elements.contextMenu.classList.remove('hidden');
});
document.addEventListener('click', () => {
elements.contextMenu.classList.add('hidden');
});
document.querySelectorAll('.context-menu-item').forEach(item => {
item.addEventListener('click', (e) => {
elements.contextMenu.classList.add('hidden');
const action = e.currentTarget.getAttribute('data-action');
if (action === 'startLottery') startLottery();
else if (action === 'stopLottery') stopLottery();
else if (action === 'viewWinners') elements.winnersScreen.classList.remove('hidden');
else if (action === 'clearWinners') clearWinners();
else if (action === 'manageNames') elements.namesManagementScreen.classList.remove('hidden');
else if (action === 'settings') elements.settingsScreen.classList.remove('hidden');
});
});
// 键盘快捷键
document.addEventListener('keydown', (e) => {
// F11 全屏
if (e.key === 'F11') {
e.preventDefault();
if (!document.fullscreenElement) {
document.documentElement.requestFullscreen().catch(err => {
console.log(`全屏错误: ${err.message}`);
});
} else {
if (document.exitFullscreen) {
document.exitFullscreen();
}
}
}
// Enter 开始/停止抽奖
if (e.key === 'Enter') {
e.preventDefault();
if (state.isDrawing) {
stopLottery();
} else {
startLottery();
}
}
// Backspace 返回主窗口
if (e.key === 'Backspace') {
if (!elements.lotteryScreen.classList.contains('hidden')) {
resetLotteryDisplay();
} else if (!elements.winnersScreen.classList.contains('hidden')) {
elements.winnersScreen.classList.add('hidden');
} else if (!elements.namesManagementScreen.classList.contains('hidden')) {
elements.namesManagementScreen.classList.add('hidden');
} else if (!elements.settingsScreen.classList.contains('hidden')) {
elements.settingsScreen.classList.add('hidden');
}
}
// Alt+P 中奖名单播放
if (e.altKey && e.key === 'p') {
e.preventDefault();
playWinners();
}
// Alt+/ 呼出设置界面
if (e.altKey && e.key === '/') {
e.preventDefault();
elements.settingsScreen.classList.remove('hidden');
}
// 空格键 回放中奖结果
if (e.key === ' ') {
e.preventDefault();
playWinners();
}
});
}
// 全局函数暴露
window.removeParticipant = removeParticipant;
window.removeLeader = removeLeader;
window.startLottery = startLottery;
window.stopLottery = stopLottery;
window.playWinners = playWinners;
// 初始化应用
function init() {
// 加载数据
loadData();
// 更新显示
updateParticipantsList();
updateLeadersList();
updateWinnersList();
updateSettingsDisplay();
// 绑定事件监听器
bindEventListeners();
}
// 启动应用
document.addEventListener('DOMContentLoaded', init);
</script>
</body>
</html>
智能抽奖系统使用说明
🎯 系统简介
本智能抽奖系统是一个功能齐全、界面美观的抽奖工具,支持多种抽奖模式和自定义设置,特别包含了隐藏的领导必中功能。系统采用现代UI设计,响应式布局,确保在各种屏幕尺寸下都能完美展示。
✨ 核心功能
1. 显示设置
- 两种背景模式:支持纯色背景和壁纸背景,颜色和图片均可自定义
- 窗口文字自定义:可自定义主标题和副标题
- 字体大小调节:支持根据需要调整抽奖时显示的字体大小
2. 抽奖功能
- 两种抽奖模式:单次循环抽奖和预设顺序抽奖
- 中奖人数设置:可自定义每次抽奖的中奖人数
- 抽奖速度调节:支持快慢速调节,适应不同场景需求
- 音效系统:抽奖和中奖时播放不同音效,提升氛围
- 视觉特效:包含烟花和彩纸特效,增强庆祝效果
3. 名单管理
- 参与者管理:支持添加、修改、删除参与者名单
- 领导名单设置:支持设置领导名单,可配置领导必中功能
- 多种导入格式:支持顿号分隔或每行一个的名单导入格式
- 数据持久化:所有名单和设置自动保存到本地存储
4. 中奖记录
- 自动保存:每次抽奖结果自动保存
- 记录查看:可查看所有中奖历史记录
- 清空功能:支持清空所有中奖记录
- 打印输出:支持将中奖名单打印出来
5. 隐藏功能
- 领导必中名单:可设置领导必中功能,支持全部领导必中或随机部分领导必中
- 隐蔽操作模式:通过快捷键隐藏呼出设置界面
6. 便捷操作
- 右键菜单:右键点击界面可快速访问常用功能
- 快捷键支持:丰富的快捷键操作,提升使用效率
- 全屏显示:支持全屏模式,适合投影演示
⌨️ 快捷键列表
| 快捷键 |
功能描述 |
| F11 |
全屏切换 |
| Enter |
开始/停止抽奖 |
| 空格键 |
当次中奖结果回放 |
| Backspace |
返回主窗口 |
| Alt+P |
中奖名单播放 |
| Alt+/ |
呼出设置界面 |
📁 名单导入格式
系统支持两种名单导入格式:
-
顿号分隔格式:
张三、李四、王五、赵六
-
每行一个格式:
张三
李四
王五
赵六
🚀 使用步骤
- 准备名单:在名单管理中添加参与者和领导名单
- 系统设置:通过右键菜单或Alt+/快捷键进入设置界面,配置抽奖参数
- 开始抽奖:点击开始按钮或按Enter键开始抽奖
- 停止抽奖:点击停止按钮或按Enter键停止抽奖,显示中奖结果
- 查看记录:点击"中奖名单"按钮查看所有中奖记录
💡 使用提示
- 每次正式抽奖前,建议先清空中奖名单,避免旧记录影响结果
- 使用领导必中功能时,请先在名单管理中添加领导名单
- 背景图片支持本地图片上传或网络图片URL
- 所有设置和数据会自动保存,刷新页面不会丢失
- 空格键可在中奖人数较多时自动翻页显示
🎨 界面预览
系统采用现代化UI设计,包含主抽奖界面、名单管理界面、中奖名单界面和设置界面,所有界面均支持响应式布局,适配各种屏幕尺寸。
🔧 技术说明
- 基于HTML5、CSS3和JavaScript开发
- 使用Tailwind CSS实现响应式布局和现代化UI
- 使用Font Awesome提供图标支持
- 通过localStorage实现本地数据持久化
- 纯前端实现,无需后端服务器支持
📋 注意事项
- 为获得最佳体验,请使用现代浏览器(Chrome、Firefox、Edge等)
- 如需投影显示,建议使用全屏模式(F11)
- 领导必中功能为隐藏功能,请合理使用
- 本系统仅供内部活动使用,请勿用于商业用途
希望本智能抽奖系统能为您的活动增添乐趣!
|
免费评分
-
查看全部评分
|