[HTML] 纯文本查看 复制代码
<!DOCTYPE html>
<html>
<head>
<meta name="screen-orientation" content="portrait">
<meta http-equiv="content-type" content="text/html; charset=utf-8">
<meta name="viewport"
content="width=device-width, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0, user-scalable=0" />
<title>年会抽奖</title>
<link rel="stylesheet" type="text/css" href="css/reset.css">
<link rel="stylesheet" type="text/css" href="css/index.css">
<script type="text/javascript" src="js/zepto.js"></script>
<script type="text/javascript" src="js/vue.js"></script>
<script type="text/javascript" src="js/tagcanvas.js"></script>
<script type="text/javascript" src="js/users.js"></script>
</head>
<body>
<div id="main" class="wall">
<!-- 中奖名单 -->
<div class="luck-user" id="luck-user">
<div class="luck-user-title">
<span>中奖名单</span>
</div>
<ul class="luck-user-list">
<li v-for="(item, index) in results" :key="index">
<div class="luckuserName">
<span class="uname">{{item[0]}}</span>
<span class="phone">{{item[1]}}</span>
</div>
</li>
</ul>
<div class="luck-user-btn">
<a href="#">中奖人</a>
</div>
</div>
<!-- 开始按钮 -->
<div id="tools" class="tools">
<button v-for="value in btns" @click="onClick(value)" class="pure-button"
:class="{ 'button-error': selected == value}">{{value}}</button>
<button class="pure-button" @click="toggle" :class="{'button-secondary': !running,
'button-success': running}">{{running?'停止':'开始'}}</button>
<button class="pure-button button-warning" @click="reset">重置</button>
</div>
</div>
<div id="result" class="result"></div>
<button id="continue" class="continue">继续抽奖</button>
</body>
<script type="text/javascript">
// 画布
var canvas = document.createElement('canvas');
canvas.id = 'myCanvas';
canvas.width = document.body.offsetWidth;
canvas.height = document.body.offsetHeight;
document.getElementById('main').appendChild(canvas);
// 取本地数据 (存储已经中奖的 key)
var choosed = JSON.parse(localStorage.getItem('choosed')) || {};
// 抽奖历史记录存储 (存储每次抽奖的结果,用于名单展示)
// 结构: { '抽奖时间': ['姓名<br>电话', ...] }
// 为了防止冲突,单独一个 key 存储,而不是散落在多个 key
var HISTORY_KEY = 'lottery_history';
// 处理函数
function speed() {
return [0.1 * Math.random() + 0.01, -(0.1 * Math.random() + 0.01)];
}
function getKey(item) {
return item.name + '-' + item.phone;
}
function createHTML() {
var html = ['<ul>'];
member.forEach(function (item, index) {
item.index = index;
var key = getKey(item);
var color = choosed[key] ? 'yellow' : 'white';
// 修复:背景色改为红色,但中奖后变暗或不同样式?保留原有逻辑,仅颜色区分
// 原逻辑是显示中奖用户为黄色,其他白色。此处保留
html.push('<li><a href="#" style="color: ' + color + ';display: block; width: 100px; height: 100px; background: red;">' + item.name + '</a></li>');
});
html.push('</ul>');
return html.join('');
}
// 抽奖核心:返回中奖者信息数组,同时更新 choosed 和页面颜色,并记录到历史
function lottery(count) {
var list = canvas.getElementsByTagName('a');
var color = 'yellow';
// 获取未中奖的成员,随机排序,取前 count 个
var winners = member
.filter(function (m) {
m.index = m.index; // 确保 index 存在(后面会用)
return !choosed[getKey(m)];
})
.map(function (m) {
return Object.assign({
score: Math.random()
}, m);
})
.sort(function (a, b) {
return a.score - b.score;
})
.slice(0, count);
// 如果没有可抽的人,返回空数组
if (winners.length === 0) {
return [];
}
// 标记中奖者并生成返回文本
var ret = winners.map(function (m) {
choosed[getKey(m)] = 1;
// 更新对应画布元素的颜色为黄色
if (list[m.index]) {
list[m.index].style.color = color;
}
// 返回格式: "姓名<br>电话"
return m.name + '<br>' + m.phone;
});
// 保存 choosed 到 localStorage
localStorage.setItem('choosed', JSON.stringify(choosed));
// 记录本次抽奖结果到历史 (使用时间戳作为key,确保唯一)
var history = JSON.parse(localStorage.getItem(HISTORY_KEY)) || {};
// 用当前时间作为记录键 (毫秒级可能重复?加随机数)
var recordKey = new Date().getTime() + '_' + Math.floor(Math.random() * 1000);
history[recordKey] = ret;
localStorage.setItem(HISTORY_KEY, JSON.stringify(history));
return ret;
}
// 功能:Vue实例 - 控制按钮和抽奖逻辑
new Vue({
el: '#tools',
data: {
selected: 1,
running: false,
btns: [1, 2, 5, 10, 30]
},
mounted() {
canvas.innerHTML = createHTML();
TagCanvas.Start('myCanvas', '', {
textColour: null,
initial: speed(),
dragControl: 1,
textHeight: 14
});
// 初始化后刷新中奖名单显示
if (window.refreshLuckList) window.refreshLuckList();
},
methods: {
reset() {
if (confirm('确定要重置么?所有之前的抽奖历史将被清除!')) {
// 清除 choosed 和 history
localStorage.removeItem('choosed');
localStorage.removeItem(HISTORY_KEY);
// 兼容之前散落的 key (可选)
// 但如果之前是散落的多个 key,这里也可以清一下,但为保险,完全清除 localStorage 但保留可能的其他?
// 直接用 localStorage.clear() 最简单,但可能会清除其他无关数据。根据需求,这里使用 clear 是原逻辑,但为了不误删,可以保留,但用户可能希望完全重置。
// 为了兼容旧版本可能散落的数据,最简单还是 clear,但为了安全我们只清除我们的key和旧的散落key?
// 原代码用的是 localStorage.clear(),我们就保持原样,但注意可能会清除其他数据。年会抽奖一般独立页面,没关系。
// 但为了不误删,可以只删特定 key。但旧版本可能存储了时间戳的key,直接 clear 也可以。我们改为更安全的方式:遍历删除除了可能需要的其他?算了,就用 clear 吧,和原来保持一致。
localStorage.clear();
location.reload(true);
}
},
onClick(num) {
$('#result').css('display', 'none');
$('#continue').css('display', 'none');
$('#main').removeClass('mask');
this.selected = num;
},
// 开始/停止抽奖
toggle() {
if (this.running) {
// 当前是运行中,点击停止 => 执行抽奖
TagCanvas.SetSpeed('myCanvas', speed());
var ret = lottery(this.selected);
if (ret.length === 0) {
$('#result').css('display', 'block').html('<span>已抽完</span>');
// 即使抽完也刷新一下名单?没有必要
return;
}
// 中奖人信息展示在 result 区域
$('#result').css('display', 'block').html('<span>' + ret.join('</span><span>') + '</span>');
$('#continue').css('display', 'block');
TagCanvas.Reload('myCanvas');
// 新增:立即刷新中奖名单显示 (触发 luck-user 组件的更新)
if (window.refreshLuckList) {
window.refreshLuckList();
}
setTimeout(function () {
// 注意:上面 lottery 已经存储了历史,这里不需要再存储了,原逻辑是存储到 localStorage 以时间戳为 key,我们现在统一用 history 存储
// 但原逻辑还做了 $('#main').addClass('mask'),我们保留
$('#main').addClass('mask');
}, 300);
} else {
// 开始抽奖:隐藏结果,移除遮罩,加速旋转
$('#result').css('display', 'none');
$('#continue').css('display', 'none');
$('#main').removeClass('mask');
TagCanvas.SetSpeed('myCanvas', [5, 1]);
}
this.running = !this.running;
}
}
});
// 中奖名单组件 - 独立Vue实例
// 为了能够从外部刷新,我们将 refresh 方法挂载到 window 上
(function() {
var luckVue = new Vue({
el: '#luck-user',
data: {
results: [] // 每个元素为 [name, phone] 数组
},
mounted() {
this.loadResults();
// 暴露刷新方法
window.refreshLuckList = () => {
this.loadResults();
};
},
methods: {
loadResults() {
// 从 localStorage 的 history 中读取所有中奖记录
var history = JSON.parse(localStorage.getItem(HISTORY_KEY)) || {};
var allResults = [];
// 按时间戳排序(时间戳越小越早),但我们的 key 是 "时间戳_随机数",提取时间戳排序
var keys = Object.keys(history);
keys.sort((a, b) => {
var tsA = parseInt(a.split('_')[0]) || 0;
var tsB = parseInt(b.split('_')[0]) || 0;
return tsA - tsB;
});
// 遍历每个记录,将每个记录中的中奖者字符串解析成 [name, phone]
keys.forEach(key => {
var record = history[key]; // 数组,元素如 "张三<br>13800000000"
if (Array.isArray(record)) {
record.forEach(itemStr => {
// 分割字符串:姓名<br>电话
var parts = itemStr.split('<br>');
if (parts.length >= 2) {
allResults.push([parts[0], parts[1]]);
} else {
// 兼容可能只有名字的情况
allResults.push([itemStr, '']);
}
});
}
});
// 去重?根据业务,同一个用户可能多次中奖?年会抽奖一般不会重复中奖,但代码逻辑是 choosed 控制,不会重复。
// 这里直接赋值
this.results = allResults;
}
}
});
})();
// 点击事件(继续抽奖)- 使用原生 jQuery/Zepto
$("#continue").click(function () {
$('#continue').css('display', 'none');
$('#main').removeClass('mask');
$('#result').css('display', 'none');
// 完全刷新页面可能导致重新抽奖逻辑重置,但为了清除状态,可以选择刷新
// 但是刷新后,画布重新生成,choosed 从 localStorage 读取,所以中奖用户依然黄色,没问题。
location.reload(true);
});
</script>
</body>
</html>