feat: 为活动支付和购买集成次数卡功能。
This commit is contained in:
parent
61df7fca5e
commit
7009b47de6
@ -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
|
||||
|
||||
|
||||
@ -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)
|
||||
}
|
||||
|
||||
|
||||
@ -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"
|
||||
/>
|
||||
|
||||
<CabinetPreviewPopup
|
||||
v-model:visible="cabinetVisible"
|
||||
:activity-id="activityId"
|
||||
/>
|
||||
|
||||
<!-- 开奖加载弹窗 -->
|
||||
<DrawLoadingPopup
|
||||
:visible="showDrawLoading"
|
||||
:progress="drawProgress"
|
||||
:total="drawTotal"
|
||||
/>
|
||||
|
||||
<GamePassPurchasePopup
|
||||
v-model:visible="purchasePopupVisible"
|
||||
:activity-id="activityId"
|
||||
@success="onPurchaseSuccess"
|
||||
/>
|
||||
|
||||
<!-- 悬浮次数卡入口 -->
|
||||
<view v-if="gamePassRemaining > 0 || true" class="game-pass-float" @tap="openPurchasePopup">
|
||||
<view class="badge-content">
|
||||
<text class="badge-icon">🎮</text>
|
||||
<text class="badge-text" v-if="gamePassRemaining > 0">{{ gamePassRemaining }}</text>
|
||||
<text class="badge-text" v-else>充值</text>
|
||||
</view>
|
||||
<view class="badge-label">超值卡</view>
|
||||
</view>
|
||||
</template>
|
||||
</ActivityPageLayout>
|
||||
</template>
|
||||
@ -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); }
|
||||
}
|
||||
</style>
|
||||
|
||||
@ -73,10 +73,22 @@
|
||||
<!-- 固定底部操作栏 -->
|
||||
<view class="float-bar" v-show="!isPaymentVisible">
|
||||
<view class="float-bar-inner">
|
||||
<view class="selection-info" v-if="selectedCount > 0">
|
||||
已选 <text class="highlight">{{ selectedCount }}</text> 个位置
|
||||
</view>
|
||||
<view class="selection-info" v-if="selectedCount > 0">
|
||||
已选 <text class="highlight">{{ selectedCount }}</text> 个位置
|
||||
</view>
|
||||
<view class="selection-info" v-else>
|
||||
<!-- 次数卡余额 / 购买入口 -->
|
||||
<view v-if="gamePassRemaining > 0" class="game-pass-badge" @tap="() => {}">
|
||||
<text class="badge-icon">🎮</text>
|
||||
<text class="badge-text" style="font-size: 24rpx; font-weight: bold; color: #10B981;">{{ gamePassRemaining }}</text>
|
||||
</view>
|
||||
<!-- 充值入口 -->
|
||||
<view class="game-pass-buy-btn" @tap="openPurchasePopup">
|
||||
<text>充值特惠</text>
|
||||
</view>
|
||||
请选择位置
|
||||
</view>
|
||||
<view class="action-buttons">
|
||||
@ -121,10 +133,17 @@
|
||||
v-model:visible="paymentVisible"
|
||||
:amount="paymentAmount"
|
||||
:coupons="paymentCoupons"
|
||||
:gamePasses="gamePasses"
|
||||
:showCards="false"
|
||||
@confirm="onPaymentConfirm"
|
||||
@cancel="onPaymentCancel"
|
||||
/>
|
||||
|
||||
<GamePassPurchasePopup
|
||||
v-model:visible="purchasePopupVisible"
|
||||
:activity-id="activityId"
|
||||
@success="onPurchaseSuccess"
|
||||
/>
|
||||
</template>
|
||||
</ActivityPageLayout>
|
||||
</template>
|
||||
@ -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) => {
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
/* 浮动操作栏扩展 - 充值按钮 & Badge */
|
||||
.game-pass-badge {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
background: rgba(16, 185, 129, 0.15);
|
||||
padding: 6rpx 16rpx;
|
||||
border-radius: 30rpx;
|
||||
border: 1rpx solid rgba(16, 185, 129, 0.3);
|
||||
margin: 0 12rpx;
|
||||
animation: pulse 2s infinite;
|
||||
|
||||
.badge-icon {
|
||||
font-size: 28rpx;
|
||||
margin-right: 6rpx;
|
||||
}
|
||||
|
||||
.badge-text {
|
||||
font-size: 24rpx;
|
||||
color: #10B981;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
&:active {
|
||||
opacity: 0.8;
|
||||
}
|
||||
}
|
||||
|
||||
.game-pass-buy-btn {
|
||||
background: linear-gradient(90deg, #FF9F43, #FF6B00);
|
||||
color: #fff;
|
||||
font-size: 22rpx;
|
||||
padding: 6rpx 16rpx;
|
||||
border-radius: 24rpx;
|
||||
margin-right: 12rpx;
|
||||
font-weight: 600;
|
||||
box-shadow: 0 4rpx 8rpx rgba(255, 107, 0, 0.2);
|
||||
|
||||
&:active {
|
||||
transform: scale(0.95);
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes pulse {
|
||||
0% { transform: scale(1); }
|
||||
50% { transform: scale(1.05); }
|
||||
100% { transform: scale(1); }
|
||||
}
|
||||
</style>
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user