06488f0237
功能: - Go后端 (Gin + GORM + PostgreSQL) - UniApp用户端 (iOS/Android/小程序) - DaisyUI5后台管理 - JWT认证 + 微信登录 - 盲选加权算法 - 会员系统 + 优惠券 - 打分评价 + 偏好学习
185 lines
5.0 KiB
Vue
185 lines
5.0 KiB
Vue
<template>
|
|
<view class="page-member">
|
|
<view class="member-header" :style="{ background: headerBg }">
|
|
<text class="member-title" v-if="active">👑 VIP会员</text>
|
|
<text class="member-title" v-else>🌟 开通VIP</text>
|
|
<text class="member-subtitle" v-if="active">尊享特权 · 每天10次盲选</text>
|
|
<text class="member-subtitle" v-else">解锁更多盲选权益</text>
|
|
</view>
|
|
|
|
<!-- 权益列表 -->
|
|
<view class="benefits card">
|
|
<text class="section-title">VIP权益</text>
|
|
<view class="benefit-item" v-for="item in benefits" :key="item">
|
|
<text class="benefit-icon">{{ item.icon }}</text>
|
|
<text class="benefit-text">{{ item.text }}</text>
|
|
</view>
|
|
</view>
|
|
|
|
<!-- 套餐选择 -->
|
|
<view class="plans card">
|
|
<text class="section-title">选择套餐</text>
|
|
<view
|
|
class="plan-card"
|
|
:class="{ selected: selectedPlan === plan.id }"
|
|
v-for="plan in plans"
|
|
:key="plan.id"
|
|
@click="selectedPlan = plan.id"
|
|
>
|
|
<view class="plan-header">
|
|
<text class="plan-name">{{ plan.name }}</text>
|
|
<view class="plan-price">
|
|
<text class="price-num">¥{{ plan.price }}</text>
|
|
<text class="price-period">/{{ plan.period }}</text>
|
|
</view>
|
|
</view>
|
|
<view class="plan-features">
|
|
<text class="feature" v-for="f in plan.features" :key="f">✓ {{ f }}</text>
|
|
</view>
|
|
</view>
|
|
</view>
|
|
|
|
<!-- 保存按钮 -->
|
|
<view class="save-area">
|
|
<button class="subscribe-btn" @click="subscribe">
|
|
立即开通 {{ selectedPlanName }}
|
|
</button>
|
|
</view>
|
|
</view>
|
|
</template>
|
|
|
|
<script setup>
|
|
import { ref, computed, onMounted } from 'vue'
|
|
import { memberApi } from '@/api/index.js'
|
|
|
|
const active = ref(false)
|
|
const selectedPlan = ref(1)
|
|
|
|
const plans = ref([
|
|
{ id: 1, name: 'VIP月卡', price: 29, period: '月', features: ['每天10次盲选', '全部分类', '优先匹配', '月度报告'] },
|
|
{ id: 2, name: 'VIP年卡', price: 199, period: '年', features: ['每天10次盲选', '全部分类', '优先匹配', '月度报告', '省¥149'] },
|
|
])
|
|
|
|
const selectedPlanName = computed(() => plans.value.find(p => p.id === selectedPlan.value)?.name || '')
|
|
|
|
const benefits = [
|
|
{ icon: '🎲', text: '每天10次盲选机会(免费用户3次)' },
|
|
{ icon: '🌍', text: '全部分类解锁(含专属VIP分类)' },
|
|
{ icon: '⭐', text: '优先匹配优质套餐和商家' },
|
|
{ icon: '📊', text: '月度盲选报告 + AI消费分析' },
|
|
{ icon: '🏷️', text: '专属VIP标签和身份标识' },
|
|
{ icon: '🔄', text: '7天去重 → 1天去重(减少重复推荐)' },
|
|
]
|
|
|
|
const headerBg = computed(() => active.value ? 'linear-gradient(135deg, #667eea, #764ba2)' : 'linear-gradient(135deg, #FF6B35, #FF8C42)')
|
|
|
|
onMounted(async () => {
|
|
try {
|
|
const status = await memberApi.getStatus()
|
|
active.value = status.active
|
|
} catch(e) {}
|
|
})
|
|
|
|
async function subscribe() {
|
|
try {
|
|
await memberApi.subscribe({
|
|
plan_id: selectedPlan.value,
|
|
payment_method: 'wechat',
|
|
})
|
|
active.value = true
|
|
uni.showToast({ title: '开通成功!', icon: 'success' })
|
|
} catch(e) {
|
|
uni.showToast({ title: '支付功能开发中', icon: 'none' })
|
|
}
|
|
}
|
|
</script>
|
|
|
|
<style lang="scss" scoped>
|
|
.page-member {
|
|
min-height: 100vh;
|
|
background: #f5f5f5;
|
|
}
|
|
|
|
.member-header {
|
|
padding: 80rpx 30rpx 50rpx;
|
|
text-align: center;
|
|
color: #fff;
|
|
.member-title { font-size: 40rpx; font-weight: 700; display: block; }
|
|
.member-subtitle { font-size: 24rpx; opacity: 0.85; margin-top: 8rpx; display: block; }
|
|
}
|
|
|
|
.card {
|
|
background: #fff;
|
|
border-radius: 20rpx;
|
|
padding: 24rpx;
|
|
margin: 20rpx 24rpx;
|
|
box-shadow: 0 4rpx 16rpx rgba(0,0,0,0.06);
|
|
}
|
|
|
|
.section-title {
|
|
font-size: 30rpx;
|
|
font-weight: 700;
|
|
margin-bottom: 16rpx;
|
|
display: block;
|
|
}
|
|
|
|
.benefit-item {
|
|
display: flex;
|
|
align-items: center;
|
|
padding: 16rpx 0;
|
|
border-bottom: 1rpx solid #f0f0f0;
|
|
.benefit-icon { font-size: 32rpx; width: 44rpx; }
|
|
.benefit-text { font-size: 26rpx; color: #555; }
|
|
}
|
|
|
|
.plan-card {
|
|
border: 2rpx solid #eee;
|
|
border-radius: 16rpx;
|
|
padding: 20rpx;
|
|
margin-bottom: 12rpx;
|
|
&.selected {
|
|
border-color: #FF6B35;
|
|
background: #FFF8F0;
|
|
}
|
|
}
|
|
|
|
.plan-header {
|
|
display: flex;
|
|
justify-content: space-between;
|
|
align-items: center;
|
|
.plan-name { font-size: 28rpx; font-weight: 600; }
|
|
.plan-price { display: flex; align-items: baseline; }
|
|
.price-num { font-size: 36rpx; font-weight: 700; color: #FF6B35; }
|
|
.price-period { font-size: 22rpx; color: #999; }
|
|
}
|
|
|
|
.plan-features {
|
|
display: flex;
|
|
flex-wrap: wrap;
|
|
gap: 8rpx;
|
|
margin-top: 12rpx;
|
|
}
|
|
|
|
.feature {
|
|
font-size: 20rpx;
|
|
color: #666;
|
|
background: #f8f8f8;
|
|
padding: 4rpx 12rpx;
|
|
border-radius: 10rpx;
|
|
}
|
|
|
|
.save-area {
|
|
padding: 40rpx 40rpx 100rpx;
|
|
}
|
|
|
|
.subscribe-btn {
|
|
background: linear-gradient(135deg, #FF6B35, #FF8C42);
|
|
color: #fff;
|
|
border: none;
|
|
border-radius: 40rpx;
|
|
font-size: 32rpx;
|
|
font-weight: 600;
|
|
box-shadow: 0 8rpx 30rpx rgba(255,107,53,0.3);
|
|
}
|
|
</style>
|