我正在参加Trae「超级体验官」创意实践征文,本文所使用的 Trae 免费下载链接:www.trae.com.cn/?utm_source…
每年年会一到,咱们老板总是照例发几句牢骚,话说得那叫一个熟练:“公司养这么多程序员,连个抽奖网站都没人有空写,最后还得我自己花钱去外面买?!”
每次听到这,我内心的小剧场就开始轰轰烈烈地上演了:老板啊,咱真不是不想写,实在是日常项目一个接一个地压过来,改 Bug、赶进度、熬夜加班,哪儿还有空给您老整抽奖网站啊?再说了,年会项目这玩意,年年用一年一更新,写起来精力不小,回头您一句“今年换个花样”,我们又得推翻重来。就说实话吧,哪有那么多时间啊!
不过今年,我决定不一样了。今年不让您再破费买什么现成的抽奖工具,也不让您再对我们程序员指指点点地吐槽。抽奖网站这活儿,今年我自己接了——就让我亲手给咱年会整一个炫酷又实用的抽奖系统,顺便也在全公司面前亮一把技术肌肉,让您刮目相看!
说干就干。既然是年会抽奖,光是普通转盘可不够看,得加点花活儿才行——比如奖品弹幕、实时中奖名单、背景音乐,最好还能连上投影,动静大点儿才有年会气氛。关键是,开发周期又不能太长,毕竟业务的活儿可一个都不少。那怎么办?聪明如我,当然要借助点“神器”——Trae AIIDE,程序员提升效率的秘密武器!
可能还有人没听说过 Trae AIIDE 是啥,那我就稍微介绍一下。这是一个集智能代码补全、项目自动结构搭建、语义理解为一体的开发辅助平台,说白了,它能理解你想干什么,然后自动帮你搭出一个项目雏形,还能快速生成页面、逻辑、样式,连后端接口也能带着搞定。就像有个不眠不休、从不抱怨的“AI搭子”天天陪着你干活。这样的工具,做个抽奖助手那不是分分钟的事?
我先把抽奖流程理了一遍:主持人一声令下,页面开始倒计时,屏幕上滚动所有参会人员的头像,最终定格显示中奖人,然后弹出炫酷的特效动画和奖品信息。除此之外,后台还要有个小型的管理系统,用来添加奖品、设定奖项数量、查看中奖历史,顺便还能做点数据分析,看看哪个部门中奖最多,谁又是“非酋之王”。
发出指令:请使用html写一美观的抽奖助手,支持人员信息录入。
有了 Trae,我不再从零开始搭建项目结构,而是通过自然语言告诉它: “我要一个抽奖助手的前端页面,支持人员滚动、奖项设置和动画效果;后端要能处理奖品数据、中奖记录和用户信息。” 几分钟内,基础代码就自动生成好了,大概相当于平时我两三个小时才能撸完的初版页面。这效率,真的不是吹。
接着我开始定制前端页面,Trae 帮我把 UI 框架搭好,我稍微调整了一下配色,配上公司 Logo 和年会主题,“Lucky Draw 2025 欢欢喜喜中大奖”几个大字一打上去,年味儿立马就出来了。动画部分我用了 CSS3 和 canvas 做了爆炸效果,每次抽奖都会有小彩球飞溅,视觉冲击力直接拉满。
发出指令:帮我写一个有渐变背景和奖项动画效果的 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> <link href="https://fonts.googleapis.com/css2?family=Poppins:wght@400;600&display=swap" rel="stylesheet"> <style> :root { --primary: #FFD700; --secondary: #C41E3A; --error: #ff4757; --gold-gradient: linear-gradient(135deg, #FFD700 0%, #B8860B 100%); } * { box-sizing: border-box; font-family: 'Poppins', sans-serif; } body { background: var(--gold-gradient); min-height: 100vh; padding: 2rem; position: relative; overflow-x: hidden; } /* 节日装饰 */ .lantern { position: absolute; width: 60px; animation: float 3s ease-in-out infinite; filter: drop-shadow(0 5px 15px rgba(255, 215, 0, 0.5)); } .ribbon { position: absolute; height: 100vh; width: 50px; background: repeating-linear-gradient( 45deg, #C41E3A, #C41E3A 10px, #FFD700 10px, #FFD700 20px ); animation: sway 5s linear infinite; } .container { max-width: 800px; margin: 0 auto; background: rgba(255,255,255,0.95); border-radius: 1rem; box-shadow: 0 10px 30px rgba(0,0,0,0.1); padding: 2rem; } .form-group { margin-bottom: 1.5rem; } label { display: block; margin-bottom: 0.5rem; color: #333; font-weight: 600; } input { width: 100%; padding: 0.8rem; border: 2px solid #e0e0e0; border-radius: 0.5rem; font-size: 1rem; transition: border-color 0.3s ease; } input:focus { outline: none; border-color: var(--primary); box-shadow: 0 0 0 3px rgba(74, 144, 226, 0.1); } .error-message { color: var(--error); font-size: 0.875rem; margin-top: 0.5rem; display: none; } .button { background: var(--primary); color: white; border: none; padding: 1rem 2rem; border-radius: 0.5rem; cursor: pointer; font-size: 1rem; transition: transform 0.2s, box-shadow 0.2s; } .button:hover { transform: translateY(-2px); box-shadow: 0 5px 15px rgba(74, 144, 226, 0.3); } /* 参与者列表 */ .participant-container { display: grid; gap: 1rem; margin-top: 1rem; max-height: 300px; overflow-y: auto; } .participant-item { display: flex; justify-content: space-between; padding: 1rem; background: #f8f9fa; border-radius: 0.5rem; animation: slideIn 0.3s ease; } /* 结果弹窗 */ .result-popup { position: fixed; top: 0; left: 0; width: 100%; height: 100%; background: rgba(0,0,0,0.5); display: flex; justify-content: center; align-items: center; animation: fadeIn 0.3s ease; } .popup-content { background: linear-gradient(45deg, #C41E3A, #FFD700); border: 3px solid #FFD700; animation: blink 1.5s ease infinite; padding: 2rem; border-radius: 1rem; text-align: center; box-shadow: 0 10px 30px rgba(0,0,0,0.2); } .winner-info { margin: 1.5rem 0; font-size: 1.2rem; } @keyframes slideIn { from { transform: translateY(20px); opacity: 0; } to { transform: translateY(0); opacity: 1; } } @keyframes float { 0%, 100% { transform: translateY(0); } 50% { transform: translateY(-20px); } } @keyframes sway { 0% { transform: rotate(0deg); } 25% { transform: rotate(2deg); } 75% { transform: rotate(-2deg); } 100% { transform: rotate(0deg); } } @keyframes blink { 0% { opacity: 0.8; } 50% { opacity: 1; text-shadow: 0 0 10px #FFD700; } 100% { opacity: 0.8; } } @keyframes firework { 0% { transform: scale(0); opacity: 1; } 100% { transform: scale(1); opacity: 0; } } @keyframes fadeIn { from { opacity: 0; } to { opacity: 1; } } </style></head><body> <!-- 节日装饰 --> <div class="lantern" style="left:10%;top:5%">🎉</div> <div class="lantern" style="right:10%;top:15%">🏮</div> <div class="ribbon" style="left:-25px"></div> <div class="ribbon" style="right:-25px"></div> <div class="container"> <h1>幸运抽奖系统</h1> <!-- 报名表单 --> <form id="registrationForm"> <div class="form-group"> <label for="name">姓名:</label> <input type="text" id="name" required> <div class="error-message" id="nameError"></div> </div> <div class="form-group"> <label for="phone">手机号:</label> <input type="tel" id="phone" pattern="\d{11}" required> <div class="error-message" id="phoneError"></div> </div> <button type="submit" class="button">立即报名</button> </form> <!-- 参与者列表 --> <div id="participantList"></div> <!-- 抽奖按钮 --> <button class="button" id="startLottery" style="margin-top: 2rem;">开始抽奖</button> </div> <script> // 数据存储逻辑 let participants = JSON.parse(localStorage.getItem('participants')) || []; const MAX_PARTICIPANTS = 200; // 初始化渲染 renderParticipantList(); updateLotteryButton(); // 表单提交处理 document.getElementById('registrationForm').addEventListener('submit', (e) => { e.preventDefault(); if (validateForm()) { const name = document.getElementById('name').value.trim(); const phone = document.getElementById('phone').value.trim(); // 检查重复报名 if (participants.some(p => p.phone === phone)) { showError('phoneError', '该手机号已报名'); return; } participants.push({ name, phone }); localStorage.setItem('participants', JSON.stringify(participants)); // 清空表单 e.target.reset(); document.querySelectorAll('.error-message').forEach(el => el.style.display = 'none'); renderParticipantList(); updateLotteryButton(); } }); // 抽奖按钮点击 document.getElementById('startLottery').addEventListener('click', startLottery); // 表单验证 function validateForm() { const name = document.getElementById('name').value.trim(); const phone = document.getElementById('phone').value.trim(); let isValid = true; // 清空错误提示 document.querySelectorAll('.error-message').forEach(el => el.style.display = 'none'); // 姓名验证 if (name.length < 2) { showError('nameError', '请输入有效姓名(至少2个字符)'); isValid = false; } // 手机号验证 if (!/^\d{11}$/.test(phone)) { showError('phoneError', '请输入有效的11位手机号'); isValid = false; } return isValid; } // 显示错误信息 function showError(elementId, message) { const errorElement = document.getElementById(elementId); errorElement.textContent = message; errorElement.style.display = 'block'; } // 渲染参与者列表 function renderParticipantList() { const listDiv = document.getElementById('participantList'); listDiv.innerHTML = `<h2>已报名人员 (${participants.length}/${MAX_PARTICIPANTS})</h2> <div class="participant-container"> ${participants.map(p => `<div class="participant-item"> <span>${p.name}</span> <span>${p.phone.replace(/(\d{3})\d{4}(\d{4})/, '$1****$2')}</span> </div>` ).join('')} </div>`; } // 更新抽奖按钮状态 function updateLotteryButton() { const btn = document.getElementById('startLottery'); btn.disabled = participants.length < 2; btn.textContent = participants.length >= 2 ? `开始抽奖 (剩余${participants.length}人)` : '至少需要2人参与抽奖'; } // 抽奖逻辑 function startLottery() { const btn = document.getElementById('startLottery'); btn.disabled = true; // 抽奖动画 let count = 0; const animation = setInterval(() => { btn.textContent = `抽奖进行中 ${['⣾','⣽','⣻','⢿','⡿','⣟','⣯','⣷'][count++ % 8]}`; }, 100); // 模拟抽奖过程 setTimeout(() => { clearInterval(animation); const winnerIndex = Math.floor(Math.random() * participants.length); const winner = participants.splice(winnerIndex, 1)[0]; localStorage.setItem('participants', JSON.stringify(participants)); showResultPopup(winner); renderParticipantList(); updateLotteryButton(); }, 2000); } // 显示结果弹窗 function showResultPopup(winner) { // 礼花特效function createFirework(x, y) { const firework = document.createElement('div'); firework.className = 'firework'; firework.style = `left:${x}px;top:${y}px;`; firework.innerHTML = '🎆'; document.body.appendChild(firework); setTimeout(() => firework.remove(), 1000);}// 显示结果弹窗const popup = document.createElement('div'); popup.className = 'result-popup'; popup.innerHTML = ` <div class="popup-content"> <h3>🎉 中奖者 🎉</h3> <div class="winner-info"> <p>姓名:${winner.name}</p> <p>电话:${winner.phone.replace(/(\d{3})\d{4}(\d{4})/, '$1****$2')}</p> </div> <button onclick="this.parentElement.parentElement.remove()">关闭</button> </div> `; document.body.appendChild(popup);// 触发礼花特效for(let i=0; i<8; i++) { setTimeout(() => { createFirework(Math.random()*window.innerWidth, Math.random()*window.innerHeight); }, i*100);} } </script></body></html>
从开始构思到完成测试,我一共用了不到小时天时间,就完成了这样一个功能齐全、界面美观、体验顺滑的抽奖系统。最重要的是,我还整了个“彩蛋”——每次高管中奖,背景会自动播放一段配乐,然后屏幕弹出“老板吉祥,财源滚滚来!”的标语。是不是很有意思?
项目上线后,年会那天效果果然惊艳到了所有人,尤其是老板。当他看到抽奖页面那一刻,先是愣了一下,然后嘴角就不自觉地上扬了。主持人一声“开始抽奖”,滚动头像、烟花动画、中奖提示一气呵成,全场一片掌声。最后老板忍不住感慨:“哎哟,今年这抽奖做得不错,是谁搞的?”
我默默走上台,假装谦虚地说:“老板,不用买了,以后年会抽奖,我一手包办。”
台下同事们笑声一片,我心里却暗自得意:这波,不仅证明了自己,也顺带让 Trae AIIDE 成了大家眼中的“神助攻”。以后谁还说程序员不浪漫、不懂氛围?咱不仅能写代码,还能点亮全场!