feat: 小程序统一走 Go 后台,咨询与登录切到 /api/v1
去掉协会 WebView 和魔方账密页,微信登录与咨询接口共用同一 token 和拦截器。 Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -0,0 +1,141 @@
|
||||
<template>
|
||||
<yxg-page title="合盘">
|
||||
<view v-if="!report" class="card">
|
||||
<text class="h1">恋爱 / 友情 / 婚姻指数</text>
|
||||
<text class="desc">选择档案中的两个人,或填写 TA 的生日生成合盘。</text>
|
||||
<picker :range="labels" :value="idxA" @change="idxA = Number($event.detail.value)">
|
||||
<view class="pick"><text>我 / A:{{ labels[idxA] || '请选择' }}</text></view>
|
||||
</picker>
|
||||
<picker :range="labels" :value="idxB" @change="idxB = Number($event.detail.value)">
|
||||
<view class="pick"><text>TA / B:{{ labels[idxB] || '请选择' }}</text></view>
|
||||
</picker>
|
||||
<text class="or">没有 TA 的档案?填写生日快速添加</text>
|
||||
<input class="inp" v-model="otherName" placeholder="TA 的称呼" />
|
||||
<view class="date-row">
|
||||
<input class="inp sm" type="number" v-model="oy" placeholder="年" />
|
||||
<input class="inp sm" type="number" v-model="om" placeholder="月" />
|
||||
<input class="inp sm" type="number" v-model="od" placeholder="日" />
|
||||
</view>
|
||||
<text v-if="error" class="err">{{ error }}</text>
|
||||
<view class="btn" :class="{ off: loading }" @click="run"><text>{{ loading ? '生成中…' : '开始合盘' }}</text></view>
|
||||
<view class="btn ghost" @click="invite"><text>{{ inviting ? '生成邀请…' : '生成邀请链接' }}</text></view>
|
||||
</view>
|
||||
<view v-else class="card">
|
||||
<text class="h1">{{ headline }}</text>
|
||||
<text class="lead">{{ oneLiner }}</text>
|
||||
<view class="navs">
|
||||
<view class="btn ghost" @click="report = null"><text>再测一次</text></view>
|
||||
<view class="btn" @click="yxgGo(`/reports/${report.id}`)"><text>完整报告</text></view>
|
||||
</view>
|
||||
</view>
|
||||
</yxg-page>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import YxgPage from '@/components/yxg/yxg-page.vue'
|
||||
import { yxgApi } from '@/util/yxgApi.js'
|
||||
import { ensureAccount, ensureOtherProfile, findSelfProfile, pickableArchiveList } from '@/util/yxgAuth.js'
|
||||
import { yxgGo } from '@/util/yxgNav.js'
|
||||
|
||||
const items = ref([])
|
||||
const idxA = ref(0)
|
||||
const idxB = ref(0)
|
||||
const otherName = ref('TA')
|
||||
const oy = ref('')
|
||||
const om = ref('')
|
||||
const od = ref('')
|
||||
const loading = ref(false)
|
||||
const inviting = ref(false)
|
||||
const error = ref('')
|
||||
const report = ref(null)
|
||||
|
||||
const labels = computed(() =>
|
||||
items.value.map((p) => p.display_name || (p.relation === 'self' ? '我' : 'TA')),
|
||||
)
|
||||
const summary = computed(() => report.value?.summary || {})
|
||||
const headline = computed(() => String(summary.value.headline || '合盘'))
|
||||
const oneLiner = computed(() => String(summary.value.one_liner || summary.value.overview || ''))
|
||||
|
||||
async function boot() {
|
||||
if (!(await ensureAccount('/synastry'))) return
|
||||
try {
|
||||
const res = await yxgApi.listProfiles()
|
||||
items.value = pickableArchiveList(res.items || [])
|
||||
const selfIdx = items.value.findIndex((p) => p.relation === 'self')
|
||||
idxA.value = selfIdx >= 0 ? selfIdx : 0
|
||||
idxB.value = items.value.length > 1 ? (selfIdx === 0 ? 1 : 0) : 0
|
||||
} catch (e) {
|
||||
error.value = e instanceof Error ? e.message : '加载失败'
|
||||
}
|
||||
}
|
||||
|
||||
async function run() {
|
||||
loading.value = true
|
||||
error.value = ''
|
||||
try {
|
||||
let a = items.value[idxA.value]
|
||||
let b = items.value[idxB.value]
|
||||
const y = Number(oy.value), m = Number(om.value), d = Number(od.value)
|
||||
if ((!b || a?.id === b?.id) && y && m && d) {
|
||||
b = await ensureOtherProfile({
|
||||
birth_date: `${y}-${String(m).padStart(2, '0')}-${String(d).padStart(2, '0')}`,
|
||||
display_name: otherName.value || 'TA',
|
||||
})
|
||||
}
|
||||
if (!a) a = await findSelfProfile()
|
||||
if (!a || !b || a.id === b.id) {
|
||||
error.value = '请选择两位不同的人,或填写 TA 的生日'
|
||||
return
|
||||
}
|
||||
report.value = await yxgApi.createSynastry(a.id, b.id)
|
||||
} catch (e) {
|
||||
error.value = e instanceof Error ? e.message : '生成失败'
|
||||
} finally {
|
||||
loading.value = false
|
||||
}
|
||||
}
|
||||
|
||||
async function invite() {
|
||||
inviting.value = true
|
||||
try {
|
||||
const self = await findSelfProfile()
|
||||
if (!self) {
|
||||
yxgGo('/profile')
|
||||
return
|
||||
}
|
||||
const inv = await yxgApi.createSynastryInvite(self.id)
|
||||
const token = inv.token || inv.id
|
||||
uni.setClipboardData({
|
||||
data: token,
|
||||
success: () => uni.showToast({ title: '邀请码已复制', icon: 'none' }),
|
||||
})
|
||||
} catch (e) {
|
||||
uni.showToast({ title: e.message || '生成失败', icon: 'none' })
|
||||
} finally {
|
||||
inviting.value = false
|
||||
}
|
||||
}
|
||||
|
||||
onShow(boot)
|
||||
</script>
|
||||
|
||||
<style>
|
||||
page { background-color: #ffd1c7; }
|
||||
</style>
|
||||
<style scoped>
|
||||
.card { margin: 12px 16px; padding: 18px 16px; background: #fff; border-radius: 18px; }
|
||||
.h1 { display: block; font-size: 20px; font-weight: 700; color: #333; }
|
||||
.desc, .lead, .or { display: block; margin-top: 8px; font-size: 13px; color: #666; }
|
||||
.pick { margin-top: 10px; padding: 12px; background: #fdfaf8; border-radius: 12px; font-size: 14px; }
|
||||
.inp { width: 100%; height: 42px; background: #fdfaf8; border-radius: 12px; padding: 0 12px; box-sizing: border-box; margin-top: 10px; }
|
||||
.date-row { display: flex; gap: 8px; }
|
||||
.inp.sm { flex: 1; text-align: center; }
|
||||
.err { display: block; margin-top: 8px; color: #e54d42; font-size: 13px; }
|
||||
.navs { display: flex; gap: 10px; margin-top: 16px; }
|
||||
.btn {
|
||||
height: 42px; border-radius: 999px; background: #e54d42; color: #fff;
|
||||
display: flex; align-items: center; justify-content: center; font-weight: 700; margin-top: 10px;
|
||||
}
|
||||
.btn.ghost { background: #f7f2ef; color: #8a4a3a; }
|
||||
.btn.off { opacity: 0.5; }
|
||||
</style>
|
||||
Reference in New Issue
Block a user