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