From 7009b47de63de81b7a188c8aac53b5cff76ad903 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=82=B9=E6=96=B9=E6=88=90?= Date: Fri, 2 Jan 2026 16:15:00 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E4=B8=BA=E6=B4=BB=E5=8A=A8=E6=94=AF?= =?UTF-8?q?=E4=BB=98=E5=92=8C=E8=B4=AD=E4=B9=B0=E9=9B=86=E6=88=90=E6=AC=A1?= =?UTF-8?q?=E6=95=B0=E5=8D=A1=E5=8A=9F=E8=83=BD=E3=80=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- components/GamePassPurchasePopup.vue | 1 + components/YifanSelector.vue | 1 + pages-activity/activity/wuxianshang/index.vue | 100 +++++++++++++++++- pages-activity/activity/yifanshang/index.vue | 96 +++++++++++++++++ 4 files changed, 197 insertions(+), 1 deletion(-) diff --git a/components/GamePassPurchasePopup.vue b/components/GamePassPurchasePopup.vue index ed544f0..908f060 100644 --- a/components/GamePassPurchasePopup.vue +++ b/components/GamePassPurchasePopup.vue @@ -74,6 +74,7 @@ async function fetchPackages() { // res 应该是数组 let list = [] if (Array.isArray(res)) list = res + else if (res && Array.isArray(res.packages)) list = res.packages else if (res && Array.isArray(res.list)) list = res.list else if (res && Array.isArray(res.data)) list = res.data diff --git a/components/YifanSelector.vue b/components/YifanSelector.vue index 23ebbc3..becae24 100644 --- a/components/YifanSelector.vue +++ b/components/YifanSelector.vue @@ -276,6 +276,7 @@ async function onPaymentConfirm(paymentData) { channel: 'miniapp', count: selectedSlots.length, coupon_id: paymentData.coupon ? Number(paymentData.coupon.id) : 0, + use_game_pass: !!paymentData.useGamePass, slot_index: selectedSlots.map(Number) } diff --git a/pages-activity/activity/wuxianshang/index.vue b/pages-activity/activity/wuxianshang/index.vue index 687a7aa..ec5d22d 100644 --- a/pages-activity/activity/wuxianshang/index.vue +++ b/pages-activity/activity/wuxianshang/index.vue @@ -67,6 +67,7 @@ v-model:visible="paymentVisible" :amount="paymentAmount" :coupons="coupons" + :gamePasses="gamePasses" :propCards="propCards" @confirm="onPaymentConfirm" /> @@ -80,12 +81,33 @@ :activity-id="activityId" /> + + + + + + + + + 🎮 + {{ gamePassRemaining }} + 充值 + + 超值卡 + @@ -105,6 +127,8 @@ import CabinetPreviewPopup from '@/components/activity/CabinetPreviewPopup.vue' import LotteryResultPopup from '@/components/activity/LotteryResultPopup.vue' import DrawLoadingPopup from '@/components/activity/DrawLoadingPopup.vue' import PaymentPopup from '@/components/PaymentPopup.vue' +import GamePassPurchasePopup from '@/components/GamePassPurchasePopup.vue' +import { getGamePasses } from '@/api/appUser' // Composables import { useActivity, useIssues, useRewards, useRecords } from '../../composables' // API @@ -160,6 +184,30 @@ const propCards = ref([]) const pendingCount = ref(1) const selectedCoupon = ref(null) const selectedCard = ref(null) +const useGamePassFlag = ref(false) + +// ============ 次数卡逻辑 ============ +const gamePasses = ref(null) +const gamePassRemaining = computed(() => gamePasses.value?.total_remaining || 0) +const purchasePopupVisible = ref(false) + +async function fetchPasses() { + if (!activityId.value) return + try { + const res = await getGamePasses(activityId.value) + gamePasses.value = res || null + } catch (e) { + gamePasses.value = null + } +} + +function openPurchasePopup() { + purchasePopupVisible.value = true +} + +function onPurchaseSuccess() { + fetchPasses() +} // ============ 业务方法 ============ function showRules() { @@ -198,6 +246,7 @@ function openPayment(count) { async function onPaymentConfirm(data) { selectedCoupon.value = data?.coupon || null selectedCard.value = data?.card || null + useGamePassFlag.value = data?.useGamePass || false paymentVisible.value = false await onMachineDraw(pendingCount.value) } @@ -317,9 +366,15 @@ async function onMachineDraw(count) { channel: 'miniapp', count: times, coupon_id: selectedCoupon.value?.id ? Number(selectedCoupon.value.id) : 0, - item_card_id: selectedCard.value?.id ? Number(selectedCard.value.id) : 0 + item_card_id: selectedCard.value?.id ? Number(selectedCard.value.id) : 0, + use_game_pass: useGamePassFlag.value }) + // 支付成功刷新次数卡 + if (useGamePassFlag.value) { + fetchPasses() + } + const orderNo = joinRes?.order_no || joinRes?.data?.order_no || joinRes?.result?.order_no if (!orderNo) throw new Error('未获取到订单号') @@ -386,6 +441,7 @@ onLoad(async (opts) => { if (currentIssueId.value) { fetchWinRecords(id, currentIssueId.value) } + fetchPasses() }) // 监听期切换,刷新记录 @@ -553,4 +609,46 @@ watch(currentIssueId, (newId) => { border: none; } } + +/* 次数卡悬浮入口 */ +.game-pass-float { + position: fixed; + right: 32rpx; + bottom: calc(180rpx + env(safe-area-inset-bottom)); + z-index: 990; + display: flex; + flex-direction: column; + align-items: center; + animation: float 3s ease-in-out infinite; +} + +.badge-content { + background: rgba(255, 255, 255, 0.95); + backdrop-filter: blur(10rpx); + border-radius: 30rpx; + padding: 8rpx 16rpx; + display: flex; + align-items: center; + box-shadow: 0 8rpx 20rpx rgba(0,0,0,0.15); + border: 1rpx solid rgba($brand-primary, 0.2); +} + +.badge-icon { font-size: 28rpx; margin-right: 6rpx; } +.badge-text { font-size: 24rpx; font-weight: 800; color: $brand-primary; } + +.badge-label { + font-size: 20rpx; + color: #fff; + background: $gradient-brand; + padding: 2rpx 8rpx; + border-radius: 8rpx; + margin-top: -6rpx; + z-index: 2; + box-shadow: 0 2rpx 6rpx rgba(0,0,0,0.2); +} + +@keyframes float { + 0%, 100% { transform: translateY(0); } + 50% { transform: translateY(-10rpx); } +} diff --git a/pages-activity/activity/yifanshang/index.vue b/pages-activity/activity/yifanshang/index.vue index a1c728c..f0028c8 100644 --- a/pages-activity/activity/yifanshang/index.vue +++ b/pages-activity/activity/yifanshang/index.vue @@ -73,10 +73,22 @@ + + 已选 {{ selectedCount }} 个位置 + 已选 {{ selectedCount }} 个位置 + + + 🎮 + {{ gamePassRemaining }} + + + + 充值特惠 + 请选择位置 @@ -121,10 +133,17 @@ v-model:visible="paymentVisible" :amount="paymentAmount" :coupons="paymentCoupons" + :gamePasses="gamePasses" :showCards="false" @confirm="onPaymentConfirm" @cancel="onPaymentCancel" /> + + @@ -144,6 +163,8 @@ import CabinetPreviewPopup from '@/components/activity/CabinetPreviewPopup.vue' import FlipGrid from '@/components/FlipGrid.vue' import YifanSelector from '@/components/YifanSelector.vue' import PaymentPopup from '@/components/PaymentPopup.vue' +import GamePassPurchasePopup from '@/components/GamePassPurchasePopup.vue' +import { getGamePasses } from '@/api/appUser' // Composables import { useActivity, useIssues, useRewards, useRecords } from '../../composables' // Utils @@ -249,6 +270,29 @@ function handlePayment() { } } +// ============ 次数卡逻辑 ============ +const gamePasses = ref(null) +const gamePassRemaining = computed(() => gamePasses.value?.total_remaining || 0) +const purchasePopupVisible = ref(false) + +async function fetchPasses() { + if (!activityId.value) return + try { + const res = await getGamePasses(activityId.value) + gamePasses.value = res || null + } catch (e) { + gamePasses.value = null + } +} + +function openPurchasePopup() { + purchasePopupVisible.value = true +} + +function onPurchaseSuccess() { + fetchPasses() +} + // ============ 倒计时相关(一番赏专属) ============ const nowMs = ref(Date.now()) let nowTimer = null @@ -364,6 +408,8 @@ onLoad(async (opts) => { if (currentIssueId.value) { fetchWinRecords(id, currentIssueId.value) } + // 获取次数卡 + fetchPasses() }) onUnload(() => { @@ -610,3 +656,53 @@ watch(currentIssueId, (newId) => { } } + +