import { appSharePageMethods } from '../../base/pageMixin'; import { AGE_BANDS, AgeBandKey } from '../../core/data/difficulty'; import { parseMiniProgramUrl } from '../../utils/index'; import { AGE_ABILITIES, AGE_TAB_SUB, AGE_WEEK_PLANS, type AbilityItem, type WeekPlan, } from './age.config'; const DEFAULT_AGE: AgeBandKey = '3-4'; const TAB_BAR_PATHS = new Set([ '/pages/home/home', '/pages/category/category', '/pages/age/age', '/pages/favorites/favorites', '/pages/profile/profile', ]); let _navigating = false; function releaseNavigateLock() { _navigating = false; } function navigateByPath(path?: string, fallbackTitle?: string) { if (_navigating) return; const p = String(path || '').trim(); if (!p) { wx.showToast({ title: fallbackTitle ? `${fallbackTitle} 即将上线` : '即将上线', icon: 'none', }); return; } const { path: basePath, query } = parseMiniProgramUrl(p); if (TAB_BAR_PATHS.has(basePath)) { if (Object.keys(query).length > 0) { console.warn( '[age navigateByPath] tabBar 不支持携带参数,已忽略 query:', basePath, query, ); } _navigating = true; wx.switchTab({ url: basePath, complete: releaseNavigateLock, fail: releaseNavigateLock, }); return; } _navigating = true; wx.navigateTo({ url: p, complete: releaseNavigateLock, fail: (err) => { console.error('navigateByPath error:', err); releaseNavigateLock(); }, }); } type RecommendedItemView = { title: string; image: string; subtitle: string; ageBand: string; difficulty: string; path: string; worksheetId?: string; }; const RECOMMENDED_FALLBACK: RecommendedItemView[] = []; const DIFFICULTY_LABELS: Record = { 1: '入门', 2: '基础', 3: '进阶', 4: '挑战', }; function toDifficultyLabel(value: unknown) { const text = String(value || '').trim(); return DIFFICULTY_LABELS[text] || text; } async function fetchAgeRecommended( ageKey: AgeBandKey, ): Promise { try { const res = await wx.cloud.callFunction({ name: 'ageRecommendedQuery', data: { ageKey }, }); const payload = (res && (res.result as any)) || null; if (!payload?.success) return []; const items = (payload.data?.items || []) as any[]; return items .map((it) => ({ title: String(it.title || ''), image: String(it.previewImg || ''), subtitle: String(it.subtitle || ''), ageBand: String(it.ageBand || it.ageRange || ''), difficulty: toDifficultyLabel( it.difficultyLabel || it.difficulty || '', ), path: String(it.path || ''), worksheetId: String(it.worksheetId || ''), })) .filter((it) => it.title); } catch (e) { console.warn('[age] fetchAgeRecommended failed:', e); return []; } } Page({ data: { ageTabs: AGE_BANDS.map((b) => ({ key: b.key, rangeText: b.label.replace(/\s*岁\s*$/, ''), subLabel: AGE_TAB_SUB[b.key], })), activeAgeKey: DEFAULT_AGE as AgeBandKey, goalTitle: '', abilityItems: [] as AbilityItem[], weekPlans: [] as WeekPlan[], recommendedItems: RECOMMENDED_FALLBACK, recommendedLoading: false, }, onLoad() { this.applyAge(DEFAULT_AGE); }, async applyAge(key: AgeBandKey) { const band = AGE_BANDS.find((b) => b.key === key); const goalTitle = band ? `${band.label}能力目标` : '能力目标'; this.setData({ activeAgeKey: key, goalTitle, abilityItems: AGE_ABILITIES[key] || [], weekPlans: AGE_WEEK_PLANS[key] || [], recommendedLoading: true, }); const recommended = await fetchAgeRecommended(key); this.setData({ recommendedItems: recommended.length > 0 ? recommended : RECOMMENDED_FALLBACK, recommendedLoading: false, }); }, onAgeTabTap(e: WechatMiniprogram.TouchEvent) { const key = e.currentTarget.dataset.key as AgeBandKey | undefined; if (!key) return; this.applyAge(key); }, onPracticeTap(e: WechatMiniprogram.TouchEvent) { const path = e.currentTarget.dataset.path as string | undefined; const title = e.currentTarget.dataset.title as string | undefined; navigateByPath(path, title); }, onRecommendMore() { wx.switchTab({ url: '/pages/home/home' }); }, onTapCard(e: WechatMiniprogram.CustomEvent) { const detail = (e.detail || {}) as { title?: string; path?: string }; const path = detail.path || (e.currentTarget.dataset.path as string | undefined); const title = detail.title || (e.currentTarget.dataset.title as string | undefined); navigateByPath(path, title); }, ...appSharePageMethods, });