diff --git a/app.js b/app.js index d90bc41..a1a7859 100644 --- a/app.js +++ b/app.js @@ -1,8 +1,8 @@ -var themeMod = require('./utils/theme') +const themeMod = require('./utils/theme') App({ - onLaunch: function () { - var settings = wx.getStorageSync('user_settings') + onLaunch() { + const settings = wx.getStorageSync('user_settings') if (!settings) { wx.setStorageSync('user_settings', { planId: 'beginner', @@ -12,7 +12,7 @@ App({ vibrate: true }) } - var streak = wx.getStorageSync('current_streak') + const streak = wx.getStorageSync('current_streak') if (!streak) { wx.setStorageSync('current_streak', { count: 0, lastDate: '' }) } diff --git a/components/calendar-heatmap/calendar-heatmap.js b/components/calendar-heatmap/calendar-heatmap.js index 350df6a..e81d55c 100644 --- a/components/calendar-heatmap/calendar-heatmap.js +++ b/components/calendar-heatmap/calendar-heatmap.js @@ -1,4 +1,4 @@ -var util = require('../../utils/util') +const util = require('../../utils/util') Component({ properties: { @@ -12,70 +12,63 @@ Component({ }, observers: { - 'year, month, records': function (year, month, records) { + 'year, month, records'(year, month, records) { this._compute(year, month, records) } }, lifetimes: { - ready: function () { - this._compute(this.properties.year, this.properties.month, this.properties.records) + ready() { + const { year, month, records } = this.properties + this._compute(year, month, records) } }, methods: { - _compute: function (year, month, records) { - var weeks = util.getMonthCalendar(year, month) - var recordMap = {} + _compute(year, month, records) { + const weeks = util.getMonthCalendar(year, month) + const recordMap = {} if (records && records.length) { - records.forEach(function (r) { - var d = parseInt(r.date.split('-')[2]) + records.forEach((r) => { + const d = parseInt(r.date.split('-')[2]) recordMap[d] = (recordMap[d] || 0) + r.duration }) } - var data = weeks.map(function (week) { - return week.map(function (day) { + const data = weeks.map((week) => + week.map((day) => { if (!day) return null - var duration = recordMap[day] || 0 - var color = 'transparent' + const duration = recordMap[day] || 0 + let color = 'transparent' if (duration > 0) { if (duration < 30) color = '#FFE0D0' else if (duration < 60) color = '#FFB088' else if (duration < 120) color = '#FF6B35' else color = '#E05520' } - return { day: day, duration: duration, color: color } + return { day, duration, color } }) - }) + ) this.setData({ weeks: data }) }, - onDayTap: function (e) { - var day = e.currentTarget.dataset.day + onDayTap(e) { + const day = e.currentTarget.dataset.day if (!day) return - var cell = null - var weeks = this.data.weeks - for (var i = 0; i < weeks.length; i++) { - for (var j = 0; j < weeks[i].length; j++) { - var c = weeks[i][j] - if (c && c.day === day) { cell = c; break } - } - if (cell) break - } + const cell = this.data.weeks.flat().find(c => c && c.day === day) if (!cell || cell.duration <= 0) return this.triggerEvent('daytap', { year: this.properties.year, month: this.properties.month, - day: day, + day, duration: cell.duration }) }, - getHeatColor: function (cell) { + getHeatColor(cell) { if (!cell || cell.duration <= 0) return 'transparent' - var d = cell.duration + const d = cell.duration if (d < 30) return '#FFE0D0' if (d < 60) return '#FFB088' if (d < 120) return '#FF6B35' diff --git a/components/progress-ring/progress-ring.js b/components/progress-ring/progress-ring.js index db48536..22da2b4 100644 --- a/components/progress-ring/progress-ring.js +++ b/components/progress-ring/progress-ring.js @@ -1,4 +1,4 @@ -var util = require('../../utils/util') +const util = require('../../utils/util') Component({ properties: { @@ -17,8 +17,8 @@ Component({ }, observers: { - 'remaining, status, duration, size, ringWidth, primaryColor': function () { - var texts = { idle: '准备开始', running: '坚持住', paused: '已暂停', completed: '完成!' } + 'remaining, status, duration, size, ringWidth, primaryColor'() { + const texts = { idle: '准备开始', running: '坚持住', paused: '已暂停', completed: '完成!' } this.setData({ displayTime: util.formatTime(this.data.remaining), statusText: texts[this.data.status] || '' @@ -28,45 +28,40 @@ Component({ }, lifetimes: { - ready: function () { - var self = this - var query = this.createSelectorQuery() + ready() { + const query = this.createSelectorQuery() query.select('#ringCanvas') .fields({ node: true, size: true }) - .exec(function (res) { + .exec((res) => { if (!res || !res[0] || !res[0].node) return - var canvas = res[0].node - var dpr = wx.getSystemInfoSync().pixelRatio || 2 - var displaySize = self.data.size + const canvas = res[0].node + const dpr = wx.getSystemInfoSync().pixelRatio || 2 + const displaySize = this.data.size canvas.width = displaySize * dpr canvas.height = displaySize * dpr - self._ctx = canvas.getContext('2d') - self._dpr = dpr - self._draw() + this._ctx = canvas.getContext('2d') + this._dpr = dpr + this._draw() }) } }, methods: { - _draw: function () { - var ctx = this._ctx + _draw() { + const ctx = this._ctx if (!ctx) return - var size = this.data.size - var dpr = this._dpr - var ringWidth = this.data.ringWidth - var duration = this.data.duration - var remaining = this.data.remaining - var primaryColor = this.data.primaryColor + const { size, ringWidth, duration, remaining, primaryColor } = this.data + const dpr = this._dpr - var w = size * dpr - var h = size * dpr + const w = size * dpr + const h = size * dpr ctx.clearRect(0, 0, w, h) - var cx = w / 2 - var cy = h / 2 - var radius = (size - ringWidth) / 2 * dpr - var lw = ringWidth * dpr + const cx = w / 2 + const cy = h / 2 + const radius = (size - ringWidth) / 2 * dpr + const lw = ringWidth * dpr // track ring ctx.beginPath() @@ -76,11 +71,11 @@ Component({ ctx.lineCap = 'round' ctx.stroke() - // progress arc (clockwise from 12 o'clock, represents remaining time) - var ratio = duration > 0 ? Math.max(0, Math.min(1, remaining / duration)) : 0 + // progress arc (clockwise from 12 o'clock) + const ratio = duration > 0 ? Math.max(0, Math.min(1, remaining / duration)) : 0 if (ratio > 0.001) { - var startAngle = -Math.PI / 2 - var endAngle = startAngle + ratio * Math.PI * 2 + const startAngle = -Math.PI / 2 + const endAngle = startAngle + ratio * Math.PI * 2 ctx.beginPath() ctx.arc(cx, cy, radius, startAngle, endAngle) ctx.strokeStyle = primaryColor diff --git a/custom-tab-bar/index.js b/custom-tab-bar/index.js index 7e8ec76..f306460 100644 --- a/custom-tab-bar/index.js +++ b/custom-tab-bar/index.js @@ -1,4 +1,4 @@ -var themeMod = require('../utils/theme') +const themeMod = require('../utils/theme') Component({ data: { @@ -7,23 +7,23 @@ Component({ }, lifetimes: { - attached: function () { - var theme = themeMod.getCurrentTheme() + attached() { + const theme = themeMod.getCurrentTheme() this.setData({ themeStyle: themeMod.getThemeStyle(theme) }) } }, pageLifetimes: { - show: function () { - var theme = themeMod.getCurrentTheme() + show() { + const theme = themeMod.getCurrentTheme() this.setData({ themeStyle: themeMod.getThemeStyle(theme) }) } }, methods: { - switchTab: function (e) { - var index = e.currentTarget.dataset.index - var pages = [ + switchTab(e) { + const index = e.currentTarget.dataset.index + const pages = [ '/pages/index/index', '/pages/records/records', '/pages/settings/settings' diff --git a/pages/index/index.js b/pages/index/index.js index d5e2a7a..debbcd8 100644 --- a/pages/index/index.js +++ b/pages/index/index.js @@ -1,7 +1,7 @@ -var storage = require('../../utils/storage') -var planMod = require('../../utils/plan') -var util = require('../../utils/util') -var themeMod = require('../../utils/theme') +const storage = require('../../utils/storage') +const planMod = require('../../utils/plan') +const util = require('../../utils/util') +const themeMod = require('../../utils/theme') Page({ data: { @@ -22,38 +22,33 @@ Page({ customInput: '' }, - onLoad: function () { + onLoad() { this.refresh() }, - onShow: function () { + onShow() { themeMod.applyThemeToPage(this) try { - var tb = this.getTabBar() + const tb = this.getTabBar() if (tb) tb.setData({ selected: 0 }) } catch (e) {} this.refresh() }, - onPullDownRefresh: function () { + onPullDownRefresh() { this.refresh() wx.stopPullDownRefresh() }, - refresh: function () { - var settings = storage.getSettings() - var streak = storage.getStreak() - var todayRecord = storage.getTodayRecord() + refresh() { + const settings = storage.getSettings() + const streak = storage.getStreak() + const todayRecord = storage.getTodayRecord() - var records = [] - var allRecords = storage.getRecords() - Object.keys(allRecords).forEach(function (key) { - records = records.concat(allRecords[key]) - }) - - var plan = planMod.getPlan(settings.planId) - var planDay = planMod.getPlanDay(settings.planId, records) - var target = planMod.getTodayTarget(settings.planId, Math.min(planDay, plan.totalDays)) + const allRecords = Object.values(storage.getRecords()).flat() + const plan = planMod.getPlan(settings.planId) + const planDay = planMod.getPlanDay(settings.planId, allRecords) + const target = planMod.getTodayTarget(settings.planId, Math.min(planDay, plan.totalDays)) this.setData({ todayTarget: target, @@ -68,37 +63,37 @@ Page({ }) }, - onStartTrain: function () { + onStartTrain() { wx.navigateTo({ url: '/pages/timer/timer' }) }, - onFreeTrain: function () { + onFreeTrain() { this.setData({ showPicker: true, customInput: '', customDuration: 60 }) }, - onClosePicker: function () { + onClosePicker() { this.setData({ showPicker: false }) }, - onSelectPreset: function (e) { - var val = e.currentTarget.dataset.value + onSelectPreset(e) { + const val = e.currentTarget.dataset.value this.setData({ customDuration: val, customInput: '' }) }, - onCustomInput: function (e) { - var val = parseInt(e.detail.value) || 0 + onCustomInput(e) { + const val = parseInt(e.detail.value) || 0 this.setData({ customInput: e.detail.value, customDuration: val }) }, - onConfirmFree: function () { - var dur = this.data.customDuration + onConfirmFree() { + const dur = this.data.customDuration if (!dur || dur <= 0) { wx.showToast({ title: '请输入有效时长', icon: 'none' }) return } this.setData({ showPicker: false }) - wx.navigateTo({ url: '/pages/timer/timer?free=' + dur }) + wx.navigateTo({ url: `/pages/timer/timer?free=${dur}` }) }, - noop: function () {} + noop() {} }) diff --git a/pages/records/records.js b/pages/records/records.js index e7a104e..36a2a8c 100644 --- a/pages/records/records.js +++ b/pages/records/records.js @@ -1,6 +1,6 @@ -var storage = require('../../utils/storage') -var util = require('../../utils/util') -var themeMod = require('../../utils/theme') +const storage = require('../../utils/storage') +const util = require('../../utils/util') +const themeMod = require('../../utils/theme') Page({ data: { @@ -19,36 +19,31 @@ Page({ dayDetail: {} }, - onLoad: function () { + onLoad() { this.refresh() }, - onShow: function () { + onShow() { themeMod.applyThemeToPage(this) try { - var tb = this.getTabBar() + const tb = this.getTabBar() if (tb) tb.setData({ selected: 1 }) } catch (e) {} this.refresh() }, - onPullDownRefresh: function () { + onPullDownRefresh() { this.refresh() wx.stopPullDownRefresh() }, - refresh: function () { - var stats = storage.getTotalStats() - var monthKey = this.data.currentYear + '-' + - (this.data.currentMonth < 10 ? '0' : '') + this.data.currentMonth - var records = storage.getRecordsByMonth(monthKey) + refresh() { + const stats = storage.getTotalStats() + const monthKey = `${this.data.currentYear}-${String(this.data.currentMonth).padStart(2, '0')}` + const records = storage.getRecordsByMonth(monthKey) - var allRecords = [] - var all = storage.getRecords() - Object.keys(all).forEach(function (key) { - allRecords = allRecords.concat(all[key]) - }) - allRecords.sort(function (a, b) { return b.date.localeCompare(a.date) }) + const allRecords = Object.values(storage.getRecords()).flat() + allRecords.sort((a, b) => b.date.localeCompare(a.date)) this.setData({ totalDuration: stats.totalDuration, @@ -61,48 +56,38 @@ Page({ }) }, - onPrevMonth: function () { - var year = this.data.currentYear - var month = this.data.currentMonth - if (month === 1) { - year-- - month = 12 + onPrevMonth() { + let { currentYear, currentMonth } = this.data + if (currentMonth === 1) { + currentYear-- + currentMonth = 12 } else { - month-- + currentMonth-- } - this.setData({ currentYear: year, currentMonth: month }) + this.setData({ currentYear, currentMonth }) this.refresh() }, - onNextMonth: function () { - var year = this.data.currentYear - var month = this.data.currentMonth - if (month === 12) { - year++ - month = 1 + onNextMonth() { + let { currentYear, currentMonth } = this.data + if (currentMonth === 12) { + currentYear++ + currentMonth = 1 } else { - month++ + currentMonth++ } - this.setData({ currentYear: year, currentMonth: month }) + this.setData({ currentYear, currentMonth }) this.refresh() }, - onDayTap: function (e) { - var detail = e.detail - var dateStr = detail.year + '-' + - (detail.month < 10 ? '0' : '') + detail.month + '-' + - (detail.day < 10 ? '0' : '') + detail.day + onDayTap(e) { + const { year, month, day } = e.detail + const dateStr = `${year}-${String(month).padStart(2, '0')}-${String(day).padStart(2, '0')}` - var allRecords = [] - var all = storage.getRecords() - Object.keys(all).forEach(function (key) { - allRecords = allRecords.concat(all[key]) - }) - - var sessions = allRecords.filter(function (r) { return r.date === dateStr }) - var totalDur = 0 - sessions.forEach(function (r) { totalDur += r.duration }) - var calories = Math.round(totalDur * 0.068) + const allRecords = Object.values(storage.getRecords()).flat() + const sessions = allRecords.filter(r => r.date === dateStr) + const totalDur = sessions.reduce((sum, r) => sum + r.duration, 0) + const calories = Math.round(totalDur * 0.068) this.setData({ showDayDetail: true, @@ -111,27 +96,26 @@ Page({ sessions: sessions.length, duration: totalDur, durationText: util.formatDuration(totalDur), - calories: calories + calories } }) }, - onCloseDayDetail: function () { + onCloseDayDetail() { this.setData({ showDayDetail: false }) }, - noop: function () {}, + noop() {}, - onDeleteRecord: function (e) { - var id = e.currentTarget.dataset.id - var self = this + onDeleteRecord(e) { + const id = e.currentTarget.dataset.id wx.showModal({ title: '删除记录', content: '确定要删除这条训练记录吗?', - success: function (res) { + success: (res) => { if (res.confirm) { storage.deleteRecord(id) - self.refresh() + this.refresh() wx.showToast({ title: '已删除', icon: 'none', duration: 1200 }) } } diff --git a/pages/settings/settings.js b/pages/settings/settings.js index 8b9f348..df1866b 100644 --- a/pages/settings/settings.js +++ b/pages/settings/settings.js @@ -1,5 +1,5 @@ -var storage = require('../../utils/storage') -var themeMod = require('../../utils/theme') +const storage = require('../../utils/storage') +const themeMod = require('../../utils/theme') Page({ data: { @@ -19,9 +19,9 @@ Page({ vibrate: true }, - onLoad: function () { - var s = storage.getSettings() - var theme = themeMod.getCurrentTheme() + onLoad() { + const s = storage.getSettings() + const theme = themeMod.getCurrentTheme() themeMod.applyThemeToPage(this) this.setData({ currentPlanId: s.planId, @@ -33,70 +33,68 @@ Page({ }) }, - onShow: function () { + onShow() { try { - var tb = this.getTabBar() + const tb = this.getTabBar() if (tb) tb.setData({ selected: 2 }) } catch (e) {} themeMod.applyThemeToPage(this) }, - onSelectTheme: function (e) { - var id = e.currentTarget.dataset.id - var theme = themeMod.setTheme(id) + onSelectTheme(e) { + const id = e.currentTarget.dataset.id + const theme = themeMod.setTheme(id) this.setData({ currentThemeId: id }) try { - var tb = this.getTabBar() - if (tb) { - tb.setData({ themeStyle: themeMod.getThemeStyle(theme) }) - } + const tb = this.getTabBar() + if (tb) tb.setData({ themeStyle: themeMod.getThemeStyle(theme) }) } catch (e) {} themeMod.applyThemeToPage(this) }, - onSelectPlan: function (e) { - var planId = e.currentTarget.dataset.id - var s = storage.getSettings() + onSelectPlan(e) { + const planId = e.currentTarget.dataset.id + const s = storage.getSettings() s.planId = planId storage.saveSettings(s) this.setData({ currentPlanId: planId }) wx.showToast({ title: '计划已切换', icon: 'success', duration: 1200 }) }, - onToggleReminder: function (e) { - var s = storage.getSettings() + onToggleReminder(e) { + const s = storage.getSettings() s.dailyReminder = e.detail.value storage.saveSettings(s) this.setData({ dailyReminder: e.detail.value }) }, - onReminderTimeChange: function (e) { - var s = storage.getSettings() + onReminderTimeChange(e) { + const s = storage.getSettings() s.reminderTime = e.detail.value storage.saveSettings(s) this.setData({ reminderTime: e.detail.value }) }, - onToggleVoice: function (e) { - var s = storage.getSettings() + onToggleVoice(e) { + const s = storage.getSettings() s.voiceGuide = e.detail.value storage.saveSettings(s) this.setData({ voiceGuide: e.detail.value }) }, - onToggleVibrate: function (e) { - var s = storage.getSettings() + onToggleVibrate(e) { + const s = storage.getSettings() s.vibrate = e.detail.value storage.saveSettings(s) this.setData({ vibrate: e.detail.value }) }, - onCopyWechat: function () { + onCopyWechat() { wx.setClipboardData({ data: '刘承', - success: function () { + success: () => { wx.showToast({ title: '已复制', icon: 'success', duration: 1500 }) } }) diff --git a/pages/timer/timer.js b/pages/timer/timer.js index 704b693..b5e9d30 100644 --- a/pages/timer/timer.js +++ b/pages/timer/timer.js @@ -1,7 +1,7 @@ -var Timer = require('../../utils/timer') -var storage = require('../../utils/storage') -var planMod = require('../../utils/plan') -var themeMod = require('../../utils/theme') +const Timer = require('../../utils/timer') +const storage = require('../../utils/storage') +const planMod = require('../../utils/plan') +const themeMod = require('../../utils/theme') Page({ data: { @@ -19,26 +19,21 @@ Page({ isFreeMode: false }, - onLoad: function (options) { + onLoad(options) { themeMod.applyThemeToPage(this) - var target - var planDay = 1 - var isFreeMode = false + let target + let planDay = 1 + let isFreeMode = false if (options && options.free) { target = parseInt(options.free) || 60 isFreeMode = true } else { - var settings = storage.getSettings() - var records = [] - var allRecords = storage.getRecords() - Object.keys(allRecords).forEach(function (key) { - records = records.concat(allRecords[key]) - }) - - var plan = planMod.getPlan(settings.planId) - planDay = planMod.getPlanDay(settings.planId, records) + 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)) } @@ -47,19 +42,18 @@ Page({ remaining: target, todayTarget: target, planDay: isFreeMode ? 0 : Math.min(planDay, 99), - isFreeMode: isFreeMode + isFreeMode }) - var self = this this._timer = new Timer({ - onTick: function (tick) { - self.setData({ + onTick: (tick) => { + this.setData({ remaining: tick.remaining > 0 ? tick.remaining : 0, - overtime: tick.remaining <= 0 ? tick.elapsed - self.data.duration : 0 + overtime: tick.remaining <= 0 ? tick.elapsed - this.data.duration : 0 }) }, - onComplete: function () { - self.setData({ status: 'completed', isCompleted: true }) + onComplete: () => { + this.setData({ status: 'completed', isCompleted: true }) if (storage.getSettings().vibrate) { try { wx.vibrateLong() } catch (e) {} } @@ -68,11 +62,11 @@ Page({ }) }, - onUnload: function () { + onUnload() { if (this._timer) this._timer.stop() }, - onStart: function () { + onStart() { if (this.data.isPaused) { this._timer.resume() this.setData({ isRunning: true, isPaused: false, status: 'running' }) @@ -83,26 +77,25 @@ Page({ this.setData({ isRunning: true, status: 'running' }) }, - onPause: function () { + onPause() { if (!this.data.isRunning || this.data.isPaused) return this._timer.pause() this.setData({ isPaused: true, status: 'paused' }) }, - onStop: function () { - var self = this + onStop() { wx.showModal({ title: '结束训练', content: '确定要结束本次训练吗?', - success: function (res) { - if (res.confirm) self.finishTraining() + success: (res) => { + if (res.confirm) this.finishTraining() } }) }, - finishTraining: function () { - var elapsed = this._timer.stop() - var today = storage.getToday() + finishTraining() { + const elapsed = this._timer.stop() + const today = storage.getToday() storage.saveRecord({ date: today, duration: elapsed, @@ -111,7 +104,7 @@ Page({ }) storage.updateStreak(today) - wx.showToast({ title: '已记录 ' + elapsed + '秒', icon: 'none', duration: 1500 }) - setTimeout(function () { wx.navigateBack() }, 1500) + wx.showToast({ title: `已记录 ${elapsed}秒`, icon: 'none', duration: 1500 }) + setTimeout(() => { wx.navigateBack() }, 1500) } }) diff --git a/utils/plan.js b/utils/plan.js index 271edd9..bf0e580 100644 --- a/utils/plan.js +++ b/utils/plan.js @@ -1,73 +1,52 @@ -var plans = { +const { formatDate } = require('./util') + +const plans = { beginner: { id: 'beginner', name: '初级 (7天)', totalDays: 7, description: '适合初学者,从30秒起步', - days: [ - { day: 1, target: 30 }, - { day: 2, target: 40 }, - { day: 3, target: 50 }, - { day: 4, target: 60 }, - { day: 5, target: 70 }, - { day: 6, target: 80 }, - { day: 7, target: 90 } - ] + days: Array.from({ length: 7 }, (_, i) => ({ day: i + 1, target: 30 + i * 10 })) }, intermediate: { id: 'intermediate', name: '中级 (14天)', totalDays: 14, description: '有一定基础,从60秒起步', - days: [ - { day: 1, target: 60 }, { day: 2, target: 60 }, - { day: 3, target: 75 }, { day: 4, target: 75 }, - { day: 5, target: 90 }, { day: 6, target: 90 }, - { day: 7, target: 105 }, { day: 8, target: 105 }, - { day: 9, target: 120 }, { day: 10, target: 120 }, - { day: 11, target: 135 }, { day: 12, target: 135 }, - { day: 13, target: 150 }, { day: 14, target: 150 } - ] + days: Array.from({ length: 14 }, (_, i) => { + const pair = Math.floor(i / 2) + return { day: i + 1, target: 60 + pair * 15 } + }) }, advanced: { id: 'advanced', name: '高级 (30天)', totalDays: 30, description: '挑战自我,从90秒起步', - days: (function () { - var arr = [] - for (var i = 1; i <= 30; i++) { - arr.push({ day: i, target: 90 + Math.floor((i - 1) / 3) * 15 }) - } - return arr - })() + days: Array.from({ length: 30 }, (_, i) => ({ + day: i + 1, + target: 90 + Math.floor(i / 3) * 15 + })) } } -function getPlan(planId) { - return plans[planId] || plans.beginner +const getPlan = (planId) => plans[planId] || plans.beginner + +const getTodayTarget = (planId, currentDay) => { + const plan = getPlan(planId) + const day = plan.days.find(d => d.day === currentDay) + return day ? day.target : plan.days[0].target } -function getTodayTarget(planId, currentDay) { - var plan = getPlan(planId) - for (var i = 0; i < plan.days.length; i++) { - if (plan.days[i].day === currentDay) return plan.days[i].target - } - return plan.days[0].target -} - -function getPlanDay(planId, records) { - var plan = getPlan(planId) - var now = new Date() - var today = now.getFullYear() + '-' + - ('0' + (now.getMonth() + 1)).slice(-2) + '-' + - ('0' + now.getDate()).slice(-2) - var dates = {} - records.forEach(function (r) { - if (r.date !== today) dates[r.date] = true - }) - var trainedDays = Object.keys(dates).length +const getPlanDay = (planId, records) => { + const plan = getPlan(planId) + const today = formatDate(new Date()) + const trainedDays = new Set( + records + .filter(r => r.date !== today && r.planId === planId) + .map(r => r.date) + ).size return Math.min(trainedDays + 1, plan.totalDays) } -module.exports = { plans: plans, getPlan: getPlan, getTodayTarget: getTodayTarget, getPlanDay: getPlanDay } +module.exports = { plans, getPlan, getTodayTarget, getPlanDay } diff --git a/utils/storage.js b/utils/storage.js index 1665e9c..b69f611 100644 --- a/utils/storage.js +++ b/utils/storage.js @@ -1,73 +1,68 @@ -var RECORDS_KEY = 'training_records' -var SETTINGS_KEY = 'user_settings' -var STREAK_KEY = 'current_streak' +const { formatDate } = require('./util') -function getRecords() { - return wx.getStorageSync(RECORDS_KEY) || {} -} +const RECORDS_KEY = 'training_records' +const SETTINGS_KEY = 'user_settings' +const STREAK_KEY = 'current_streak' -function saveRecord(record) { +const getRecords = () => wx.getStorageSync(RECORDS_KEY) || {} + +const saveRecord = (record) => { record.id = Date.now() - var records = getRecords() - var month = record.date.substring(0, 7) + const records = getRecords() + const month = record.date.substring(0, 7) if (!records[month]) records[month] = [] records[month].push(record) - records[month].sort(function (a, b) { return b.date.localeCompare(a.date) }) + records[month].sort((a, b) => b.date.localeCompare(a.date)) wx.setStorageSync(RECORDS_KEY, records) } -function deleteRecord(recordId) { - var records = getRecords() - Object.keys(records).forEach(function (month) { - records[month] = records[month].filter(function (r) { return r.id !== recordId }) +const deleteRecord = (recordId) => { + const records = getRecords() + Object.keys(records).forEach((month) => { + records[month] = records[month].filter((r) => r.id !== recordId) if (records[month].length === 0) delete records[month] }) wx.setStorageSync(RECORDS_KEY, records) } -function getRecordsByMonth(month) { - var records = getRecords() +const getRecordsByMonth = (month) => { + const records = getRecords() return records[month] || [] } -function getTotalStats() { - var records = getRecords() - var totalDuration = 0 - var totalSessions = 0 - var maxDuration = 0 - Object.keys(records).forEach(function (key) { - var list = records[key] - list.forEach(function (r) { +const getTotalStats = () => { + const records = getRecords() + let totalDuration = 0 + let totalSessions = 0 + let maxDuration = 0 + Object.keys(records).forEach((key) => { + records[key].forEach((r) => { totalDuration += r.duration totalSessions++ if (r.duration > maxDuration) maxDuration = r.duration }) }) - return { totalDuration: totalDuration, totalSessions: totalSessions, maxDuration: maxDuration } + return { totalDuration, totalSessions, maxDuration } } -function getSettings() { - return wx.getStorageSync(SETTINGS_KEY) || { - planId: 'beginner', - dailyReminder: true, - reminderTime: '08:00', - voiceGuide: true, - vibrate: true - } +const getSettings = () => wx.getStorageSync(SETTINGS_KEY) || { + planId: 'beginner', + dailyReminder: true, + reminderTime: '08:00', + voiceGuide: true, + vibrate: true } -function saveSettings(settings) { +const saveSettings = (settings) => { wx.setStorageSync(SETTINGS_KEY, settings) } -function getStreak() { - return wx.getStorageSync(STREAK_KEY) || { count: 0, lastDate: '' } -} +const getStreak = () => wx.getStorageSync(STREAK_KEY) || { count: 0, lastDate: '' } -function updateStreak(date) { - var streak = getStreak() - var today = date || getToday() - var yesterday = getDateOffset(today, -1) +const updateStreak = (date) => { + const streak = getStreak() + const today = date || getToday() + const yesterday = getDateOffset(today, -1) if (streak.lastDate === today) return streak @@ -81,52 +76,42 @@ function updateStreak(date) { return streak } -function getToday() { - return formatDate(new Date()) -} +const getToday = () => formatDate(new Date()) -function formatDate(date) { - var y = date.getFullYear() - var m = String(date.getMonth() + 1) - if (m.length < 2) m = '0' + m - var d = String(date.getDate()) - if (d.length < 2) d = '0' + d - return y + '-' + m + '-' + d -} - -function getDateOffset(dateStr, offset) { - var d = new Date(dateStr) +const getDateOffset = (dateStr, offset) => { + const d = new Date(dateStr) d.setDate(d.getDate() + offset) return formatDate(d) } -function getTodayRecord() { - var today = getToday() - var month = today.substring(0, 7) - var records = getRecordsByMonth(month) - var totalDuration = 0 - var hasRecord = false - for (var i = 0; i < records.length; i++) { - if (records[i].date === today) { - totalDuration += records[i].duration - hasRecord = true - } - } +const getTodayRecord = () => { + const today = getToday() + const records = getRecords() + let totalDuration = 0 + let hasRecord = false + Object.keys(records).forEach((month) => { + records[month].forEach((r) => { + if (r.date === today) { + totalDuration += r.duration + hasRecord = true + } + }) + }) return hasRecord ? { date: today, duration: totalDuration } : null } module.exports = { - getRecords: getRecords, - saveRecord: saveRecord, - deleteRecord: deleteRecord, - getRecordsByMonth: getRecordsByMonth, - getTotalStats: getTotalStats, - getSettings: getSettings, - saveSettings: saveSettings, - getStreak: getStreak, - updateStreak: updateStreak, - getToday: getToday, - formatDate: formatDate, - getDateOffset: getDateOffset, - getTodayRecord: getTodayRecord + getRecords, + saveRecord, + deleteRecord, + getRecordsByMonth, + getTotalStats, + getSettings, + saveSettings, + getStreak, + updateStreak, + getToday, + formatDate, + getDateOffset, + getTodayRecord } diff --git a/utils/theme.js b/utils/theme.js index 1182a23..485bc13 100644 --- a/utils/theme.js +++ b/utils/theme.js @@ -1,4 +1,4 @@ -var THEMES = [ +const THEMES = [ { id: 'orange', name: '活力橙', @@ -41,25 +41,23 @@ var THEMES = [ } ] -var DEFAULT_THEME_ID = 'orange' -var THEME_KEY = 'app_theme' -var _lastNavColor = '' -var _navColorTimer = null +const DEFAULT_THEME_ID = 'orange' +const THEME_KEY = 'app_theme' +let _lastNavColor = '' +let _navColorTimer = null -function getThemeById(id) { - return THEMES.find(function (t) { return t.id === id }) || THEMES[0] -} +const getThemeById = (id) => THEMES.find(t => t.id === id) || THEMES[0] -function getCurrentTheme() { - var id = wx.getStorageSync(THEME_KEY) || DEFAULT_THEME_ID +const getCurrentTheme = () => { + const id = wx.getStorageSync(THEME_KEY) || DEFAULT_THEME_ID return getThemeById(id) } -function _setNavBarColor(primary) { +const _setNavBarColor = (primary) => { if (_lastNavColor === primary) return _lastNavColor = primary if (_navColorTimer) clearTimeout(_navColorTimer) - _navColorTimer = setTimeout(function () { + _navColorTimer = setTimeout(() => { try { wx.setNavigationBarColor({ frontColor: '#ffffff', @@ -69,35 +67,35 @@ function _setNavBarColor(primary) { }, 50) } -function setTheme(id) { +const setTheme = (id) => { wx.setStorageSync(THEME_KEY, id) - var theme = getThemeById(id) + const theme = getThemeById(id) _setNavBarColor(theme.primary) - var app = getApp() + const app = getApp() if (app && app.globalData) app.globalData.theme = theme return theme } -function applyThemeToPage(self) { - var theme = getCurrentTheme() +const applyThemeToPage = (self) => { + const theme = getCurrentTheme() self.setData({ - theme: theme, - themeStyle: '--primary:' + theme.primary + ';--primary-light:' + theme.primaryLight + ';--primary-bg:' + theme.primaryBg + ';--primary-rgb:' + theme.primaryRgb + ';' + theme, + themeStyle: `--primary:${theme.primary};--primary-light:${theme.primaryLight};--primary-bg:${theme.primaryBg};--primary-rgb:${theme.primaryRgb};` }) _setNavBarColor(theme.primary) } -function getThemeStyle(theme) { - var t = theme || getCurrentTheme() - return '--primary:' + t.primary + ';--primary-light:' + t.primaryLight + ';--primary-bg:' + t.primaryBg + ';--primary-rgb:' + t.primaryRgb + ';' +const getThemeStyle = (theme) => { + const t = theme || getCurrentTheme() + return `--primary:${t.primary};--primary-light:${t.primaryLight};--primary-bg:${t.primaryBg};--primary-rgb:${t.primaryRgb};` } module.exports = { - THEMES: THEMES, - DEFAULT_THEME_ID: DEFAULT_THEME_ID, - getThemeById: getThemeById, - getCurrentTheme: getCurrentTheme, - setTheme: setTheme, - applyThemeToPage: applyThemeToPage, - getThemeStyle: getThemeStyle + THEMES, + DEFAULT_THEME_ID, + getThemeById, + getCurrentTheme, + setTheme, + applyThemeToPage, + getThemeStyle } diff --git a/utils/timer.js b/utils/timer.js index f69cb0e..c0d1c41 100644 --- a/utils/timer.js +++ b/utils/timer.js @@ -1,92 +1,77 @@ -function Timer(options) { - options = options || {} - this.onTick = options.onTick || function () {} - this.onComplete = options.onComplete || function () {} +class Timer { + constructor(options = {}) { + this.onTick = options.onTick || (() => {}) + this.onComplete = options.onComplete || (() => {}) - this._duration = 0 - this._remaining = 0 - this._elapsed = 0 - this._startTime = 0 - this._pausedTime = 0 - this._intervalId = null - this._running = false - this._paused = false - this._completed = false -} - -Timer.prototype.start = function (duration) { - this._duration = duration - this._remaining = duration - this._elapsed = 0 - this._completed = false - this._running = true - this._paused = false - this._startTime = Date.now() - this._tick() - var self = this - this._intervalId = setInterval(function () { self._tick() }, 1000) -} - -Timer.prototype.pause = function () { - if (!this._running || this._paused) return - this._paused = true - this._pausedTime = Date.now() - clearInterval(this._intervalId) - this._intervalId = null -} - -Timer.prototype.resume = function () { - if (!this._running || !this._paused) return - this._startTime += Date.now() - this._pausedTime - this._paused = false - this._tick() - var self = this - this._intervalId = setInterval(function () { self._tick() }, 1000) -} - -Timer.prototype.stop = function () { - this._running = false - this._paused = false - clearInterval(this._intervalId) - this._intervalId = null - return this._elapsed -} - -Timer.prototype._tick = function () { - if (!this._running || this._paused) return - this._elapsed = Math.floor((Date.now() - this._startTime) / 1000) - this._remaining = Math.max(0, this._duration - this._elapsed) - - this.onTick({ - remaining: this._remaining, - elapsed: this._elapsed, - duration: this._duration - }) - - if (this._remaining <= 0 && !this._completed) { - this._completed = true - this.onComplete({ elapsed: this._elapsed, duration: this._duration }) + this._duration = 0 + this._remaining = 0 + this._elapsed = 0 + this._startTime = 0 + this._pausedTime = 0 + this._intervalId = null + this._running = false + this._paused = false + this._completed = false } + + start(duration) { + this._duration = duration + this._remaining = duration + this._elapsed = 0 + this._completed = false + this._running = true + this._paused = false + this._startTime = Date.now() + this._tick() + this._intervalId = setInterval(() => { this._tick() }, 1000) + } + + pause() { + if (!this._running || this._paused) return + this._paused = true + this._pausedTime = Date.now() + clearInterval(this._intervalId) + this._intervalId = null + } + + resume() { + if (!this._running || !this._paused) return + this._startTime += Date.now() - this._pausedTime + this._paused = false + this._tick() + this._intervalId = setInterval(() => { this._tick() }, 1000) + } + + stop() { + this._running = false + this._paused = false + clearInterval(this._intervalId) + this._intervalId = null + return this._elapsed + } + + _tick() { + if (!this._running || this._paused) return + this._elapsed = Math.floor((Date.now() - this._startTime) / 1000) + this._remaining = Math.max(0, this._duration - this._elapsed) + + this.onTick({ + remaining: this._remaining, + elapsed: this._elapsed, + duration: this._duration + }) + + if (this._remaining <= 0 && !this._completed) { + this._completed = true + this.onComplete({ elapsed: this._elapsed, duration: this._duration }) + } + } + + get isRunning() { return this._running && !this._paused } + get isPaused() { return this._paused } + get isCompleted() { return this._completed } + get remaining() { return this._remaining } + get elapsed() { return this._elapsed } } -Object.defineProperty(Timer.prototype, 'isRunning', { - get: function () { return this._running && !this._paused } -}) - -Object.defineProperty(Timer.prototype, 'isPaused', { - get: function () { return this._paused } -}) - -Object.defineProperty(Timer.prototype, 'isCompleted', { - get: function () { return this._completed } -}) - -Object.defineProperty(Timer.prototype, 'remaining', { - get: function () { return this._remaining } -}) - -Object.defineProperty(Timer.prototype, 'elapsed', { - get: function () { return this._elapsed } -}) - module.exports = Timer diff --git a/utils/util.js b/utils/util.js index d0ec503..dd4efab 100644 --- a/utils/util.js +++ b/utils/util.js @@ -1,31 +1,28 @@ -function formatTime(seconds) { - var m = Math.floor(seconds / 60) - var s = seconds % 60 - return (m < 10 ? '0' : '') + m + ':' + (s < 10 ? '0' : '') + s +const formatTime = (seconds) => { + const m = Math.floor(seconds / 60) + const s = seconds % 60 + return `${String(m).padStart(2, '0')}:${String(s).padStart(2, '0')}` } -function formatDuration(seconds) { - if (seconds < 60) return seconds + '秒' - var m = Math.floor(seconds / 60) - var s = seconds % 60 - return s > 0 ? m + '分' + s + '秒' : m + '分钟' +const formatDuration = (seconds) => { + if (seconds < 60) return `${seconds}秒` + const m = Math.floor(seconds / 60) + const s = seconds % 60 + return s > 0 ? `${m}分${s}秒` : `${m}分钟` } -function getDaysInMonth(year, month) { - return new Date(year, month, 0).getDate() -} +const getDaysInMonth = (year, month) => new Date(year, month, 0).getDate() -function getMonthCalendar(year, month) { - var firstDay = new Date(year, month - 1, 1) - var lastDay = new Date(year, month, 0) - var daysInMonth = lastDay.getDate() - var startDayOfWeek = firstDay.getDay() +const getMonthCalendar = (year, month) => { + const firstDay = new Date(year, month - 1, 1) + const daysInMonth = new Date(year, month, 0).getDate() + const startDayOfWeek = firstDay.getDay() - var weeks = [] - var week = [null, null, null, null, null, null, null] + const weeks = [] + let week = [null, null, null, null, null, null, null] - for (var d = 1; d <= daysInMonth; d++) { - var dow = (startDayOfWeek + d - 1) % 7 + for (let d = 1; d <= daysInMonth; d++) { + const dow = (startDayOfWeek + d - 1) % 7 week[dow] = d if (dow === 6 || d === daysInMonth) { weeks.push(week.slice()) @@ -36,9 +33,17 @@ function getMonthCalendar(year, month) { return weeks } -module.exports = { - formatTime: formatTime, - formatDuration: formatDuration, - getDaysInMonth: getDaysInMonth, - getMonthCalendar: getMonthCalendar +const formatDate = (date) => { + const y = date.getFullYear() + const m = String(date.getMonth() + 1).padStart(2, '0') + const d = String(date.getDate()).padStart(2, '0') + return `${y}-${m}-${d}` +} + +module.exports = { + formatTime, + formatDuration, + getDaysInMonth, + getMonthCalendar, + formatDate }