210 lines
4.6 KiB
Vue
210 lines
4.6 KiB
Vue
<template>
|
|
<view class="membership-page">
|
|
<!-- 会员宣传长图 -->
|
|
<image
|
|
v-if="bannerUrl"
|
|
class="membership-banner"
|
|
:src="bannerUrl"
|
|
mode="widthFix"
|
|
/>
|
|
|
|
<!-- 会员商品区域 -->
|
|
<view class="products-section" v-if="products.length">
|
|
<view
|
|
v-for="product in products"
|
|
:key="product.productId"
|
|
class="product-card"
|
|
>
|
|
<view class="product-info">
|
|
<text class="product-name">{{ product.name }}</text>
|
|
<text class="product-price">¥{{ product.price }}</text>
|
|
</view>
|
|
|
|
<!-- 按钮状态逻辑 -->
|
|
<template v-if="product.type === 'monthly'">
|
|
<!-- 单月会员:已开通时隐藏 -->
|
|
<button
|
|
v-if="!isMember"
|
|
class="buy-btn"
|
|
@click="onPurchase(product)"
|
|
>
|
|
{{ t('membership.joinBtn') }}
|
|
</button>
|
|
<button
|
|
v-else
|
|
class="buy-btn disabled"
|
|
disabled
|
|
>
|
|
{{ t('membership.joinedBtn') }}
|
|
</button>
|
|
</template>
|
|
|
|
<template v-if="product.type === 'subscription'">
|
|
<!-- 订阅会员 -->
|
|
<button
|
|
v-if="!isSubscribed"
|
|
class="buy-btn subscribe-btn"
|
|
@click="onSubscribe(product)"
|
|
>
|
|
{{ t('membership.subscribeBtn') }}
|
|
</button>
|
|
<button
|
|
v-else
|
|
class="buy-btn disabled"
|
|
disabled
|
|
>
|
|
{{ t('membership.subscribedBtn') }}
|
|
</button>
|
|
</template>
|
|
</view>
|
|
</view>
|
|
</view>
|
|
</template>
|
|
|
|
<script setup>
|
|
import { ref, computed, onMounted } from 'vue'
|
|
import { useI18n } from 'vue-i18n'
|
|
import { useMembershipStore } from '../../stores/membership.js'
|
|
import { getMembershipBanner } from '../../api/content.js'
|
|
import { resolveImageUrl } from '../../utils/image.js'
|
|
|
|
const { t } = useI18n()
|
|
const membershipStore = useMembershipStore()
|
|
|
|
// 宣传Banner图URL
|
|
const bannerUrl = ref('')
|
|
|
|
// 商品列表
|
|
const products = computed(() => membershipStore.products)
|
|
|
|
// 是否为会员
|
|
const isMember = computed(() => {
|
|
return !!membershipStore.membershipInfo?.isMember
|
|
})
|
|
|
|
// 是否已订阅
|
|
const isSubscribed = computed(() => {
|
|
return !!membershipStore.subscriptionStatus?.isSubscribed
|
|
})
|
|
|
|
/**
|
|
* 购买单月会员
|
|
*/
|
|
async function onPurchase(product) {
|
|
try {
|
|
await membershipStore.purchase(product.productId, product.price)
|
|
uni.showToast({ title: t('membership.joinedBtn'), icon: 'success' })
|
|
} catch (e) {
|
|
if (e.message === 'cancelled') return
|
|
// 支付成功但后端确认失败
|
|
if (e.message?.includes('purchase')) {
|
|
uni.showToast({ title: t('membership.payConfirmPending'), icon: 'none' })
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* 订阅会员
|
|
*/
|
|
async function onSubscribe(product) {
|
|
try {
|
|
await membershipStore.subscribe(product.productId, product.price)
|
|
uni.showToast({ title: t('membership.subscribedBtn'), icon: 'success' })
|
|
} catch (e) {
|
|
if (e.message === 'cancelled') return
|
|
if (e.message?.includes('subscribe')) {
|
|
uni.showToast({ title: t('membership.payConfirmPending'), icon: 'none' })
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* 加载页面数据
|
|
*/
|
|
async function loadData() {
|
|
try {
|
|
const res = await getMembershipBanner()
|
|
bannerUrl.value = resolveImageUrl(res.data?.imageUrl || res.data || '')
|
|
} catch (e) { /* 错误已统一处理 */ }
|
|
|
|
try {
|
|
await membershipStore.fetchProducts()
|
|
} catch (e) { /* 错误已统一处理 */ }
|
|
|
|
try {
|
|
await membershipStore.fetchMembershipInfo()
|
|
} catch (e) { /* 错误已统一处理 */ }
|
|
|
|
try {
|
|
await membershipStore.fetchSubscriptionStatus()
|
|
} catch (e) { /* 错误已统一处理 */ }
|
|
}
|
|
|
|
onMounted(() => {
|
|
loadData()
|
|
})
|
|
</script>
|
|
|
|
<style scoped>
|
|
.membership-page {
|
|
min-height: 100vh;
|
|
background-color: #f5f5f5;
|
|
}
|
|
|
|
.membership-banner {
|
|
width: 100%;
|
|
}
|
|
|
|
.products-section {
|
|
padding: 30rpx 24rpx;
|
|
}
|
|
|
|
.product-card {
|
|
background-color: #ffffff;
|
|
border-radius: 16rpx;
|
|
padding: 30rpx;
|
|
margin-bottom: 24rpx;
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: space-between;
|
|
}
|
|
|
|
.product-info {
|
|
display: flex;
|
|
flex-direction: column;
|
|
}
|
|
|
|
.product-name {
|
|
font-size: 30rpx;
|
|
color: #333;
|
|
margin-bottom: 8rpx;
|
|
}
|
|
|
|
.product-price {
|
|
font-size: 36rpx;
|
|
color: #ff6600;
|
|
font-weight: bold;
|
|
}
|
|
|
|
.buy-btn {
|
|
min-width: 200rpx;
|
|
height: 72rpx;
|
|
line-height: 72rpx;
|
|
text-align: center;
|
|
background-color: #ff6600;
|
|
color: #ffffff;
|
|
border-radius: 36rpx;
|
|
font-size: 28rpx;
|
|
border: none;
|
|
}
|
|
|
|
.subscribe-btn {
|
|
background-color: #6c5ce7;
|
|
}
|
|
|
|
.buy-btn.disabled {
|
|
background-color: #cccccc;
|
|
color: #999999;
|
|
}
|
|
</style>
|