const storage = require('../../utils/storage') const planMod = require('../../utils/plan') const util = require('../../utils/util') const themeMod = require('../../utils/theme') const iconsMod = require('../../utils/icons') const MAX_CUSTOM_DURATION = 3600 // 1 hour max Page({ data: { theme: { primary: '#FF6B35', primaryLight: '#FF8C5A', primaryBg: '#FFF3ED', primaryRgb: '255,107,53' }, themeStyle: themeMod.BASE_VARS, todayTarget: 0, todayDone: false, todayDuration: 0, todayTargetText: '', streakCount: 0, planName: '', planDay: 1, planTotal: 7, planProgress: 0, showPicker: false, presets: [30, 60, 90, 120, 180, 300], customDuration: 60, customInput: '', icons: iconsMod.build() }, onLoad() { themeMod.applyThemeToPage(this) this._firstShow = true }, onShow() { themeMod.applyThemeToPage(this) try { const tb = this.getTabBar() if (tb) tb.setData({ selected: 0 }) } catch (e) {} // Skip the first onShow to avoid double-refresh; subsequent tab switches still refresh. if (this._firstShow) { this._firstShow = false this.refresh() this._checkFreshTrain() return } this.refresh() this._checkFreshTrain() }, /** * If user just returned from completing a training, briefly highlight * the "今日已完成" badge so the success feels tangible. The flag is * timestamped; older than 10s is treated as stale (e.g. user reopened * the app later). */ _checkFreshTrain() { try { const at = wx.getStorageSync('_last_train_at') if (!at) return const age = Date.now() - at if (age < 0 || age > 10 * 1000) { wx.removeStorageSync('_last_train_at') return } wx.removeStorageSync('_last_train_at') this.setData({ justCompleted: true }) if (this._justCompletedTimer) clearTimeout(this._justCompletedTimer) this._justCompletedTimer = setTimeout(() => { this.setData({ justCompleted: false }) }, 3000) } catch (e) {} }, onPullDownRefresh() { this.refresh() wx.stopPullDownRefresh() }, refresh() { const settings = storage.getSettings() const streak = storage.validateStreak() const todayRecord = storage.getTodayRecord() const allRecords = Object.values(storage.getRecords()).flat() const customPlans = storage.getCustomPlans() const plan = planMod.getPlan(settings.planId, customPlans) const planDay = planMod.getPlanDay(settings.planId, allRecords, settings.planStartDate) const target = planMod.getTodayTarget(settings.planId, Math.min(planDay, plan.totalDays)) const theme = themeMod.getCurrentTheme() this.setData({ theme, icons: iconsMod.build(theme), todayTarget: target, todayDone: todayRecord && todayRecord.duration >= target, todayDuration: todayRecord ? todayRecord.duration : 0, todayTargetText: util.formatTime(target), streakCount: streak.count, planName: plan.name, planDay: Math.min(planDay, plan.totalDays), planTotal: plan.totalDays, planProgress: Math.round((Math.min(planDay, plan.totalDays) / plan.totalDays) * 100) }) }, onStartTrain() { wx.navigateTo({ url: '/pages/timer/timer' }) }, onFreeTrain() { this.setData({ showPicker: true, customInput: '', customDuration: 60 }) }, onClosePicker() { this.setData({ showPicker: false }) }, onSelectPreset(e) { const val = e.currentTarget.dataset.value this.setData({ customDuration: val, customInput: '' }) }, onCustomInput(e) { let val = parseInt(e.detail.value) || 0 if (val > MAX_CUSTOM_DURATION) val = MAX_CUSTOM_DURATION this.setData({ customInput: e.detail.value, customDuration: val }) }, onConfirmFree() { const dur = this.data.customDuration if (!dur || dur <= 0) { wx.showToast({ title: '请输入有效时长', icon: 'none' }) return } if (dur > MAX_CUSTOM_DURATION) { wx.showToast({ title: '最大时长为1小时', icon: 'none' }) return } this.setData({ showPicker: false }) wx.navigateTo({ url: `/pages/timer/timer?free=${dur}` }) } })