Files
lc b6d94b21cd fix(timer): 分段弧光点居中置顶 + 拉大与进度弧间距
- 光点移到段中点(am=(a0+a1)/2),两端粗细对称;重构为两遍绘制,
  光点统一后绘浮于所有弧之上,不再被相邻圆头吞掉;加大加亮成珠状
- glowPad 6→18 与 _drawSetArcs pad 同步,arcR 外移 3→14,
  分段弧与进度弧间距 -1 → +10dpr(size=420),呼吸光环不重叠
2026-08-12 10:34:54 +08:00

15 KiB
Raw Permalink Blame History

2026-08-12 工作日志

循环训练页遮挡问题分析与 redesign 规划

  • 读取 pages/timer/timer.wxml/wxss/js,定位循环训练态(circuit mode)布局。
  • 问题根因:.timer-pageflex columnmin-height: 100vh 但无滚动,中间圆环 420rpx + 多层呼吸环 488/620rpx + 顶部卡片 + 状态文字 + 目标卡 + 提示气泡的总高度在小屏/大字体下容易超过视口;底部 .controlsmargin-top: auto 贴底,结果会被内容顶出可视区域或被安全区截断。
  • 规划方案(未改代码):
    1. 圆环从 420rpx 缩到 340rpx,呼吸环同步缩小。
    2. 顶部卡片内嵌组进度条,组数/阶段/配置摘要合一,减少一层垂直空间。
    3. 状态文字与圆环内副标题、目标卡与姿态提示错位排布,避免信息重复。
    4. 底部控件固定高度 + padding-bottom: calc(32rpx + env(safe-area-inset-bottom)),保证始终在安全区上方可见。
    5. 整体改为 justify-content: space-between 的 flex 布局,顶部-中部-底部三大块按可用空间分配。
  • 已输出 SVG 线框图,待确认后再落地代码。

方案修正(用户反馈:timer 页是公用页面,仅循环模式有组进度条)

  • 用户指出原规划把页面当"恒有顶部卡片"设计,切换模式重心会跳。
  • 修订方案(未改代码):组进度从独立顶部面板改为「圆环外圈分段弧」——
    • progress-ring canvas 里加 sets/currentSet/isResting 属性,track 环外侧画一圈分段弧(已完成=主色、进行中=主色+端点光点、未开始=浅灰、休息时下一段=success 绿)。
    • 单组/自由模式不传 sets → 不渲染分段弧,页面结构与现状完全一致,零影响。
    • 圆环内副标题循环模式显示「第 X/Y 组」,单组显示「目标 X」。
    • 组数 >15 时退化为圆环下方细线进度条。
    • 顶部 circuit-bar 面板(wxml 20-53 行、wxss 15-225 行)整个删除,垂直空间全部还给圆环区与底部控件,从根上解决遮挡。
  • 已确认 components/progress-ring 为 canvas 2d 实现(_draw() 内 ctx.arc/stroke),扩分段弧同套 API,可行。

落地:循环训练组进度改造(用户批准后实施)

  • components/progress-ring/progress-ring.js
    • 新增属性 sets/currentSet/resting/successColorsets<=0 时零渲染,单组/自由模式不受影响)。
    • 新增 _drawSetArcs(pulse):track 环外侧画分段弧(arcR = radius + ringWidth/2 + 3rpx,弧宽 8rpx,段间隔 2.5°)。三态:已完成=primaryColor、进行中=primaryColor+端点光点、休息时下一段=successColor('#00B578'),未开始=trackColor。
    • 呼吸动画用 canvas.requestAnimationFrame 循环(周期 1.6s,sin 相位),只清外圈环带(clip 环形避免碰内圈倒计时弧);paused 时冻结为静态;detached 时 cancel。
    • _draw() 末尾补调 _drawSetArcs(_setPulsePhase || 0.6),保证每秒全量重绘后分段弧仍在。
  • pages/timer/timer.wxml:删除整个 circuit-bar 面板(原 18-53 行);<progress-ring> 新增 sets="{{totalSets}}" currentSet="{{currentSet}}" resting="{{isResting}}"
  • pages/timer/timer.js:删除 circuitDots/circuitShowDots/circuitTotalWork/dotsDone/dotsActive/dotsNext 字段与 DOTS_MAX 点阵构建;onTick 由 dots* 改为 ringSubText: 第 X/Y 组_initCircuit 的 ringSubText 改为 共 X 组 · 休息 Y 秒rest=0 省略休息段),goalLine 保持 每组 X · 共 Y 组
  • pages/timer/timer.wxss:删除全部 circuit 样式(.circuit-bar/.circuit-dots/.circuit-track/.circuit-meta/.circuit-count/.circuit-phase/.circuit-sub 等)。
  • 落地时的设计决策:组数上限 50_int clamp),环形 360° 空间充裕,50 段也不挤线(旧 DOTS_MAX=15 是横向卡片宽度受限),故不做数量降级;原方案"组数>15 退化线性条"在环形下无必要。
  • 验证:node --check 通过;grep 无残留代码引用(仅注释说明文字)。

呼吸环淡化(用户反馈"圆线条太明显")

  • timer.wxss.breath-auraborder 6rpx/0.55 → 4rpx/0.20box-shadow 外层 40rpx/0.45 → 30rpx/0.22、内层 28rpx/0.22 → 20rpx/0.10auraBreathe 透明度 0.55↔0.85 → 0.30↔0.50fast 版 0.6↔0.9 → 0.34↔0.55。
  • .breathe-ring 三档径向渐变强度:0.20/0.26/0.34 → 0.13/0.17/0.22,柔光更淡雅,不与倒计时环抢视觉。

目标卡与提示气泡轻量化(用户反馈"两个提示框不好看")

  • 问题:.goal-card 是白底卡片+右箭头,看起来像可点按钮但无 tap;.timer-tip 是白底气泡+左侧绿条+上方小三角+呼吸阴影,与目标卡叠在一起视觉噪音大。
  • timer.wxml:删除 .goal-card 中的右箭头 goal-arrow
  • timer.wxss
    • .goal-card 改为轻量胶囊标签:inline-flex、主色 8% 淡底、无边框无阴影、圆角 999rpxpadding 24→14rpx/24rpx;图标 40→32rpx;文字 28→26rpx、权重 600→500、主色。
    • .timer-tip 改为药丸标签:去掉 border-left、小三角、box-shadow、tipPulse 呼吸动画;背景主色 8% 淡底(done 态 success 10%);padding 20/32→12/24rpx;圆角 999rpx;图标 40→30rpx;文字 30→26rpx、权重 600→500。
  • 验证:grep 无 goal-arrow/tipPulse/timer-tip::before/border-left: 8rpx 残留。

目标卡 + 提示气泡合并为单气泡(用户反馈"字体小了、能否合并、页面三模式公用")

  • 新结构 .info-bubbletimer.wxml/wxss):一张主色 8% 淡底圆角卡,两行——
    • info-line--goaltarget 图标 + goalLine26rpx/500/主色(静态摘要,常驻)
    • 分隔线 info-divider(1rpx 主色 14% 淡线,仅提示出现时渲染)
    • info-line--tiptipIcon + runningTip30rpx/600/--text(动态提示,比目标行大一号突出);--done 态 success 绿
  • 三模式共用同一容器:单组/自由/循环都走 info-bubble;循环休息/暂停时 runningTip='' → 分隔线与提示行整体消失,气泡自动收缩只留目标行,布局不跳。
  • .goal-card/.goal-icon/.goal-text/.timer-tip/.timer-tip-icon/.timer-tip-text 全部删除,grep 无残留。

状态文案并入信息气泡(用户反馈"撑住"等硬编码文案能否整合进气泡)

  • 背景:环下方 .timer-statusstatusText:准备开始/撑住/休息中/已暂停)是独立一行,用户希望圆环下只留一张卡。
  • timer.wxml:删除 .timer-status 行,气泡改为三行结构——上 info-line--status(小圆点 + statusText+ 恒显分隔线 + 中 info-line--goal + 提示行(条件渲染)。
  • timer.wxss.timer-status 样式删除,新增 .info-line--status/.info-status-dot/.info-status-text
    • 状态行 32rpx/700,小圆点 14rpx 用 background: currentColor 跟随状态色(纯 CSS,规避 SVG 图标烤死问题)。
    • 配色:status--running=主色(圆点呼吸 1.6s);休息时 status 字段仍是 running,靠 isResting 追加 info-line--rest 覆盖为 success 绿(呼吸 1.8s);status--paused/idle=text-secondary 灰,paused 圆点冻结动画。
    • .info-bubble margin-top 24→40rpx(承接原 timer-status 间距)、padding 20→24rpx。
  • 关键机制备忘:resting 时 status 字段值仍是 'running',状态行转绿必须靠 isResting 单独加类,不能只看 status。
  • 验证:grep 无 timer-status 代码残留(仅注释文字),js 未改动。

进度弧"0 点对齐"问题:两轮修复被否定,已全部回滚(待用户澄清)

  • 用户反馈(两次截图):训练时粗进度弧起点与 0 点/顶部起点差一点没对齐,运动过程中更明显(循环与单组模式都出现过)。
  • 尝试过两轮修复(progress-ring.js _drawSetArcs 半径/清除区微调),用户判定"完全理解错了",要求撤销
  • 已回滚:git diff 确认 progress-ring.js 与 HEAD05c4763 分段弧初始实现:glowPad=6、arcR=radius+lw/2+3、arcW=8、清除区 clip 内缘 arcR-band)完全一致,node --check 通过。
  • 教训:对齐类问题不要凭数值推理直接改半径,先让用户明确"0 点"的参照物(刻度环/呼吸环/分段弧?)与出现模式,再定位。
  • 最终定位与修复(用户澄清"所有运动中,进度弧零点与表盘 0 点没对齐")
    • 根因确凿:_drawSetArcs 每段起点 +gap/21.25°),外圈分段弧第一段从 12 点偏右 1.25° 开始(半径 ~207dpr 处 ≈ 4.5dpr ≈ 1.5px),而内圈进度弧/12 点长刻度都从精确 -π/2 开始 → 循环模式外圈与内圈 0 点肉眼错开。
    • 修复:a0 = startAngle + (i-1)*segAngle(第一段精确 -π/2 起),a1 = a0 + segAngle - gap(段尾留 gap)。段间空隙均匀(2.5°×3),收尾空隙落在 12 点左侧,环带以 12 点为起点。node 验算:段起点 270°/30°/150°,空隙 2.5° 均匀,首段 12 点 ✓。
    • 单组/自由模式无分段弧,canvas 内刻度/进度弧同基准(-π/2),数学对齐;若用户仍反馈错位需再查(可能涉及 canvas 布局/参照物)。
    • 注意:gap/2 对称偏移是"段内居中空隙"的常见写法,环形进度环带与刻度基准对齐时必须从 -π/2 起算。
  • 用户叫停("算了,这个问题先不修复了"):零点对齐问题整体搁置。该轮 progress-ring.js 的角度修复(仅影响循环模式、覆盖不了单组模式现象)已 git checkout 回退,与 HEAD 一致。等用户想继续时再排查,方向可能是 canvas 布局/参照物而非半径。

新功能:训练时长低于阈值不记录(config.minRecordSeconds,默认 20 秒)

  • 需求:训练有效时长 < 20 秒(可配置)不写入记录,并给用户明确提示;阈值收进 config.js。
  • config.js:新增 minRecordSeconds: 20(带注释:不写记录、不更新连胜;循环按有效撑持秒数=各组时长之和判断)。
  • pages/timer/timer.js
    • finishTraining()elapsed >= minSec 才播完成语音(低于阈值不庆祝)。
    • _onCircuitComplete():循环自然完成路径同样按 workTotal >= minSec 播语音。
    • _saveAndShowCompletion(elapsed) 开头加阈值兜底elapsed < minSec_showNotRecorded(elapsed, minSec) 直接 return。手动结束与循环自然完成两条路径都汇聚到这里,任何入口都不会把短时训练落库。
    • 新增 _showNotRecorded(elapsed, minSec):复用完成弹窗(避免系统原生 modal 在 WebView stacking context 下 hit-test 不稳),不保存记录/连胜、无 confetti/streak/科学提示,大数字照常 countUp 到 elapsed;置 completionNotRecorded: trueminRecordSeconds: minSec、标题"未达最低记录时长"。
    • data 新增初始字段 completionNotRecorded: falseminRecordSeconds: 20
    • 状态残留坑(已修)onTrainAgain(再来一次)与 _saveAndShowCompletion 正常分支都必须显式 completionNotRecorded: false,否则上轮未记录后重练,下次正常完成弹窗会误显示"未计入记录"且隐藏分享/记录按钮。
  • timer.wxml:完成弹窗新增 .completion-not-recorded 提示块(infoFill 图标 + "本次训练未计入记录" + 副行"撑满 X 秒以上才会记录并计入连续打卡");未记录态 wx:if="{{!completionNotRecorded}}" 隐藏"查看记录/分享"(没有成绩可看/可晒),仅留"再来一次 + 回到首页"。
  • timer.wxss:新增 .completion-not-recorded 主色淡底信息块(与 completion-tip 同风格,tipIn 延迟 0.5s 入场)。
  • 保留逻辑:elapsed < 3 秒仍走 toast「训练时间太短」+ navigateBack(几乎未开始,不弹完成弹窗)。
  • 验证:node --check 通过;grep 确认 minRecordSeconds/completionNotRecorded/_showNotRecorded 三处字段在 config/js/wxml 引用一致。

分段弧两端粗细不一致(已修)

  • 用户反馈:循环训练时分段弧"两端粗细不一致"。
  • 根因(progress-ring.js _drawSetArcs):发光光点坐标固定取段尾角 a1dx=cx+arcR*cos(a1)),当前段(active)/休息预告段(next)的尾端 = 光点+8dpr 发光晕(直径≈弧宽+),首端却只是 lineCap:'round' 普通圆头 → 同段弧尾粗头细。已完成/未开始段两端都是普通圆头,粗细一致,所以现象集中在运动中那一段。
  • 修复:光点移到段中点 am=(a0+a1)/2(3 行),两端自然对称,光点仍作"当前组"标记。node --check 通过。
  • 注意:若以后想给分段弧加"当前组跟随倒计时移动"的进度感,光点可改为随剩余时间在段内插值,但需先确认用户是否要这个效果。

分段弧间距 + 光点置顶(用户反馈"两弧太近、弧压着光点")

  • 用户反馈两点:①分段弧与进度弧距离太近;②光点被分段弧压住(视觉上弧盖着光点)。
  • 间距修复progress-ring.jssize=420 时验证):
    • 根因:间距 = gap arcW/2 = 34 = 1dpr(重叠 1。因为分段弧 arcR 仅比进度弧外缘靠外 3dpr,而弧半宽 4dpr。
    • _draw()glowPad 6→14dpr(进度弧半径内缩 8,给外圈腾空间);_drawSetArcs() 的 radius pad 6→14两处必须同步,已加注释)且 arcR 间距 +3→+9dpr。结果:进度弧外缘 204→196、分段弧内缘 203→201,间距 −1→+5dpr。副作用:单组/自由模式的进度环也内缩 ~8dpr(约 4%),中心数字区略小;进度弧尾端发光点 shadowBlur=12 阴影反而从"被 canvas 裁"变完整。
    • 段间空隙 gap=2.5° 是段间距,与环间距无关,不动
  • 光点置顶:原实现光点在逐段循环内、每段弧 stroke 之后画,理论上应在弧上,但视觉上被 round cap 相邻段边缘"吞掉"。重构为两遍绘制:pass1 只画所有弧并收集 emphasized 段光点(x/y/color),pass2 统一在所有弧之上画光点。同时光点加大加亮:dotR 从 0.85~1.2×弧半宽1.15~1.4×alpha 0.55~1.00.7~1.0,白芯 0.85→0.9,读起来像"珠珠骑在弧上"。
  • 光点仍居段中点(沿用上轮两端对称修复);外缘 209dpr 不超 canvas 半宽 210,与 breath-aura(内缘 ~232)无重叠。
  • 验证:node --check 通过;数值全部核算。未提交 git。
  • 间距仍不够(用户反馈"还是太近")→ 再翻倍canvas 半宽 210 是硬上限,剩余空间仅 ~5dpr,要明显拉开只能继续内缩进度弧。glowPad 14→18、arcR 外移量 9→14,间距 5→10dpr(进度弧外缘 196→192,分段弧内缘 201→202,光点外缘 211.6 超画布 0.8px 亚像素无感)。进度环直径累计缩 ~6%(408→384)。约束备忘:间距 = arcR外移量 arcW/2,且 ≤ glowPad arcW margin;想再拉开只能继续缩环或减弧宽。