|
|
<template> <div v-if="showOne"> <div class="prize-panel-root"> <div v-if="showNotification" class="auto-hide-notification"> {{ notificationMessage }} </div> <div class="prize-panel-list" v-if="prizes && prizes.length"> <div class="prize-panel-item" v-for="(prize, idx) in prizes" :key="prize.type || idx" :class="{ 'revealed-highlight': idx === lastRevealedIdx, disabled: idx === nextRevealIdx && !canRevealPrize(idx), }" @click="handleReveal(idx)" :style="{ cursor: idx === nextRevealIdx && !canRevealPrize(idx) ? 'not-allowed' : 'pointer', }" > <div v-if="isRevealed(idx)" class="prize-card"> <div class="prize-img-wrap"> <img class="prize-img" :src="prize.img" :alt="prize.title" /> </div> <div class="prize-info"> <div class="prize-row prize-row-top"> <span class="prize-level">{{ prize.title }}</span> <span class="prize-name">{{ prize.text }}</span> </div> <div class="prize-row prize-row-bottom"> <div class="progress-bar-bg"> <div class="progress-bar-fill" :style="{ width: getProgressPercent(prize) + '%' }" ></div> <span class="progress-bar-text"> {{ getLeftCount(prize) }}/{{ prize.count }} </span> </div> </div> </div> </div> <div v-else class="prize-card prize-card-mask"> <img src="../../../assets/daijiemi.png" alt="待揭秘" class="prize-mask-img" /> </div> </div> </div> <div class="prize-panel-footer"> <div class="arrow-up" @click="openWinnerList"></div> <button ref="winnerBtnRef" class="winner-btn" @click="openWinnerList"> 获奖名单 </button> </div> </div> </div>
<div v-else> <div class="prize-panel-root"> <div class="prize-panel-list1" v-if="prizes && prizes.length && lastRevealedIdx >= 0" > <div class="prize-panel-item" :key="prizes[lastRevealedIdx].type || lastRevealedIdx" :class="{ 'revealed-highlight': true }" style="cursor: pointer" > <div class="prize-card"> <div class="prize-img-wrap"> <img class="prize-img" :src="prizes[lastRevealedIdx].img" :alt="prizes[lastRevealedIdx].title" /> </div> <div class="prize-info"> <div class="prize-row prize-row-top"> <span class="prize-level">{{ prizes[lastRevealedIdx].title }}</span> <span class="prize-name">{{ prizes[lastRevealedIdx].text }}</span> </div> <div class="prize-row prize-row-bottom"> <div class="progress-bar-bg"> <div class="progress-bar-fill" :style="{ width: getProgressPercent(prizes[lastRevealedIdx]) + '%', }" ></div> <span class="progress-bar-text"> {{ getLeftCount(prizes[lastRevealedIdx]) }}/{{ prizes[lastRevealedIdx].count }} </span> </div> <div class="prize-panel-footer"> <div class="arrow-down" @click="toggleWinnerList"></div> <div v-if="showWinnerList" class="winner-modal-mask" @click="closeWinnerList" > <div class="winner-modal" :style="{ position: 'absolute', left: modalLeft + 'px', top: modalTop + 'px', }" @click.stop > <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" style=" display: flex; justify-content: space-between; align-items: center; " > <!-- <span>{{ user.id }}</span> - <span>{{ user.name }}</span> - --> <span>{{ user.jwcode }}</span> <span>{{ user.prizeName }}</span> </li> </ul> </div> </div> </div> </div> </div> </div> </div> </div> </div> </div> </template>
<script setup> import { ref, computed, nextTick, watch, onMounted } from "vue"; import { useLotteryStore } from "../../../store/lottery"; import { useDataManager } from "../lottery/dataManager";
const showNotification = ref(false); const notificationMessage = ref('');
// 显示提示并自动消失
const showAutoHideNotification = (message, duration = 1500) => { notificationMessage.value = message; showNotification.value = true; setTimeout(() => { showNotification.value = false; }, duration); }; const props = defineProps({ prizes: Array, }); // 新增:控制已揭秘奖品数量
const revealedCount = ref(0); // 新增:记录最新揭秘的奖品索引
const lotteryStore = useLotteryStore(); const lastRevealed = computed({ get: () => lotteryStore.lastRevealedIdx, set: (val) => lotteryStore.setLastRevealedIdx(val), }); const waitingForNextReveal = computed({ get: () => lotteryStore.waitingForNextReveal, set: (val) => lotteryStore.setWaitingForNextReveal(val), });
const winners = computed({ get: () => lotteryStore.winners, set: (val) => lotteryStore.setWinners(val), });
// 用watch监听winners的变化
// watch(winners, (newVal) => {
// console.log("中奖人数列表winners", newVal);
// fakeWinners.value = newVal;
// });
const lastRevealedIdx = ref(-1);
lastRevealedIdx.value = lastRevealed.value;
const showOne = ref(true);
// 计算哪些奖品已揭秘
const isRevealed = (idx) => idx >= (props.prizes?.length || 0) - revealedCount.value; // 允许点击的卡片index
const nextRevealIdx = computed( () => (props.prizes?.length || 0) - revealedCount.value - 1 );
// 检查指定奖品是否可以揭秘
function canRevealPrize(idx) { // 如果这是第一个要揭秘的奖品,直接允许
if (lastRevealedIdx.value === -1) { return true; }
// 检查上一个揭秘的奖品是否已经抽完
const lastPrize = props.prizes[lastRevealedIdx.value]; if (lastPrize) { const leftCount = getLeftCount(lastPrize); // 如果上一个奖品还有剩余,则不能揭秘下一个
if (leftCount > 0) { waitingForNextReveal.value = false; return false; } waitingForNextReveal.value = true; }
return true; }
// 卡片点击事件
function handleReveal(idx) { // 检查是否可以揭秘这个奖品
if (idx !== nextRevealIdx.value && !isRevealed(idx)) { // alert("请按顺序揭秘奖品!");
showAutoHideNotification("请按顺序揭秘奖品!"); return; } if (idx === nextRevealIdx.value && canRevealPrize(idx)) { revealedCount.value++; lastRevealedIdx.value = idx; // 记录最新揭秘的索引
if (idx === 0) { waitingForNextReveal.value = false; } console.log("lastRevealedIdx.value", lastRevealedIdx.value); lastRevealed.value = idx; console.log("lastRevealed.value", lastRevealed.value); } else if (idx === nextRevealIdx.value && !canRevealPrize(idx)) { // 可以在这里添加提示信息,告知用户上一个奖品还未抽完
console.log("上一个奖品还未抽完,不能揭秘下一个奖品"); // 可以添加一个提示弹窗或toast
// alert("上一个奖品还未抽完,请等待抽奖完成后再揭秘下一个奖品");
} } // 计算未抽取数量
function getLeftCount(prize) { // 这里假设奖品有 type 字段,且 dataManager.state.basicData.luckyUsers 可用
// 由于本组件无 luckyUsers 数据,建议父组件传入或全局可访问
// 这里用 window.dataManager 兼容演示
let luckyUsers = (window.dataManager && window.dataManager.state.basicData.luckyUsers) || {}; let got = luckyUsers[prize.type]?.length || 0; return prize.remainNum; }
// 新增部分
const showWinnerList = ref(false); const fakeWinners = ref([]); // fakeWinners.value = winners.value;
console.log("fakeWinners", fakeWinners.value);
import { getGetPrizeUserListApi } from "../../../api/API"; const updateWinners = async () => { try { const response = await getGetPrizeUserListApi({ pageSize: 1000, pageNum: 1, }); console.log("updatePrizeList response", response); fakeWinners.value = response.data.list; console.log("updateWinners fakeWinners", fakeWinners.value); } catch (error) { console.error("updatePrizeList error", error); } }; async function openWinnerList() { // showWinnerList.value = true;
if (!showWinnerList.value) { if (revealedCount.value === 0) { // alert("请先揭晓奖品,并抽奖!");
showAutoHideNotification("请先揭晓奖品,并抽奖!");
} // await updatePrizeList();
} if (revealedCount.value > 0) { showWinnerList.value = true; } // 当存在最新揭秘的奖品时,点击获奖名单将showOne设置为false
if (lastRevealedIdx.value >= 0) { showOne.value = false; } } function closeWinnerList() { showWinnerList.value = false; // 当关闭获奖名单且showOne为false时,将其切换回true
if (!showOne.value) { showOne.value = true; } }
const winnerBtnRef = ref(null); const modalLeft = ref(0); const modalTop = ref(0);
async function toggleWinnerList() { await updateWinners();
showWinnerList.value = !showWinnerList.value; console.log( "toggleWinnerList - showWinnerList:", showWinnerList.value, "showOne:", showOne.value, "lastRevealedIdx:", lastRevealedIdx.value ); if (!showWinnerList.value) { if (revealedCount.value === 0) { // alert("请先揭晓奖品,并抽奖!");
showAutoHideNotification("请先揭晓奖品,并抽奖!"); } }
if (showWinnerList.value) { // 当存在最新揭秘的奖品时,点击获奖名单将showOne设置为false
if (lastRevealedIdx.value > 0) { showOne.value = false; console.log("设置 showOne 为 false"); } } else { // 当关闭获奖名单且showOne为false时,将其切换回true
if (!showOne.value) { showOne.value = true;
console.log("设置 showOne 为 true"); } } }
function getProgressPercent(prize) { const total = prize.count || 1; const left = getLeftCount(prize); // 返回剩余数量的百分比,这样开始时是满的,抽完后是空的
return Math.round((left / total) * 100); }
onMounted(() => { updateWinners(); }); </script>
<style scoped> .auto-hide-notification { position: fixed; top: 300px; left: 50%; transform: translateX(-50%); color: #e61414; padding: 8px 16px; border-radius: 4px; font-size: 50px; z-index: 1000;} .prize-panel-list { position: relative; background: none; z-index: 10; min-width: 300px; max-width: 362px; text-align: left; display: flex; flex-direction: column; gap: 18px; max-height: 700px; overflow-x: hidden !important; overflow-y: auto; padding-right: 10px; padding-left: 10px; scrollbar-width: thin; scrollbar-color: #ffd283 rgba(255, 210, 131, 0.3); /* Firefox */ } .prize-panel-list1 { position: relative; background: none; z-index: 10; min-width: 320px; max-width: 342px; padding-right: 10px; padding-left: 10px; text-align: left; display: flex; }
.prize-panel-list::-webkit-scrollbar { width: 6px; }
.prize-panel-list::-webkit-scrollbar-track { background: rgba(255, 210, 131, 0.3); border-radius: 3px; }
.prize-panel-list::-webkit-scrollbar-thumb { background-color: #ffd283; border-radius: 3px; } .prize-panel-item { background: #ffd283; border-radius: 6px 6px 6px 6px; box-shadow: 0 2px 8px rgba(0, 0, 0, 0.08); display: flex; align-items: center; min-width: 320px; } .prize-card { display: flex; align-items: center; width: 100%; padding: 10px 18px; } .prize-img-wrap { width: 64px; height: 64px; border-radius: 50%; background: #fff; display: flex; align-items: center; justify-content: center; overflow: hidden; margin-right: 18px; border: 2px solid #fff3e0; } .prize-img { width: 60px; height: 60px; object-fit: contain; } .prize-info { flex: 1; display: flex; flex-direction: column; justify-content: center; } .prize-row { display: flex; align-items: center; background: #ffffff; border-radius: 93px 93px 93px 93px; } .prize-row-top { margin-bottom: 8px; border: 1px solid #ea2b0a; } .prize-level { background: linear-gradient(90deg, #ff9800 0%, #ff5722 100%); color: #fff; border-radius: 15.71px 15.71px 15.71px 15.71px; padding: 2px 18px; font-size: 18px; font-weight: bold; margin-right: 12px; } .prize-name { font-size: 18px; color: #d84315; font-weight: 500; } .prize-row-bottom { /* margin-bottom: 8px; */ /* border: 1px solid #ea2b0a; */ } .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; } .prize-divider { margin: 0 4px; font-size: 20px; } .prize-total { font-size: 20px; font-weight: bold; } .prize-panel-root { position: absolute; top: 20px; left: 20px; background: none; z-index: 10; min-width: 320px; max-width: 362px; display: flex; flex-direction: column; }
.prize-panel-footer { position: relative; /* width: 100%; */ display: flex; flex-direction: column; align-items: center; z-index: 20; padding: 10px 0; border-radius: 0 0 6px 6px; margin-top: 10px; } .arrow-up { position: relative; width: 50px; height: 30px; margin-bottom: 4px; cursor: pointer; background-image: url("../../../assets/展开.png"); background-size: cover; background-position: center; transform: rotate(180deg); } .arrow-down { position: fixed; top: 100px; left: 150px; width: 47px; height: 28px; margin-bottom: 4px; cursor: pointer; background-image: url("../../../assets/展开.png"); background-size: cover; background-position: center; } .winner-btn { background: rgba(255, 210, 131, 0.8); color: #d5291f; border: #fff; border-radius: 8px; padding: 15px 79px; font-size: 20px; font-weight: bold; cursor: pointer; box-shadow: 0 2px 8px rgba(0, 0, 0, 0.08); outline: none; } .winner-modal-mask { position: fixed; top: 142px; left: -4px; width: 100vw; height: 100vh; background: rgba(0, 0, 0, 0.01); z-index: 1000; display: flex; align-items: flex-start; justify-content: center; } .winner-modal { background: rgba(255, 210, 131, 0.8); border-radius: 12px; padding-top: 12px; padding-left: 25px; padding-right: 25px; padding-bottom: 10px; min-width: 280px; max-width: 90vw; box-shadow: 0 4px 24px rgba(0, 0, 0, 0.12); position: relative; margin-left: 10px; } .winner-modal-title { font-size: 22px; font-weight: bold; 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; right: 18px; top: 12px; font-size: 26px; color: #888; cursor: pointer; } .winner-list { max-height: 260px; /* background: rgba(255, 210, 131, 0.8);/ */ overflow-y: auto; padding: 0; margin: 0; list-style: none; /* 隐藏滚动条但保留滚动功能 */ scrollbar-width: none; /* Firefox */ -ms-overflow-style: none; /* IE and Edge */ }
.winner-list::-webkit-scrollbar { display: none; /* Chrome, Safari and Opera */ } .winner-list li { padding: 8px 0; /* border-bottom: 1px solid #f2f2f2; */ font-size: 17px; color: #d84315; display: flex; gap: 12px; align-items: center; justify-content: center; text-align: center; } .progress-bar-bg { position: relative; width: 228px; height: 30px; background: #e9620e; border-radius: 16px; overflow: hidden; display: flex; align-items: center; margin: 0 auto; border: #e13726; } .progress-bar-fill { position: absolute; left: 0; top: 0; /* width: 100%; */ height: 100%; /* background: linear-gradient(90deg, #ff9800 0%, #8a3500 100%); */ background: #8a3500; border-radius: 16px; transition: width 0.4s; z-index: 1; } .progress-bar-text { position: relative; width: 100%; text-align: center; color: #ffffff; font-size: 18px; font-weight: bold; z-index: 2; letter-spacing: 1px; } .prize-card-mask { position: relative; width: 342px; height: 88px; display: flex; /* align-items: center; justify-content: center; */ padding: 0; overflow: hidden; } .prize-mask-img { object-fit: cover; position: absolute; width: 100%; height: 98%; object-fit: cover; left: 0; top: 0; border-radius: 8px 8px 8px 8px; } .prize-panel-item.revealed-highlight { /* border: 3px solid #ff9800; */ box-shadow: 0 0 16px 4px #ff9800aa; transform: scale(1.03); z-index: 2; transition: all 0.3s; /* 确保放大的元素不被遮挡 */ position: relative; /* margin: 8px 0; */ /* 为放大的元素留出空间 */ transform-origin: center center; }
.prize-panel-item.disabled { cursor: not-allowed !important; position: relative; }
.prize-panel-item.disabled::after { content: "请先抽完上一个奖品"; position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%); background: rgba(0, 0, 0, 0.8); color: white; padding: 8px 12px; border-radius: 6px; font-size: 14px; white-space: nowrap; z-index: 10; opacity: 0; transition: opacity 0.3s; pointer-events: none; }
.prize-panel-item.disabled:hover::after { opacity: 1; } </style>
|