Commit 4d26b95e authored by fushaowu's avatar fushaowu

feat: + 年会抽奖

parents
# 年会抽奖
## 目录
```
├── README.md
├── package-lock.json
├── package.json
└── src
├── admin.html // 管理页面
├── assets
│ └── favicon.ico
├── style
│ └── common.css
├── info.js //人员信息
├── list.html //列表页面
├── lottery.html // html
├── lottery.js // 逻辑页面
├── vue.js
└── xlsxToJson.js
```
## 抽奖使用
- 打开`admin.html`页面,输入人数(必填),标题(必填),奖品信息(非必填)
- 点击`打开抽奖页面`即打开新抽奖页面
- 点击`打开中奖人员名单`即打开中奖人员名单
## 抽奖规则
- 每一位人员只能中一次奖,下一次将从奖池中删除
## 抽奖逻辑
**获取抽奖名单**
```
function getLotteryList(num = 20, wonList = []) {
let personInfoList = [...personInfoMap.values()]
let personMap = new Map();
// 获取抽奖总数的数组
while (personMap.size < num) {
// 随机数抽取获取中奖名单索引
let random = Math.floor(Math.random() * personInfoList.length);
if (!wonList.includes(personInfoList[random]['id'])) {
personMap.set(personInfoList[random]['id'], personInfoList[random])
};
}
return [...personMap.values()];
}
```
**每一次中奖后就从奖池中删除该成员**
```
for (const key in winPerson) {
winPerson[key].forEach(val => {
wonList.push(val.id)
// 删除奖池中中奖人员名单
personInfoMap.delete(val.id)
});
}
```
This diff is collapsed.
{
"name": "node",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"dev": "nodemon src/index.js --watch src"
},
"keywords": [],
"author": "",
"license": "ISC",
"devDependencies": {
"puppeteer": "^5.5.0",
"xls-to-json": "^2.1.0"
}
}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>抽奖配置</title>
<link rel="shortcut icon" href="./assets/favicon.ico" type="image/x-icon" />
<style>
html,
body {
width: 100%;
height: 100%;
}
#admin {
width: 100%;
height: 100%;
display: flex;
justify-content: center;
align-items: center;
flex-wrap: wrap;
}
.form {
display: flex;
justify-content: center;
align-items: center;
width: 100%;
}
.btn-box {
margin-top: 30px;
display: flex;
justify-content: center;
width: 100%;
align-items: center;
}
</style>
</head>
<body>
<div id="admin">
<div>
<div class="form">
<div>
<label for="" style="margin-left: 50px">人数:</label>
<input type="number" name="" id="num" style="width: 100px" />
</div>
<div>
<label for="" style="margin-left: 50px">标题:</label>
<input type="text" name="" id="title" style="width: 300px" />
</div>
<div>
<label for="" style="margin-left: 50px">奖品信息:</label>
<input type="text" name="" id="info" style="width: 300px" />
</div>
</div>
<div class="btn-box">
<div><button style="margin-left: 50px" onclick="submit()">打开抽奖页面</button></div>
<div><button style="margin-left: 50px" onclick="window.open('./list.html')">打开中奖人员名单</button></div>
<div><button style="margin-left: 50px" onclick="window.open('./lottery.html?num=10&title=一等奖&info=奖品:macpro一部')">一等奖</button></div>
<div><button style="margin-left: 50px" onclick="window.open('./lottery.html?num=20&title=二等奖&info=奖品:mac air一部')">二等奖</button></div>
<div><button style="margin-left: 50px" onclick="window.open('./lottery.html?num=30&title=三等奖&info=奖品:iphone 12一部')">三等奖</button></div>
</div>
</div>
</div>
<script>
function submit() {
let winPerson = localStorage.getItem('yit') ? JSON.parse(localStorage.getItem('yit')) : {}
let num = document.getElementById('num').value;
let title = document.getElementById('title').value;
let info = document.getElementById('info').value;
if(winPerson[title]) {
let status = window.confirm('该标题已存在,跳转至抽奖结果页面')
status && window.open('./list.html')
} else {
if (num && title) {
window.open(`./lottery.html?num=${num}&title=${title}&info=${info}`);
} else {
alert('请输入人数和标题')
}
}
}
</script>
</body>
</html>
This diff is collapsed.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>中奖名单</title>
<link rel="shortcut icon" href="./assets/favicon.ico" type="image/x-icon" />
<link rel="stylesheet" href="./style/common.css" />
<script src="./info.js"></script>
<script src="./vue.js"></script>
</head>
<body>
<div id="v1">
<div v-for="(item, index) in persons" class="list-item">
<h3 class="title">{{index}}</h3>
<div class="jump-box" style="margin-left: 20px">
<div v-for="it in item" class="jump-item">{{it.name}} {{it.firstLevelDepartment}}</div>
</div>
</div>
</div>
<script src="./lottery.js"></script>
</body>
</html>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>抽奖</title>
<link rel="shortcut icon" href="./assets/favicon.ico" type="image/x-icon" />
<link rel="stylesheet" href="./style/common.css" />
<script src="./info.js"></script>
<script src="./vue.js"></script>
<script></script>
</head>
<body onkeydown="submit(event)">
<div id="v1" data-num="10">
<div class="step1" v-if="step === 1">
<div class="title">{{awardTitle}}</div>
<div class="info" v-if="awardInfo">奖品:{{awardInfo}}</div>
</div>
<div v-if="step !== 1" class="step2">
<h3>幸运员工&nbsp;&nbsp;({{statusText}})</h3>
<div class="jump-box">
<div v-for="item in jumpList" class="jump-item">{{item.name}} {{item.firstLevelDepartment}}</div>
</div>
</div>
</div>
<script src="./lottery.js"></script>
</body>
</html>
function getLotteryList(num = 20, wonList = []) {
let personInfoList = [...personInfoMap.values()];
if (num > personInfoList.length) {
vue.num = personInfoList.length;
num = personInfoList.length;
}
let personMap = new Map();
while (personMap.size < num) {
let random = Math.floor(Math.random() * personInfoList.length);
if (!wonList.includes(personInfoList[random]['name'])) {
personMap.set(personInfoList[random]['name'], personInfoList[random]);
}
}
return [...personMap.values()];
}
let vue = new Vue({
el: '#v1',
data: () => {
return {
awardTitle: '', // 标题
awardInfo: '', // 奖品信息
step: 1,
jumpList: [], // 中奖列表
persons: {}, // list 页面
personInfoList: personInfoList, // 人员名单
interval: null,
num: 0, // 人数
statusText: '抽奖中...'
};
},
created() {
this.persons = localStorage.getItem('yit') ? JSON.parse(localStorage.getItem('yit')) : {};
let urlParams = window.decodeURI(location.href).split('?')[1]?.split('&');
let params = {};
if (urlParams) {
urlParams.forEach(val => {
let v = val.split('=');
params[v[0]] = v[1];
});
this.num = params.num;
this.awardTitle = params.title;
this.awardInfo = params.info;
}
this.jumpList = getLotteryList(this.num, []);
},
watch: {
step(newValue, oldValue) {
if (newValue === 2) {
let wonList = [];
let winPerson = localStorage.getItem('yit');
if (winPerson) {
winPerson = JSON.parse(winPerson);
for (const key in winPerson) {
winPerson[key].forEach(val => {
wonList.push(val.name);
personInfoMap.delete(val.name);
});
}
}
if(personInfoMap.size === 0) {
let status = window.confirm('没有未中奖人员, 去往抽奖结果页面');
status && window.open('./list.html');
this.jumpList = []
this.step = 1
this.statusText = '抽奖完成'
return
}
this.interval = setInterval(() => {
this.jumpList = getLotteryList(this.num, wonList);
}, 100);
} else {
if (this.interval) {
clearInterval(this.interval);
this.interval = null;
this.statusText = '抽奖完成'
this.saveData();
}
}
},
},
methods: {
saveData() {
let winPerson = {};
this.jumpList = getLotteryList(this.num, []);
if (localStorage.getItem('yit')) {
winPerson = JSON.parse(localStorage.getItem('yit'));
}
winPerson[this.awardTitle] = this.jumpList;
localStorage['yit'] = JSON.stringify(winPerson);
},
},
});
function submit(event) {
if (event.keyCode === 13) {
if (vue.step === 1) {
vue.step = 2;
} else if (vue.step === 2) {
if (vue.interval) {
clearInterval(vue.interval);
vue.interval = null;
vue.statusText = '抽奖完成'
vue.saveData();
}
}
}
}
html, body {
width: 100%;
}
* {
padding: 0;
margin: 0;
}
#v1 {
width: 100%;
height: 100%;
}
.step1 {
width: 100%;
height: 100%;
position: absolute;
display: flex;
align-items: center;
justify-content: center;
flex-direction: column;
}
.title, .info {
text-align: center;
}
.title {
letter-spacing: 10px;
font-size: 32px;
}
.info {
margin-top: 20px;
font-size: 16px;
}
.step2 {
padding-top: 35vh;;
width: 100%;
text-align: center;
}
.jump-item {
background-color: #dda9e6;
margin-left: 2%;
margin-right: 2%;
height: 50px;
line-height: 50px;
width: 16%;
text-align: center;
margin-top: 30px;
margin-bottom: 30px;
}
.jump-box {
width: 100%;
display: flex;
align-items: center;
justify-content: flex-start;
flex-wrap: wrap;
}
.list-item:nth-child(1) h3 {
padding-top: 30px;
}
\ No newline at end of file
This diff is collapsed.
let xlsxj = require('xls-to-json');
const path = require('path');
xlsxj(
{
input: path.join(process.cwd(), 'file', 'test.xls'),
output: path.join(process.cwd(), 'src', 'info.json'),
},
function (err, result) {
if (err) {
console.error(err);
} else {
console.log(result);
}
}
);
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment