引言
年会是企业文化的缩影,而抽奖环节往往能极大地提升员工的参与度和幸福感。本文将介绍如何使用Vue.js框架构建一个年会抽奖应用,该应用不仅具备基本的抽奖功能,还能允许管理员动态调整各个奖项的中奖概率,从而增加抽奖的趣味性和公平性。
技术栈
- 前端框架:Vue.js 3
- 状态管理:Vuex 4(用于全局状态管理)
- UI组件库:Element Plus(用于快速构建用户界面)
- 路由管理:Vue Router 4(虽然本示例较为简单,但展示了基本的路由配置)
项目结构
/src
/assets # 静态资源文件夹
/components # Vue组件文件夹
- Draw.vue # 抽奖界面组件
- Admin.vue # 管理员界面组件
/store # Vuex状态管理文件夹
- index.js # Vuex主文件
/views # 页面视图文件夹
- Home.vue # 主页视图
- AdminPage.vue # 管理员页面视图
App.vue # 根组件
main.js # 入口文件
router/index.js # Vue Router配置
实现步骤
- 初始化项目:使用Vue CLI创建一个新的Vue 3项目,并安装Element Plus和Vuex。
vue create annual-meeting-lottery
cd annual-meeting-lottery
vue add router
vue add vuex
npm install element-plus --save
- 配置Vuex:在
/store/index.js
中定义状态管理逻辑,包括奖项列表和概率配置。
// /store/index.js
import { createStore } from 'vuex';
export default createStore({
state: {
prizes: [
{ name: '一等奖', probability: 0.01 },
{ name: '二等奖', probability: 0.05 },
{ name: '三等奖', probability: 0.1 },
// 更多奖项...
{ name: '参与奖', probability: 0.84 }
],
selectedPrize: null
},
mutations: {
setPrizes(state, prizes) {
state.prizes = prizes;
},
setSelectedPrize(state, prize) {
state.selectedPrize = prize;
}
},
actions: {
draw({ commit, state }) {
const totalProbability = state.prizes.reduce((sum, prize) => sum + prize.probability, 0);
const random = Math.random();
let cumulativeProbability = 0;
for (let prize of state.prizes) {
cumulativeProbability += prize.probability / totalProbability;
if (random < cumulativeProbability) {
commit('setSelectedPrize', prize);
break;
}
}
}
},
getters: {
prizes: state => state.prizes,
selectedPrize: state => state.selectedPrize
}
});
- 创建抽奖组件:在
/components/Draw.vue
中实现抽奖界面和按钮点击事件。
<!-- /components/Draw.vue -->
<template>
<div class="draw-container">
<el-button type="primary" @click="startDrawing">开始抽奖</el-button>
<div v-if="selectedPrize">
<h2>恭喜你抽中:{{ selectedPrize.name }}</h2>
</div>
</div>
</template>
<script>
import { mapActions, mapGetters } from 'vuex';
export default {
computed: {
...mapGetters(['selectedPrize'])
},
methods: {
...mapActions(['draw']),
startDrawing() {
this.draw();
// 可添加动画效果,例如使用CSS动画或第三方动画库
setTimeout(() => {
this.$message.success(`恭喜你抽中:${this.selectedPrize.name}`);
}, 1000); // 模拟动画延迟
}
},
data() {
return {
selectedPrize: null
};
},
watch: {
selectedPrize(newVal) {
if (newVal) {
// 可以在这里重置抽奖状态或执行其他逻辑
}
}
}
};
</script>
<style scoped>
.draw-container {
text-align: center;
margin-top: 50px;
}
</style>
- 创建管理员界面:在
/components/Admin.vue
中实现奖项和概率的编辑功能。
<!-- /components/Admin.vue -->
<template>
<div class="admin-container">
<el-form :model="form">
<el-form-item v-for="(prize, index) in prizes" :key="index" :label="'奖项 ' + (index + 1)">
<el-input v-model="prize.name" placeholder="请输入奖项名称"></el-input>
<el-input-number v-model="prize.probability" :controls="false" placeholder="请输入中奖概率"></el-input-number>
</el-form-item>
<el-form-item>
<el-button type="primary" @click="savePrizes">保存</el-button>
</el-form-item>
</el-form>
</div>
</template>
<script>
import { mapState, mapMutations } from 'vuex';
export default {
data() {
return {
form: {}
};
},
computed: {
...mapState(['prizes'])
},
methods: {
...mapMutations(['setPrizes']),
savePrizes() {
// 这里假设直接保存当前state中的prizes,实际应用中可能需要发送到后端保存
this.setPrizes([...this.prizes]);
this.$message.success('奖项配置已保存');
}
}
};
</script>
<style scoped>
.admin-container {
width: 60%;
margin: 0 auto;
}
</style>
- 配置路由:在
/router/index.js
中配置抽奖页面和管理员页面的路由。
// /router/index.js
import { createRouter, createWebHistory } from 'vue-router';
import Home from '../views/Home.vue';
import AdminPage from '../views/AdminPage.vue';
const routes = [
{
path: '/',
name: 'Home',
component: Home
},
{
path: '/admin',
name: 'Admin',
component: AdminPage
}
];
const router = createRouter({
history: createWebHistory(process.env.BASE_URL),
routes
});
export default router;
- 创建视图组件:在
/views
文件夹下创建Home.vue
和AdminPage.vue
,分别用于展示抽奖界面和管理员界面。
<!-- /views/Home.vue -->
<template>
<div>
<Draw />
<el-button type="text" @click="goToAdmin">管理员配置</el-button>
</div>
</template>
<script>
import Draw from '../components/Draw.vue';
export default {
components: { Draw },
methods: {
goToAdmin() {
this.$router.push('/admin');
}
}
};
</script>
<!-- /views/AdminPage.vue -->
<template>
<div>
<Admin />
<el-button type="text" @click="goToHome">返回抽奖页面</el-button>
</div>
</template>
<script>
import Admin from '../components/Admin.vue';
export default {
components: { Admin },
methods: {
goToHome() {
this.$router.push('/');
}
}
};
</script>
- 集成Element Plus:在
/main.js
中引入Element Plus组件库。
// /main.js
import { createApp } from 'vue';
import App from './App.vue';
import router from './router';
import store from './store';
import ElementPlus from 'element-plus';
import 'element-plus/dist/index