Files
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

68 lines
2.6 KiB
Plaintext
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/* 宿主节点必须显式声明 display —— 自定义组件宿主默认是 inline,而内部是 block。
inline 盒被 block 子元素打断后会碎成「前半段/后半段」两个零宽行盒,页面侧一旦
在 <ui-card> 标签上加 border / box-shadow,就只会画在这两个碎片上,看起来是
「角上冒出两根竖条」(首页 .just-completed 高亮踩过这个坑)transform 对非替换
inline 元素更是完全无效,缩放脉冲动画一次都不会跑。
margin-bottom 也一并上提到宿主:外边距归宿主、内边距归内部,页面侧加边框时
才不会把 24rpx 外边距一起圈进框里。 */
:host {
display: block;
margin-bottom: 24rpx;
box-sizing: border-box;
}
.ui-card {
background: var(--card-bg, #FFFFFF);
border-radius: 24rpx;
padding: 32rpx;
box-shadow: 0 2rpx 16rpx rgba(0, 0, 0, 0.06);
box-sizing: border-box;
}
/* Dark mode: shadows barely read against the darker backdrop, so add a
faint bright edge to keep cards elevated and separated from the page. */
@media (prefers-color-scheme: dark) {
.ui-card {
box-shadow: 0 4rpx 20rpx rgba(0, 0, 0, 0.45), 0 0 0 1rpx rgba(255, 255, 255, 0.04);
}
}
.ui-card--flush {
padding: 0;
}
/* Soft variant: subtle background tint, no shadow */
.ui-card.soft {
background: rgba(var(--primary-rgb, 255, 107, 53), 0.04);
box-shadow: none;
border-radius: 20rpx;
}
/* Gradient variant: hero card filled with the theme gradient, white text.
Descendant elements override --text / --text-secondary locally so any
generic text inside automatically flips to white. */
.ui-card.gradient {
background: linear-gradient(135deg, var(--primary) 0%, var(--primary-light) 100%);
box-shadow: 0 8rpx 28rpx rgba(var(--primary-rgb), 0.35);
/* These custom properties are the ONLY channel that crosses the component
style-isolation boundary into slotted page content (see MEMORY.md). Any
text/fill inside the hero card must read from them, never var(--primary). */
--text: #FFFFFF;
--text-secondary: rgba(255, 255, 255, 0.85);
--border: rgba(255, 255, 255, 0.28);
--on-primary: #FFFFFF;
}
/* Staggered entrance animation.
交错延迟由页面传入的 index 换算成内联 animation-delay(见 ui-card.wxml)
不能用 :nth-child —— .ui-card 在组件内部永远是根节点下唯一的第 1 个子元素,
恒匹配 nth-child(1),所有卡片延迟都会是同一个值,压根不交错。 */
.ui-card.in {
animation: uiCardIn 0.45s ease both;
}
@keyframes uiCardIn {
from { opacity: 0; transform: translateY(40rpx); }
to { opacity: 1; transform: translateY(0); }
}