import { computed, onMounted, ref } from 'vue' import type { GrowthReport } from '@yuxingu/types' import { validateBirth } from '@yuxingu/utils' import { api } from '../api/client' import { AnalyticsEvent, track } from '../lib/analytics' export const promptRows = [ { icon: '🌊', label: '最近情绪有点乱,帮我理一理', scene: '情绪整理' }, { icon: '💬', label: '和 TA 相处时,我总在重复什么模式?', scene: '关系反思' }, { icon: '🪞', label: '我想更了解自己此刻的状态', scene: '自我觉察' }, { icon: '🍃', label: '生活节奏太快,我需要一点方向感', scene: '生活节奏' }, ] export function useImageCardPage() { const scenes = ref<{ key: string; label: string }[]>([]) const scene = ref('情绪整理') const quota = ref<{ remaining: number; daily_free: number; unlimited: boolean } | null>(null) const year = ref('') const month = ref('') const day = ref('') const wantDepth = ref(false) const drawing = ref(false) const paying = ref(false) const error = ref('') const bootError = ref('') const cards = ref<{ id: string; title: string; imagery: string; prompt: string; tip: string }[]>([]) const report = ref(null) const questionInput = ref('') const showBirth = ref(false) const summary = computed(() => (report.value?.summary || {}) as Record) const detail = computed(() => (report.value?.detail || null) as Record | null) const quotaLabel = computed(() => { if (!quota.value) return '…' if (quota.value.unlimited) return '不限(会员)' return `${quota.value.remaining} / ${quota.value.daily_free}` }) function birthFilled() { const y = Number(year.value) const m = Number(month.value) const d = Number(day.value) return !validateBirth(y, m, d) } function selectScene(key: string) { scene.value = key track('cards_scene_selected', { scene: key }) } function onPromptClick(row: { label: string; scene: string }) { selectScene(row.scene) questionInput.value = row.label if (birthFilled()) { draw() } else { showBirth.value = true } } function sendDraw() { if (questionInput.value.trim()) { scene.value = questionInput.value.trim() } draw() } async function refreshQuota() { quota.value = await api.getImageCardQuota() } async function boot() { try { const [sc] = await Promise.all([api.listImageCardScenes(), refreshQuota()]) scenes.value = sc.items || [] if (scenes.value.length && !scenes.value.find((s) => s.key === scene.value)) { scene.value = scenes.value[0].key } } catch (e) { bootError.value = e instanceof Error ? e.message : '加载失败' } } async function draw() { error.value = '' const y = Number(year.value) const m = Number(month.value) const d = Number(day.value) const msg = validateBirth(y, m, d) if (msg) { error.value = msg showBirth.value = true return } drawing.value = true 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: '我' }) const out = await api.drawImageCard({ profile_id: profile.id, scene: scene.value, depth: wantDepth.value, }) cards.value = out.cards || [] report.value = out.report quota.value = { remaining: out.quota_left, daily_free: quota.value?.daily_free || 3, unlimited: !!quota.value?.unlimited, } track('cards_drawn', { scene: scene.value, depth: wantDepth.value ? 1 : 0 }) } catch (e) { const m = e instanceof Error ? e.message : '抽取失败' error.value = m if (m.includes('次数')) track('cards_quota_exhausted') } finally { drawing.value = false } } async function buyDeep() { if (!report.value) return paying.value = true error.value = '' track(AnalyticsEvent.DeepAccessClicked, { surface: 'cards' }) 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(boot) return { scene, quotaLabel, year, month, day, wantDepth, drawing, paying, error, bootError, cards, report, questionInput, showBirth, summary, detail, onPromptClick, sendDraw, draw, buyDeep, } }