import { NAV_INNER_PX } from '../../utils/navMetrics'; import { getFavoriteList, removeFavorite } from '../../utils/favorites'; import { DOWNLOAD_HISTORY_MAX, getDownloadLogs, } from '../../utils/downloadLogs'; import type { FavoriteRecord } from '../../utils/favorites'; import type { DownloadLogRecord } from '../../utils/downloadLogs'; import { getCategoryName } from '../../core/data/categories'; const { statusBarHeight } = wx.getWindowInfo(); const NAV_BLOCK_HEIGHT = statusBarHeight + NAV_INNER_PX; type FavoritesTab = 'favorites' | 'downloads'; type FavoriteItem = { id: string; worksheetId: string; path: string; title: string; metaLine: string; stars: number; timeBadge: string; thumb: string; }; type DownloadRow = { id: string; worksheetId: string; path: string; title: string; metaLine: string; stars: number; time: string; status: string; statusHighlight: boolean; thumb?: string; placeholder?: 'draw'; }; type DownloadSection = { key: string; label: string; items: DownloadRow[]; }; /** 跳转路径仅以云库 worksheets.path 为准 */ function getWorksheetNavPath( ws: FavoriteRecord['worksheet'] | DownloadLogRecord['worksheet'], ): string { const path = ws?.path?.trim(); return path && path.startsWith('/') ? path : ''; } function mapFavoriteToItem(record: FavoriteRecord): FavoriteItem { const ws = record.worksheet; const title = ws?.title || '未知题型'; const category = ws?.category || ''; const categoryName = getCategoryName(category); const ageRange = ws ? `${ws.ageMin}-${ws.ageMax}岁` : ''; const metaLine = [categoryName, ageRange].filter(Boolean).join(' · ') + ' · '; const difficulty = ws?.difficulty || 0; const timeBadge = formatTimeBadge(record.createdAt); return { id: record._id, worksheetId: record.worksheetId, path: getWorksheetNavPath(ws), title, metaLine, stars: Math.min(difficulty, 3), timeBadge, thumb: ws?.previewImg || '', }; } function formatTimeBadge(dateStr: string): string { const date = new Date(dateStr); const now = new Date(); // 按日历天数计算差值 const todayStart = new Date( now.getFullYear(), now.getMonth(), now.getDate(), ).getTime(); const dateStart = new Date( date.getFullYear(), date.getMonth(), date.getDate(), ).getTime(); const days = Math.round((todayStart - dateStart) / (1000 * 60 * 60 * 24)); if (days === 0) return '收藏于今天'; if (days === 1) return '收藏于昨天'; if (days < 7) return `收藏于 ${days} 天前`; if (days < 30) return `收藏于 ${Math.floor(days / 7)} 周前`; return `收藏于 ${Math.floor(days / 30)} 个月前`; } function groupDownloadsByDate(records: DownloadLogRecord[]): DownloadSection[] { const now = new Date(); const todayStr = formatDateKey(now); const yesterday = new Date(now.getTime() - 24 * 60 * 60 * 1000); const yesterdayStr = formatDateKey(yesterday); const groups: Record = {}; for (const record of records) { const date = new Date(record.createdAt); const key = formatDateKey(date); let label: string; if (key === todayStr) { label = '今天'; } else if (key === yesterdayStr) { label = '昨天'; } else { label = `${date.getMonth() + 1}月${date.getDate()}日`; } if (!groups[key]) { groups[key] = { label, items: [] }; } const ws = record.worksheet; const category = ws?.category || ''; const categoryName = getCategoryName(category); const ageRange = ws ? `${ws.ageMin}-${ws.ageMax}岁` : ''; const metaLine = [categoryName, ageRange].filter(Boolean).join(' · ') + ' · '; const difficulty = ws?.difficulty || 0; groups[key].items.push({ id: record._id, worksheetId: record.worksheetId, path: getWorksheetNavPath(ws), title: ws?.title || '未知题型', metaLine, stars: Math.min(difficulty, 3), time: `${String(date.getHours()).padStart(2, '0')}:${String(date.getMinutes()).padStart(2, '0')}`, status: '已保存到相册', statusHighlight: true, thumb: ws?.previewImg, }); } return Object.keys(groups).map((key) => ({ key, label: groups[key].label, items: groups[key].items, })); } function formatDateKey(date: Date): string { return `${date.getFullYear()}-${date.getMonth() + 1}-${date.getDate()}`; } Page({ data: { favScrollHeight: 0, activeTab: 'favorites' as FavoritesTab, favoriteList: [] as FavoriteItem[], downloadSections: [] as DownloadSection[], favLoading: false, dlLoading: false, }, onLoad() { const win = wx.getWindowInfo(); this.setData({ favScrollHeight: win.windowHeight - NAV_BLOCK_HEIGHT, }); }, onShow() { const tab = wx.getStorageSync('favorites_active_tab') as FavoritesTab; if (tab === 'downloads' || tab === 'favorites') { this.setData({ activeTab: tab }); wx.removeStorageSync('favorites_active_tab'); } this.setData({ favoriteList: [], downloadSections: [] }); this.loadActiveTab(); }, loadActiveTab() { const tab = this.data.activeTab; if (tab === 'favorites' && this.data.favoriteList.length === 0) { this.loadFavorites(); } else if ( tab === 'downloads' && this.data.downloadSections.length === 0 ) { this.loadDownloads(); } }, onTabSwitch(e: WechatMiniprogram.TouchEvent) { const tab = e.currentTarget.dataset.tab as FavoritesTab; if (tab !== 'favorites' && tab !== 'downloads') return; if (tab === this.data.activeTab) return; this.setData({ activeTab: tab }); // 只在数据为空时才请求 if (tab === 'favorites' && this.data.favoriteList.length === 0) { this.loadFavorites(); } else if ( tab === 'downloads' && this.data.downloadSections.length === 0 ) { this.loadDownloads(); } }, async loadFavorites() { this.setData({ favLoading: true }); try { const records = await getFavoriteList(); this.setData({ favoriteList: records.map((r) => mapFavoriteToItem(r)), }); } finally { this.setData({ favLoading: false }); } }, async loadDownloads() { this.setData({ dlLoading: true }); try { const records = await getDownloadLogs(1, DOWNLOAD_HISTORY_MAX); this.setData({ downloadSections: groupDownloadsByDate(records) }); } finally { this.setData({ dlLoading: false }); } }, onDiscoverTap() { wx.switchTab({ url: '/pages/home/home' }); }, onCardTap(e: WechatMiniprogram.TouchEvent) { const path = e.currentTarget.dataset.path as string | undefined; if (!path) { wx.showToast({ title: '该练习已下架', icon: 'none' }); return; } wx.navigateTo({ url: path }); }, onSearchTap() { wx.showToast({ title: '搜索功能开发中', icon: 'none' }); }, async onRemoveFavorite(e: WechatMiniprogram.TouchEvent) { const id = e.currentTarget.dataset.id as string | undefined; if (!id) return; const item = (this.data.favoriteList as FavoriteItem[]).find( (i) => i.id === id, ); if (!item) return; try { await removeFavorite(item.worksheetId); const list = (this.data.favoriteList as FavoriteItem[]).filter( (i) => i.id !== id, ); this.setData({ favoriteList: list }); wx.showToast({ title: '已取消收藏', icon: 'success' }); } catch { wx.showToast({ title: '操作失败,请重试', icon: 'none' }); } }, onClearHistory() { wx.showModal({ title: '清空下载历史', content: '确定清空本地展示的历史记录吗?', success: (res) => { if (!res.confirm) return; this.setData({ downloadSections: [] }); wx.showToast({ title: '已清空', icon: 'none' }); }, }); }, });