import type { WorksheetDefinition, WorksheetType, } from '../../core/models/worksheet'; import { getWorksheetPath, getWorksheetsByAge, getWorksheetsByCategory, } from '../../core/data/worksheets'; type AgeFilterKey = 'all' | '3-4' | '4-5' | '5-6' | '6-7' | '7-8'; type DiffFilterKey = 'all' | 'beginner' | 'basic' | 'intermediate'; const AGE_BAND: Record, [number, number]> = { '3-4': [3, 4], '4-5': [4, 5], '5-6': [5, 6], '6-7': [6, 7], '7-8': [7, 8], }; const DIFF_LABEL: Record = { beginner: '入门', basic: '基础', intermediate: '进阶', advanced: '进阶+', }; type DisplayItem = WorksheetType & { ageRangeLabel: string; difficultyLabel: string; }; function filterByAgeBand( list: WorksheetType[], band: AgeFilterKey, ): WorksheetType[] { if (band === 'all') return list; const [lo, hi] = AGE_BAND[band]; const map = new Map(); for (let age = lo; age <= hi; age += 1) { getWorksheetsByAge(list, age).forEach((w) => map.set(w.id, w)); } return Array.from(map.values()); } function filterByDifficulty( list: WorksheetType[], diff: DiffFilterKey, ): WorksheetType[] { if (diff === 'all') return list; return list.filter((w) => w.difficulty === diff); } function toDisplayList(list: WorksheetType[]): DisplayItem[] { return list.map((w) => ({ ...w, ageRangeLabel: w.ageRange && w.ageRange.length === 2 ? `${w.ageRange[0]}-${w.ageRange[1]}岁` : '', difficultyLabel: w.difficulty ? DIFF_LABEL[w.difficulty] || '' : '', })); } Page({ data: { title: '分类', sourceItems: [] as WorksheetDefinition[], items: [] as DisplayItem[], ageFilters: [ { key: 'all', label: '全部' }, { key: '3-4', label: '3-4岁' }, { key: '4-5', label: '4-5岁' }, { key: '5-6', label: '5-6岁' }, { key: '6-7', label: '6-7岁' }, { key: '7-8', label: '7-8岁' }, ], diffFilters: [ { key: 'all', label: '全部' }, { key: 'beginner', label: '⭐ 入门' }, { key: 'basic', label: '⭐⭐ 基础' }, { key: 'intermediate', label: '⭐⭐⭐ 进阶' }, ], activeAge: 'all' as AgeFilterKey, activeDiff: 'all' as DiffFilterKey, }, onLoad(options: { category?: string; minAge?: string; maxAge?: string; title?: string; }) { const category = options.category || 'all'; let base = getWorksheetsByCategory(category); const minAge = options.minAge != null ? Number(options.minAge) : NaN; const maxAge = options.maxAge != null ? Number(options.maxAge) : NaN; if (!Number.isNaN(minAge) && !Number.isNaN(maxAge)) { const map = new Map(); const lo = Math.min(minAge, maxAge); const hi = Math.max(minAge, maxAge); for (let age = lo; age <= hi; age += 1) { getWorksheetsByAge(base, age).forEach((w) => map.set(w.id, w)); } base = Array.from(map.values()); } const title = options.title ? decodeURIComponent(options.title) : '分类'; this.setData({ title, sourceItems: base, }); wx.setNavigationBarTitle({ title }); this.applyFilters(); }, applyFilters() { const { sourceItems, activeAge, activeDiff } = this.data; let next = filterByAgeBand(sourceItems, activeAge); next = filterByDifficulty(next, activeDiff); this.setData({ items: toDisplayList(next) }); }, onAgeFilter(e: WechatMiniprogram.TouchEvent) { const key = e.currentTarget.dataset.key as AgeFilterKey; if (!key) return; this.setData({ activeAge: key }, () => this.applyFilters()); }, onDiffFilter(e: WechatMiniprogram.TouchEvent) { const key = e.currentTarget.dataset.key as DiffFilterKey; if (!key) return; this.setData({ activeDiff: key }, () => this.applyFilters()); }, buildWorksheetUrl(w: WorksheetType): string { let url = getWorksheetPath(w); if (!url) return ''; if (w.mode) { url += url.includes('?') ? `&mode=${w.mode}` : `?mode=${w.mode}`; } return url; }, onCardTap(e: WechatMiniprogram.TouchEvent) { const id = e.currentTarget.dataset.id as string; const w = this.data.items.find((item) => item.id === id); if (!w) return; const url = this.buildWorksheetUrl(w); if (!url) { wx.showToast({ title: '暂无法打开', icon: 'none' }); return; } wx.navigateTo({ url }); }, });