import { request, redirectToLogin } from '../../utils/request' import * as auth from '../../utils/auth' import { HoroscopeData } from '../../types/models' const COLOR_MAP: Record = { 红色: '#FF3B30', 橙色: '#FF9500', 黄色: '#FFCC00', 绿色: '#34C759', 蓝色: '#007AFF', 紫色: '#5856D6', 粉色: '#FF2D55', 白色: '#FFFFFF', 黑色: '#000000', 灰色: '#8E8E93', } // 今日日期(YYYYMMDD),用于判断运势数据是否跨天 function todayStatDate(): number { const d = new Date() const pad = (n: number) => (n < 10 ? `0${n}` : String(n)) return Number(`${d.getFullYear()}${pad(d.getMonth() + 1)}${pad(d.getDate())}`) } Page({ data: { horoscope: null as HoroscopeData | null, statDate: '', luckyColorHex: '#007AFF', loading: true, noBirth: false, error: false, errorText: '', }, onShow() { this.syncTabBar() // 未登录直接回登录页(幂等跳转),不再发出必然 401 的请求 if (!auth.isLoggedIn()) { redirectToLogin() return } // 跨天回到本页时旧数据仍是昨天的,需重新拉取 const stale = !this.data.horoscope || Number(this.data.horoscope.stat_date) !== todayStatDate() if (stale) this.fetchHoroscope(0) }, syncTabBar() { const tabBar = (this as any).getTabBar && (this as any).getTabBar() if (tabBar) tabBar.setData({ selected: 2 }) }, fetchHoroscope(retry: number) { this.clearRetryTimer() this.setData({ loading: true, error: false, errorText: '' }) request({ url: '/horoscope/today', showError: false }) .then((res) => { this.setData({ horoscope: res, statDate: this.formatStatDate(res.stat_date), luckyColorHex: COLOR_MAP[res.lucky_color] || '#007AFF', loading: false, noBirth: false, error: false, }) }) .catch((e: any) => { const code = e && e.code const details = (e && e.details) || [] const noBirth = details.some((d: string) => d.indexOf('生日') >= 0) if (code === 10000 && noBirth) { this.setData({ noBirth: true, loading: false }) } else if (code === 90300 && retry < 3) { wx.showToast({ title: '运势生成中,请稍后重试', icon: 'none' }) // 定时器挂实例并在页面卸载时清理,避免离开页面后继续请求 ;(this as any).retryTimer = setTimeout(() => this.fetchHoroscope(retry + 1), 4000) } else { // 失败必须有可见反馈:否则会渲染一张数据为 null 的空卡 this.setData({ loading: false, error: true, errorText: (e && e.message) || '运势加载失败,请重试', }) } }) }, clearRetryTimer() { const timer = (this as any).retryTimer if (timer) { clearTimeout(timer) ;(this as any).retryTimer = null } }, onRetry() { this.fetchHoroscope(0) }, formatStatDate(d: number): string { const s = String(d) return `${s.slice(0, 4)}.${s.slice(4, 6)}.${s.slice(6, 8)}` }, onGoProfile() { wx.switchTab({ url: '/pages/profile/profile' }) }, onGenerate() { wx.navigateTo({ url: '/pages/ai-recommend/ai-recommend' }) }, onUnload() { this.clearRetryTimer() }, })