Files
wx_pbzc/pages/timer/timer.js
T
lc 8079242daf fix: theme not applying to training/records pages
Root cause: themeStyle was on .container only, but modals (picker,
day-detail) were siblings of .container in the WXML tree. CSS custom
properties set via inline style on .container don't cascade to
sibling elements — those elements fall back to app.wxss page-level
defaults (always orange). Users saw modal buttons in orange and
concluded the whole page didn't follow theme.

Fixes:
- index.wxml: Move picker modal inside .container so it inherits
  themeStyle CSS variables (position:fixed is viewport-relative,
  so nesting doesn't affect modal positioning)
- index.js, records.js: Add applyThemeToPage in onLoad alongside
  onShow, preventing a flash of default orange before onShow fires
- timer.js: Add onShow with applyThemeToPage as lifecycle safety
  net; extract _init from onLoad for clean separation
2026-06-04 16:53:53 +08:00

119 lines
3.0 KiB
JavaScript

const Timer = require('../../utils/timer')
const storage = require('../../utils/storage')
const planMod = require('../../utils/plan')
const themeMod = require('../../utils/theme')
Page({
data: {
theme: { primary: '#FF6B35', primaryLight: '#FF8C5A', primaryBg: '#FFF3ED', primaryRgb: '255,107,53' },
themeStyle: '',
duration: 60,
remaining: 60,
status: 'idle',
isRunning: false,
isPaused: false,
isCompleted: false,
overtime: 0,
todayTarget: 0,
planDay: 1,
isFreeMode: false
},
onLoad(options) {
themeMod.applyThemeToPage(this)
this._init(options)
},
onShow() {
themeMod.applyThemeToPage(this)
},
_init(options) {
let target
let planDay = 1
let isFreeMode = false
if (options && options.free) {
target = parseInt(options.free) || 60
isFreeMode = true
} else {
const settings = storage.getSettings()
const allRecords = Object.values(storage.getRecords()).flat()
const plan = planMod.getPlan(settings.planId)
planDay = planMod.getPlanDay(settings.planId, allRecords)
target = planMod.getTodayTarget(settings.planId, Math.min(planDay, plan.totalDays))
}
this.setData({
duration: target,
remaining: target,
todayTarget: target,
planDay: isFreeMode ? 0 : planDay,
isFreeMode
})
this._timer = new Timer({
onTick: (tick) => {
this.setData({
remaining: tick.remaining > 0 ? tick.remaining : 0,
overtime: tick.remaining <= 0 ? tick.elapsed - this.data.duration : 0
})
},
onComplete: () => {
this.setData({ status: 'completed', isCompleted: true })
if (storage.getSettings().vibrate) {
try { wx.vibrateLong() } catch (e) {}
}
wx.showToast({ title: '目标完成! 太棒了!', icon: 'success', duration: 2000 })
}
})
},
onUnload() {
if (this._timer) this._timer.stop()
},
onStart() {
if (this.data.isPaused) {
this._timer.resume()
this.setData({ isRunning: true, isPaused: false, status: 'running' })
return
}
if (this.data.isRunning) return
this._timer.start(this.data.duration)
this.setData({ isRunning: true, status: 'running' })
},
onPause() {
if (!this.data.isRunning || this.data.isPaused) return
this._timer.pause()
this.setData({ isPaused: true, status: 'paused' })
},
onStop() {
wx.showModal({
title: '结束训练',
content: '确定要结束本次训练吗?',
success: (res) => {
if (res.confirm) this.finishTraining()
}
})
},
finishTraining() {
const elapsed = this._timer.stop()
const today = storage.getToday()
storage.saveRecord({
date: today,
duration: elapsed,
planId: storage.getSettings().planId,
day: this.data.planDay
})
storage.updateStreak(today)
wx.showToast({ title: `已记录 ${elapsed}秒`, icon: 'none', duration: 1500 })
setTimeout(() => { wx.navigateBack() }, 3000)
}
})