Files
blind-select/frontend-app/pages/member/member.vue
T
admin 06488f0237 Initial commit: 帮我选盲选应用
功能:
- Go后端 (Gin + GORM + PostgreSQL)
- UniApp用户端 (iOS/Android/小程序)
- DaisyUI5后台管理
- JWT认证 + 微信登录
- 盲选加权算法
- 会员系统 + 优惠券
- 打分评价 + 偏好学习
2026-06-08 20:18:31 +00:00

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>