| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217 |
- <template>
- <view class="page-profile">
- <!-- US-5.1 §13: Profile incomplete banner -->
- <view v-if="userStore.isLoggedIn && userStore.profileIncomplete" class="banner" @click="goEditProfile">
- <text class="banner-text">📝 请完善个人资料,开启能量匹配</text>
- <text class="banner-arrow">›</text>
- </view>
- <!-- User info card -->
- <view class="user-card" @click="goLogin">
- <view class="avatar">
- <image :src="userStore.avatarUrl || '/static/default-avatar.png'" mode="aspectFill" />
- </view>
- <text class="nickname">{{ userStore.nickname || '未登录' }}</text>
- <text v-if="!userStore.isLoggedIn" class="login-hint">点击登录</text>
- <view v-if="userStore.isVip" class="vip-badge">VIP 会员</view>
- </view>
- <!-- VIP status -->
- <view v-if="userStore.vipType === 'practitioner'" class="vip-card pro" @click="goPayment">
- <view class="vip-info">
- <text class="vip-title">能量师会员</text>
- <text class="vip-desc">
- 有效期至: {{ userStore.vipEndTime?.slice(0, 10) }}
- </text>
- </view>
- <text class="vip-action">续费</text>
- </view>
- <view v-else-if="userStore.vipType === 'annual'" class="vip-card annual" @click="goUpgradePractitioner">
- <view class="vip-info">
- <text class="vip-title">C端会员</text>
- <text class="vip-desc">
- 有效期至: {{ userStore.vipEndTime?.slice(0, 10) }}
- </text>
- </view>
- <text class="vip-action">升级能量师</text>
- </view>
- <view v-else class="vip-card" @click="goPayment">
- <view class="vip-info">
- <text class="vip-title">VIP 会员</text>
- <text class="vip-desc">
- 开通VIP获取完整分析
- </text>
- </view>
- <text class="vip-action">立即开通</text>
- </view>
- <!-- Daily quota (non-VIP) -->
- <view v-if="!userStore.isVip" class="quota-card">
- <view class="quota-item">
- <text class="quota-label">今日分析</text>
- <text class="quota-value">{{ userStore.usedCharts }}/{{ userStore.maxCharts }}</text>
- </view>
- <view class="quota-divider"></view>
- <view class="quota-item">
- <text class="quota-label">今日解读</text>
- <text class="quota-value">{{ userStore.usedChats }}/{{ userStore.maxChats }}</text>
- </view>
- </view>
- <!-- Menu list -->
- <view class="menu-section">
- <view class="menu-item" @click="goEditProfile">
- <text>✏️ 编辑资料</text>
- <text class="menu-arrow">›</text>
- </view>
- <view class="menu-item" @click="goRecords">
- <text>📋 我的分析</text>
- <text class="menu-arrow">›</text>
- </view>
- <view class="menu-item" @click="goCommission">
- <text>💰 我的推广</text>
- <text class="menu-arrow">›</text>
- </view>
- <view class="menu-item" @click="copyReferral">
- <text>🔗 推广码: {{ userStore.referralCode || '加载中' }}</text>
- <text class="menu-tip">点击复制</text>
- </view>
- </view>
- <!-- Actions -->
- <view class="menu-section">
- <view class="menu-item" @click="handleLogout">
- <text style="color: #EF4444;">退出登录</text>
- </view>
- </view>
- </view>
- </template>
- <script setup>
- import { onShow } from '@dcloudio/uni-app'
- import { useUserStore } from '@/stores/user'
- const userStore = useUserStore()
- onShow(() => {
- if (userStore.isLoggedIn) {
- userStore.fetchProfile()
- userStore.fetchQuota()
- userStore.fetchCommissionSummary()
- }
- })
- function goEditProfile() {
- if (!userStore.isLoggedIn) {
- uni.navigateTo({ url: '/pages/login/index' })
- return
- }
- uni.navigateTo({ url: '/pages/profile/edit' })
- }
- function goLogin() {
- if (!userStore.isLoggedIn) {
- uni.navigateTo({ url: '/pages/login/index' })
- }
- }
- function goPayment() {
- uni.navigateTo({ url: '/pages/payment/index?product=annual' })
- }
- function goUpgradePractitioner() {
- uni.navigateTo({ url: '/pages/payment/index?product=practitioner' })
- }
- function goRecords() {
- uni.switchTab({ url: '/pages/records/index' })
- }
- function goCommission() {
- if (!userStore.isLoggedIn) {
- uni.navigateTo({ url: '/pages/login/index' })
- return
- }
- uni.navigateTo({ url: '/pages/commission/index' })
- }
- function copyReferral() {
- if (userStore.referralCode) {
- uni.setClipboardData({
- data: userStore.referralCode,
- success: () => uni.showToast({ title: '已复制推广码', icon: 'success' })
- })
- }
- }
- function handleLogout() {
- uni.showModal({
- title: '确认退出',
- content: '确定要退出登录吗?',
- success: (res) => {
- if (res.confirm) {
- userStore.logout()
- uni.showToast({ title: '已退出', icon: 'success' })
- }
- }
- })
- }
- </script>
- <style scoped lang="scss">
- .page-profile { padding: 16px; }
- .user-card {
- text-align: center; padding: 30px 0; background: #fff;
- border-radius: 12px; margin-bottom: 16px;
- }
- .avatar {
- width: 64px; height: 64px; border-radius: 50%; overflow: hidden;
- margin: 0 auto 12px;
- }
- .avatar image { width: 100%; height: 100%; }
- .nickname { font-size: 18px; font-weight: 600; display: block; color: #1F2937; }
- .login-hint { font-size: 12px; color: #3B82F6; display: block; margin-top: 4px; }
- .vip-badge {
- display: inline-block; background: #FEF3C7; color: #D97706;
- padding: 2px 12px; border-radius: 12px; font-size: 12px; margin-top: 8px;
- }
- .vip-card {
- background: linear-gradient(135deg, #3B82F6, #2563EB); border-radius: 12px;
- padding: 16px; display: flex; justify-content: space-between;
- align-items: center; margin-bottom: 16px;
- }
- .vip-card.annual {
- background: linear-gradient(135deg, #f59e0b, #d97706);
- }
- .vip-card.pro {
- background: linear-gradient(135deg, #7c3aed, #6d28d9);
- }
- .vip-title { color: #fff; font-weight: 600; font-size: 16px; display: block; }
- .vip-desc { color: rgba(255,255,255,0.8); font-size: 12px; display: block; margin-top: 4px; }
- .vip-action { color: #fff; font-size: 14px; font-weight: 500; }
- .menu-section { background: #fff; border-radius: 12px; margin-bottom: 16px; overflow: hidden; }
- .menu-item {
- display: flex; justify-content: space-between; align-items: center;
- padding: 14px 16px; border-bottom: 1px solid #F3F4F6;
- }
- .menu-item:last-child { border-bottom: none; }
- .menu-arrow { color: #9CA3AF; font-size: 18px; }
- .menu-tip { color: #3B82F6; font-size: 12px; }
- .quota-card {
- background: #fff; border-radius: 12px; padding: 16px; margin-bottom: 16px;
- display: flex; align-items: center; justify-content: space-around;
- }
- .quota-item { text-align: center; }
- .quota-label { font-size: 12px; color: #6B7280; display: block; margin-bottom: 4px; }
- .quota-value { font-size: 20px; font-weight: 700; color: #1F2937; }
- .quota-divider { width: 1px; height: 36px; background: #E5E7EB; }
- /* US-5.1 §13 profile incomplete banner */
- .banner {
- background: #FEF3C7; border: 1px solid #FDE68A; border-radius: 10px;
- padding: 10px 14px; margin-bottom: 12px;
- display: flex; justify-content: space-between; align-items: center;
- }
- .banner-text { font-size: 13px; color: #92400E; flex: 1; }
- .banner-arrow { font-size: 18px; color: #92400E; margin-left: 8px; }
- </style>
|