From 9d401a9c9360879cc97049a0e8970a0ccf213feb Mon Sep 17 00:00:00 2001 From: Gsh <15170702455@163.com> Date: Sat, 1 Nov 2025 17:56:19 +0800 Subject: [PATCH] =?UTF-8?q?fix:=20=E7=BF=BB=E7=89=8C=E6=A0=B7=E5=BC=8F?= =?UTF-8?q?=E4=BC=98=E5=8C=96=EF=BC=8C=E5=8A=A8=E7=94=BB=E6=95=88=E6=9E=9C?= =?UTF-8?q?=E5=AE=8C=E5=96=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../components/CardFlipActivity.vue | 836 ++++++++++-------- 1 file changed, 457 insertions(+), 379 deletions(-) diff --git a/Yi.Ai.Vue3/src/components/userPersonalCenter/components/CardFlipActivity.vue b/Yi.Ai.Vue3/src/components/userPersonalCenter/components/CardFlipActivity.vue index b389056d..36280145 100644 --- a/Yi.Ai.Vue3/src/components/userPersonalCenter/components/CardFlipActivity.vue +++ b/Yi.Ai.Vue3/src/components/userPersonalCenter/components/CardFlipActivity.vue @@ -38,8 +38,8 @@ const showDoubleRewardDialog = ref(false); /** 最后一次翻牌结果:保存最近一次翻牌的返回数据 */ const lastFlipResult = ref(null); -/** 邀请码区域展开状态:控制邀请码区域的显示/隐藏 */ -const showInviteSection = ref(false); +/** 我的邀请码对话框显示状态 */ +const showMyInviteCodeDialog = ref(false); /** 翻牌动画状态集合:存储正在执行翻牌动画的卡片编号 */ const flippingCards = ref>(new Set()); @@ -69,6 +69,9 @@ const clonedCardElement = ref(null); /** 系统logo图片路径 */ const systemLogo = '/images/logo.png'; +/** 洗牌交换序列(记录哪些卡片要交换位置) */ +const shuffleSwaps = ref>([]); + // ============ 生命周期 ============ onMounted(async () => { // 页面加载时立即获取任务状态 @@ -86,7 +89,7 @@ onMounted(async () => { * 完整流程: * 1. 展示3张大奖卡片正面(神秘大奖)- 2.5秒 * 2. 大奖卡片翻转到背面 - 0.8秒 - * 3. 卡片在网格内随机交换位置 - 2秒 + * 3. 卡片在网格内随机交换位置 - 3秒(多次交换) */ async function playShuffleAnimation() { if (isShuffling.value) @@ -95,7 +98,7 @@ async function playShuffleAnimation() { isShuffling.value = true; // 随机选择3张大奖卡片 - bigPrizeCards.value = [3, 6, 9]; // 可以改为随机:generateRandomCards(3, 10) + bigPrizeCards.value = generateRandomCards(3, 10); // 阶段1:展示大奖卡片正面(2.5秒) shuffleStage.value = 'showing'; @@ -105,14 +108,15 @@ async function playShuffleAnimation() { shuffleStage.value = 'flipping'; await new Promise(resolve => setTimeout(resolve, 800)); - // 阶段3:卡片在网格内随机交换动画(2秒) + // 阶段3:生成随机交换序列并执行洗牌动画 shuffleStage.value = 'shuffling'; - await new Promise(resolve => setTimeout(resolve, 2000)); + await performShuffleSwaps(); // 完成 shuffleStage.value = 'done'; isShuffling.value = false; bigPrizeCards.value = []; + shuffleSwaps.value = []; } /** @@ -126,6 +130,80 @@ function generateRandomCards(count: number, max: number): number[] { return Array.from(cards); } +/** + * 执行洗牌交换动画 + * 更快速、更多次的交换,让所有卡片都参与 + */ +async function performShuffleSwaps() { + const swapCount = 15; // 增加到15次交换,确保所有卡片都参与 + const swapDuration = 300; // 减少到300ms,速度更快 + const swapDelay = 50; // 减少间隔时间 + + // 确保每张卡片至少参与一次交换 + const allCards = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]; + const shuffledPairs: Array<[number, number]> = []; + + // 先生成确保所有卡片都参与的交换序列 + for (let i = 0; i < allCards.length; i++) { + const card1 = allCards[i]; + const card2 = allCards[(i + 1 + Math.floor(Math.random() * 5)) % allCards.length]; + if (card1 !== card2) { + shuffledPairs.push([card1, card2]); + } + } + + // 再添加额外的随机交换 + for (let i = shuffledPairs.length; i < swapCount; i++) { + const card1 = Math.floor(Math.random() * 10) + 1; + let card2 = Math.floor(Math.random() * 10) + 1; + while (card2 === card1) { + card2 = Math.floor(Math.random() * 10) + 1; + } + shuffledPairs.push([card1, card2]); + } + + // 执行交换动画 + for (const [card1, card2] of shuffledPairs) { + shuffleSwaps.value.push([card1, card2]); + + // 获取两张卡片的DOM元素 + const element1 = document.querySelector(`[data-card-number="${card1}"]`) as HTMLElement; + const element2 = document.querySelector(`[data-card-number="${card2}"]`) as HTMLElement; + + if (element1 && element2) { + // 获取位置信息 + const rect1 = element1.getBoundingClientRect(); + const rect2 = element2.getBoundingClientRect(); + + // 计算位移距离 + const deltaX = rect2.left - rect1.left; + const deltaY = rect2.top - rect1.top; + + // 添加交换动画类 + element1.classList.add('swapping'); + element2.classList.add('swapping'); + + // 应用位移 + element1.style.transform = `translate(${deltaX}px, ${deltaY}px) scale(1.05)`; + element2.style.transform = `translate(${-deltaX}px, ${-deltaY}px) scale(1.05)`; + + // 等待动画完成 + await new Promise(resolve => setTimeout(resolve, swapDuration)); + + // 重置transform + element1.style.transform = ''; + element2.style.transform = ''; + + // 移除动画类 + element1.classList.remove('swapping'); + element2.classList.remove('swapping'); + + // 短暂延迟 + await new Promise(resolve => setTimeout(resolve, swapDelay)); + } + } +} + // ============ 数据获取 ============ /** * 获取任务状态 @@ -276,7 +354,7 @@ async function handleFlipCard(record: CardFlipRecord) { await new Promise(resolve => requestAnimationFrame(resolve)); // 4. 移动克隆卡片到屏幕中心并放大(考虑边界限制) - const scale = 1.8; + const scale = Math.min(1.8, window.innerWidth / rect.width * 0.6); // 动态计算缩放比例 const scaledWidth = rect.width * scale; const scaledHeight = rect.height * scale; @@ -284,18 +362,19 @@ async function handleFlipCard(record: CardFlipRecord) { let centerX = window.innerWidth / 2; let centerY = window.innerHeight / 2; - // 边界检查:确保卡片完全在视口内 - const minX = scaledWidth / 2; - const maxX = window.innerWidth - scaledWidth / 2; - const minY = scaledHeight / 2; - const maxY = window.innerHeight - scaledHeight / 2; + // 边界检查:确保卡片完全在视口内(留20px边距) + const margin = 20; + const minX = scaledWidth / 2 + margin; + const maxX = window.innerWidth - scaledWidth / 2 - margin; + const minY = scaledHeight / 2 + margin; + const maxY = window.innerHeight - scaledHeight / 2 - margin; centerX = Math.max(minX, Math.min(maxX, centerX)); centerY = Math.max(minY, Math.min(maxY, centerY)); clonedCard.style.left = `${centerX}px`; clonedCard.style.top = `${centerY}px`; - clonedCard.style.transform = 'translate(-50%, -50%) scale(1.8)'; + clonedCard.style.transform = `translate(-50%, -50%) scale(${scale})`; // 等待移动动画完成 await new Promise(resolve => setTimeout(resolve, 600)); @@ -393,7 +472,9 @@ function showEnhancedWinAnimation() { const confetti = document.createElement('div'); confetti.className = 'confetti enhanced'; - // 随机水平位置 + // 设置初始位置(从顶部开始) + confetti.style.position = 'absolute'; + confetti.style.top = '-10%'; confetti.style.left = `${Math.random() * 100}%`; // 随机动画延迟,让纸屑不同时落下 @@ -440,9 +521,9 @@ function showEnhancedWinAnimation() { container.appendChild(flash); setTimeout(() => flash.remove(), 1000); - // 添加震动效果 - container.classList.add('win-shake'); - setTimeout(() => container.classList.remove('win-shake'), 500); + // 移除震动效果(按用户要求) + // container.classList.add('win-shake'); + // setTimeout(() => container.classList.remove('win-shake'), 500); } } @@ -634,12 +715,7 @@ function getCardClass(record: CardFlipRecord): string[] { return classes; } -/** - * 切换邀请码区域的显示/隐藏状态 - */ -function toggleInviteSection() { - showInviteSection.value = !showInviteSection.value; -} +// 删除 toggleInviteSection 函数,使用对话框代替