Commit Graph

17 Commits

Author SHA1 Message Date
lc 187c426243 chore: 上线前优化 — 清理调试日志/启用组件按需注入/补全组件声明
- 移除全项目 34 处调试 console.* 输出
- project.config.json: minified true、uploadWithSourceMap false、启用 lazyCodeLoading(requiredComponents 组件按需注入)
- pages/records/records.json 补全 ui-skeleton 组件声明(此前漏声明,WXML 已使用)
- 删除根目录残留 preview-buttons.html
2026-08-04 14:05:16 +08:00
lc 3532d0111b feat: 循环训练模式 + 语音补全 / 屏幕常亮 / 卡片渲染修复
循环训练(circuit)
- 新增 utils/circuitTimer.js 状态机: 工作->休息->...->完成, stop() 返回有效撑总秒(不含休息)
- 首页新增「循环训练·分组练习」入口 + stepper 配置弹窗
- 配置本地持久化 circuit_config(每组时长/组数/休息/每周目标), 下次自动预填
- 记录以 planId:'circuit' + mode:'circuit' 落库, duration 语义不变 -> 排行榜/统计/每日计划进度零改动
- 记录页展示「循环 N组xMs·休Rs」

计时器顶部循环进度面板
- 组进度点阵按组数等分铺满(flex:1 1 0, 去掉 max-width 封顶), 当前组以增高而非加宽强调
- 大号「X/Y 组」+ 四态阶段徽章(撑住/休息中/准备开始/已暂停) + 累计秒数副行
- 状态灯用纯 CSS 圆点(SVG 图标颜色烤死在 data URI 里, CSS 改不动)
- 超过 15 组自动降级为线性进度条; 面板不设固定高度, 规避真机大字体档裁字

修复: 循环训练全程无语音
- 根因: circuit 的 onTick 走 _circuitCue(只有震动), 从未调用 _remind
- 接入整场进度播报, 基准为 sets x holdPerSet(而非每组), 避免 4 组播 4 次「已完成一半」
- 新增 restStart/nextSet/lastSet 三条不含数字的词条, 客户端与 tts 云函数词表同步
- 修复必然撞车的时序: 偶数组时 halfway 与休息切换同一 tick, 加 2.6s 优先窗口让位
- 防吵闸门: 每组 <10s 不播过场语音, 休息 <5s 不播; 预载按模式取词条

训练期间屏幕常亮
- wx.setKeepScreenOn: onStart 开 / onUnload 关 / onShow 在 isRunning 时重新武装
- 切后台再回来该标志会被系统清掉, 故必须重新武装, 否则后半程丢语音与震动
- 低基础库与 Android 省电模式静默降级, 不弹 toast

修复: 首页打卡卡片左侧两个竖条
- 根因: ui-card 宿主节点无 display 声明为 inline, 页面侧加的 border 被打断成两个零宽行盒碎片
- ui-card 加 :host{display:block}, margin-bottom 从内部 view 上提到宿主
- 高亮由 border 改为 box-shadow spread 描边(不占布局, 无跳动) + 补 border-radius
- 连带修复失效的交错入场: nth-child 跨组件边界恒匹配 1, 改为 index 属性驱动内联 animation-delay, 14 处调用点补序号

注意: tts 云函数需重新部署, 否则新增的 3 条词条返回 Unknown prompt key(静默降级不报错)
2026-08-03 16:34:22 +08:00
lc c5ae332cbe feat(records): 训练勋章 UI 改造
- 勋章图标从 emoji 改为矢量 SVG 线性图标(utils/icons.js 新增 bolt/moon/diamond 路径及 white 变体)
- 命名改为累计语义(一周累计/半月累计/月度累计/双月累计/百日累计),并标注"非连续打卡"
- 进度条改回等距节点,解锁时填充正好抵达节点、满级满格
- 新增单枚解锁庆祝:持久化已见解锁集合,进入页面弹 toast + 节点 pop 动画
- 已解锁节点常驻显示勋章名 + 右上角 ✓ 角标,直观体现"已拥有"
- utils/storage.js 新增 totalDays(累计去重训练日),为勋章统计提供数据源
2026-07-28 16:25:55 +08:00
lc e2becc24aa feat(ui): 排行榜与首页打卡卡片多项优化
排行榜性能:
- 客户端乐观缓存:进页面/切周期秒显旧数据,后台静默刷新,消除 2-3s 空白
- 云函数实例缓存 TTL 60s -> 5min,降低全表扫描频率

排行榜 UI:
- 空状态重设计:奖杯光环插画(径向光晕 + 闪光漂浮)
- 领奖台 slot 撑满对齐列表、金银铜底座配色、角标与昵称间距修复、底线对齐

首页打卡卡片:
- 火焰光晕脉动 + 72rpx 大数字 + 分段进度格子
- 计划 >10 天时进度退化为里程碑连续条

Co-Authored-By: Claude <noreply@anthropic.com>
2026-07-27 17:28:53 +08:00
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 1c140bd503 fix: 修复 4 个正确性问题(分享秒数/主题同步/云推送定位/streak重算)
- timer: 完成弹窗存实际时长 completionActualElapsed,分享改用它,避免用动画值导致秒数错误
- theme: setTheme 补 _markLocalChanged,避免云恢复覆盖未同步的主题改动
- cloud: _doPush 重定位查询补 orderBy(updatedAt desc),与 pullAll 一致,避免命中最旧文档
- storage: deleteRecord 改用 recomputeStreak,修复删连续链中间某天 streak 虚高

Co-Authored-By: Claude <noreply@anthropic.com>
2026-07-25 14:51:09 +08:00
lc ed16ac5efd fix(vibrate): 修复旧用户震动失效 + 新增震动强度选项
根因:user_settings 早期无 vibrate 字段,getSettings 未兜底,
_remind 的 !s.vibrate 误判 undefined 为关闭,导致震动静默失效,
需手动操作开关才恢复。

- storage: getSettings 兜底 vibrate/voiceGuide/vibrateIntensity 默认值
- timer: !s.vibrate 改 === false,字段缺失视为开(与 voiceGuide 一致)
- timer: vibrate 按 vibrateIntensity 选 API(light/medium=vibrateShort,
  heavy=vibrateLong),fail 回调辅助排查
- settings: 新增"震动强度"三档(短促/标准/强烈),默认强烈

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-09 10:36:14 +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 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 486390917c fix: 拒绝保存未来日期的记录(防止改手机时间污染数据)
用户改手机时间到未来,record.date 就会变成未来时间,
推上云后污染排行榜统计。saveRecord 增加 1 分钟宽容度的
未来时间校验,触发时 toast 提示 + 静默拒绝保存。
2026-07-08 14:11:07 +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 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
lc a04c017e37 feat: cloud sync with WeChat CloudBase — data survives app deletion
Problem: All data stored in wx.StorageSync is permanently lost when
user deletes the mini-program or clears cache.

Solution: Sync data to WeChat CloudBase (wx.cloud.database).
- Graceful degradation: if cloud env isn't configured, all local
  storage works exactly as before.
- On app launch: if local records are empty, pull from cloud.
- On writes: push to cloud (debounced 2s) after saveRecord,
  deleteRecord, saveSettings, updateStreak, setTheme.
- Clear data in settings also clears cloud.

Files:
- utils/cloud.js: cloud sync wrapper (init, pullAll, pushAll, clearAll)
- app.js: cloud.init() + restore on fresh install
- utils/storage.js: cloud.pushAll() after every mutation
- utils/theme.js: cloud.pushAll() after setTheme
- pages/settings/settings.js: cloud.clearAll() when clearing data
- project.config.json: cloudfunctionRoot added

Setup required (one-time in WeChat DevTools):
  1. Open 'Cloud Development' panel → enable CloudBase
  2. Create environment → copy env ID
  3. In app.js, change wx.cloud.init() → wx.cloud.init({ env: 'YOUR-ENV-ID' })
  4. Create 'plank_data' collection in cloud database
  5. Set collection permission to 'Only creator can read/write'
2026-06-04 17:13:35 +08:00
lc 8c7f633541 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
2026-06-04 16:29:25 +08:00
lc ff2700c067 backup: snapshot before optimization 2026-06-04 16:25:43 +08:00