Commit Graph

14 Commits

Author SHA1 Message Date
liucheng 983ae1b9cb fix: 缓存击穿/play竞态/onUnload泄漏/清除数据UI/统计NaN
- leaderboard 云函数: _fetchLatestByOpenid 加 in-flight promise,并发请求复用同一次扫描,防缓存击穿
- voice: play 加序列号,丢弃过期播放,避免旧语音截断新语音
- timer: onUnload 补取消 _completionCountUp,系统返回手势不再泄漏动画定时器
- settings: 清除数据 setData 补 voiceGender/vibrateIntensity 重置,避免 UI 与存储不一致
- storage: getTotalStats 对 r.duration 防御(Number||0),避免脏数据产生 NaN 传染

Co-Authored-By: Claude <noreply@anthropic.com>
2026-07-25 15:01:51 +08:00
liucheng 41aa81083f fix: tts fileID 校验归属 + 排行榜不下发他人 openid
- tts: client 传的 fileID 校验必须属于 tts-cache 目录,防伪造 cloud:// 换取他人私有文件
- leaderboard: ranked 去掉他人 openid 改用 isMe 标记,wxml 用 item.isMe 高亮

Co-Authored-By: Claude <noreply@anthropic.com>
2026-07-25 14:59:15 +08:00
liucheng 88a2c349f4 fix(tts): 服务端 tts_cache 去重,防传 null 强制重合成刷 TTS 账单
- 合成前先查 tts_cache 集合,命中则直接 getTempFileURL,不重复合成
- 合成后写 tts_cache,相同参数组合只合成一次
- 集合不存在时 catch 走原合成路径不崩(需在云开发控制台建 tts_cache 集合启用去重)

Co-Authored-By: Claude <noreply@anthropic.com>
2026-07-25 14:55:23 +08:00
liucheng b47a48259e fix: 修复审查发现的 4 个高优先级问题
- plan: getTodayTarget 补 customPlans 参数,timer/index 调用点传值,修复自定义计划每日目标失效
- leaderboard: fetchRank 加请求序列号丢弃过期响应,修复快速切换周期竞态
- leaderboard 云函数:遍历记录加防御(r.date/duration/数组校验),避免单条脏数据崩溃全榜
- tts: _upload cloudPath 补 volume/speed,避免不同音量语速音频互相覆盖

Co-Authored-By: Claude <noreply@anthropic.com>
2026-07-25 14:48:09 +08:00
lc 6176f2c341 feat(ui): 记录页月份联动与多项 UI 美化/修复
- records: 底部列表与月份选择器联动,新增 [本月|最近] 分段控件;标题/空态随模式切换
- leaderboard: 领奖台布局(冠军居中+皇冠)、次数标注于底座且三档水平对齐;头像 cloud:// 批量预解析提速(云函数需重新部署)
- index/timer: 主色底图标改白色变体修复隐形;目标数字按微信字体缩放补偿真机遮挡
- settings: 配色方案横滑渐变色卡;头像上传前压缩至 200px
- theme: 新增 teal 主题;暗黑背景统一对齐
- 圆形头像双保险(image 自身 border-radius)修复月/年榜方图

注: cloudfunctions/leaderboard 改动须在开发者工具重新部署才生效。
2026-07-22 09:36:22 +08:00
lc 1eff3d60c4 fix(ui): 多项 UI 修复 — 弹窗遮挡/按钮可见性/暗黑闪烁/云函数版本
- 计划编辑弹窗移出 .container 避免 fixed 降级 + 修复滚动
- dock bottom 40rpx→8rpx 紧贴底部, sheet padding 同步调整
- 计划编辑器取消/恢复默认按钮可见性修复(bg 匹配容器)
- ui-btn--danger 按钮可见性修复
- 清除确认弹窗跟随暗黑模式切换
- icons.js build() 中 Fill 路径覆盖 outlined 路径修复
- plan.js getPlanDay 忽略 customPlans 修复
- darkMode.js 冗余三元简化
- util.js fileToDataURI fallback 可读性提升
- theme.js: BASE_VARS 与 getThemeStyle 统一来源, 去 50ms navbar 延迟
- app.wxss: 移除 page transition 和 background-color 减少闪白
- 云函数 wx-server-sdk 版本统一 ~2.6.3, tts cloud.init 一致化
- 闪白问题: wx.setBackgroundColor 三层防护(onLaunch/applyThemeToPage/switchTab)

Co-Authored-By: Claude <noreply@anthropic.com>
2026-07-10 09:40:04 +08:00
lc a7ed017267 feat(voice): 语音参数移入 config.js + 设置页男女声切换
- config: 新增 tts.female/male 两组参数(voiceType/volume/speed),
  直接改数字即可调音色,无需改逻辑代码
- storage: getSettings 兜底 voiceGender(旧用户迁移为女声)
- voice: 新增 _getTtsParams 读 config+性别;缓存 key 含完整参数,
  改音色/音量/性别自动重新合成,无需手动清缓存
- settings: 训练偏好加"语音音色"segmented(女声/男声)
- tts 云函数: _synthesize 用传入 opts 合成;_upload 路径含 voiceType
  (男/女不同文件);需重新部署

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-09 10:08:09 +08:00
lc dd9cd1859c feat(timer): 训练到目标时长不再自动结束,支持超长发挥
- Timer: 到时间触发 onGoalReached(提示)而非自动结束,elapsed/overtime
  继续累加直到用户手动停止
- timer: onGoalReached 播 goal 语音 + goalReached 状态;finishTraining
  补 complete 语音;完成弹窗显示"超长发挥 +X 秒"
- wxml: 超时 badge 训练中也显示;新增 goalReached hint 分支
- voice/tts: 新增 goal 语音 prompt(需部署 tts 云函数)
- config: 版本号 v2.5 -> v2.6

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-09 09:37:32 +08:00
lc 850f919269 fix(sync): 数据同步合并化 + 排行榜缓存与游标分页
- storage: 新增 mergeRecords,云端记录与本地按 id 去重合并,restore
  不再覆盖,解决训练中冷启动丢记录与多设备记录丢失
- storage: 新增 recomputeStreak,restore 后基于合并记录重算 streak,
  不再信任云端 streak 值
- storage: 新增 _local_changed_at 标记,settings/profile/customPlans
  在本地有未同步改动时保留本地,避免被云端旧值覆盖
- app: _restoreFromCloud 改合并 + 时间戳保护 + streak 重算;Case 2
  合并后回推让两端收敛
- leaderboard: 模块级 60s 缓存 + 游标分页(_id > lastId)替代 skip,
  全表扫描从每次打开降到 60s 内一次

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-09 09:06:44 +08:00
lc d817d5d012 fix: 13项数据存储与排行榜修复
致命修复:
- leaderboard: 日榜日期比较改用 dateOnly() 替代严格全等
- plan: 计划天数计算日期比较改用 dateOnly()
- cloud: pullAll 添加 orderBy('updatedAt','desc') 确保取最新文档避免数据丢失

严重修复:
- cloud: 新增 cancelPendingPush() 防止清除数据后被延迟推送复活
- settings: _doClearData 补充 user_profile 清除, 先取消推送再清除
- app: 云端同步改为时间戳比对策略, 支持跨设备拉取
- app: _restoreFromCloud 增加空数据保护和 profile 恢复
- storage: 记录ID改用时间戳+自增计数器确保唯一性

中等修复:
- cloud: init/_fetchOpenid 日志升级, 新增 syncStatus getter
- leaderboard云函数: 添加90天活跃过滤减少全表扫描
- storage: validateStreak 增加lastDate无记录时的通用修复
- leaderboard页面: 云函数失败时Toast提示用户而非静默降级

轻微修复:
- timer: onUnload 添加 voice.destroy() 释放音频上下文
- records: onLongPressDelete 委托给 onDeleteRecord 消除重复代码

Co-Authored-By: Claude <noreply@anthropic.com>
2026-06-24 12:22:54 +08:00
liucheng 6d1992869e fix: 修复排行榜数据自增长(冷启动重复创建云端文档)
每次小程序冷启动都会为同一用户创建新的云端文档,
导致 leaderboard 把同一份数据累加 N 次。

改动:
- app.js: onLaunch 改为 async,每次启动先 pullAll 填充 _openid / _docId 缓存
- utils/cloud.js: 引入 _ensureOpenid() 单次解析;_doPush 总是先按 openid
  定位现有文档;update 失败不再回退到 add()(避免创建重复文档)
- utils/storage.js: getTodayRecord 按日期部分比较,修复一天第二次训练
2026-06-21 22:56:51 +08:00
lc 47f718a129 feat: 训练开始时添加语音播报 2026-06-11 11:51:14 +08:00
lc 2e2594d154 feat: 修复清除数据、语音缓存、排行榜限制,新增项目配置文件
- 修复 cloud.clearAll 静默失败导致重启后数据恢复
- 清除数据弹窗改用自定义 ui-modal 替代 wx.showModal
- TTS 语音合成增加 fileID 持久化缓存,重启不再重新合成
- 排行榜限制前15名,maxRank 参数化到 config.js
- 新增 config.js 统一管理版本号/更新日期/开发者/排行榜限制
- progress-ring 消除 getSystemInfoSync 弃用警告
- voice.js 增加 InnerAudioContext 错误监听
- storage/util 完善用户资料、打卡日期精度、记录日志
2026-06-11 11:30:47 +08:00
lc 1d55df72b3 feat: v1.5 — plan editor, voice prompts, UI polish
Major features:
- Training plan editor: edit preset days/duration per plan (in-place
  override via custom_plans storage; preset ids preserved so existing
  records stay valid)
- Voice prompts at 4 fixed points during training (halfway / 30s /
  10s / done) via Tencent Cloud TTS (cloudfunctions/tts + utils/voice.js)
- Free-training button: switched from outline (transparent) to ghost
  variant (theme-tinted) for visual weight

Bug fixes:
- 4 functional pages: SVG data URIs failed to render in WeChat because
  '\#' in colors was parsed as a data-URI fragment delimiter. encode the
  whole SVG via encodeURIComponent in utils/icons.js build().
- Old records (saved before id field was added) could not be deleted
  (data-id was empty, triggered defensive guard). Backfill stable
  legacy-<month>-<index>-<duration> ids in getRecords() and persist.
- settings.js plan-row editor button event was bubbling up to the row's
  bindtap (which also fired onSelectPlan). Wrapped in catch:tap.

UI:
- Settings page: 3 hardcoded plans replaced with dynamic buildPlansList
  that overlays custom_plans on top of presets
- Plan editor: bottom-sheet modal in settings page (regular view, not
  ui-modal — WeChat custom component root element drops position:fixed
  in this runtime)
- Free-training button: rounded pill style, full-width, 24rpx gap from
  primary action; bottom sheet uses max-height: 88vh + internal scroll
- Version bumped to v1.5, last updated 2026-06-10

Removed:
- Daily reminder section (dailyReminder / reminderTime) — replaced by
  the 4 voice prompts which cover the same user need without requiring
  long-term scheduling that WeChat mini-programs can't actually do

Misc:
- utils/plan.js refactored to formula-driven: presets declare
  totalDays/startTarget/increment/cycleDays, days[] is generated. Same
  formula applies to custom plans.
- Timer _remind() guards each prompt on minimum duration so short
  free-mode sessions don't fire 'last30' at the start
- Cloud storage cloud_plans field added to data push payload; restored
  on first install via _restoreFromCloud
- .gitignore added for local AI tool caches (.reasonix/, reasonix.toml,
  .codegraph/daemon.pid)
2026-06-10 17:23:13 +08:00