feat: 训练完成全屏弹窗 (大数字+countUp+超时+3按钮)

替换原来不显眼的 wx.showToast:
- 全屏遮罩 + 大圆角卡片,scale-in 弹性入场
- 大数字 180rpx countUp 从 0 滚到实际秒数(1.2s)
- 超时标签 +Xs 秒超时(OvertimePop 弹性出现,延迟 1.1s 等数字到末尾)
- 连续打卡显示 🔥
- 3 按钮:再来一次(留在当前页重置) / 查看记录(跳记录页) / 回到首页
- 装饰 emoji 圆形 1.6s 循环脉冲
- onComplete 触发时自动保存,不需要再手动点结束
This commit is contained in:
2026-07-08 14:19:40 +08:00
parent f052327276
commit 503f01f6e9
3 changed files with 323 additions and 17 deletions
+185
View File
@@ -208,3 +208,188 @@
0% { opacity: 1; transform: translateX(-50%) scale(1); }
100% { opacity: 0; transform: translateX(-50%) scale(0.8); }
}
/* ---- completion modal (full-screen summary after training ends) ---- */
.completion-mask {
position: fixed;
inset: 0;
background: rgba(0, 0, 0, 0.55);
z-index: 10000;
display: flex;
align-items: center;
justify-content: center;
padding: 40rpx;
box-sizing: border-box;
animation: completionMaskIn 0.3s ease;
}
@keyframes completionMaskIn {
from { opacity: 0; }
to { opacity: 1; }
}
.completion-card {
width: 100%;
max-width: 640rpx;
background: var(--card-bg);
border-radius: 32rpx;
padding: 56rpx 40rpx 40rpx;
display: flex;
flex-direction: column;
align-items: center;
box-shadow: 0 16rpx 48rpx rgba(0, 0, 0, 0.25);
animation: completionCardIn 0.5s cubic-bezier(0.34, 1.56, 0.64, 1);
}
@keyframes completionCardIn {
0% { transform: scale(0.6) translateY(40rpx); opacity: 0; }
100% { transform: scale(1) translateY(0); opacity: 1; }
}
.completion-emoji-wrap {
width: 140rpx;
height: 140rpx;
border-radius: 50%;
background: linear-gradient(135deg, var(--primary), var(--primary-light));
display: flex;
align-items: center;
justify-content: center;
margin-bottom: 24rpx;
box-shadow: 0 8rpx 24rpx rgba(var(--primary-rgb), 0.4);
animation: completionEmojiPulse 1.6s ease-in-out infinite;
}
@keyframes completionEmojiPulse {
0%, 100% { transform: scale(1); }
50% { transform: scale(1.08); }
}
.completion-emoji {
font-size: 80rpx;
line-height: 1;
}
.completion-title {
font-size: 32rpx;
font-weight: 600;
color: var(--text);
margin-bottom: 32rpx;
text-align: center;
}
.completion-number-wrap {
display: flex;
align-items: baseline;
justify-content: center;
margin-bottom: 8rpx;
}
.completion-number {
font-size: 180rpx;
font-weight: 800;
color: var(--primary);
line-height: 1;
font-variant-numeric: tabular-nums;
letter-spacing: -4rpx;
text-shadow: 0 4rpx 12rpx rgba(var(--primary-rgb), 0.2);
}
.completion-unit {
font-size: 36rpx;
font-weight: 600;
color: var(--text-secondary);
margin-left: 8rpx;
}
.completion-label {
font-size: 26rpx;
color: var(--text-secondary);
margin-bottom: 24rpx;
}
.completion-overtime {
display: flex;
align-items: baseline;
gap: 6rpx;
background: rgba(var(--primary-rgb), 0.12);
padding: 12rpx 24rpx;
border-radius: 32rpx;
margin-bottom: 16rpx;
animation: overtimePop 0.4s cubic-bezier(0.34, 1.56, 0.64, 1) 1.1s both;
}
@keyframes overtimePop {
0% { transform: scale(0); opacity: 0; }
100% { transform: scale(1); opacity: 1; }
}
.overtime-plus {
font-size: 32rpx;
font-weight: 700;
color: var(--primary);
line-height: 1;
}
.overtime-label {
font-size: 24rpx;
color: var(--primary);
font-weight: 500;
}
.completion-streak {
display: flex;
align-items: center;
gap: 8rpx;
margin-bottom: 36rpx;
font-size: 26rpx;
color: var(--text);
}
.streak-flame {
font-size: 32rpx;
}
.streak-text {
font-weight: 500;
}
.completion-actions {
display: flex;
gap: 20rpx;
width: 100%;
margin-bottom: 12rpx;
}
.completion-btn {
flex: 1;
height: 88rpx;
display: flex;
align-items: center;
justify-content: center;
border-radius: 44rpx;
font-size: 30rpx;
font-weight: 600;
transition: transform 0.15s ease, opacity 0.15s ease, background 0.2s ease;
background: var(--bg-soft);
color: var(--text);
}
.completion-btn:active {
transform: scale(0.96);
opacity: 0.85;
}
.completion-btn--primary {
background: linear-gradient(135deg, var(--primary), var(--primary-light));
color: #FFFFFF;
box-shadow: 0 8rpx 20rpx rgba(var(--primary-rgb), 0.3);
}
.completion-btn--text {
background: transparent;
color: var(--text-secondary);
font-weight: 500;
height: 64rpx;
font-size: 26rpx;
margin-top: 4rpx;
}