统计
  • 建站日期:2022-01-17
  • 分类总数:43 个
  • 文章总数:6633 篇
  • 评论总数:62626条
  • 最后更新:2025-07-23

纯html做的年会抽奖网页

作者头像
首页 综合教程 正文
广告
广告

纯html做的年会抽奖网页

image.png

<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>年会抽奖程序 (纯离线版)</title>
    <style>
        /* --- 全局和基础样式 --- */
        body {
            font-family: 'Microsoft YaHei', 'Inter', sans-serif;
            background-color: #111827;
            color: #f3f4f6;
            margin: 0;
            padding: 0;
            display: flex;
            justify-content: center;
        }
        .main-container {
            max-width: 1200px;
            width: 100%;
            margin: auto;
            padding: 2rem;
            box-sizing: border-box;
        }
        .hidden {
            display: none !important;
        }

        /* --- 文本样式 --- */
        h1 {
            font-size: 2.25rem;
            font-weight: 700;
            text-align: center;
            margin-bottom: 0.5rem;
            color: #ffffff;
        }
        h2 {
            font-size: 1.5rem;
            font-weight: 600;
            margin-bottom: 1rem;
            color: #ffffff;
        }
        h3 {
            font-size: 1.125rem;
            font-weight: 600;
        }
        p {
            margin: 0;
        }
        .text-center {
            text-align: center;
        }
        .text-gray-400 {
            color: #9ca3af;
        }

        /* --- 布局 --- */
        .grid {
            display: grid;
            gap: 2rem;
        }
        [url=home.php?mod=space&uid=945662]@media[/url] (min-width: 768px) {
            .md-grid-cols-2 {
                grid-template-columns: repeat(2, minmax(0, 1fr));
            }
        }
         @media (min-width: 1024px) {
            .lg-grid-cols-3 {
                grid-template-columns: repeat(3, minmax(0, 1fr));
            }
            .lg-col-span-2 {
                grid-column: span 2 / span 2;
            }
            .lg-col-span-1 {
                grid-column: span 1 / span 1;
            }
        }
        .flex {
            display: flex;
        }
        .items-center {
            align-items: center;
        }
        .justify-between {
            justify-content: space-between;
        }
        .justify-center {
            justify-content: center;
        }
        .space-x-2 > * + * { margin-left: 0.5rem; }
        .space-x-4 > * + * { margin-left: 1rem; }
        .space-y-4 > * + * { margin-top: 1rem; }
        .mb-4 { margin-bottom: 1rem; }
        .mb-8 { margin-bottom: 2rem; }
        .mt-4 { margin-top: 1rem; }
        .mt-6 { margin-top: 1.5rem; }
        .mt-8 { margin-top: 2rem; }

        /* --- 组件样式 --- */
        .card {
            background-color: #1f2937;
            border: 1px solid #374151;
            border-radius: 0.75rem;
            padding: 1.5rem;
            box-shadow: 0 10px 15px -3px rgba(0, 0, 0, 0.1), 0 4px 6px -2px rgba(0, 0, 0, 0.05);
        }
        .btn {
            display: inline-block;
            padding: 0.75rem 1.5rem;
            border-radius: 0.5rem;
            font-weight: 600;
            text-align: center;
            transition: all 0.3s ease;
            cursor: pointer;
            border: none;
            color: white;
        }
        .btn-primary { background-color: #4f46e5; }
        .btn-primary:hover { background-color: #4338ca; }
        .btn-secondary { background-color: #4b5563; }
        .btn-secondary:hover { background-color: #374151; }
        .btn-danger { background-color: #dc2626; }
        .btn-danger:hover { background-color: #b91c1c; }
        .btn-lg {
            font-size: 1.125rem;
            padding: 0.75rem 2rem;
        }
         .btn-xl {
            font-size: 1.25rem;
            padding: 1rem 3rem;
        }

        input, textarea, select {
            background-color: #374151;
            border: 1px solid #4b5563;
            color: #f3f4f6;
            border-radius: 0.375rem;
            padding: 0.5rem 0.75rem;
            width: 100%;
            box-sizing: border-box;
        }
        textarea {
            resize: vertical;
        }

        /* --- 特定元素 --- */
        .rolling-display {
            font-size: 3rem;
            font-weight: 700;
            text-align: center;
            padding: 4rem 1rem;
            background: linear-gradient(145deg, #374151, #1f2937);
            border-radius: 0.75rem;
            color: #f59e0b;
            min-height: 200px;
            display: flex;
            flex-direction: column;
            align-items: center;
            justify-content: center;
            text-shadow: 0 0 15px #f59e0b;
        }
        .winner-list-item {
            background-color: #374151;
            padding: 0.75rem;
            border-radius: 0.5rem;
            margin-bottom: 0.5rem;
            display: flex;
            justify-content: space-between;
            align-items: center;
        }
        #modal {
            position: fixed;
            top: 0;
            left: 0;
            width: 100%;
            height: 100%;
            background-color: rgba(0,0,0,0.7);
            display: none;
            justify-content: center;
            align-items: center;
            z-index: 1000;
        }
        .modal-content {
            background-color: #1f2937;
            padding: 2rem;
            border-radius: 0.75rem;
            width: 90%;
            max-width: 500px;
            text-align: center;
            box-sizing: border-box;
        }
    </style>
</head>
<body>

    <div class="main-container">
        <h1>年会抽奖程序</h1>
        <p class="text-center text-gray-400 mb-8">公平、公正、公开</p>

        <!-- Setup View -->
        <div id="setupView">
            <div class="grid md-grid-cols-2">
                <!-- Participants Setup -->
                <div class="card">
                    <h2>第一步: 导入参与人员</h2>
                    <p class="text-gray-400 mb-4">每行一人,格式为:姓名,工号 (用英文逗号分隔)。</p>
                    <textarea id="participantsInput" rows="8" class="mb-4" placeholder="例如:张三,1001李四,1002王五,1003"></textarea>
                    <div class="flex items-center justify-between">
                        <label for="fileInput" class="btn btn-secondary">从文件导入 (.txt, .csv)</label>
                        <input type="file" id="fileInput" class="hidden" accept=".txt,.csv">
                        <span id="participantCount" class="text-gray-400">当前人数: 0</span>
                    </div>
                </div>

                <!-- Prizes Setup -->
                <div class="card">
                    <h2>第二步: 设置奖项</h2>
                    <div id="prizeList" class="space-y-4 mb-4">
                        <!-- Prize items will be added here -->
                    </div>
                    <button id="addPrizeBtn" class="btn btn-secondary" style="width: 100%;">添加新奖项</button>
                </div>
            </div>
            <div class="text-center mt-8">
                <button id="startDrawBtn" class="btn btn-primary btn-lg">开始抽奖!</button>
            </div>
        </div>

        <!-- Draw View -->
        <div id="drawView" class="hidden">
            <div class="grid lg-grid-cols-3">
                <!-- Draw Controls -->
                <div class="card lg-col-span-2">
                    <div class="flex justify-between items-center mb-4">
                         <h2>抽奖环节</h2>
                         <button id="backToSetupBtn" class="btn btn-secondary">返回设置</button>
                    </div>

                    <div class="mb-4">
                        <label for="prizeSelect" style="display:block; margin-bottom: 0.5rem; font-weight: 500;" class="text-gray-300">当前抽取的奖项:</label>
                        <select id="prizeSelect"></select>
                    </div>
                    <div class="rolling-display" id="rollingDisplay">
                        准备开始...
                    </div>
                    <div class="mt-6 flex justify-center space-x-4">
                        <button id="toggleDrawBtn" class="btn btn-primary btn-xl">开始滚动</button>
                        <button id="resetBtn" class="btn btn-danger btn-xl">重置程序</button>
                    </div>
                </div>

                <!-- Winners List -->
                <div class="card lg-col-span-1">
                    <h2>&#127881; 中奖名单</h2>
                    <div id="winnerDisplay" class="space-y-4" style="max-height: 24rem; overflow-y: auto;">
                        <!-- Winner lists will be generated here -->
                    </div>
                     <div class="mt-4">
                        <button id="exportWinnersBtn" class="btn btn-secondary" style="width: 100%;">导出中奖名单</button>
                    </div>
                </div>
            </div>
        </div>
    </div>

    <!-- Modal for alerts -->
    <div id="modal">
        <div class="modal-content">
            <h3 id="modalTitle" style="color:white; margin-bottom: 1rem;">提示</h3>
            <p id="modalMessage" class="text-gray-300" style="margin-bottom: 1.5rem;"></p>
            <button id="modalCloseBtn" class="btn btn-primary">好的</button>
        </div>
    </div>

    <script>
        // --- DOM Elements ---
        const setupView = document.getElementById('setupView');
        const drawView = document.getElementById('drawView');
        const participantsInput = document.getElementById('participantsInput');
        const fileInput = document.getElementById('fileInput');
        const participantCount = document.getElementById('participantCount');
        const prizeList = document.getElementById('prizeList');
        const addPrizeBtn = document.getElementById('addPrizeBtn');
        const startDrawBtn = document.getElementById('startDrawBtn');
        const backToSetupBtn = document.getElementById('backToSetupBtn');
        const prizeSelect = document.getElementById('prizeSelect');
        const rollingDisplay = document.getElementById('rollingDisplay');
        const toggleDrawBtn = document.getElementById('toggleDrawBtn');
        const winnerDisplay = document.getElementById('winnerDisplay');
        const resetBtn = document.getElementById('resetBtn');
        const exportWinnersBtn = document.getElementById('exportWinnersBtn');

        // Modal elements
        const modal = document.getElementById('modal');
        const modalTitle = document.getElementById('modalTitle');
        const modalMessage = document.getElementById('modalMessage');
        const modalCloseBtn = document.getElementById('modalCloseBtn');

        // --- State Management ---
        let allParticipants = [];
        let remainingParticipants = [];
        let prizes = [];
        let winners = {}; // { prizeId: [winner1, winner2] }
        let rollingInterval = null;
        let isRolling = false;

        // --- Utility Functions ---
        function showAlert(title, message) {
            modalTitle.textContent = title;
            modalMessage.textContent = message;
            modal.style.display = 'flex';
        }

        modalCloseBtn.onclick = () => {
            modal.style.display = 'none';
        }

        // --- Core Functions ---

        function updateParticipantCount() {
            allParticipants = participantsInput.value.split('\n').filter(line => line.trim() !== '').map(line => {
                const parts = line.split(/,|,/); // Support both English and Chinese commas
                return { name: parts[0]?.trim() || '', id: parts[1]?.trim() || '' };
            }).filter(p => p.name && p.id);
            participantCount.textContent = `当前人数: ${allParticipants.length}`;
        }

        function handleFileUpload(event) {
            const file = event.target.files[0];
            if (!file) return;

            const reader = new FileReader();
            reader.onload = function(e) {
                participantsInput.value = e.target.result;
                updateParticipantCount();
            };
            reader.readAsText(file);
        }

        function addPrize() {
            const prizeId = `prize-${Date.now()}`;
            const prizeItem = document.createElement('div');
            prizeItem.className = 'flex items-center space-x-2';
            prizeItem.id = prizeId;
            prizeItem.innerHTML = `
                <input type="text" class="prize-name" placeholder="奖项名称 (如: 特等奖)">
                <input type="number" class="prize-quantity" placeholder="数量" min="1" style="width: 80px;">
                <button class="remove-prize-btn btn btn-danger" style="padding: 0.5rem;">X</button>
            `;
            prizeList.appendChild(prizeItem);
            prizeItem.querySelector('.remove-prize-btn').addEventListener('click', () => {
                prizeItem.remove();
            });
        }

        function savePrizes() {
            prizes = [];
            const prizeItems = prizeList.querySelectorAll('.flex');
            prizeItems.forEach(item => {
                const name = item.querySelector('.prize-name').value.trim();
                const quantity = parseInt(item.querySelector('.prize-quantity').value, 10);
                if (name && quantity > 0) {
                    prizes.push({ id: item.id, name, quantity });
                }
            });
        }

        function initializeDrawView() {
            // Reset state
            remainingParticipants = [...allParticipants];
            winners = {};
            prizes.forEach(p => winners[p.id] = []);

            // Populate prize select dropdown
            prizeSelect.innerHTML = '';
            prizes.forEach(p => {
                const option = document.createElement('option');
                option.value = p.id;
                option.textContent = `${p.name} (剩余 ${p.quantity} 名)`;
                prizeSelect.appendChild(option);
            });

            updateWinnerDisplay();
            rollingDisplay.textContent = '准备开始...';
            toggleDrawBtn.textContent = '开始滚动';
            toggleDrawBtn.disabled = false;
        }

        function updatePrizeSelectOptions() {
            const selectedPrizeId = prizeSelect.value;
            prizes.forEach(p => {
                const option = prizeSelect.querySelector(`option[value="${p.id}"]`);
                if (option) {
                    const remaining = p.quantity - (winners[p.id] ? winners[p.id].length : 0);
                    option.textContent = `${p.name} (剩余 ${remaining} 名)`;
                }
            });
            prizeSelect.value = selectedPrizeId;
        }

        function updateWinnerDisplay() {
            winnerDisplay.innerHTML = '';
            prizes.forEach(p => {
                if (winners[p.id] && winners[p.id].length > 0) {
                    const prizeGroup = document.createElement('div');
                    prizeGroup.innerHTML = `<h3 style="color: #f59e0b;">${p.name} (${winners[p.id].length}/${p.quantity})</h3>`;
                    const list = document.createElement('div');
                    winners[p.id].forEach(winner => {
                        const winnerItem = document.createElement('div');
                        winnerItem.className = 'winner-list-item';
                        winnerItem.innerHTML = `
                            <span>${winner.name}</span>
                            <span class="text-gray-400">${winner.id}</span>`;
                        list.appendChild(winnerItem);
                    });
                    prizeGroup.appendChild(list);
                    winnerDisplay.appendChild(prizeGroup);
                }
            });
        }

        function startRolling() {
            const currentPrizeId = prizeSelect.value;
            const currentPrize = prizes.find(p => p.id === currentPrizeId);

            if (!currentPrize) {
                showAlert('错误', '无效的奖项!');
                return;
            }

            const winnersForPrize = winners[currentPrizeId] || [];
            if (winnersForPrize.length >= currentPrize.quantity) {
                showAlert('提示', `【${currentPrize.name}】的奖项已经抽完啦!`);
                return;
            }
            if (remainingParticipants.length === 0) {
                showAlert('提示', '所有人都已经中奖啦!没有可抽的人员了。');
                return;
            }

            isRolling = true;
            toggleDrawBtn.textContent = '停止!';
            toggleDrawBtn.classList.remove('btn-primary');
            toggleDrawBtn.classList.add('btn-danger');

            rollingInterval = setInterval(() => {
                const randomIndex = Math.floor(Math.random() * remainingParticipants.length);
                const randomParticipant = remainingParticipants[randomIndex];
                rollingDisplay.innerHTML = `${randomParticipant.name}<br><span style="font-size: 1.5rem;">${randomParticipant.id}</span>`;
            }, 50);
        }

        function stopRolling() {
            clearInterval(rollingInterval);
            rollingInterval = null;
            isRolling = false;

            if (remainingParticipants.length === 0) return;

            const winnerIndex = Math.floor(Math.random() * remainingParticipants.length);
            const winner = remainingParticipants[winnerIndex];

            // Display winner
            rollingDisplay.innerHTML = `${winner.name}<br><span style="font-size: 1.5rem; color: #34d399;">${winner.id}</span>`;

            // Update state
            const currentPrizeId = prizeSelect.value;
            winners[currentPrizeId].push(winner);
            remainingParticipants.splice(winnerIndex, 1);

            // Update UI
            updateWinnerDisplay();
            updatePrizeSelectOptions();

            const currentPrize = prizes.find(p => p.id === currentPrizeId);
            const winnersForPrize = winners[currentPrizeId];
            if (winnersForPrize.length >= currentPrize.quantity) {
                showAlert('恭喜', `【${currentPrize.name}】已全部抽出!`);
                toggleDrawBtn.disabled = true;
            } else {
                 toggleDrawBtn.textContent = '开始滚动';
                 toggleDrawBtn.classList.remove('btn-danger');
                 toggleDrawBtn.classList.add('btn-primary');
            }
        }

        function exportWinners() {
            let csvContent = "奖项,姓名,工号\n";
            prizes.forEach(p => {
                if(winners[p.id]) {
                    winners[p.id].forEach(winner => {
                        csvContent += `${p.name},${winner.name},${winner.id}\n`;
                    });
                }
            });

            const blob = new Blob([new Uint8Array([0xEF, 0xBB, 0xBF]), csvContent], { type: 'text/csv;charset=utf-8;' });
            const link = document.createElement("a");
            const url = URL.createObjectURL(blob);
            link.setAttribute("href", url);
            link.setAttribute("download", "中奖名单.csv");
            link.style.visibility = 'hidden';
            document.body.appendChild(link);
            link.click();
            document.body.removeChild(link);
        }

        function resetApplication() {
            if (confirm('您确定要重置整个抽奖程序吗?所有设置和中奖结果都将被清空。')) {
                 location.reload();
            }
        }

        // --- Event Listeners ---
        participantsInput.addEventListener('input', updateParticipantCount);
        fileInput.addEventListener('change', handleFileUpload);
        addPrizeBtn.addEventListener('click', addPrize);

        startDrawBtn.addEventListener('click', () => {
            updateParticipantCount(); // Final check on participants
            savePrizes();

            if (allParticipants.length === 0) {
                showAlert('错误', '请先添加参与抽奖的人员!');
                return;
            }
            if (prizes.length === 0) {
                showAlert('错误', '请至少设置一个奖项!');
                return;
            }

            let totalPrizesCount = prizes.reduce((sum, p) => sum + p.quantity, 0);
            if (totalPrizesCount > allParticipants.length) {
                showAlert('警告', '奖品总数大于参与人数,请检查设置。');
                return;
            }

            setupView.classList.add('hidden');
            drawView.classList.remove('hidden');
            initializeDrawView();
        });

        backToSetupBtn.addEventListener('click', () => {
            if (isRolling) {
                stopRolling();
            }
            drawView.classList.add('hidden');
            setupView.classList.remove('hidden');
        });

        toggleDrawBtn.addEventListener('click', () => {
            if (isRolling) {
                stopRolling();
            } else {
                startRolling();
            }
        });

        prizeSelect.addEventListener('change', () => {
            if (isRolling) return; // Don't change prize while rolling
            const currentPrizeId = prizeSelect.value;
            const currentPrize = prizes.find(p => p.id === currentPrizeId);
            const winnersForPrize = winners[currentPrizeId] || [];

            if (winnersForPrize.length >= currentPrize.quantity) {
                toggleDrawBtn.disabled = true;
                rollingDisplay.textContent = `【${currentPrize.name}】已抽完`;
            } else {
                toggleDrawBtn.disabled = false;
                rollingDisplay.textContent = '准备就绪';
            }
        });

        resetBtn.addEventListener('click', resetApplication);
        exportWinnersBtn.addEventListener('click', exportWinners);

        // --- Initial Setup ---
        addPrize(); // Add one prize field by default
    </script>
</body>
</html>

版权说明
文章采用: 《署名-非商业性使用-相同方式共享 4.0 国际 (CC BY-NC-SA 4.0)》许可协议授权。
版权声明:本站资源来自互联网收集,仅供用于学习和交流,请勿用于商业用途。如有侵权、不妥之处,请联系客服并出示版权证明以便删除!
自适应双端自动采集电脑壁纸系统源码v2.0
下一篇 » 07-23