Browse Source

Merge branch 'pangluotong/feature-20250712103401-抽奖' into milestone-20250722-抽奖

songtongtong/feature-20250717104937-众筹
pangluotong 4 weeks ago
parent
commit
18214e3901
  1. 1059
      package-lock.json
  2. 10
      package.json
  3. BIN
      src/assets/loginback.png
  4. BIN
      src/assets/展开.png
  5. 16
      src/main.js
  6. 20
      src/router/index.js
  7. 20
      src/stores/auth.js
  8. 102
      src/views/choujiang/Login.vue
  9. 136
      src/views/choujiang/lottery/PrizePanel.vue
  10. 5
      vite.config.js

1059
package-lock.json
File diff suppressed because it is too large
View File

10
package.json

@ -12,11 +12,21 @@
"@tweenjs/tween.js": "^18.6.4",
"@vitejs/plugin-vue": "^4.6.2",
"axios": "^1.10.0",
<<<<<<< HEAD
"element-plus": "^2.10.3",
"pinia": "^3.0.3",
"three": "^0.150.1",
=======
"element-plus": "^2.10.4",
"pinia": "^3.0.3",
"pinia-plugin-persistedstate": "^4.4.1",
>>>>>>> pangluotong/feature-20250712103401-
"vite": "^4.5.3",
"vue": "^3.5.17",
"vue-router": "^4.5.1"
},
"devDependencies": {
"unplugin-auto-import": "^19.3.0",
"unplugin-vue-components": "^28.8.0"
}
}

BIN
src/assets/loginback.png

After

Width: 1920  |  Height: 1080  |  Size: 1.7 MiB

BIN
src/assets/展开.png

After

Width: 40  |  Height: 34  |  Size: 2.9 KiB

16
src/main.js

@ -1,4 +1,5 @@
import { createApp } from 'vue'
<<<<<<< HEAD
import { createPinia } from 'pinia'
import './style.css'
@ -7,3 +8,18 @@ import router from './router'
// import { createPinia } from 'pinia'
createApp(App).use(router).use(createPinia()).mount('#app')
=======
import { createPinia } from 'pinia';
import piniaPluginPersistedstate from 'pinia-plugin-persistedstate';
import App from './App.vue'
import router from './router'
// import { createPinia } from 'pinia'
import ElementPlus from 'element-plus'
import 'element-plus/dist/index.css'
const app = createApp(App);
const pinia = createPinia().use(piniaPluginPersistedstate);
app.use(pinia)
.use(router)
.use(ElementPlus)
.mount('#app');
>>>>>>> pangluotong/feature-20250712103401-抽奖

20
src/router/index.js

@ -1,4 +1,5 @@
import { createRouter, createWebHistory } from 'vue-router'
import { useAuthStore } from '../stores/auth';
const routes = [
{
path: '/',
@ -21,6 +22,11 @@ const routes = [
path: '/zhongchou',
name: 'zhongchou',
component: () => import('../views/zhongchou/index.vue'),
},
{
path: '/login',
name: 'login',
component: () => import('../views/choujiang/Login.vue'),
}
]
// 创建路由实例
@ -28,5 +34,19 @@ const router = createRouter({
history: createWebHistory(import.meta.env.VITE_PUBLIC_PATH),
routes
})
// 添加路由守卫
router.beforeEach((to, from, next) => {
const authStore = useAuthStore(); // 获取auth store实例
// 仅对/choujiang路由进行登录验证
if (to.path === '/choujiang') {
if (!authStore.isLoggedIn) {
// 如果未登录,重定向到登录页面
next('/login');
return;
}
}
next();
})
// 导出
export default router

20
src/stores/auth.js

@ -0,0 +1,20 @@
import { defineStore } from 'pinia';
import { ref } from 'vue';
export const useAuthStore = defineStore('auth', () => {
// 登录状态
const isLoggedIn = ref(false);
// 登录方法
const login = () => {
isLoggedIn.value = true;
};
// 登出方法
const logout = () => {
isLoggedIn.value = false;
};
return {
isLoggedIn,
login,
logout
};
},{persist : false});
//开启持久化)

102
src/views/choujiang/Login.vue

@ -0,0 +1,102 @@
<template>
<div class="login-container">
<div class="login-card">
<form @submit.prevent="handleLogin">
<div class="form-group">
<input
type="password"
id="password"
v-model="password"
placeholder="请输入密码"
/>
</div>
<button type="submit" class="login-button">进入抽奖</button>
</form>
</div>
</div>
</template>
<script setup>
import { ref } from 'vue';
import { useRouter } from 'vue-router';
import { useAuthStore } from '../../stores/auth';
const password = ref('');
const CORRECT_PASSWORD = '123456';
const router = useRouter();
const authStore = useAuthStore();
const handleLogin = () => {
if (password.value === '') {
alert('请输入密码');
return;
}
if (password.value === CORRECT_PASSWORD) {
alert('登录成功,即将跳转到抽奖页面');
//
authStore.login(); // 使Pinia
router.push('/choujiang');
} else {
alert('密码错误,请重试');
}
};
//
console.log('登录信息:', {
password: password.value,
});
// API
</script>
<style scoped>
.login-container {
background-image: url('../../assets/loginback.png'); /* 确保路径正确 */
background-position: center;
background-size: cover;
height: 100vh; /* 确保背景图片覆盖整个视口高度 */
width: 100vw; /* 确保背景图片覆盖整个视口宽度 */
position: fixed; /* 使用fixed定位确保背景图片覆盖整个页面 */
top: 0;
left: 0;
z-index: -1; /* 确保背景图片在其他内容下方 */
}
.login-card {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
width: 300px; /* 设置固定宽度 */
height: 200px; /* 设置固定高度 */
padding: 2rem;
background: rgba(255, 255, 255, 0.8); /* 调整背景颜色为半透明白色 */
border-radius: 8px;
box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1);
box-sizing: border-box;
z-index: 1; /* 确保卡片在背景图片上方 */
}
input {
width: 100%;
padding: 0.8rem;
border: 1px solid #ddd;
border-radius: 4px;
font-size: 1rem;
margin-bottom: 2rem;
box-sizing: border-box
}
.login-button {
width: 100%;
padding: 0.8rem;
background-color: #42b983;
color: white;
border: none;
border-radius: 4px;
font-size: 1rem;
cursor: pointer;
transition: background-color 0.3s;
box-sizing: border-box
}
.login-button:hover {
background-color: #359469;
}
</style>

136
src/views/choujiang/lottery/PrizePanel.vue

@ -61,7 +61,7 @@
>
获奖名单
</button>
<div
<!-- <div
v-if="showWinnerList"
class="winner-modal-mask"
@click="closeWinnerList"
@ -78,13 +78,12 @@
<div class="winner-modal-title">Homily ID</div>
<ul class="winner-list">
<li v-for="(user, idx) in fakeWinners" :key="idx">
<!-- <span>{{ user.id }}</span> - <span>{{ user.name }}</span> - -->
<span>{{ user.id }}</span>
<span>{{ user.prize }}</span>
</li>
</ul>
</div>
</div>
</div> -->
<!-- </div> -->
</div>
</div>
</div>
@ -137,19 +136,17 @@
</div>
</div>
</div>
<div></div>
<div></div>
<div></div>
<div></div>
<div class="prize-panel-footer">
<div class="arrow-up" @click="openWinnerList"></div>
<div class="arrow-down" @click="toggleWinnerList"></div>
<!-- <div class="arrow-up " @click="openWinnerList"> </div>
<button
ref="winnerBtnRef"
class="winner-btn"
@click="toggleWinnerList"
>
获奖名单
</button>
</button> -->
<div
v-if="showWinnerList"
class="winner-modal-mask"
@ -164,11 +161,12 @@
}"
@click.stop
>
<div class="winner-modal-title">Homily ID</div>
<div class="winner-modal-title"><span>Homily ID</span><span>奖项</span></div>
<div style="background:linear-gradient(to left, rgb(232 76 10), rgb(195 6 6), rgb(240 90 9));height:1px;"></div>
<ul class="winner-list">
<li v-for="(user, idx) in fakeWinners" :key="idx">
<li v-for="(user, idx) in fakeWinners" :key="idx" style="display: flex; justify-content: space-between; align-items: center;" >
<!-- <span>{{ user.id }}</span> - <span>{{ user.name }}</span> - -->
<span>{{ user.id }}</span>
<span >{{ user.id }}</span>
<span>{{ user.prize }}</span>
</li>
</ul>
@ -274,20 +272,26 @@ const fakeWinners = ref([
{ id: "90044069", name: "小明", prize: "六等奖" },
]);
function openWinnerList() {
showWinnerList.value = true;
// showWinnerList.value = true;
if (!showWinnerList.value) {
if (revealedCount.value === 0) {
alert('请先揭晓奖品,并抽奖!');}
}
if(revealedCount.value > 0)
{ showWinnerList.value = true;}
// showOnefalse
if (lastRevealedIdx.value >= 0) {
showOne.value = false;
}
//
nextTick(() => {
const btn = winnerBtnRef.value;
if (btn) {
const rect = btn.getBoundingClientRect();
modalLeft.value = rect.left - 23;
modalTop.value = rect.bottom + 18; // 4px
}
});
// nextTick(() => {
// const btn = winnerBtnRef.value;
// if (btn) {
// const rect = btn.getBoundingClientRect();
// modalLeft.value = rect.left - 23;
// modalTop.value = rect.bottom + 18; // 4px
// }
// });
}
function closeWinnerList() {
showWinnerList.value = false;
@ -303,35 +307,35 @@ const modalTop = ref(0);
function toggleWinnerList() {
showWinnerList.value = !showWinnerList.value;
console.log(
"toggleWinnerList - showWinnerList:",
showWinnerList.value,
"showOne:",
showOne.value,
"lastRevealedIdx:",
lastRevealedIdx.value
);
console.log('toggleWinnerList - showWinnerList:', showWinnerList.value, 'showOne:', showOne.value, 'lastRevealedIdx:', lastRevealedIdx.value);
if (!showWinnerList.value) {
if (revealedCount.value === 0) {
alert('请先揭晓奖品,并抽奖!');}
}
if (showWinnerList.value) {
// showOnefalse
if (lastRevealedIdx.value >= 0) {
if (lastRevealedIdx.value > 0) {
showOne.value = false;
console.log("设置 showOne 为 false");
console.log('设置 showOne 为 false');
}
//
nextTick(() => {
const btn = winnerBtnRef.value;
if (btn) {
const rect = btn.getBoundingClientRect();
modalLeft.value = rect.left - 23;
modalTop.value = rect.bottom + 18; // 4px
}
});
// nextTick(() => {
// const btn = winnerBtnRef.value;
// if (btn) {
// const rect = btn.getBoundingClientRect();
// modalLeft.value = rect.left - 23;
// modalTop.value = rect.bottom + 18; // 4px
// }
// });
} else {
// showOnefalsetrue
if (!showOne.value) {
showOne.value = true;
console.log("设置 showOne 为 true");
console.log('设置 showOne 为 true');
}
}
}
@ -352,6 +356,7 @@ function getProgressPercent(prize) {
background: none;
z-index: 10;
min-width: 320px;
max-width: 342px;
text-align: left;
display: flex;
flex-direction: column;
@ -363,7 +368,8 @@ function getProgressPercent(prize) {
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.08);
display: flex;
align-items: center;
min-width: 300px;
min-width: 320px;
}
.prize-card {
display: flex;
@ -402,6 +408,7 @@ function getProgressPercent(prize) {
}
.prize-row-top {
margin-bottom: 8px;
border: 1px solid #ea2b0a;
}
.prize-level {
background: linear-gradient(90deg, #ff9800 0%, #ff5722 100%);
@ -428,6 +435,17 @@ function getProgressPercent(prize) {
justify-content: center;
min-width: 80px;
} */
.custom-arrow-icon {
font-size: 24px; /* 图标大小 */
color: #d84315; /* 图标颜色,使用项目主题橙色 */
margin: 5px; /* 外边距 */
cursor: pointer; /* 鼠标悬停样式 */
transition: transform 0.3s ease; /* 过渡动画 */
}
.custom-arrow-icon:hover {
transform: scale(1.1); /* 悬停放大效果 */
}
.prize-count {
font-size: 20px;
font-weight: bold;
@ -443,7 +461,7 @@ function getProgressPercent(prize) {
.prize-panel-footer {
position: absolute;
left: 0;
bottom: 0;
bottom: -26px;
width: 100%;
display: flex;
flex-direction: column;
@ -452,11 +470,27 @@ function getProgressPercent(prize) {
/* 移除 move-up 相关 */
}
.arrow-up {
position: relative;
width: 36px;
height: 24px;
background: url("@/assets/arrow-up.svg") no-repeat center/contain;
margin-bottom: 4px;
cursor: pointer;
background-image: url('../../../assets/展开.png');
background-size: cover;
background-position: center;
}
.arrow-down {
position: fixed;
top: 120px;
left: 165px;
width: 36px;
height: 38px;
margin-bottom: 4px;
cursor: pointer;
background-image: url('../../../assets/展开.png');
background-size: cover;
background-position: center;
transform: rotate(180deg);
}
.winner-btn {
background: rgba(255, 210, 131, 0.8);
@ -471,8 +505,8 @@ function getProgressPercent(prize) {
}
.winner-modal-mask {
position: fixed;
top: 0;
left: 0;
top: 155px;
left:10px;
width: 100vw;
height: 100vh;
background: rgba(0, 0, 0, 0.01);
@ -485,6 +519,8 @@ function getProgressPercent(prize) {
background: rgba(255, 210, 131, 0.8);
border-radius: 12px;
padding-top: 12px;
padding-left: 25px;
padding-right: 25px;
min-width: 280px;
max-width: 90vw;
box-shadow: 0 4px 24px rgba(0, 0, 0, 0.12);
@ -493,8 +529,14 @@ function getProgressPercent(prize) {
.winner-modal-title {
font-size: 22px;
font-weight: bold;
margin-bottom: 18px;
color: #e64f39;
margin-bottom: 5px;
text-align: center;
display: flex;
justify-content: space-between; /* 左右对齐 */
align-items: center; /* 垂直居中对齐 */
/* 可添加padding或margin调整整体间距 */
padding: 5px 0;
}
.winner-modal-close {
position: absolute;

5
vite.config.js

@ -3,6 +3,7 @@ import vue from '@vitejs/plugin-vue'
// https://vite.dev/config/
export default defineConfig({
<<<<<<< HEAD
plugins: [vue()],
server: {
host: '0.0.0.0',
@ -16,4 +17,8 @@ export default defineConfig({
}
}
}
=======
plugins: [vue(),
],
>>>>>>> pangluotong/feature-20250712103401-抽奖
})
Loading…
Cancel
Save