好友
阅读权限10
听众
最后登录1970-1-1
|
飞个天高
发表于 2026-1-17 11:23
在楼主的基础上把每个奖项都增加了礼品设置,中奖的时候能够直接抽中相应的礼品。
<!DOCTYPE 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);
}
}
@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, .firework, .firework-burst {
position: fixed;
pointer-events: none;
z-index: 9999;
}
.firework {
width: 10px;
height: 10px;
border-radius: 50%;
}
.firework-burst {
width: 5px;
height: 5px;
border-radius: 50%;
}
</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 id="awardInfo" class="mb-6 text-xl font-bold text-primary hidden">
<span id="currentAwardName">一等奖</span> - 第<span id="currentRound">1</span>轮
</div>
<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 id="awardsList" class="mb-6 space-y-4">
<!-- 奖项将在这里动态生成 -->
</div>
<div class="flex flex-wrap gap-2">
<button id="addAwardButton" 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="resetAwardsButton" class="px-4 py-2 bg-gray-200 hover:bg-gray-300 text-gray-700 rounded-lg transition-colors">
<i class="fa fa-refresh mr-2"></i>重置奖项
</button>
</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">抽奖速度: <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="allowRepeat" 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="noRepeat" 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 class="mt-4">
<button id="resetAlreadyWonButton" class="px-4 py-2 bg-orange-500 hover:bg-orange-600 text-white rounded-lg transition-colors text-sm">
<i class="fa fa-refresh mr-2"></i>重置已中奖名单
</button>
<div class="text-xs text-gray-400 mt-1">仅重置不可重复中奖模式的已中奖限制</div>
</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: [], // 中奖记录
awards: [
{
id: 1,
name: "一等奖",
total: 5,
perRound: 1,
currentRound: 1,
drawnCount: 0,
gifts: [
{ id: 1, name: "iPhone 16", count: 2, remaining: 2 },
{ id: 2, name: "MacBook Air", count: 2, remaining: 2 },
{ id: 3, name: "iPad Pro", count: 1, remaining: 1 }
]
},
{
id: 2,
name: "二等奖",
total: 15,
perRound: 5,
currentRound: 1,
drawnCount: 0,
gifts: [
{ id: 4, name: "AirPods Pro", count: 10, remaining: 10 },
{ id: 5, name: "Apple Watch", count: 5, remaining: 5 }
]
},
{
id: 3,
name: "三等奖",
total: 30,
perRound: 10,
currentRound: 1,
drawnCount: 0,
gifts: [
{ id: 6, name: "无线充电器", count: 15, remaining: 15 },
{ id: 7, name: "蓝牙音箱", count: 10, remaining: 10 },
{ id: 8, name: "运动耳机", count: 5, remaining: 5 }
]
}
], // 奖项设置
currentAwardIndex: 0, // 当前抽奖的奖项索引
settings: {
lotterySpeed: 5, // 抽奖速度(1-10,10最快)
fontSize: 10, // 字体大小(1-20,10正常)
lotteryMode: 'allowRepeat', // 抽奖模式:allowRepeat允许重复中奖,noRepeat不允许重复中奖
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, // 抽奖定时器
alreadyWonParticipants: [] // 已中奖的参与者(用于不可重复中奖模式)
};
// DOM元素引用对象
const elements = {};
// 工具函数:安全访问元素
function safeElement(elementName) {
return elements[elementName] || null;
}
// 初始化DOM元素引用
function initializeElements() {
// 主界面元素
elements.lotteryScreen = document.getElementById('lotteryScreen');
elements.mainTitle = document.getElementById('mainTitle');
elements.subtitle = document.getElementById('subtitle');
elements.lotteryContainer = document.getElementById('lotteryContainer');
elements.lotteryName = document.getElementById('lotteryName');
elements.startButton = document.getElementById('startButton');
elements.stopButton = document.getElementById('stopButton');
elements.viewWinnersButton = document.getElementById('viewWinnersButton');
elements.manageNamesButton = document.getElementById('manageNamesButton');
elements.awardInfo = document.getElementById('awardInfo');
elements.currentAwardName = document.getElementById('currentAwardName');
elements.currentRound = document.getElementById('currentRound');
// 中奖名单界面元素
elements.winnersScreen = document.getElementById('winnersScreen');
elements.backToMainButton = document.getElementById('backToMainButton');
elements.winnersList = document.getElementById('winnersList');
elements.clearWinnersButton = document.getElementById('clearWinnersButton');
elements.printWinnersButton = document.getElementById('printWinnersButton');
// 名单管理界面元素
elements.namesManagementScreen = document.getElementById('namesManagementScreen');
elements.backFromNamesButton = document.getElementById('backFromNamesButton');
elements.participantsInput = document.getElementById('participantsInput');
elements.participantsList = document.getElementById('participantsList');
elements.participantsCount = document.getElementById('participantsCount');
elements.addParticipantsButton = document.getElementById('addParticipantsButton');
elements.clearParticipantsButton = document.getElementById('clearParticipantsButton');
elements.deleteAllParticipantsButton = document.getElementById('deleteAllParticipantsButton');
elements.loadExampleParticipantsButton = document.getElementById('loadExampleParticipantsButton');
elements.leadersInput = document.getElementById('leadersInput');
elements.leadersList = document.getElementById('leadersList');
elements.leadersCount = document.getElementById('leadersCount');
elements.addLeadersButton = document.getElementById('addLeadersButton');
elements.clearLeadersButton = document.getElementById('clearLeadersButton');
elements.deleteAllLeadersButton = document.getElementById('deleteAllLeadersButton');
// 设置界面元素
elements.settingsScreen = document.getElementById('settingsScreen');
elements.closeSettingsButton = document.getElementById('closeSettingsButton');
elements.saveSettingsButton = document.getElementById('saveSettingsButton');
elements.resetSettingsButton = document.getElementById('resetSettingsButton');
elements.lotterySpeed = document.getElementById('lotterySpeed');
elements.lotterySpeedValue = document.getElementById('lotterySpeedValue');
elements.fontSize = document.getElementById('fontSize');
elements.fontSizeValue = document.getElementById('fontSizeValue');
elements.titleInput = document.getElementById('titleInput');
elements.subtitleInput = document.getElementById('subtitleInput');
elements.backgroundColor = document.getElementById('backgroundColor');
elements.backgroundGradient = document.getElementById('backgroundGradient');
elements.backgroundColorContainer = document.getElementById('backgroundColorContainer');
elements.backgroundImage = document.getElementById('backgroundImage');
elements.backgroundImageContainer = document.getElementById('backgroundImageContainer');
elements.enableDrawSound = document.getElementById('enableDrawSound');
elements.enableWinSound = document.getElementById('enableWinSound');
elements.enableFireworks = document.getElementById('enableFireworks');
elements.awardsList = document.getElementById('awardsList');
elements.addAwardButton = document.getElementById('addAwardButton');
elements.resetAwardsButton = document.getElementById('resetAwardsButton');
elements.resetAlreadyWonButton = document.getElementById('resetAlreadyWonButton');
// 右键菜单
elements.contextMenu = document.getElementById('contextMenu');
// 音效元素
elements.drawSound = document.getElementById('drawSound');
elements.winSound = document.getElementById('winSound');
}
// 更新设置显示
function updateSettingsDisplay() {
if (!elements.lotterySpeed || !elements.fontSize) {
return;
}
elements.lotterySpeed.value = data.settings.lotterySpeed;
elements.lotterySpeedValue.textContent = data.settings.lotterySpeed;
elements.fontSize.value = data.settings.fontSize;
elements.fontSizeValue.textContent = data.settings.fontSize;
if (elements.titleInput) elements.titleInput.value = data.settings.mainTitle;
if (elements.subtitleInput) elements.subtitleInput.value = data.settings.subtitle;
if (elements.backgroundColor) elements.backgroundColor.value = data.settings.backgroundColor;
if (elements.backgroundGradient) elements.backgroundGradient.value = data.settings.backgroundGradient;
if (elements.backgroundImage) elements.backgroundImage.value = data.settings.backgroundImage;
if (elements.enableDrawSound) elements.enableDrawSound.checked = data.settings.enableDrawSound;
if (elements.enableWinSound) elements.enableWinSound.checked = data.settings.enableWinSound;
if (elements.enableFireworks) elements.enableFireworks.checked = data.settings.enableFireworks;
// 设置抽奖模式
const lotteryModeRadio = document.querySelector(`input[name="lotteryMode"][value="${data.settings.lotteryMode}"]`);
if (lotteryModeRadio) lotteryModeRadio.checked = true;
// 设置背景模式
const backgroundModeRadio = document.querySelector(`input[name="backgroundMode"][value="${data.settings.backgroundMode}"]`);
if (backgroundModeRadio) backgroundModeRadio.checked = true;
// 更新背景模式相关UI
if (elements.backgroundColorContainer && elements.backgroundImageContainer) {
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();
// 应用标题
if (elements.mainTitle) elements.mainTitle.textContent = data.settings.mainTitle;
if (elements.subtitle) elements.subtitle.textContent = data.settings.subtitle;
// 应用字体大小
if (elements.lotteryName) {
const fontSizeMultiplier = 0.5 + (data.settings.fontSize * 0.05);
elements.lotteryName.style.fontSize = `clamp(${2 * fontSizeMultiplier}rem, ${8 * fontSizeMultiplier}vw, ${5 * fontSizeMultiplier}rem)`;
}
// 更新奖项列表
updateAwardsList();
}
// 更新奖项列表
function updateAwardsList() {
if (!elements.awardsList) {
return;
}
elements.awardsList.innerHTML = '';
if (data.awards.length === 0) {
elements.awardsList.innerHTML = '<p class="text-gray-400 text-sm">暂无奖项设置</p>';
return;
}
data.awards.forEach((award, index) => {
const awardItem = document.createElement('div');
awardItem.className = 'bg-white p-4 rounded-lg border border-gray-200';
// 计算总人数(所有礼品数量之和)
const totalCount = award.gifts.reduce((sum, gift) => sum + gift.count, 0);
awardItem.innerHTML = `
<div class="flex justify-between items-center mb-3">
<input type="text" value="${award.name}" class="award-name w-full p-2 border border-gray-300 rounded font-bold text-lg" data-index="${index}" placeholder="奖项名称">
<button class="text-red-500 hover:text-red-700 ml-2">
<i class="fa fa-trash"></i>
</button>
</div>
<!-- 礼品设置区域 -->
<div class="mb-4">
<div class="flex justify-between items-center mb-2">
<h4 class="font-semibold text-gray-700">礼品设置</h4>
<button class="text-primary hover:text-primary/80 text-sm flex items-center">
<i class="fa fa-plus mr-1"></i>添加礼品
</button>
</div>
<!-- 礼品列表 -->
<div class="space-y-3">
`;
// 显示所有礼品
award.gifts.forEach((gift, giftIndex) => {
const giftItemHTML = `
<div class="flex gap-3">
<input type="text" value="${gift.name}" class="gift-name flex-1 p-2 border border-gray-300 rounded" data-award-index="${index}" data-gift-index="${giftIndex}" placeholder="礼品名称">
<input type="number" min="1" value="${gift.count}" class="gift-count w-24 p-2 border border-gray-300 rounded" data-award-index="${index}" data-gift-index="${giftIndex}" placeholder="数量">
<button class="text-red-500 hover:text-red-700 flex items-center">
<i class="fa fa-times"></i>
</button>
</div>
`;
awardItem.innerHTML += giftItemHTML;
});
// 添加剩余的HTML结构
awardItem.innerHTML += `
</div>
</div>
<!-- 奖项统计信息 -->
<div class="grid grid-cols-1 md:grid-cols-3 gap-4">
<div>
<label class="block text-sm text-gray-700 mb-1">总人数(自动计算)</label>
<div class="p-2 bg-green-50 border border-green-200 rounded text-center font-medium">${totalCount}人</div>
</div>
<div>
<label class="block text-sm text-gray-700 mb-1">每轮人数</label>
<input type="number" min="1" value="${award.perRound}" class="award-per-round w-full p-2 border border-gray-300 rounded" data-index="${index}">
</div>
<div>
<label class="block text-sm text-gray-700 mb-1">已抽取</label>
<div class="p-2 bg-gray-100 rounded text-center">${award.drawnCount}/${totalCount}</div>
</div>
</div>
`;
elements.awardsList.appendChild(awardItem);
});
}
// 添加礼品
function addGift(awardIndex) {
const newGift = {
id: Date.now(),
name: `礼品${data.awards[awardIndex].gifts.length + 1}`,
count: 1,
remaining: 1
};
data.awards[awardIndex].gifts.push(newGift);
updateAwardsList();
}
// 删除礼品
function removeGift(awardIndex, giftIndex) {
if (data.awards[awardIndex].gifts.length <= 1) {
alert('每个奖项至少需要一个礼品');
return;
}
data.awards[awardIndex].gifts.splice(giftIndex, 1);
updateAwardsList();
}
// 添加奖项
function addAward() {
const newAward = {
id: Date.now(),
name: `奖项${data.awards.length + 1}`,
total: 5,
perRound: 1,
currentRound: 1,
drawnCount: 0,
gifts: [
{ id: Date.now(), name: `礼品${data.awards.length + 1}-1`, count: 3, remaining: 3 },
{ id: Date.now() + 1, name: `礼品${data.awards.length + 1}-2`, count: 2, remaining: 2 }
]
};
data.awards.push(newAward);
updateAwardsList();
}
// 移除奖项
function removeAward(index) {
if (confirm(`确定要删除"${data.awards[index].name}"吗?`)) {
data.awards.splice(index, 1);
updateAwardsList();
}
}
// 重置奖项
function resetAwards() {
if (confirm('确定要重置所有奖项吗?当前奖项设置将被清除。')) {
data.awards = [
{
id: 1,
name: "一等奖",
total: 5,
perRound: 1,
currentRound: 1,
drawnCount: 0,
gifts: [
{ id: 1, name: "iPhone 16", count: 2, remaining: 2 },
{ id: 2, name: "MacBook Air", count: 2, remaining: 2 },
{ id: 3, name: "iPad Pro", count: 1, remaining: 1 }
]
},
{
id: 2,
name: "二等奖",
total: 15,
perRound: 5,
currentRound: 1,
drawnCount: 0,
gifts: [
{ id: 4, name: "AirPods Pro", count: 10, remaining: 10 },
{ id: 5, name: "Apple Watch", count: 5, remaining: 5 }
]
},
{
id: 3,
name: "三等奖",
total: 30,
perRound: 10,
currentRound: 1,
drawnCount: 0,
gifts: [
{ id: 6, name: "无线充电器", count: 15, remaining: 15 },
{ id: 7, name: "蓝牙音箱", count: 10, remaining: 10 },
{ id: 8, name: "运动耳机", count: 5, remaining: 5 }
]
}
];
updateAwardsList();
}
}
// 保存设置
function saveSettings() {
try {
// 获取基本设置
data.settings.lotterySpeed = parseInt(elements.lotterySpeed?.value) || 5;
data.settings.fontSize = parseInt(elements.fontSize?.value) || 10;
// 获取抽奖模式
const lotteryModeElement = document.querySelector('input[name="lotteryMode"]:checked');
data.settings.lotteryMode = lotteryModeElement?.value || 'allowRepeat';
// 获取标题设置
data.settings.mainTitle = elements.titleInput?.value || '智能抽奖系统';
data.settings.subtitle = elements.subtitleInput?.value || '点击开始按钮或按Enter键开始抽奖';
// 获取背景设置
const backgroundModeElement = document.querySelector('input[name="backgroundMode"]:checked');
data.settings.backgroundMode = backgroundModeElement?.value || 'solid';
data.settings.backgroundColor = elements.backgroundColor?.value || '#4F46E5';
data.settings.backgroundGradient = elements.backgroundGradient?.value || '#7C3AED';
data.settings.backgroundImage = elements.backgroundImage?.value || 'https://picsum.photos/id/1067/1920/1080';
// 获取特效设置
data.settings.enableDrawSound = elements.enableDrawSound?.checked ?? true;
data.settings.enableWinSound = elements.enableWinSound?.checked ?? true;
data.settings.enableFireworks = elements.enableFireworks?.checked ?? true;
// 保存奖项设置
saveAwardsSettings();
// 应用设置
updateSettingsDisplay();
// 保存到本地存储
saveData();
// 关闭设置界面
if (elements.settingsScreen) {
elements.settingsScreen.classList.add('hidden');
}
alert('设置已保存!');
} catch (error) {
console.error('保存设置失败:', error);
alert('保存设置失败,请重试');
}
}
// 保存奖项设置
function saveAwardsSettings() {
// 保存奖项名称和每轮人数
const awardNameInputs = document.querySelectorAll('.award-name');
const awardPerRoundInputs = document.querySelectorAll('.award-per-round');
awardNameInputs.forEach((input, index) => {
if (data.awards[index]) {
data.awards[index].name = input.value || `奖项${index + 1}`;
}
});
// 保存礼品信息
const giftNameInputs = document.querySelectorAll('.gift-name');
const giftCountInputs = document.querySelectorAll('.gift-count');
// 按奖项分组保存礼品
const awardsGiftMap = {};
// 遍历所有礼品输入框
giftNameInputs.forEach((nameInput, inputIndex) => {
const awardIndex = parseInt(nameInput.getAttribute('data-award-index'));
const giftIndex = parseInt(nameInput.getAttribute('data-gift-index'));
if (!awardsGiftMap[awardIndex]) {
awardsGiftMap[awardIndex] = [];
}
// 获取礼品名称和数量
const giftName = nameInput.value || `礼品${giftIndex + 1}`;
const giftCount = Math.max(1, parseInt(giftCountInputs[inputIndex]?.value) || 1);
awardsGiftMap[awardIndex][giftIndex] = {
name: giftName,
count: giftCount
};
});
// 更新奖项信息
Object.keys(awardsGiftMap).forEach(awardIndexStr => {
const awardIndex = parseInt(awardIndexStr);
if (data.awards[awardIndex]) {
// 更新礼品列表
const giftDatas = awardsGiftMap[awardIndex];
const updatedGifts = [];
giftDatas.forEach((giftData, giftIndex) => {
// 如果礼品已存在,更新信息;否则创建新礼品
const existingGift = data.awards[awardIndex].gifts[giftIndex];
const gift = {
id: existingGift?.id || Date.now(),
name: giftData.name,
count: giftData.count,
remaining: existingGift?.remaining || giftData.count
};
updatedGifts.push(gift);
});
data.awards[awardIndex].gifts = updatedGifts;
// 自动计算总人数(所有礼品数量之和)
const totalCount = updatedGifts.reduce((sum, gift) => sum + gift.count, 0);
data.awards[awardIndex].total = totalCount;
// 确保每轮人数不超过总人数
const perRoundInput = awardPerRoundInputs[awardIndex];
if (perRoundInput) {
let perRound = Math.max(1, parseInt(perRoundInput.value) || 1);
perRound = Math.min(perRound, totalCount);
data.awards[awardIndex].perRound = perRound;
perRoundInput.value = perRound; // 更新输入框显示
}
}
});
}
// 重置设置
function resetSettings() {
if (confirm('确定要重置所有设置吗?')) {
// 重置为默认设置
data.settings = {
lotterySpeed: 5,
fontSize: 10,
lotteryMode: 'allowRepeat',
enableDrawSound: true,
enableWinSound: true,
enableFireworks: true,
mainTitle: '智能抽奖系统',
subtitle: '点击开始按钮或按Enter键开始抽奖',
backgroundMode: 'solid',
backgroundColor: '#4F46E5',
backgroundGradient: '#7C3AED',
backgroundImage: 'https://picsum.photos/id/1067/1920/1080'
};
// 重置奖项
resetAwards();
// 更新显示
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">
${data.winners.length - 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>
<p class="text-sm text-gray-500 mt-1">${winner.award} - 第${winner.round}轮</p>
<p class="text-sm font-medium text-primary mt-2">获得: ${winner.gift}</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 || data.participants.length === 0) {
alert('请先添加参与者名单!');
return;
}
if (!data.awards || data.awards.length === 0) {
alert('请先设置奖项!');
return;
}
// 检查是否还有未完成的奖项
let currentAward = data.awards[data.currentAwardIndex];
if (!currentAward) {
alert('所有奖项已抽完!');
return;
}
// 检查当前奖项是否已抽完
if (currentAward.drawnCount >= currentAward.total) {
// 当前奖项已抽完,切换到下一个奖项
data.currentAwardIndex++;
currentAward = data.awards[data.currentAwardIndex];
if (!currentAward) {
alert('所有奖项已抽完!');
return;
}
currentAward.currentRound = 1;
}
// 对于不可重复中奖模式,检查是否还有可用参与者
if (data.settings.lotteryMode === 'noRepeat') {
const availableParticipants = data.participants.filter(name => !state.alreadyWonParticipants.includes(name));
if (availableParticipants.length === 0) {
if (confirm('所有参与者已中奖,是否重置中奖名单并继续抽奖?')) {
state.alreadyWonParticipants = [];
} else {
return;
}
}
}
// 重置抽奖显示,确保第二次点击抽奖时能直接回到滚动效果
resetLotteryDisplay();
// 检查必要的元素
if (!elements.startButton || !elements.stopButton || !elements.lotteryName) {
alert('系统初始化未完成,请刷新页面后重试');
return;
}
state.isDrawing = true;
elements.startButton.classList.add('hidden');
elements.stopButton.classList.remove('hidden');
elements.lotteryName.classList.add('lottery-animation');
if (elements.awardInfo) {
elements.awardInfo.classList.remove('hidden');
}
// 更新奖项信息显示
updateAwardInfo();
// 停止获奖音效并重置其状态
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 = Math.max(50, 300 - (data.settings.lotterySpeed * 25));
// 设置抽奖循环
state.drawInterval = setInterval(() => {
// 根据抽奖模式决定可用的参与者
let availableParticipants;
if (data.settings.lotteryMode === 'noRepeat') {
// 不可重复中奖模式:排除已中奖的参与者
availableParticipants = data.participants.filter(name => !state.alreadyWonParticipants.includes(name));
} else {
// 可以重复中奖模式:所有参与者都可用
availableParticipants = [...data.participants];
}
// 随机选取一个参与者显示
if (availableParticipants.length > 0) {
const randomIndex = Math.floor(Math.random() * availableParticipants.length);
elements.lotteryName.textContent = availableParticipants[randomIndex];
} else {
// 没有可用参与者时显示原始名单
const 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 result = selectWinners();
const winners = result.winners;
const awardIndex = result.awardIndex;
const displayRound = result.displayRound;
// 显示中奖者
displayWinners(winners, awardIndex, displayRound);
// 播放中奖音效
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);
// 更新奖项信息
updateAwardInfo();
}
// 更新奖项信息
function updateAwardInfo() {
const currentAward = data.awards[data.currentAwardIndex];
if (currentAward) {
elements.currentAwardName.textContent = currentAward.name;
elements.currentRound.textContent = currentAward.currentRound;
elements.awardInfo.classList.remove('hidden');
// 显示剩余人数信息
const remaining = currentAward.total - currentAward.drawnCount;
if (remaining > 0) {
elements.awardInfo.innerHTML = `
<span id="currentAwardName">${currentAward.name}</span> -
第<span id="currentRound">${currentAward.currentRound}</span>轮
<span class="text-sm ml-2">(剩余${remaining}人)</span>
`;
} else {
elements.awardInfo.innerHTML = `
<span id="currentAwardName">${currentAward.name}</span> -
已完成
`;
}
} else {
elements.awardInfo.innerHTML = '<span>所有奖项已完成</span>';
}
}
// 选择中奖者
function selectWinners() {
const currentAward = data.awards[data.currentAwardIndex];
if (!currentAward) return {winners: [], awardIndex: -1, displayRound: 1};
const winners = [];
// 根据抽奖模式决定可用的参与者
let availableParticipants;
if (data.settings.lotteryMode === 'noRepeat') {
// 不可重复中奖模式:排除已中奖的参与者
availableParticipants = data.participants.filter(name => !state.alreadyWonParticipants.includes(name));
// 如果没有可用参与者,使用全部参与者(防止出错)
if (availableParticipants.length === 0) {
availableParticipants = [...data.participants];
}
} else {
// 可以重复中奖模式:所有参与者都可用
availableParticipants = [...data.participants];
}
// 计算领导必中人数 (50%的概率让领导必中,随机选择1-3名领导)
const shouldLeadersWin = Math.random() > 0.5 && data.leaders.length > 0;
let leadersToWin = [];
if (shouldLeadersWin) {
// 限制领导中奖人数不超过每轮设置的人数
const maxLeaders = Math.min(currentAward.perRound, data.leaders.length);
const leadersCount = Math.min(Math.floor(Math.random() * 3) + 1, maxLeaders);
// 在不可重复中奖模式下,过滤已中奖的领导
let availableLeaders;
if (data.settings.lotteryMode === 'noRepeat') {
availableLeaders = data.leaders.filter(name => !state.alreadyWonParticipants.includes(name));
} else {
availableLeaders = [...data.leaders];
}
// 从可用领导中随机选择
if (availableLeaders.length > 0) {
const shuffledLeaders = [...availableLeaders].sort(() => Math.random() - 0.5);
leadersToWin = shuffledLeaders.slice(0, Math.min(leadersCount, availableLeaders.length));
}
// 将选中的领导从可用参与者中移除
availableParticipants = availableParticipants.filter(participant =>
!leadersToWin.includes(participant)
);
}
// 计算普通参与者中奖人数,确保总人数不超过每轮设置的人数
const normalWinnersCount = Math.min(
currentAward.perRound - leadersToWin.length,
availableParticipants.length
);
// 记录当前轮次用于显示
const displayRound = currentAward.currentRound;
// 随机选择礼品的函数
function getRandomGift(award) {
// 过滤出有剩余数量的礼品
const availableGifts = award.gifts.filter(gift => gift.remaining > 0);
if (availableGifts.length === 0) {
// 如果所有礼品都已抽完,返回第一个礼品
return award.gifts[0] || { name: '未知礼品', count: 0, remaining: 0 };
}
// 随机选择一个礼品
const randomIndex = Math.floor(Math.random() * availableGifts.length);
return availableGifts[randomIndex];
}
// 添加领导中奖者
leadersToWin.forEach(name => {
// 随机选择礼品
const randomGift = getRandomGift(currentAward);
winners.push({
name: name,
isLeader: true,
award: currentAward.name,
round: displayRound,
gift: randomGift.name
});
// 在不可重复中奖模式下,将中奖者添加到已中奖名单
if (data.settings.lotteryMode === 'noRepeat') {
if (!state.alreadyWonParticipants.includes(name)) {
state.alreadyWonParticipants.push(name);
}
}
// 减少礼品剩余数量
if (randomGift.remaining > 0) {
randomGift.remaining--;
}
});
// 添加普通参与者中奖者
for (let i = 0; i < normalWinnersCount && availableParticipants.length > 0; i++) {
const randomIndex = Math.floor(Math.random() * availableParticipants.length);
const winnerName = availableParticipants[randomIndex];
const isLeader = data.leaders.includes(winnerName);
// 随机选择礼品
const randomGift = getRandomGift(currentAward);
winners.push({
name: winnerName,
isLeader: isLeader,
award: currentAward.name,
round: displayRound,
gift: randomGift.name
});
// 在不可重复中奖模式下,将中奖者添加到已中奖名单
if (data.settings.lotteryMode === 'noRepeat') {
if (!state.alreadyWonParticipants.includes(winnerName)) {
state.alreadyWonParticipants.push(winnerName);
}
}
// 减少礼品剩余数量
if (randomGift.remaining > 0) {
randomGift.remaining--;
}
// 从可用参与者中移除(避免同一轮中重复中奖)
availableParticipants.splice(randomIndex, 1);
}
// 保存当前奖项索引,用于显示中奖者
const displayAwardIndex = data.currentAwardIndex;
// 更新奖项状态
currentAward.drawnCount += winners.length;
// 计算下一轮次
if (currentAward.drawnCount >= currentAward.total) {
// 当前奖项已抽完,准备切换到下一个奖项
currentAward.currentRound = 1;
data.currentAwardIndex++;
} else {
// 当前奖项未抽完,递增轮次
currentAward.currentRound++;
}
// 更新奖项列表显示
updateAwardsList();
// 打乱中奖顺序(避免领导总是排在前面)
const shuffledWinners = winners.sort(() => Math.random() - 0.5);
// 返回中奖者和显示信息
return {
winners: shuffledWinners,
awardIndex: displayAwardIndex,
displayRound: displayRound
};
}
// 显示中奖者
function displayWinners(winners, awardIndex, displayRound) {
// 清空当前显示
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-4';
title.textContent = '恭喜中奖!';
winnersContainer.appendChild(title);
// 当前奖项信息 - 使用传入的奖项索引和轮次
const currentAward = data.awards[awardIndex];
const awardInfo = document.createElement('p');
awardInfo.className = 'text-xl text-gray-600 mb-8';
// 直接使用传入的轮次
awardInfo.textContent = `${currentAward.name} - 第${displayRound}轮`;
winnersContainer.appendChild(awardInfo);
// 如果没有中奖者,显示提示信息
if (winners.length === 0) {
const noWinnerMessage = document.createElement('div');
noWinnerMessage.className = 'text-2xl text-gray-500 mb-8';
noWinnerMessage.textContent = '本轮没有中奖者';
winnersContainer.appendChild(noWinnerMessage);
} else {
// 中奖者列表 - 横向排列
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-2 ${winner.isLeader ? 'text-secondary' : 'text-gray-800'}`;
name.textContent = winner.name;
winnerCard.appendChild(name);
// 礼品信息
const gift = document.createElement('div');
gift.className = `text-sm font-medium mb-3 ${winner.isLeader ? 'text-secondary' : 'text-primary'}`;
gift.textContent = `获得: ${winner.gift}`;
winnerCard.appendChild(gift);
// 如果是领导,添加特殊标识
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();
// 更新奖项信息
updateAwardInfo();
};
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,
award: winner.award,
round: winner.round,
gift: winner.gift
});
});
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-2 ${isLeader ? 'text-secondary' : 'text-gray-800'}`;
name.textContent = winner.name;
winnerCard.appendChild(name);
// 编号
const rank = document.createElement('div');
rank.className = `w-12 h-12 rounded-full flex items-center justify-center mb-3 text-lg font-bold ${isLeader ? 'bg-secondary text-white' : 'bg-primary text-white'}`;
rank.textContent = currentIndex + 1;
winnerCard.insertBefore(rank, winnerCard.firstChild);
// 时间
const time = document.createElement('div');
time.className = 'text-sm text-gray-500 mb-1';
time.textContent = winner.time;
winnerCard.appendChild(time);
// 奖项和轮次
const awardInfo = document.createElement('div');
awardInfo.className = 'text-sm text-gray-500 mb-2';
awardInfo.textContent = `${winner.award} - 第${winner.round}轮`;
winnerCard.appendChild(awardInfo);
// 礼品信息
const giftInfo = document.createElement('div');
giftInfo.className = `text-sm font-medium mb-3 ${isLeader ? 'text-secondary' : 'text-primary'}`;
giftInfo.textContent = `获得: ${winner.gift}`;
winnerCard.appendChild(giftInfo);
// 如果是领导,添加特殊标识
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 = [];
// 重置奖项状态
data.awards.forEach(award => {
award.drawnCount = 0;
award.currentRound = 1;
});
data.currentAwardIndex = 0;
// 重置已中奖参与者名单(不可重复中奖模式)
state.alreadyWonParticipants = [];
updateWinnersList();
updateAwardInfo();
updateAwardsList();
saveData();
}
}
// 重置已中奖名单(仅用于不可重复中奖模式)
function resetAlreadyWon() {
if (confirm('确定要重置已中奖名单吗?这将允许已中奖的人员再次参与抽奖。')) {
state.alreadyWonParticipants = [];
alert('已中奖名单已重置,所有参与者现在都可以再次参与抽奖。');
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; }
.winner-award { color: #666; font-size: 14px; margin-bottom: 5px; }
.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-award">${winner.award} - 第${winner.round}轮</div>
<div class="winner-gift" style="font-weight: bold; color: #4F46E5; margin: 5px 0;">获得: ${winner.gift}</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.style.background = '';
body.style.backgroundImage = '';
body.style.backgroundSize = '';
body.style.backgroundPosition = '';
body.style.backgroundRepeat = '';
if (data.settings.backgroundMode === 'solid') {
// 纯色渐变背景
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('lotteryAwards', JSON.stringify(data.awards));
localStorage.setItem('lotteryCurrentAwardIndex', JSON.stringify(data.currentAwardIndex));
localStorage.setItem('lotterySettings', JSON.stringify(data.settings));
localStorage.setItem('lotteryAlreadyWonParticipants', JSON.stringify(state.alreadyWonParticipants));
}
// 从本地存储加载数据
function loadData() {
const dataKeys = [
{ key: 'lotteryParticipants', target: 'participants', description: '参与者名单' },
{ key: 'lotteryLeaders', target: 'leaders', description: '领导名单' },
{ key: 'lotteryWinners', target: 'winners', description: '中奖记录' },
{ key: 'lotteryAwards', target: 'awards', description: '奖项设置' },
{ key: 'lotteryCurrentAwardIndex', target: 'currentAwardIndex', description: '当前奖项索引' }
];
// 加载主数据
dataKeys.forEach(({ key, target, description }) => {
const saved = localStorage.getItem(key);
if (saved) {
try {
data[target] = JSON.parse(saved);
} catch (e) {
console.error(`加载${description}失败:`, e);
}
}
});
// 加载设置
const savedSettings = localStorage.getItem('lotterySettings');
if (savedSettings) {
try {
const loadedSettings = JSON.parse(savedSettings);
data.settings = {
...data.settings,
...loadedSettings,
backgroundImage: loadedSettings.backgroundImage || 'https://picsum.photos/id/1067/1920/1080'
};
} catch (e) {
console.error('加载设置失败:', e);
}
}
// 加载已中奖参与者名单
const savedAlreadyWonParticipants = localStorage.getItem('lotteryAlreadyWonParticipants');
if (savedAlreadyWonParticipants) {
try {
state.alreadyWonParticipants = JSON.parse(savedAlreadyWonParticipants);
} catch (e) {
console.error('加载已中奖参与者名单失败:', e);
}
}
}
// 删除全部参与者
function deleteAllParticipants() {
if (confirm('确定要删除所有参与者名单吗?此操作不可恢复。')) {
data.participants = [];
updateParticipantsList();
saveData();
}
}
// 删除全部领导
function deleteAllLeaders() {
if (confirm('确定要删除所有领导名单吗?此操作不可恢复。')) {
data.leaders = [];
updateLeadersList();
saveData();
}
}
// 绑定事件监听器
function bindEventListeners() {
// 检查必要的元素是否存在
const requiredElements = ['startButton', 'stopButton', 'lotteryName'];
const missingElements = requiredElements.filter(name => !elements[name]);
if (missingElements.length > 0) {
console.error('关键元素未找到:', missingElements);
return;
}
// 抽奖控制
elements.startButton.addEventListener('click', startLottery);
elements.stopButton.addEventListener('click', stopLottery);
// 界面切换
if (elements.viewWinnersButton) {
elements.viewWinnersButton.addEventListener('click', () => {
elements.winnersScreen.classList.remove('hidden');
});
}
if (elements.backToMainButton) {
elements.backToMainButton.addEventListener('click', () => {
elements.winnersScreen.classList.add('hidden');
});
}
if (elements.manageNamesButton) {
elements.manageNamesButton.addEventListener('click', () => {
elements.namesManagementScreen.classList.remove('hidden');
});
}
if (elements.backFromNamesButton) {
elements.backFromNamesButton.addEventListener('click', () => {
elements.namesManagementScreen.classList.add('hidden');
});
}
// 名单管理
if (elements.addParticipantsButton) {
elements.addParticipantsButton.addEventListener('click', addParticipants);
}
if (elements.addLeadersButton) {
elements.addLeadersButton.addEventListener('click', addLeaders);
}
if (elements.clearParticipantsButton) {
elements.clearParticipantsButton.addEventListener('click', () => {
elements.participantsInput.value = '';
});
}
if (elements.clearLeadersButton) {
elements.clearLeadersButton.addEventListener('click', () => {
elements.leadersInput.value = '';
});
}
if (elements.deleteAllParticipantsButton) {
elements.deleteAllParticipantsButton.addEventListener('click', deleteAllParticipants);
}
if (elements.deleteAllLeadersButton) {
elements.deleteAllLeadersButton.addEventListener('click', deleteAllLeaders);
}
if (elements.loadExampleParticipantsButton) {
elements.loadExampleParticipantsButton.addEventListener('click', loadExampleParticipants);
}
// 奖项管理
if (elements.addAwardButton) {
elements.addAwardButton.addEventListener('click', addAward);
}
if (elements.resetAwardsButton) {
elements.resetAwardsButton.addEventListener('click', resetAwards);
}
if (elements.resetAlreadyWonButton) {
elements.resetAlreadyWonButton.addEventListener('click', resetAlreadyWon);
}
// 中奖名单操作
if (elements.clearWinnersButton) {
elements.clearWinnersButton.addEventListener('click', clearWinners);
}
if (elements.printWinnersButton) {
elements.printWinnersButton.addEventListener('click', printWinners);
}
// 设置操作
if (elements.closeSettingsButton) {
elements.closeSettingsButton.addEventListener('click', () => {
elements.settingsScreen.classList.add('hidden');
});
}
if (elements.saveSettingsButton) {
elements.saveSettingsButton.addEventListener('click', saveSettings);
}
if (elements.resetSettingsButton) {
elements.resetSettingsButton.addEventListener('click', resetSettings);
}
// 设置范围输入监听
if (elements.lotterySpeed && elements.lotterySpeedValue) {
elements.lotterySpeed.addEventListener('input', (e) => {
elements.lotterySpeedValue.textContent = e.target.value;
});
}
if (elements.fontSize && elements.fontSizeValue && elements.lotteryName) {
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;
window.addAward = addAward;
window.removeAward = removeAward;
window.resetAwards = resetAwards;
window.resetAlreadyWon = resetAlreadyWon;
// 初始化应用
function init() {
// 初始化DOM元素引用
initializeElements();
// 加载数据
loadData();
// 更新显示
updateParticipantsList();
updateLeadersList();
updateWinnersList();
updateSettingsDisplay();
updateAwardInfo();
// 绑定事件监听器
bindEventListeners();
}
// 启动应用
document.addEventListener('DOMContentLoaded', init);
</script>
</body>
</html> |
|