找回密码
 立即注册
搜索
查看: 1507|回复: 0

纯html做的年会抽奖网页

[复制链接]
  • 打卡等级:暂无等级
  • 打卡总天数:189
  • 打卡月天数:13
  • 打卡总奖励:145
  • 最近打卡:2025-11-13 10:56:25
灌水成绩
13860
48
2034797
主题
帖子
积分

等级头衔

ID : 1

管理员

积分成就 威望 : 999999
贡献 : 9999
下载币 : 10892
在线时间 : 1011 小时
注册时间 : 2013-9-5
最后登录 : 2025-11-13

发表于 昨天 18:17 | 显示全部楼层 |阅读模式 IP:广东东莞
免责
免费领取大流量卡,每日更新蔡州手游APP源码密码加入群聊接手游搭建—``下载币--购买服务器☆长期招聘游戏测试员(无偿),有兴趣联系站长QQ58493525微信A0396C




  1. <!DOCTYPE html>
  2. <html lang="zh-CN">
  3. <head>
  4.     <meta charset="UTF-8">
  5.     <meta name="viewport" content="width=device-width, initial-scale=1.0">
  6.     <title>年会抽奖程序 (纯离线版)</title>
  7.     <style>
  8.         /* --- 全局和基础样式 --- */
  9.         body {
  10.             font-family: 'Microsoft YaHei', 'Inter', sans-serif;
  11.             background-color: #111827;
  12.             color: #f3f4f6;
  13.             margin: 0;
  14.             padding: 0;
  15.             display: flex;
  16.             justify-content: center;
  17.         }
  18.         .main-container {
  19.             max-width: 1200px;
  20.             width: 100%;
  21.             margin: auto;
  22.             padding: 2rem;
  23.             box-sizing: border-box;
  24.         }
  25.         .hidden {
  26.             display: none !important;
  27.         }

  28.         /* --- 文本样式 --- */
  29.         h1 {
  30.             font-size: 2.25rem;
  31.             font-weight: 700;
  32.             text-align: center;
  33.             margin-bottom: 0.5rem;
  34.             color: #ffffff;
  35.         }
  36.         h2 {
  37.             font-size: 1.5rem;
  38.             font-weight: 600;
  39.             margin-bottom: 1rem;
  40.             color: #ffffff;
  41.         }
  42.         h3 {
  43.             font-size: 1.125rem;
  44.             font-weight: 600;
  45.         }
  46.         p {
  47.             margin: 0;
  48.         }
  49.         .text-center {
  50.             text-align: center;
  51.         }
  52.         .text-gray-400 {
  53.             color: #9ca3af;
  54.         }

  55.         /* --- 布局 --- */
  56.         .grid {
  57.             display: grid;
  58.             gap: 2rem;
  59.         }
  60.         [url=home.php?mod=space&uid=945662]@media[/url] (min-width: 768px) {
  61.             .md-grid-cols-2 {
  62.                 grid-template-columns: repeat(2, minmax(0, 1fr));
  63.             }
  64.         }
  65.          @media (min-width: 1024px) {
  66.             .lg-grid-cols-3 {
  67.                 grid-template-columns: repeat(3, minmax(0, 1fr));
  68.             }
  69.             .lg-col-span-2 {
  70.                 grid-column: span 2 / span 2;
  71.             }
  72.             .lg-col-span-1 {
  73.                 grid-column: span 1 / span 1;
  74.             }
  75.         }
  76.         .flex {
  77.             display: flex;
  78.         }
  79.         .items-center {
  80.             align-items: center;
  81.         }
  82.         .justify-between {
  83.             justify-content: space-between;
  84.         }
  85.         .justify-center {
  86.             justify-content: center;
  87.         }
  88.         .space-x-2 > * + * { margin-left: 0.5rem; }
  89.         .space-x-4 > * + * { margin-left: 1rem; }
  90.         .space-y-4 > * + * { margin-top: 1rem; }
  91.         .mb-4 { margin-bottom: 1rem; }
  92.         .mb-8 { margin-bottom: 2rem; }
  93.         .mt-4 { margin-top: 1rem; }
  94.         .mt-6 { margin-top: 1.5rem; }
  95.         .mt-8 { margin-top: 2rem; }

  96.         /* --- 组件样式 --- */
  97.         .card {
  98.             background-color: #1f2937;
  99.             border: 1px solid #374151;
  100.             border-radius: 0.75rem;
  101.             padding: 1.5rem;
  102.             box-shadow: 0 10px 15px -3px rgba(0, 0, 0, 0.1), 0 4px 6px -2px rgba(0, 0, 0, 0.05);
  103.         }
  104.         .btn {
  105.             display: inline-block;
  106.             padding: 0.75rem 1.5rem;
  107.             border-radius: 0.5rem;
  108.             font-weight: 600;
  109.             text-align: center;
  110.             transition: all 0.3s ease;
  111.             cursor: pointer;
  112.             border: none;
  113.             color: white;
  114.         }
  115.         .btn-primary { background-color: #4f46e5; }
  116.         .btn-primary:hover { background-color: #4338ca; }
  117.         .btn-secondary { background-color: #4b5563; }
  118.         .btn-secondary:hover { background-color: #374151; }
  119.         .btn-danger { background-color: #dc2626; }
  120.         .btn-danger:hover { background-color: #b91c1c; }
  121.         .btn-lg {
  122.             font-size: 1.125rem;
  123.             padding: 0.75rem 2rem;
  124.         }
  125.          .btn-xl {
  126.             font-size: 1.25rem;
  127.             padding: 1rem 3rem;
  128.         }

  129.         input, textarea, select {
  130.             background-color: #374151;
  131.             border: 1px solid #4b5563;
  132.             color: #f3f4f6;
  133.             border-radius: 0.375rem;
  134.             padding: 0.5rem 0.75rem;
  135.             width: 100%;
  136.             box-sizing: border-box;
  137.         }
  138.         textarea {
  139.             resize: vertical;
  140.         }
  141.          
  142.         /* --- 特定元素 --- */
  143.         .rolling-display {
  144.             font-size: 3rem;
  145.             font-weight: 700;
  146.             text-align: center;
  147.             padding: 4rem 1rem;
  148.             background: linear-gradient(145deg, #374151, #1f2937);
  149.             border-radius: 0.75rem;
  150.             color: #f59e0b;
  151.             min-height: 200px;
  152.             display: flex;
  153.             flex-direction: column;
  154.             align-items: center;
  155.             justify-content: center;
  156.             text-shadow: 0 0 15px #f59e0b;
  157.         }
  158.         .winner-list-item {
  159.             background-color: #374151;
  160.             padding: 0.75rem;
  161.             border-radius: 0.5rem;
  162.             margin-bottom: 0.5rem;
  163.             display: flex;
  164.             justify-content: space-between;
  165.             align-items: center;
  166.         }
  167.         #modal {
  168.             position: fixed;
  169.             top: 0;
  170.             left: 0;
  171.             width: 100%;
  172.             height: 100%;
  173.             background-color: rgba(0,0,0,0.7);
  174.             display: none;
  175.             justify-content: center;
  176.             align-items: center;
  177.             z-index: 1000;
  178.         }
  179.         .modal-content {
  180.             background-color: #1f2937;
  181.             padding: 2rem;
  182.             border-radius: 0.75rem;
  183.             width: 90%;
  184.             max-width: 500px;
  185.             text-align: center;
  186.             box-sizing: border-box;
  187.         }
  188.     </style>
  189. </head>
  190. <body>

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

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

  208.                 <!-- Prizes Setup -->
  209.                 <div class="card">
  210.                     <h2>第二步: 设置奖项</h2>
  211.                     <div id="prizeList" class="space-y-4 mb-4">
  212.                         <!-- Prize items will be added here -->
  213.                     </div>
  214.                     <button id="addPrizeBtn" class="btn btn-secondary" style="width: 100%;">添加新奖项</button>
  215.                 </div>
  216.             </div>
  217.             <div class="text-center mt-8">
  218.                 <button id="startDrawBtn" class="btn btn-primary btn-lg">开始抽奖!</button>
  219.             </div>
  220.         </div>

  221.         <!-- Draw View -->
  222.         <div id="drawView" class="hidden">
  223.             <div class="grid lg-grid-cols-3">
  224.                 <!-- Draw Controls -->
  225.                 <div class="card lg-col-span-2">
  226.                     <div class="flex justify-between items-center mb-4">
  227.                          <h2>抽奖环节</h2>
  228.                          <button id="backToSetupBtn" class="btn btn-secondary">返回设置</button>
  229.                     </div>
  230.                     
  231.                     <div class="mb-4">
  232.                         <label for="prizeSelect" style="display:block; margin-bottom: 0.5rem; font-weight: 500;" class="text-gray-300">当前抽取的奖项:</label>
  233.                         <select id="prizeSelect"></select>
  234.                     </div>
  235.                     <div class="rolling-display" id="rollingDisplay">
  236.                         准备开始...
  237.                     </div>
  238.                     <div class="mt-6 flex justify-center space-x-4">
  239.                         <button id="toggleDrawBtn" class="btn btn-primary btn-xl">开始滚动</button>
  240.                         <button id="resetBtn" class="btn btn-danger btn-xl">重置程序</button>
  241.                     </div>
  242.                 </div>

  243.                 <!-- Winners List -->
  244.                 <div class="card lg-col-span-1">
  245.                     <h2>&#127881; 中奖名单</h2>
  246.                     <div id="winnerDisplay" class="space-y-4" style="max-height: 24rem; overflow-y: auto;">
  247.                         <!-- Winner lists will be generated here -->
  248.                     </div>
  249.                      <div class="mt-4">
  250.                         <button id="exportWinnersBtn" class="btn btn-secondary" style="width: 100%;">导出中奖名单</button>
  251.                     </div>
  252.                 </div>
  253.             </div>
  254.         </div>
  255.     </div>
  256.      
  257.     <!-- Modal for alerts -->
  258.     <div id="modal">
  259.         <div class="modal-content">
  260.             <h3 id="modalTitle" style="color:white; margin-bottom: 1rem;">提示</h3>
  261.             <p id="modalMessage" class="text-gray-300" style="margin-bottom: 1.5rem;"></p>
  262.             <button id="modalCloseBtn" class="btn btn-primary">好的</button>
  263.         </div>
  264.     </div>

  265.     <script>
  266.         // --- DOM Elements ---
  267.         const setupView = document.getElementById('setupView');
  268.         const drawView = document.getElementById('drawView');
  269.         const participantsInput = document.getElementById('participantsInput');
  270.         const fileInput = document.getElementById('fileInput');
  271.         const participantCount = document.getElementById('participantCount');
  272.         const prizeList = document.getElementById('prizeList');
  273.         const addPrizeBtn = document.getElementById('addPrizeBtn');
  274.         const startDrawBtn = document.getElementById('startDrawBtn');
  275.         const backToSetupBtn = document.getElementById('backToSetupBtn');
  276.         const prizeSelect = document.getElementById('prizeSelect');
  277.         const rollingDisplay = document.getElementById('rollingDisplay');
  278.         const toggleDrawBtn = document.getElementById('toggleDrawBtn');
  279.         const winnerDisplay = document.getElementById('winnerDisplay');
  280.         const resetBtn = document.getElementById('resetBtn');
  281.         const exportWinnersBtn = document.getElementById('exportWinnersBtn');
  282.          
  283.         // Modal elements
  284.         const modal = document.getElementById('modal');
  285.         const modalTitle = document.getElementById('modalTitle');
  286.         const modalMessage = document.getElementById('modalMessage');
  287.         const modalCloseBtn = document.getElementById('modalCloseBtn');


  288.         // --- State Management ---
  289.         let allParticipants = [];
  290.         let remainingParticipants = [];
  291.         let prizes = [];
  292.         let winners = {}; // { prizeId: [winner1, winner2] }
  293.         let rollingInterval = null;
  294.         let isRolling = false;

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

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

  304.         // --- Core Functions ---

  305.         function updateParticipantCount() {
  306.             allParticipants = participantsInput.value.split('\n').filter(line => line.trim() !== '').map(line => {
  307.                 const parts = line.split(/,|,/); // Support both English and Chinese commas
  308.                 return { name: parts[0]?.trim() || '', id: parts[1]?.trim() || '' };
  309.             }).filter(p => p.name && p.id);
  310.             participantCount.textContent = `当前人数: ${allParticipants.length}`;
  311.         }
  312.          
  313.         function handleFileUpload(event) {
  314.             const file = event.target.files[0];
  315.             if (!file) return;

  316.             const reader = new FileReader();
  317.             reader.onload = function(e) {
  318.                 participantsInput.value = e.target.result;
  319.                 updateParticipantCount();
  320.             };
  321.             reader.readAsText(file);
  322.         }

  323.         function addPrize() {
  324.             const prizeId = `prize-${Date.now()}`;
  325.             const prizeItem = document.createElement('div');
  326.             prizeItem.className = 'flex items-center space-x-2';
  327.             prizeItem.id = prizeId;
  328.             prizeItem.innerHTML = `
  329.                 <input type="text" class="prize-name" placeholder="奖项名称 (如: 特等奖)">
  330.                 <input type="number" class="prize-quantity" placeholder="数量" min="1" style="width: 80px;">
  331.                 <button class="remove-prize-btn btn btn-danger" style="padding: 0.5rem;">X</button>
  332.             `;
  333.             prizeList.appendChild(prizeItem);
  334.             prizeItem.querySelector('.remove-prize-btn').addEventListener('click', () => {
  335.                 prizeItem.remove();
  336.             });
  337.         }
  338.          
  339.         function savePrizes() {
  340.             prizes = [];
  341.             const prizeItems = prizeList.querySelectorAll('.flex');
  342.             prizeItems.forEach(item => {
  343.                 const name = item.querySelector('.prize-name').value.trim();
  344.                 const quantity = parseInt(item.querySelector('.prize-quantity').value, 10);
  345.                 if (name && quantity > 0) {
  346.                     prizes.push({ id: item.id, name, quantity });
  347.                 }
  348.             });
  349.         }
  350.          
  351.         function initializeDrawView() {
  352.             // Reset state
  353.             remainingParticipants = [...allParticipants];
  354.             winners = {};
  355.             prizes.forEach(p => winners[p.id] = []);

  356.             // Populate prize select dropdown
  357.             prizeSelect.innerHTML = '';
  358.             prizes.forEach(p => {
  359.                 const option = document.createElement('option');
  360.                 option.value = p.id;
  361.                 option.textContent = `${p.name} (剩余 ${p.quantity} 名)`;
  362.                 prizeSelect.appendChild(option);
  363.             });
  364.             
  365.             updateWinnerDisplay();
  366.             rollingDisplay.textContent = '准备开始...';
  367.             toggleDrawBtn.textContent = '开始滚动';
  368.             toggleDrawBtn.disabled = false;
  369.         }

  370.         function updatePrizeSelectOptions() {
  371.             const selectedPrizeId = prizeSelect.value;
  372.             prizes.forEach(p => {
  373.                 const option = prizeSelect.querySelector(`option[value="${p.id}"]`);
  374.                 if (option) {
  375.                     const remaining = p.quantity - (winners[p.id] ? winners[p.id].length : 0);
  376.                     option.textContent = `${p.name} (剩余 ${remaining} 名)`;
  377.                 }
  378.             });
  379.             prizeSelect.value = selectedPrizeId;
  380.         }

  381.         function updateWinnerDisplay() {
  382.             winnerDisplay.innerHTML = '';
  383.             prizes.forEach(p => {
  384.                 if (winners[p.id] && winners[p.id].length > 0) {
  385.                     const prizeGroup = document.createElement('div');
  386.                     prizeGroup.innerHTML = `<h3 style="color: #f59e0b;">${p.name} (${winners[p.id].length}/${p.quantity})</h3>`;
  387.                     const list = document.createElement('div');
  388.                     winners[p.id].forEach(winner => {
  389.                         const winnerItem = document.createElement('div');
  390.                         winnerItem.className = 'winner-list-item';
  391.                         winnerItem.innerHTML = `
  392.                             <span>${winner.name}</span>
  393.                             <span class="text-gray-400">${winner.id}</span>`;
  394.                         list.appendChild(winnerItem);
  395.                     });
  396.                     prizeGroup.appendChild(list);
  397.                     winnerDisplay.appendChild(prizeGroup);
  398.                 }
  399.             });
  400.         }

  401.         function startRolling() {
  402.             const currentPrizeId = prizeSelect.value;
  403.             const currentPrize = prizes.find(p => p.id === currentPrizeId);
  404.             
  405.             if (!currentPrize) {
  406.                 showAlert('错误', '无效的奖项!');
  407.                 return;
  408.             }

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

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

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

  428.         function stopRolling() {
  429.             clearInterval(rollingInterval);
  430.             rollingInterval = null;
  431.             isRolling = false;

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

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

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

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

  441.             // Update UI
  442.             updateWinnerDisplay();
  443.             updatePrizeSelectOptions();

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

  455.         function exportWinners() {
  456.             let csvContent = "奖项,姓名,工号\n";
  457.             prizes.forEach(p => {
  458.                 if(winners[p.id]) {
  459.                     winners[p.id].forEach(winner => {
  460.                         csvContent += `${p.name},${winner.name},${winner.id}\n`;
  461.                     });
  462.                 }
  463.             });

  464.             const blob = new Blob([new Uint8Array([0xEF, 0xBB, 0xBF]), csvContent], { type: 'text/csv;charset=utf-8;' });
  465.             const link = document.createElement("a");
  466.             const url = URL.createObjectURL(blob);
  467.             link.setAttribute("href", url);
  468.             link.setAttribute("download", "中奖名单.csv");
  469.             link.style.visibility = 'hidden';
  470.             document.body.appendChild(link);
  471.             link.click();
  472.             document.body.removeChild(link);
  473.         }
  474.          
  475.         function resetApplication() {
  476.             if (confirm('您确定要重置整个抽奖程序吗?所有设置和中奖结果都将被清空。')) {
  477.                  location.reload();
  478.             }
  479.         }


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

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

  487.             if (allParticipants.length === 0) {
  488.                 showAlert('错误', '请先添加参与抽奖的人员!');
  489.                 return;
  490.             }
  491.             if (prizes.length === 0) {
  492.                 showAlert('错误', '请至少设置一个奖项!');
  493.                 return;
  494.             }
  495.             
  496.             let totalPrizesCount = prizes.reduce((sum, p) => sum + p.quantity, 0);
  497.             if (totalPrizesCount > allParticipants.length) {
  498.                 showAlert('警告', '奖品总数大于参与人数,请检查设置。');
  499.                 return;
  500.             }

  501.             setupView.classList.add('hidden');
  502.             drawView.classList.remove('hidden');
  503.             initializeDrawView();
  504.         });

  505.         backToSetupBtn.addEventListener('click', () => {
  506.             if (isRolling) {
  507.                 stopRolling();
  508.             }
  509.             drawView.classList.add('hidden');
  510.             setupView.classList.remove('hidden');
  511.         });

  512.         toggleDrawBtn.addEventListener('click', () => {
  513.             if (isRolling) {
  514.                 stopRolling();
  515.             } else {
  516.                 startRolling();
  517.             }
  518.         });

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

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

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

  534.         // --- Initial Setup ---
  535.         addPrize(); // Add one prize field by default
  536.     </script>
  537. </body>
  538. </html>
复制代码


免责
帖子地址打造全网最多免费游戏网站
今日来客 列表模式
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

本站已运行 ©2013-2026

QQ|Archiver|手机版|小黑屋|蔡州手游 |网站地图

GMT+8, 2025-11-13 17:13

Powered by Discuz! X3.5

© 2001-2025 Discuz! Team.

快速回复 返回顶部 返回列表