feat: P1 合盘/星座/问答与测测完整设计包及模拟器取证工具
落地 synastry/star/ask API 与 H5 页面,补齐 cece-frontend-re complete-design 证据文档,并加入 Android 模拟器截图抓取脚本。 Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -1,18 +1,94 @@
|
||||
<template>
|
||||
<main class="page">
|
||||
<button class="back" type="button" @click="$router.back()">← 返回</button>
|
||||
<h1>成长会员</h1>
|
||||
<p class="sub">完整分析 · AI成长助手更多次数 · 专属内容</p>
|
||||
<div class="card">
|
||||
月 / 季 / 年套餐与模拟支付将接入 /api/v1/orders。亦可在成长报告内选择「深度版」单次完整分析。
|
||||
<main class="yxg-page">
|
||||
<div class="yxg-hero">
|
||||
<BackButton />
|
||||
<PageTitle feature="membership" title="成长会员" sub="完整分析 · AI成长助手更多次数 · 专属内容" />
|
||||
</div>
|
||||
<div class="yxg-sheet sheet-pad">
|
||||
<p v-if="loading" class="yxg-hint">加载中…</p>
|
||||
<p v-else-if="error" class="yxg-err">
|
||||
{{ error }}
|
||||
<button type="button" class="yxg-link" @click="load">重试</button>
|
||||
</p>
|
||||
<template v-else>
|
||||
<div v-if="me?.active" class="yxg-card ok">
|
||||
<p class="ok-title">会员有效 · {{ planLabel }}</p>
|
||||
<p v-if="me.expires_at" class="yxg-meta">到期:{{ formatDate(me.expires_at) }}</p>
|
||||
<p class="yxg-meta">问答额度剩余:{{ me.ask_quota_left ?? 0 }}</p>
|
||||
</div>
|
||||
<div v-else class="yxg-card">
|
||||
<p>尚未开通成长会员。开通后可查看画像与关系理解的完整分析。</p>
|
||||
<button class="yxg-btn" type="button" :disabled="paying" @click="subscribe('month')">开通月卡(模拟支付)</button>
|
||||
<button class="yxg-btn yxg-btn-ghost" type="button" :disabled="paying" @click="subscribe('quarter')">季卡</button>
|
||||
<button class="yxg-btn yxg-btn-ghost" type="button" :disabled="paying" @click="subscribe('year')">年卡</button>
|
||||
</div>
|
||||
</template>
|
||||
</div>
|
||||
</main>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { computed, onMounted, ref } from 'vue'
|
||||
import type { MembershipMe } from '@yuxingu/types'
|
||||
import { api } from '../api/client'
|
||||
import BackButton from '../components/BackButton.vue'
|
||||
import PageTitle from '../components/PageTitle.vue'
|
||||
import { AnalyticsEvent, track } from '../lib/analytics'
|
||||
|
||||
const loading = ref(true)
|
||||
const paying = ref(false)
|
||||
const error = ref('')
|
||||
const me = ref<MembershipMe | null>(null)
|
||||
|
||||
const planLabel = computed(() => {
|
||||
const p = me.value?.plan
|
||||
if (p === 'quarter') return '季卡'
|
||||
if (p === 'year') return '年卡'
|
||||
if (p === 'month') return '月卡'
|
||||
return p || '成长会员'
|
||||
})
|
||||
|
||||
function formatDate(iso: string) {
|
||||
try {
|
||||
return new Date(iso).toLocaleDateString('zh-CN')
|
||||
} catch {
|
||||
return iso
|
||||
}
|
||||
}
|
||||
|
||||
async function load() {
|
||||
loading.value = true
|
||||
error.value = ''
|
||||
try {
|
||||
me.value = await api.getMembership()
|
||||
} catch (e) {
|
||||
error.value = e instanceof Error ? e.message : '加载失败'
|
||||
} finally {
|
||||
loading.value = false
|
||||
}
|
||||
}
|
||||
|
||||
async function subscribe(plan: string) {
|
||||
paying.value = true
|
||||
error.value = ''
|
||||
try {
|
||||
const { order_id } = await api.createOrder({ kind: 'membership', plan })
|
||||
await api.payMock(order_id)
|
||||
me.value = await api.getMembership()
|
||||
track(AnalyticsEvent.PurchaseCompleted, { kind: 'membership' })
|
||||
} catch (e) {
|
||||
error.value = e instanceof Error ? e.message : '支付失败'
|
||||
} finally {
|
||||
paying.value = false
|
||||
}
|
||||
}
|
||||
|
||||
onMounted(load)
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.page{padding:16px}
|
||||
.back{border:none;background:#fff;border-radius:10px;padding:8px 12px;margin-bottom:12px}
|
||||
h1{font-size:22px}
|
||||
.sub{color:var(--yxg-sub);margin:8px 0 14px;font-size:13px}
|
||||
.card{background:#fff;border-radius:16px;padding:18px;font-size:14px;line-height:1.7;color:#555}
|
||||
.yxg-card{margin-top:8px}
|
||||
.ok{border:1px solid #c8e6c9;background:#f4fff4}
|
||||
.ok-title{font-size:15px;font-weight:650;color:#222;margin-bottom:6px}
|
||||
.yxg-btn{margin-top:12px;margin-right:8px}
|
||||
</style>
|
||||
|
||||
Reference in New Issue
Block a user