去掉协会 WebView 和魔方账密页,微信登录与咨询接口共用同一 token 和拦截器。 Co-authored-by: Cursor <cursoragent@cursor.com>
121 lines
4.0 KiB
Vue
121 lines
4.0 KiB
Vue
<template>
|
||
<yxg-page title="探索">
|
||
<view class="head">
|
||
<yxg-tool-icon name="mbti" :size="40" />
|
||
<view>
|
||
<text class="title">探索</text>
|
||
<text class="sub">题库测评 · 工具 · 自我理解</text>
|
||
</view>
|
||
</view>
|
||
|
||
<view class="sec">
|
||
<text class="sec-t">题库精选</text>
|
||
<text v-if="bankLoading" class="hint">加载中…</text>
|
||
<text v-else-if="bankError" class="err" @click="loadBank">{{ bankError }} · 重试</text>
|
||
<view v-else class="grid">
|
||
<view v-for="t in featured" :key="t.slug" class="g-item" @click="yxgGo(t.path)">
|
||
<yxg-tool-icon :name="iconName(t.icon)" :size="40" />
|
||
<text class="g-label">{{ t.title }}</text>
|
||
</view>
|
||
</view>
|
||
</view>
|
||
|
||
<view class="sec">
|
||
<text class="sec-t">题库分类</text>
|
||
<view class="list">
|
||
<view v-for="c in categories" :key="c.key" class="row" @click="yxgGo(c.path)">
|
||
<yxg-tool-icon :name="iconName(c.icon)" :size="28" />
|
||
<view class="row-body">
|
||
<text class="row-t">{{ c.title }}</text>
|
||
<text class="row-d">{{ c.description }} · {{ c.count }} 套</text>
|
||
</view>
|
||
<text class="chev">›</text>
|
||
</view>
|
||
</view>
|
||
</view>
|
||
|
||
<view class="sec">
|
||
<text class="sec-t">其它工具</text>
|
||
<view class="grid">
|
||
<view v-for="t in tools" :key="t.to" class="g-item" @click="yxgGo(t.to)">
|
||
<yxg-tool-icon :name="t.icon" :size="40" />
|
||
<text class="g-label">{{ t.label }}</text>
|
||
</view>
|
||
</view>
|
||
</view>
|
||
</yxg-page>
|
||
</template>
|
||
|
||
<script setup>
|
||
import YxgPage from '@/components/yxg/yxg-page.vue'
|
||
import YxgToolIcon from '@/components/yxg/yxg-tool-icon.vue'
|
||
import { yxgApi } from '@/util/yxgApi.js'
|
||
import { ensureAccount } from '@/util/yxgAuth.js'
|
||
import { resolveIcon } from '@/util/yxgCatalog.js'
|
||
import { yxgGo } from '@/util/yxgNav.js'
|
||
|
||
const tools = [
|
||
{ to: '/star', label: '星座', icon: 'star' },
|
||
{ to: '/portrait', label: '愈心解码', icon: 'portrait' },
|
||
{ to: '/rhythm', label: '身心节律', icon: 'rhythm' },
|
||
{ to: '/synastry', label: '合盘', icon: 'synastry' },
|
||
{ to: '/ask', label: 'AI问答', icon: 'ask' },
|
||
{ to: '/cards', label: '意象卡片', icon: 'cards' },
|
||
{ to: '/relation', label: '人格匹配', icon: 'relation' },
|
||
{ to: '/companion', label: '节气陪伴', icon: 'companion' },
|
||
]
|
||
const featured = ref([])
|
||
const categories = ref([])
|
||
const bankLoading = ref(true)
|
||
const bankError = ref('')
|
||
|
||
function iconName(raw) {
|
||
return resolveIcon(raw)
|
||
}
|
||
|
||
async function loadBank() {
|
||
bankLoading.value = true
|
||
bankError.value = ''
|
||
try {
|
||
const res = await yxgApi.getScaleBankCatalog()
|
||
featured.value = res.featured || []
|
||
categories.value = res.categories || []
|
||
} catch (e) {
|
||
bankError.value = e instanceof Error ? e.message : '加载失败'
|
||
} finally {
|
||
bankLoading.value = false
|
||
}
|
||
}
|
||
|
||
onShow(async () => {
|
||
if (!(await ensureAccount('/explore'))) {
|
||
bankLoading.value = false
|
||
return
|
||
}
|
||
await loadBank()
|
||
})
|
||
</script>
|
||
|
||
<style>
|
||
page { background-color: #ffd1c7; }
|
||
</style>
|
||
<style scoped>
|
||
.head { display: flex; align-items: center; gap: 12px; padding: 8px 16px 4px; }
|
||
.title { display: block; font-size: 22px; font-weight: 700; color: #333; }
|
||
.sub { display: block; margin-top: 2px; font-size: 12px; color: rgba(0,0,0,.38); }
|
||
.sec { padding: 0 16px; margin-top: 18px; }
|
||
.sec-t { display: block; font-size: 17px; font-weight: 700; color: #333; margin-bottom: 12px; }
|
||
.grid { display: flex; flex-wrap: wrap; }
|
||
.g-item { width: 25%; display: flex; flex-direction: column; align-items: center; gap: 6px; padding: 8px 0; }
|
||
.g-label { font-size: 11px; color: #555; text-align: center; }
|
||
.list { background: #fafafa; border-radius: 16px; }
|
||
.row { display: flex; align-items: center; gap: 12px; padding: 14px 10px; border-bottom: 1px solid #f0ebe8; }
|
||
.row:last-child { border-bottom: none; }
|
||
.row-body { flex: 1; min-width: 0; }
|
||
.row-t { display: block; font-size: 15px; font-weight: 650; color: #222; }
|
||
.row-d { display: block; font-size: 12px; color: #999; margin-top: 2px; }
|
||
.chev { color: #ccc; }
|
||
.hint, .err { font-size: 13px; color: #999; }
|
||
.err { color: #e54d42; }
|
||
</style>
|