|
|
@@ -10,87 +10,96 @@
|
|
|
</template>
|
|
|
|
|
|
<template v-else>
|
|
|
- <!-- C端 ¥131 方案 -->
|
|
|
- <view
|
|
|
- class="plan-card"
|
|
|
- :class="{ selected: selectedPlan === 'annual' }"
|
|
|
- @click="selectedPlan = 'annual'"
|
|
|
- >
|
|
|
- <view class="plan-badge popular">推荐</view>
|
|
|
- <view class="plan-top">
|
|
|
- <text class="plan-name">C端会员</text>
|
|
|
- <view class="plan-price-row">
|
|
|
- <text class="price-symbol">¥</text>
|
|
|
- <text class="price">{{ formatYuan(pricing.annualFee) }}</text>
|
|
|
- <text class="per">/年</text>
|
|
|
- </view>
|
|
|
- <text class="price-daily">每天仅 ¥{{ (pricing.annualFee / 100 / 365).toFixed(2) }}</text>
|
|
|
- </view>
|
|
|
- <view class="plan-features">
|
|
|
- <text class="feature">✦ AI 互动问答 — 无限次</text>
|
|
|
- <text class="feature">✦ 获得推广权限,赚取佣金</text>
|
|
|
- <text class="feature">✦ 一级 40% + 二级 5% 佣金比例</text>
|
|
|
- <text class="feature">✦ VIP 标识</text>
|
|
|
+ <view v-if="visiblePlans.length === 0" class="already-vip">
|
|
|
+ <text class="already-vip__icon">✓</text>
|
|
|
+ <text class="already-vip__title">您已是能量师</text>
|
|
|
+ <text class="already-vip__desc">解锁了全部功能,可在命盘页使用 AI 解读</text>
|
|
|
</view>
|
|
|
- </view>
|
|
|
|
|
|
- <!-- B端 ¥1,314 方案 -->
|
|
|
- <view
|
|
|
- class="plan-card plan-pro"
|
|
|
- :class="{ selected: selectedPlan === 'practitioner' }"
|
|
|
- @click="selectedPlan = 'practitioner'"
|
|
|
- >
|
|
|
- <view class="plan-badge pro">专业</view>
|
|
|
- <view class="plan-top">
|
|
|
- <text class="plan-name">能量师</text>
|
|
|
- <view class="plan-price-row">
|
|
|
- <text class="price-symbol">¥</text>
|
|
|
- <text class="price">{{ formatYuan(currentPractitionerPrice) }}</text>
|
|
|
- <text class="per">/年</text>
|
|
|
+ <view v-show="visiblePlans.length > 0" class="plans-section">
|
|
|
+ <view
|
|
|
+ v-if="visiblePlans.includes('annual')"
|
|
|
+ class="plan-card"
|
|
|
+ :class="{ selected: selectedPlan === 'annual' }"
|
|
|
+ @click="selectedPlan = 'annual'"
|
|
|
+ >
|
|
|
+ <view class="plan-badge popular">推荐</view>
|
|
|
+ <view class="plan-top">
|
|
|
+ <text class="plan-name">C端会员</text>
|
|
|
+ <view class="plan-price-row">
|
|
|
+ <text class="price-symbol">¥</text>
|
|
|
+ <text class="price">{{ formatYuan(pricing.annualFee) }}</text>
|
|
|
+ <text class="per">/年</text>
|
|
|
+ </view>
|
|
|
+ <text class="price-daily">每天仅 ¥{{ (pricing.annualFee / 100 / 365).toFixed(2) }}</text>
|
|
|
+ </view>
|
|
|
+ <view class="plan-features">
|
|
|
+ <text class="feature">✦ AI 互动问答 — 无限次</text>
|
|
|
+ <text class="feature">✦ 获得推广权限,赚取佣金</text>
|
|
|
+ <text class="feature">✦ 一级 40% + 二级 5% 佣金比例</text>
|
|
|
+ <text class="feature">✦ VIP 标识</text>
|
|
|
+ </view>
|
|
|
</view>
|
|
|
- <view v-if="pricing.isSeedPrice" class="seed-badge">
|
|
|
- 种子价 · 仅剩 {{ pricing.remainingSeats }}/{{ pricing.seedLimit }} 个名额
|
|
|
+
|
|
|
+ <view
|
|
|
+ v-if="visiblePlans.includes('practitioner')"
|
|
|
+ class="plan-card plan-pro"
|
|
|
+ :class="{ selected: selectedPlan === 'practitioner' }"
|
|
|
+ @click="selectedPlan = 'practitioner'"
|
|
|
+ >
|
|
|
+ <view class="plan-badge pro">专业</view>
|
|
|
+ <view class="plan-top">
|
|
|
+ <text class="plan-name">能量师</text>
|
|
|
+ <view class="plan-price-row">
|
|
|
+ <text class="price-symbol">¥</text>
|
|
|
+ <text class="price">{{ formatYuan(currentPractitionerPrice) }}</text>
|
|
|
+ <text class="per">/年</text>
|
|
|
+ </view>
|
|
|
+ <view v-if="pricing.isSeedPrice" class="seed-badge">
|
|
|
+ 种子价 · 仅剩 {{ pricing.remainingSeats }}/{{ pricing.seedLimit }} 个名额
|
|
|
+ </view>
|
|
|
+ <text class="price-daily">每天仅 ¥{{ (currentPractitionerPrice / 100 / 365).toFixed(2) }}</text>
|
|
|
+ </view>
|
|
|
+ <view class="plan-features">
|
|
|
+ <text class="feature">✦ 包含 C 端全部权益</text>
|
|
|
+ <text class="feature">✦ 无限命盘生成</text>
|
|
|
+ <text class="feature">✦ AI 五区完整解读,随问随答</text>
|
|
|
+ <text class="feature">✦ 全部历史记录永久保存</text>
|
|
|
+ <text class="feature">✦ 推广佣金 — 固定 ¥500/人 + 二级 ¥100/人</text>
|
|
|
+ </view>
|
|
|
</view>
|
|
|
- <text class="price-daily">每天仅 ¥{{ (currentPractitionerPrice / 100 / 365).toFixed(2) }}</text>
|
|
|
- </view>
|
|
|
- <view class="plan-features">
|
|
|
- <text class="feature">✦ 包含 C 端全部权益</text>
|
|
|
- <text class="feature">✦ 无限命盘生成</text>
|
|
|
- <text class="feature">✦ AI 五区完整解读,随问随答</text>
|
|
|
- <text class="feature">✦ 全部历史记录永久保存</text>
|
|
|
- <text class="feature">✦ 推广佣金 — 固定 ¥500/人 + 二级 ¥100/人</text>
|
|
|
- </view>
|
|
|
- </view>
|
|
|
|
|
|
- <!-- Compare table -->
|
|
|
- <view class="compare-card">
|
|
|
- <view class="compare-header">
|
|
|
- <text class="col">功能</text>
|
|
|
- <text class="col">普通</text>
|
|
|
- <text class="col c">C端</text>
|
|
|
- <text class="col pro">能量师</text>
|
|
|
- </view>
|
|
|
- <view class="compare-row" v-for="row in compareData" :key="row.label">
|
|
|
- <text class="col">{{ row.label }}</text>
|
|
|
- <text class="col">{{ row.free }}</text>
|
|
|
- <text class="col c">{{ row.c }}</text>
|
|
|
- <text class="col pro">{{ row.pro }}</text>
|
|
|
- </view>
|
|
|
- </view>
|
|
|
+ <view class="compare-card">
|
|
|
+ <view class="compare-header">
|
|
|
+ <text class="col">功能</text>
|
|
|
+ <text class="col">普通</text>
|
|
|
+ <text class="col c">C端</text>
|
|
|
+ <text class="col pro">能量师</text>
|
|
|
+ </view>
|
|
|
+ <view class="compare-row" v-for="row in compareData" :key="row.label">
|
|
|
+ <text class="col">{{ row.label }}</text>
|
|
|
+ <text class="col">{{ row.free }}</text>
|
|
|
+ <text class="col c">{{ row.c }}</text>
|
|
|
+ <text class="col pro">{{ row.pro }}</text>
|
|
|
+ </view>
|
|
|
+ </view>
|
|
|
|
|
|
- <!-- Pay button -->
|
|
|
- <button class="pay-btn" @click="onPay" :disabled="paying">
|
|
|
- {{ paying ? '处理中...' : payButtonText }}
|
|
|
- </button>
|
|
|
- <text class="note">支付即表示同意《订阅协议》</text>
|
|
|
+ <button class="pay-btn" @click="onPay" :disabled="paying">
|
|
|
+ {{ paying ? '处理中...' : payButtonText }}
|
|
|
+ </button>
|
|
|
+ <text class="note">支付即表示同意《订阅协议》</text>
|
|
|
+ </view>
|
|
|
</template>
|
|
|
</view>
|
|
|
</template>
|
|
|
|
|
|
<script setup>
|
|
|
-import { ref, computed, onMounted } from 'vue'
|
|
|
+import { ref, computed, onMounted, watch } from 'vue'
|
|
|
+import { useUserStore } from '@/stores/user'
|
|
|
import { payApi, pricingApi } from '@/utils/api'
|
|
|
|
|
|
+const userStore = useUserStore()
|
|
|
+
|
|
|
const paying = ref(false)
|
|
|
const loading = ref(true)
|
|
|
const selectedPlan = ref('annual')
|
|
|
@@ -131,6 +140,8 @@ function formatYuan(cents) {
|
|
|
|
|
|
onMounted(async () => {
|
|
|
try {
|
|
|
+ // Ensure user profile is loaded (for vipType check)
|
|
|
+ await userStore.fetchProfile()
|
|
|
const res = await pricingApi.current()
|
|
|
if (res) pricing.value = res
|
|
|
} catch (e) {
|
|
|
@@ -139,18 +150,30 @@ onMounted(async () => {
|
|
|
loading.value = false
|
|
|
})
|
|
|
|
|
|
+// Show plans based on current VIP status
|
|
|
+const visiblePlans = computed(() => {
|
|
|
+ const vipType = userStore.vipType
|
|
|
+ if (!vipType) return ['annual', 'practitioner']
|
|
|
+ if (vipType === 'annual') return ['practitioner']
|
|
|
+ if (vipType === 'practitioner') return []
|
|
|
+ return ['annual', 'practitioner']
|
|
|
+})
|
|
|
+
|
|
|
+// Auto-select first visible plan when VIP status changes
|
|
|
+watch(visiblePlans, (newPlans) => {
|
|
|
+ if (newPlans.length === 0) return
|
|
|
+ if (!newPlans.includes(selectedPlan.value)) {
|
|
|
+ selectedPlan.value = newPlans[0]
|
|
|
+ }
|
|
|
+}, { immediate: true })
|
|
|
+
|
|
|
async function onPay() {
|
|
|
- paying.value = true
|
|
|
- try {
|
|
|
- const totalFee = selectedPlan.value === 'annual' ? pricing.value.annualFee : currentPractitionerPrice.value
|
|
|
- const productType = selectedPlan.value
|
|
|
- await payApi.create({ totalFee, payType: 'wxpay', productType })
|
|
|
- uni.showToast({ title: '开通成功!', icon: 'success' })
|
|
|
- setTimeout(() => uni.navigateBack(), 1500)
|
|
|
- } catch (e) {
|
|
|
- uni.showToast({ title: '支付失败,请重试', icon: 'none' })
|
|
|
+ if (selectedPlan.value === 'annual') {
|
|
|
+ uni.navigateTo({ url: '/pages/payment/index?product=annual' })
|
|
|
+ return
|
|
|
}
|
|
|
- paying.value = false
|
|
|
+ // practitioner — go to payment page
|
|
|
+ uni.navigateTo({ url: '/pages/payment/index?product=practitioner' })
|
|
|
}
|
|
|
</script>
|
|
|
|
|
|
@@ -342,4 +365,33 @@ async function onPay() {
|
|
|
font-size: 12px;
|
|
|
color: rgba(255,255,255,0.25);
|
|
|
}
|
|
|
+
|
|
|
+.already-vip {
|
|
|
+ display: flex;
|
|
|
+ flex-direction: column;
|
|
|
+ align-items: center;
|
|
|
+ justify-content: center;
|
|
|
+ padding: 60px 20px;
|
|
|
+ text-align: center;
|
|
|
+ background: rgba(255,255,255,0.03);
|
|
|
+ border: 1px solid rgba(255,255,255,0.08);
|
|
|
+ border-radius: 16px;
|
|
|
+ margin-top: 20px;
|
|
|
+}
|
|
|
+.already-vip__icon {
|
|
|
+ font-size: 40px;
|
|
|
+ margin-bottom: 16px;
|
|
|
+ color: #22c55e;
|
|
|
+}
|
|
|
+.already-vip__title {
|
|
|
+ font-size: 18px;
|
|
|
+ font-weight: 600;
|
|
|
+ color: rgba(255,255,255,0.85);
|
|
|
+ margin-bottom: 6px;
|
|
|
+}
|
|
|
+.already-vip__desc {
|
|
|
+ font-size: 13px;
|
|
|
+ color: rgba(255,255,255,0.4);
|
|
|
+ line-height: 1.5;
|
|
|
+}
|
|
|
</style>
|