import { computed, onMounted, ref } from 'vue' import { useRoute, useRouter } from 'vue-router' import type { GrowthReport } from '@yuxingu/types' import { validateBirth } from '@yuxingu/utils' import { api } from '../api/client' import { AnalyticsEvent, track } from '../lib/analytics' import { ensureAccount, loadSelfLatest } from '../lib/authSession' import type { PortraitSharePayload } from '../lib/shareLink' export function usePortraitPage() { const route = useRoute() const router = useRouter() const loading = ref(false) const needBirth = ref(true) const error = ref('') const formError = ref('') const report = ref(null) const paying = ref(false) const shareOpen = ref(false) const year = ref(String(route.query.y || '')) const month = ref(String(route.query.m || '')) const day = ref(String(route.query.d || '')) const summary = computed(() => (report.value?.summary || {}) as Record) const detail = computed(() => (report.value?.detail || null) as Record | null) const headline = computed(() => String(summary.value.headline || '')) const oneLiner = computed(() => String(summary.value.one_liner || '')) const keywords = computed(() => Array.isArray(summary.value.keywords) ? (summary.value.keywords as string[]) : [], ) const sharePayload = computed(() => { if (!report.value) return null return { type: 'portrait', title: headline.value || String(summary.value.person_title || '愈心解码'), line: oneLiner.value, keywords: keywords.value, } }) async function generate(y: number, m: number, d: number) { loading.value = true error.value = '' formError.value = '' needBirth.value = false try { const birth = `${y}-${String(m).padStart(2, '0')}-${String(d).padStart(2, '0')}` const profile = await api.createProfile({ relation: 'self', birth_date: birth, display_name: '我' }) report.value = await api.getLatestReport(profile.id, 'portrait') track(AnalyticsEvent.PortraitCompleted, { source: 'form' }) } catch (e) { error.value = e instanceof Error ? e.message : '加载失败' needBirth.value = true } finally { loading.value = false } } async function start() { const y = Number(year.value) const m = Number(month.value) const d = Number(day.value) const msg = validateBirth(y, m, d) if (msg) { formError.value = msg return } await generate(y, m, d) } async function load() { if (!(await ensureAccount(router, route.fullPath))) return const reportId = String(route.query.report_id || '') if (reportId) { loading.value = true needBirth.value = false error.value = '' try { report.value = await api.getReport(reportId) track(AnalyticsEvent.PortraitCompleted, { source: 'report_id' }) } catch (e) { error.value = e instanceof Error ? e.message : '加载失败' needBirth.value = true } finally { loading.value = false } return } loading.value = true error.value = '' try { const cached = await loadSelfLatest('portrait') if (cached.report) { report.value = cached.report needBirth.value = false track(AnalyticsEvent.PortraitCompleted, { source: 'cache' }) return } if (cached.profile) { report.value = await api.createPortrait(cached.profile.id) needBirth.value = false return } const y = Number(route.query.y) const m = Number(route.query.m) const d = Number(route.query.d) if (y && m && d && !validateBirth(y, m, d)) { year.value = String(y) month.value = String(m) day.value = String(d) await generate(y, m, d) return } needBirth.value = true } catch (e) { error.value = e instanceof Error ? e.message : '加载失败' needBirth.value = true } finally { loading.value = false } } function retry() { if (report.value) { load() return } needBirth.value = true error.value = '' } async function buyDeep() { if (!report.value) return paying.value = true error.value = '' track(AnalyticsEvent.DeepAccessClicked, { surface: 'portrait' }) try { const { order_id } = await api.createOrder({ kind: 'deep_access', report_id: report.value.id }) await api.payMock(order_id) report.value = await api.getReport(report.value.id) track(AnalyticsEvent.PurchaseCompleted, { kind: 'deep_access' }) } catch (e) { error.value = e instanceof Error ? e.message : '支付失败' } finally { paying.value = false } } onMounted(load) return { loading, needBirth, error, formError, report, paying, shareOpen, year, month, day, summary, detail, sharePayload, start, retry, buyDeep, } }