export const ICON_NAMES = [ 'mbti', 'star', 'portrait', 'rhythm', 'synastry', 'astro', 'companion', 'ask', 'cards', 'reports', 'growth', 'relation', 'nine', 'eq', 'stress', 'sleep', ] export function resolveIcon(raw, fallback = 'mbti') { return ICON_NAMES.includes(raw) ? raw : fallback } export function toolIconFor(pathOrKey) { const s = String(pathOrKey || '').toLowerCase() if (s.includes('mbti') || s.includes('人格类型') || s.includes('tests')) return 'mbti' if (s.includes('synastry') || s.includes('合盘')) return 'synastry' if (s.includes('portrait') || s.includes('decode') || s.includes('解码')) return 'portrait' if (s.includes('star') || s.includes('星座') || s.includes('星盘')) return 'star' if (s.includes('rhythm') || s.includes('节律')) return 'rhythm' if (s.includes('companion') || s.includes('节气') || s.includes('mood')) return 'companion' if (s.includes('ask') || s.includes('问答')) return 'ask' if (s.includes('card') || s.includes('意象')) return 'cards' if (s.includes('report') || s.includes('报告')) return 'reports' if (s.includes('growth') || s.includes('计划') || s.includes('会员') || s.includes('member')) return 'growth' if (s.includes('relation') || s.includes('匹配') || s.includes('love')) return 'relation' if (s.includes('astro') || s.includes('星象')) return 'astro' if (s.includes('explore') || s.includes('探索') || s.includes('分类')) return 'mbti' return 'portrait' } export function typeLabel(type) { const map = { portrait: '愈心解码', star: '星座排盘', rhythm: '身心节律', synastry: '合盘', relation: '人格匹配', scale: '测评', } return map[type] || '成长报告' } export function formatDate(iso) { if (!iso) return '' const d = new Date(iso) if (Number.isNaN(d.getTime())) return String(iso).slice(0, 10) return `${d.getFullYear()}-${String(d.getMonth() + 1).padStart(2, '0')}-${String(d.getDate()).padStart(2, '0')}` } export function headlineOf(report) { const s = report?.summary || {} return s.headline || s.one_liner || s.label || s.title || typeLabel(report?.type) } export const homeGridRow1 = [ { to: '/scales/mbti-lite', icon: 'mbti', label: 'MBTI测试' }, { to: '/star', icon: 'star', label: '星座' }, { to: '/portrait', icon: 'portrait', label: '愈心解码', badge: '热', badgeTone: 'hot' }, { to: '/rhythm', icon: 'rhythm', label: '身心节律' }, { to: '/synastry', icon: 'synastry', label: '合盘', badge: '新', badgeTone: 'new' }, { to: '/star', icon: 'astro', label: '星象性格' }, ] export const homeGridRow2 = [ { to: '/companion', icon: 'companion', label: '节气陪伴' }, { to: '/ask', icon: 'ask', label: 'AI问答' }, { to: '/cards', icon: 'cards', label: '意象卡片' }, { to: '/reports', icon: 'reports', label: '成长报告', badge: '新', badgeTone: 'new' }, { to: '/growth-plan', icon: 'growth', label: '成长计划' }, { to: '/relation', icon: 'relation', label: '人格匹配' }, ] export const homeFeeds = [ { to: '/portrait', icon: 'portrait', title: '愈心解码', meta: '一个生日,读懂性格与身心节奏', stat: '核心入口', tone: 'fc-e', tag: '热' }, { to: '/ask', icon: 'ask', title: 'AI 成长助手', meta: '结合档案聊聊卡住的事', stat: '随时可问', tone: 'fc-a', tag: 'AI' }, { to: '/star', icon: 'star', title: '星座排盘', meta: '本命盘 · 相位 · 日周月运势', stat: '本周热门', tone: 'fc-b', tag: '新' }, { to: '/synastry', icon: 'synastry', title: '合盘', meta: '恋爱 / 友情 / 婚姻指数', stat: '了解彼此', tone: 'fc-c' }, { to: '/scales/mbti-lite', icon: 'mbti', title: 'MBTI测试', meta: '四维偏好探索,看见自己的能量与决策节奏', stat: '热门测评', tone: 'fc-a' }, { to: '/membership', icon: 'growth', title: '成长会员', meta: '深度报告与全年节气陪伴', stat: '解锁更多', tone: 'fc-e' }, ] export const mineGroupArchive = [ { to: '/profile', label: '个人档案', icon: 'portrait' }, { to: '/reports', label: '我的成长报告', icon: 'reports' }, { to: '/portrait', label: '愈心解码', icon: 'portrait' }, { to: '/star', label: '星象性格', icon: 'star' }, { to: '/rhythm', label: '身心节律', icon: 'rhythm' }, { to: '/cards', label: '意象卡片', icon: 'cards' }, ] export const mineGroupGrowth = [ { to: '/relation', label: '人格匹配', icon: 'relation' }, { to: '/ask', label: 'AI 成长助手', icon: 'ask' }, { to: '/explore', label: '探索测试', icon: 'mbti' }, { to: '/growth-plan', label: '成长计划', icon: 'growth' }, { to: '/membership', label: '成长会员', icon: 'growth' }, ] const FEED_TONES = ['fc-e', 'fc-a', 'fc-b', 'fc-c', 'fc-a', 'fc-e'] export function mapHomeBannersToFeeds(items) { const sorted = [...(items || [])].sort((a, b) => (a.sort_order ?? 0) - (b.sort_order ?? 0)) const out = [] for (let i = 0; i < sorted.length; i++) { const it = sorted[i] const to = String(it.link_path || '').trim() if (!to.startsWith('/') || to.includes('://')) continue out.push({ to, icon: 'portrait', title: it.title, meta: '运营推荐', stat: '推荐', tone: FEED_TONES[i % FEED_TONES.length], tag: '荐', }) } return out } export function mapHomeTools(items) { const toTool = (it) => { if (!ICON_NAMES.includes(it.icon)) return null const t = { to: it.path, icon: it.icon, label: it.label } if (it.badge) t.badge = it.badge if (it.badge_tone === 'hot' || it.badge_tone === 'new') t.badgeTone = it.badge_tone return t } const sorted = [...(items || [])].sort( (a, b) => a.row_index - b.row_index || a.sort_order - b.sort_order, ) const row1 = [] const row2 = [] for (const it of sorted) { const t = toTool(it) if (!t) continue if (it.row_index === 1) row1.push(t) else if (it.row_index === 2) row2.push(t) } return { row1, row2 } }