You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 

723 lines
18 KiB

<template>
<div v-if="showOne">
<div class="prize-panel-root">
<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>
<div></div>
<div></div>
<div></div>
<div class="prize-panel-footer">
<div class="arrow-up" @click="openWinnerList"></div>
<button
ref="winnerBtnRef"
class="winner-btn"
@click="toggleWinnerList"
>
获奖名单
</button>
<!-- <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">Homily ID</div>
<ul class="winner-list">
<li v-for="(user, idx) in fakeWinners" :key="idx">
<span>{{ user.id }}</span>
<span>{{ user.prize }}</span>
</li>
</ul>
</div> -->
<!-- </div> -->
</div>
</div>
</div>
</div>
<div v-else>
<div class="prize-panel-root">
<div
class="prize-panel-list"
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>
</div>
</div>
</div>
<div class="prize-panel-footer">
<div class="arrow-down" @click="toggleWinnerList"></div>
<!-- <div class="arrow-up " @click="openWinnerList"> </div>
<button
ref="winnerBtnRef"
class="winner-btn"
@click="toggleWinnerList"
>
获奖名单
</button> -->
<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>
</template>
<script setup>
import { ref, computed, nextTick, watch, onMounted } from "vue";
import { useLotteryStore } from "../../../store/lottery";
import { useDataManager } from "../lottery/dataManager";
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 && 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);
const updateWinners = async () => {
try {
const response = await useDataManager().updatePrizeList();
console.log("updatePrizeList response", response);
fakeWinners.value = response.data.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("请先揭晓奖品,并抽奖!");
}
// await updatePrizeList();
}
if (revealedCount.value > 0) {
showWinnerList.value = true;
}
// 当存在最新揭秘的奖品时,点击获奖名单将showOne设置为false
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间距
// }
// });
}
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("请先揭晓奖品,并抽奖!");
}
}
if (showWinnerList.value) {
// 当存在最新揭秘的奖品时,点击获奖名单将showOne设置为false
if (lastRevealedIdx.value > 0) {
showOne.value = 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间距
// }
// });
} 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>
.prize-panel-list {
position: absolute;
top: 20px;
left: 20px;
background: none;
z-index: 10;
min-width: 320px;
max-width: 342px;
text-align: left;
display: flex;
flex-direction: column;
gap: 18px;
}
.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 {
background: linear-gradient(90deg, #ff9800 0%, #ff5722 100%);
background: #8a3500;
border-radius: 16px;
color: #fff;
font-size: 20px;
font-weight: bold;
padding: 2px 0 2px 0;
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;
}
.prize-divider {
margin: 0 4px;
font-size: 20px;
}
.prize-total {
font-size: 20px;
font-weight: bold;
}
.prize-panel-footer {
position: absolute;
left: 0;
bottom: -26px;
width: 100%;
display: flex;
flex-direction: column;
align-items: center;
z-index: 20;
/* 移除 move-up 相关 */
}
.arrow-up {
position: relative;
width: 36px;
height: 24px;
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);
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);
}
.winner-modal-mask {
position: fixed;
top: 155px;
left: 10px;
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: 220px;
height: 28px;
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;
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.05);
z-index: 2;
transition: all 0.3s;
}
.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>