需要用到 xlsx 和 file-saver 包,如果有帮助,还请点个赞哟!
css动画
/* css动画效果 */
@keyframes scale {
0% {
transform: scale(0);
}
100% {
transform: scale(1)
}
}
@keyframes flash {
0% {
opacity: 0;
-webkit-transform: scale(1.5);
transform: scale(1.5);
color: transparent;
text-shadow: 0 0 5px rgba(0, 0, 0, 0.5)
}
50% {
opacity: 1
}
100% {
opacity: 0;
-webkit-transform: scale(0.5);
transform: scale(0.5)
}
}
@keyframes flow {
0% {
background-position: 50% 0
}
100% {
background-position: 50% -250px
}
}
@keyframes flash {
0% {
opacity: 0;
-webkit-transform: scale(1.5);
transform: scale(1.5);
color: transparent;
text-shadow: 0 0 5px rgba(0, 0, 0, 0.5)
}
50% {
opacity: 1
}
100% {
opacity: 0;
-webkit-transform: scale(0.5);
transform: scale(0.5)
}
}
@keyframes shake {
0% {
-webkit-transform: translateX(5px);
transform: translateX(5px)
}
20% {
-webkit-transform: translateX(-10px);
transform: translateX(-10px)
}
40% {
-webkit-transform: translateX(15px);
transform: translateX(15px)
}
60% {
-webkit-transform: translateX(-20px);
transform: translateX(-20px)
}
80% {
-webkit-transform: translateX(15px);
transform: translateX(15px)
}
100% {
-webkit-transform: translateX(-10px);
transform: translateX(-10px)
}
}
@keyframes dinnerTip {
0%,
100% {
opacity: 0;
-webkit-transform: perspective(600px) translate3d(-50%, 7px, 0) scale(0.7) rotateY(180deg);
transform: perspective(600px) translate3d(-50%, 7px, 0) scale(0.7) rotateY(180deg)
}
20%,
80% {
opacity: 1;
-webkit-transform: perspective(600px) translate3d(-50%, 0, 0) rotateY(0deg);
transform: perspective(600px) translate3d(-50%, 0, 0) rotateY(0deg)
}
}
@keyframes comment {
0%,
100% {
opacity: 0;
-webkit-transform: translate3d(-50%, 200%, 0) scale(0.7);
transform: translate3d(-50%, 200%, 0) scale(0.7)
}
20%,
80% {
opacity: 1;
-webkit-transform: translate3d(-50%, 0, 0);
transform: translate3d(-50%, 0, 0)
}
}
主体代码
<!--
Name: 抽奖首页
author: xingyuelongchen
QQ : 237956234
Date : 2021-09-23
-->
<template>
<div class="body">
<el-tooltip effect="dark" content="抽奖设置" placement="right">
<span class="setting" @click="$router.push('/setting')"></span>
</el-tooltip>
<div class="bg"></div>
<div class="temp_container">
<div class="temp" v-for="(item,index) in domlist" :key="item.phone+'-'+index" v-bind="item">{{item.phone}}</div>
</div>
<div class="box">
<div class="title">{{tips}}</div>
<div class="title">{{msg}}</div>
<div class="btn" @click="start">
<span class="start">
<span>{{btn}}</span>
</span>
</div>
</div>
<div v-show="show" class="dialog">
<div class="dialog-bg" @click="show=false"> </div>
<div class="border"></div>
<div class="dialog-box">{{winning}}</div>
</div>
</div>
</template>
<script>
export default {
name: "index",
data() {
return {
show: false,
winning: "",
tips: "",
msg: "抽奖即将开始!",
btn: "开始",
current: null,
list: [],
domlist: [],
status: false,
width: null,
height: null
};
},
mounted() {
this.list = JSON.parse(localStorage.getItem("list") || "[]");
this.width = window.innerWidth;
this.height = window.innerHeight;
window.onresize = () => {
this.width = window.innerWidth;
this.height = window.innerHeight;
};
},
methods: {
async start() {
if (!this.list.length) {
if (await this.$confirm("无参与抽奖的人员,是否去添加?", "提示!", { type: "warning" })) {
this.$router.push("/setting");
}
return;
}
if (this.status) return this.stop();
if (this.show) return;
this.tan();
this.status = true;
this.current = null;
this.tips = "正在抽奖";
this.btn = "停止";
this.timer = setInterval(() => {
let index = this.random(0, this.list.length);
this.current = index;
let name = this.list[index]?.name || "";
let phone = this.list[index]?.phone || "";
this.msg = this.re(name, 1, 2) + " " + this.re(phone, 3, 7, "****");
}, 50);
},
stop() {
clearInterval(this.timer);
clearTimeout(this.tanTimer);
this.status = false;
this.btn = "继续";
let { phone } = this.list[this.current];
this.winning = `${this.re(phone, 3, 7, "****")}`;
this.show = true;
let list = this.list.splice(this.current, 1);
let arr = JSON.parse(localStorage.getItem("draw") || "[]");
localStorage.setItem("list", JSON.stringify(this.list));
localStorage.setItem("draw", JSON.stringify(list.concat(arr)));
},
tan() {
clearTimeout(this.tanTimer);
let arr = new Array(10).fill().map(() => {
let index = this.random(0, this.list.length);
let name = this.re(this.list[index]?.name || "", 1, 2);
let phone = this.re(this.list[index]?.phone || "", 3, 7, "****");
let left = this.random(0, this.width) + "px";
let top = this.random(0, this.height) + "px";
let fontSize = this.random(10, 30) + "px";
let color = `rgba(0,0,0,${this.random(3, 8) / 10})`;
let style = { left, top, fontSize, color };
return { name, phone: Math.ceil(Math.random() * 1 - 0.5) ? name : phone, style };
});
this.domlist.push(...arr);
this.tanTimer = setTimeout(() => this.tan(), 1000);
},
random(s, e) {
return Math.floor(Math.random() * (e - s) + s);
},
re(val = "", s = 0, e = 0, k = "*") {
val = val + "";
return val.replace(val.slice(s, e), k);
}
}
};
</script>
<style scoped>
.setting {
width: 100px;
height: 100px;
cursor: pointer;
position: absolute;
top: 0%;
right: 0;
z-index: 99;
}
.body {
background: #e9e9e9;
}
.box {
position: absolute;
top: 0;
right: 0;
bottom: 0;
left: 0;
margin: auto;
width: 300px;
height: 61px;
display: flex;
justify-content: center;
flex-direction: column;
align-items: center;
}
.box .title {
margin: 0 0 30px;
min-height: 50px;
padding: 0;
font-weight: 400;
font-size: 32px;
color: #333;
white-space: nowrap;
/* overflow: hidden;
text-overflow: ellipsis; */
}
.box .title.shake {
animation: shake 0.4s;
}
.bg {
background: #e9e9e9 url(~@/assets/images/bg.jpg) 50% 0;
transform: translate3d(0, 0, 0);
animation: flow 16s linear infinite;
position: fixed;
top: 0;
left: 0;
right: 0;
bottom: 0;
z-index: -1;
}
.playing .bg {
animation-play-state: paused;
}
.temp_container {
transform: translate3d(0, 0, 0);
overflow: hidden;
height: 100%;
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
z-index: 0;
}
.temp_container .temp {
position: absolute;
color: #777;
animation: flash 1.6s ease-out both;
white-space: nowrap;
}
.btn .start {
background: rgba(0, 0, 0, 0.1);
border-radius: 40px;
padding: 5px;
box-shadow: inset 0 2px 3px rgba(0, 0, 0, 0.07), 0 1px rgba(255, 255, 255, 0.5);
display: inline-block;
cursor: pointer;
}
.btn .start span {
border-radius: 35px;
width: 180px;
height: 60px;
line-height: 60px;
background: linear-gradient(to bottom, #ffba30, #ff911e);
color: #fff;
text-align: center;
display: block;
font-size: 32px;
text-shadow: 0 1px 2px rgba(0, 0, 0, 0.3);
box-shadow: inset 0 1px #ffd17c, 0 2px 3px rgba(0, 0, 0, 0.2);
border: 1px solid #e88e1d;
}
.btn .start:hover span {
background: linear-gradient(to bottom, #ffce44, #ffa532);
box-shadow: inset 0 1px #ffe696, 0 2px 3px rgba(0, 0, 0, 0.2);
}
.btn .start:active span {
background: linear-gradient(to bottom, #ff911e, #ffbb30);
box-shadow: inset 0 1px #ffb050, 0 2px 3px rgba(0, 0, 0, 0.2);
}
.dialog {
position: fixed;
top: 0;
left: 0;
right: 0;
bottom: 0;
margin: auto;
/* background: url(~@/assets/images/bg1.jpeg) center center / 100% 100%; */
background: rgba(214, 71, 65, 1);
color: #fff;
width: 800px;
height: 375px;
border-radius: 7px;
box-shadow: 0 0 50px 10px rgba(0, 0, 0, 0.3);
z-index: 10000;
animation: scale 1.2s;
}
.dialog .dialog-bg {
position: absolute;
top: -125px;
left: 0;
right: 0;
margin: auto;
background: url(~@/assets/images/top.png) no-repeat center center / 100% 100%;
width: 300px;
height: 106px;
cursor: pointer;
}
.dialog .border {
margin: 15px;
border: 5px solid rgba(255, 245, 33, 0.6);
height: 340px;
border-radius: 10px;
}
.dialog .dialog-box {
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
margin: auto;
width: 450px;
height: 130px;
background: rgba(255, 255, 255, 0.8);
border-radius: 7px;
color: rgba(214, 71, 65, 1);
font-size: 60px;
text-align: center;
line-height: 130px;
}
</style>
配置页
<!--
Name: setting
author: xingyuelongchen
QQ : 237956234
Date : 2021-09-15
-->
<template>
<div>
<div class="page">
<el-card style="flex:0 0 400px">
<div slot="header">
<span>上传列表</span>
<el-button @click="down" size="mini" type="success" style="float:right">下载模板</el-button>
</div>
<el-upload action="#" :on-change="uploadFile" :accept="accept" :auto-upload="false" :show-file-list="false" drag>
<i class="el-icon-upload"></i>
<div class="el-upload__text">将文件拖到此处,或<em>点击上传</em></div>
<div class="el-upload__tip">只允许({{accept}})表格文件</div>
</el-upload>
<el-form ref="form" :model="formData" :rules="rules">
<el-form-item v-for="item in formFields" v-bind="item" :key="item.prop">
<el-input v-model="formData[item.prop]"></el-input>
</el-form-item>
<el-form-item>
<el-button @click="add" type="primary">添加</el-button>
</el-form-item>
</el-form>
</el-card>
<el-card style="flex:1 1 auto;margin-left:20px">
<div slot="header">
<span>参与抽奖人员列表</span>
<el-button @click="to" size="mini" type="success" style="float:right">去抽奖</el-button>
</div>
<el-table :data="tableData" border height="500px" stripe>
<el-table-column label="姓名" prop="name" />
<el-table-column label="手机号" prop="phone" />
<el-table-column>
<template slot-scope="{row}">
<el-button type="danger" size="mini" @click="del(row)">删除</el-button>
</template>
</el-table-column>
</el-table>
</el-card>
<el-card style="flex:0 0 500px;margin-left:20px">
<div slot="header">
<span>中奖名单</span>
<el-button @click="downTable" size="mini" type="success" style="float:right">下载数据</el-button>
</div>
<el-table :data="tableDraw" border height="500px" stripe :show-header="false" ref="table" id="table">
<el-table-column label="姓名" prop="name" />
<el-table-column label="手机号" prop="phone" />
</el-table>
</el-card>
</div>
</div>
</template>
<script>
import XLSX from "xlsx";
import FileSaver from "file-saver";
export default {
name: "setting",
data() {
return {
accept: ".xlsx,.xls",
tableData: JSON.parse(localStorage.getItem("list") || "[]"),
tableDraw: JSON.parse(localStorage.getItem("draw") || "[]"),
formData: {},
formFields: [
{ label: "姓名", prop: "name" },
{ label: "手机号", prop: "phone", maxLength: 11 }
],
rules: {
name: { required: true, pattern: /^[\u4e00-\u9fa5]{2,10}$/, message: "请输入正确的姓名", trigger: ["blur"] },
phone: { required: true, pattern: /^1[3-9][0-9]{9}$/, message: "请输入正确的11位手机号", trigger: ["blur"] }
}
};
},
methods: {
downTable() {
let wb = XLSX.utils.table_to_book(document.querySelector("#table"), { raw: true });
let wbout = XLSX.write(wb, {
type: "array",
bookSST: true,
bookType: "xlsx"
});
try {
FileSaver.saveAs(new Blob([wbout], { type: "appliction/octet-stream" }), "中奖名单.xlsx");
} catch (error) {
console.log(error, wbout);
}
return wbout;
},
down() {
let a = document.createElement("a");
a.download = "人员信息上传模板.xlsx";
a.href = "/template.xlsx";
a.click();
},
del(row) {
this.tableData = [...this.tableData].filter((e) => e.phone !== row.phone);
this.save();
},
async add() {
await this.$refs.form.validate();
this.tableData.push({ ...this.formData });
this.$refs.form.resetFields();
this.save();
},
save() {
let json = JSON.stringify(this.tableData);
window.localStorage.setItem("list", json);
},
async to() {
if (this.tableData.length) this.$router.push("/");
else if (await this.$confirm("添加了0个人,确定离开?", "提示!", { type: "warning" })) {
this.$router.push("/");
}
},
async uploadFile(file) {
if (!/(\.xlsx|\.xls)$/g.test(file.name)) {
this.$message.error("请上传excel表格文件");
return;
}
let { Sheets, SheetNames } = await this.readWorkbookFromLocalFile(file.raw);
// let obj = [];
this.tableData = [];
SheetNames.forEach((name) => {
let json = XLSX.utils.sheet_to_json(Sheets[name]);
this.tableData.push(...json);
});
this.save();
return false;
},
async readWorkbookFromLocalFile(file, callback) {
return new Promise((resolve, reject) => {
try {
var reader = new FileReader();
reader.onload = function (e) {
var data = e.target.result;
var workbook = XLSX.read(data, { type: "binary" });
if (callback) callback(workbook);
resolve(workbook);
};
reader.readAsBinaryString(file);
} catch (error) {
reject(error);
}
});
}
}
};
</script>
<style scoped>
.page {
display: flex;
justify-content: space-between;
align-items: stretch;
margin: 50px;
}
.mix-form {
margin-top: 20px;
}
</style>
项目地址:文字抽奖 (gitee.com);
请点个赞再走吧~
网友评论