update
This commit is contained in:
@@ -14,6 +14,46 @@
|
|||||||
<view class="menu-arrow">›</view>
|
<view class="menu-arrow">›</view>
|
||||||
</view> -->
|
</view> -->
|
||||||
|
|
||||||
|
<view class="menu-item" @click="goto('/training/pages/dumbbell')">
|
||||||
|
<view class="menu-icon menu-icon--dumbbell">
|
||||||
|
<view class="dumbbell-shape">
|
||||||
|
<view class="dumbbell-plate dumbbell-plate-left" />
|
||||||
|
<view class="dumbbell-bar" />
|
||||||
|
<view class="dumbbell-plate dumbbell-plate-right" />
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
<view class="menu-info">
|
||||||
|
<text class="menu-title">哑铃</text>
|
||||||
|
<text class="menu-sub">力量塑形</text>
|
||||||
|
</view>
|
||||||
|
<view class="menu-arrow">›</view>
|
||||||
|
</view>
|
||||||
|
|
||||||
|
<view class="menu-item" @click="goto('/training/pages/foot-pedal')">
|
||||||
|
<view class="menu-icon menu-icon--pedal">
|
||||||
|
<view class="foot-pedal-shape">
|
||||||
|
<view class="pedal-bar pedal-bar-left" />
|
||||||
|
<view class="pedal-bar pedal-bar-right" />
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
<view class="menu-info">
|
||||||
|
<text class="menu-title">脚蹬器</text>
|
||||||
|
<text class="menu-sub">下肢有氧</text>
|
||||||
|
</view>
|
||||||
|
<view class="menu-arrow">›</view>
|
||||||
|
</view>
|
||||||
|
|
||||||
|
<view class="menu-item" @click="goto('/training/pages/pilates-ring')">
|
||||||
|
<view class="menu-icon menu-icon--pilates">
|
||||||
|
<view class="pilates-ring-shape" />
|
||||||
|
</view>
|
||||||
|
<view class="menu-info">
|
||||||
|
<text class="menu-title">瑜伽环</text>
|
||||||
|
<text class="menu-sub">核心塑形</text>
|
||||||
|
</view>
|
||||||
|
<view class="menu-arrow">›</view>
|
||||||
|
</view>
|
||||||
|
|
||||||
<view class="menu-item" @click="goto('/training/pages/grip-ring')">
|
<view class="menu-item" @click="goto('/training/pages/grip-ring')">
|
||||||
<view class="menu-icon menu-icon--grip">
|
<view class="menu-icon menu-icon--grip">
|
||||||
<view class="grip-ring-shape" />
|
<view class="grip-ring-shape" />
|
||||||
@@ -262,6 +302,18 @@ $brand-light: #34d399;
|
|||||||
&--train {
|
&--train {
|
||||||
background: linear-gradient(140deg, $brand-light, $brand-deep);
|
background: linear-gradient(140deg, $brand-light, $brand-deep);
|
||||||
}
|
}
|
||||||
|
&--dumbbell {
|
||||||
|
background: linear-gradient(140deg, #93c5fd, #3b82f6);
|
||||||
|
box-shadow: 0 2rpx 8rpx rgba(59, 130, 246, 0.36);
|
||||||
|
}
|
||||||
|
&--pedal {
|
||||||
|
background: linear-gradient(140deg, #fdba74, #f97316);
|
||||||
|
box-shadow: 0 2rpx 8rpx rgba(249, 115, 22, 0.36);
|
||||||
|
}
|
||||||
|
&--pilates {
|
||||||
|
background: linear-gradient(140deg, #c4b5fd, #8b5cf6);
|
||||||
|
box-shadow: 0 2rpx 8rpx rgba(139, 92, 246, 0.36);
|
||||||
|
}
|
||||||
&--grip {
|
&--grip {
|
||||||
background: linear-gradient(140deg, #5eead4, #14b8a6);
|
background: linear-gradient(140deg, #5eead4, #14b8a6);
|
||||||
box-shadow: 0 2rpx 8rpx rgba(20, 184, 166, 0.36);
|
box-shadow: 0 2rpx 8rpx rgba(20, 184, 166, 0.36);
|
||||||
@@ -278,6 +330,83 @@ $brand-light: #34d399;
|
|||||||
line-height: 1;
|
line-height: 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* 哑铃小 icon */
|
||||||
|
.dumbbell-shape {
|
||||||
|
width: 40rpx;
|
||||||
|
height: 20rpx;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.dumbbell-plate {
|
||||||
|
width: 10rpx;
|
||||||
|
height: 18rpx;
|
||||||
|
background: #fff;
|
||||||
|
border-radius: 3rpx;
|
||||||
|
box-shadow: 0 1rpx 2rpx rgba(0, 0, 0, 0.18);
|
||||||
|
}
|
||||||
|
|
||||||
|
.dumbbell-bar {
|
||||||
|
width: 16rpx;
|
||||||
|
height: 5rpx;
|
||||||
|
background: #fff;
|
||||||
|
border-radius: 2rpx;
|
||||||
|
margin: 0 2rpx;
|
||||||
|
box-shadow: 0 1rpx 2rpx rgba(0, 0, 0, 0.18);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 脚蹬器小 icon: 左右踏板 */
|
||||||
|
.foot-pedal-shape {
|
||||||
|
width: 40rpx;
|
||||||
|
height: 28rpx;
|
||||||
|
display: flex;
|
||||||
|
align-items: flex-end;
|
||||||
|
justify-content: center;
|
||||||
|
gap: 6rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.pedal-bar {
|
||||||
|
width: 14rpx;
|
||||||
|
background: #fff;
|
||||||
|
border-radius: 4rpx 4rpx 2rpx 2rpx;
|
||||||
|
box-shadow: 0 1rpx 2rpx rgba(0, 0, 0, 0.18);
|
||||||
|
}
|
||||||
|
|
||||||
|
.pedal-bar-left {
|
||||||
|
height: 18rpx;
|
||||||
|
transform: rotate(-12deg);
|
||||||
|
}
|
||||||
|
|
||||||
|
.pedal-bar-right {
|
||||||
|
height: 22rpx;
|
||||||
|
transform: rotate(12deg);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 瑜伽环小 icon: 双弧阻力环 */
|
||||||
|
.pilates-ring-shape {
|
||||||
|
width: 36rpx;
|
||||||
|
height: 36rpx;
|
||||||
|
border-radius: 50%;
|
||||||
|
border: 5rpx solid #fff;
|
||||||
|
position: relative;
|
||||||
|
box-shadow:
|
||||||
|
0 1rpx 2rpx rgba(0, 0, 0, 0.18),
|
||||||
|
inset 0 1rpx 2rpx rgba(255, 255, 255, 0.6);
|
||||||
|
|
||||||
|
&::after {
|
||||||
|
content: '';
|
||||||
|
position: absolute;
|
||||||
|
top: 50%;
|
||||||
|
left: 50%;
|
||||||
|
width: 18rpx;
|
||||||
|
height: 18rpx;
|
||||||
|
transform: translate(-50%, -50%);
|
||||||
|
border-radius: 50%;
|
||||||
|
border: 3rpx solid rgba(255, 255, 255, 0.85);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* 握力环小 icon: 白色描边的环(甜甜圈) */
|
/* 握力环小 icon: 白色描边的环(甜甜圈) */
|
||||||
.grip-ring-shape {
|
.grip-ring-shape {
|
||||||
width: 32rpx;
|
width: 32rpx;
|
||||||
|
|||||||
@@ -124,8 +124,35 @@
|
|||||||
"backgroundColor": "#f8fafc"
|
"backgroundColor": "#f8fafc"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"path": "pages/metronome",
|
"path": "pages/pilates-ring",
|
||||||
|
"style": {
|
||||||
|
"navigationBarTitleText": "瑜伽环训练",
|
||||||
|
"navigationBarBackgroundColor": "#f8fafc",
|
||||||
|
"navigationBarTextStyle": "black",
|
||||||
|
"backgroundColor": "#f8fafc"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"path": "pages/foot-pedal",
|
||||||
|
"style": {
|
||||||
|
"navigationBarTitleText": "脚蹬器训练",
|
||||||
|
"navigationBarBackgroundColor": "#f8fafc",
|
||||||
|
"navigationBarTextStyle": "black",
|
||||||
|
"backgroundColor": "#f8fafc"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"path": "pages/dumbbell",
|
||||||
|
"style": {
|
||||||
|
"navigationBarTitleText": "哑铃训练",
|
||||||
|
"navigationBarBackgroundColor": "#f8fafc",
|
||||||
|
"navigationBarTextStyle": "black",
|
||||||
|
"backgroundColor": "#f8fafc"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"path": "pages/metronome",
|
||||||
"style": {
|
"style": {
|
||||||
"navigationBarTitleText": "耗糖节拍器",
|
"navigationBarTitleText": "耗糖节拍器",
|
||||||
"navigationBarBackgroundColor": "#f8fafc",
|
"navigationBarBackgroundColor": "#f8fafc",
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -112,6 +112,11 @@
|
|||||||
<text class="preset-desc">{{ p.desc }}</text>
|
<text class="preset-desc">{{ p.desc }}</text>
|
||||||
</view>
|
</view>
|
||||||
</view>
|
</view>
|
||||||
|
<!-- 当前强度预估消耗 -->
|
||||||
|
<view class="intensity-estimate">
|
||||||
|
<text class="estimate-icon">🔥</text>
|
||||||
|
<text class="estimate-text">{{ estimateText }}</text>
|
||||||
|
</view>
|
||||||
</view>
|
</view>
|
||||||
|
|
||||||
<view class="deck-divider" />
|
<view class="deck-divider" />
|
||||||
@@ -134,10 +139,38 @@
|
|||||||
</view>
|
</view>
|
||||||
</view>
|
</view>
|
||||||
|
|
||||||
<!-- 仅暂停时显示一行提示 + 结束训练文字链 -->
|
<view class="deck-divider" />
|
||||||
<view v-if="isPaused" class="action-bar">
|
|
||||||
<text class="paused-hint-text">已暂停 · 点击握力环继续</text>
|
<!-- 训练功效介绍(可折叠) -->
|
||||||
<text class="end-link" @click="onEndTraining">结束训练 ›</text>
|
<view class="benefit-block">
|
||||||
|
<view class="benefit-header" @click="benefitExpanded = !benefitExpanded">
|
||||||
|
<text class="benefit-title">训练功效</text>
|
||||||
|
<text class="benefit-toggle">{{ benefitExpanded ? '收起 ▲' : '展开 ▼' }}</text>
|
||||||
|
</view>
|
||||||
|
<view v-if="benefitExpanded" class="benefit-content">
|
||||||
|
<view class="benefit-row">
|
||||||
|
<text class="benefit-label">主要锻炼</text>
|
||||||
|
<view class="muscle-tags">
|
||||||
|
<text v-for="m in TRAINING_BENEFIT.muscles" :key="m" class="muscle-tag">{{ m }}</text>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
<view class="benefit-row">
|
||||||
|
<text class="benefit-label">训练效果</text>
|
||||||
|
<text class="benefit-effect">{{ TRAINING_BENEFIT.effect }}</text>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
|
||||||
|
<!-- 暂停时显示醒目大按钮(老年友好) -->
|
||||||
|
<view v-if="isPaused" class="pause-actions">
|
||||||
|
<button class="big-btn big-btn-resume" @click="onTogglePlay">
|
||||||
|
<text class="big-btn-icon">▶</text>
|
||||||
|
<text class="big-btn-text">继续训练</text>
|
||||||
|
</button>
|
||||||
|
<button class="big-btn big-btn-end" @click="onEndTraining">
|
||||||
|
<text class="big-btn-icon">■</text>
|
||||||
|
<text class="big-btn-text">结束训练</text>
|
||||||
|
</button>
|
||||||
</view>
|
</view>
|
||||||
</view>
|
</view>
|
||||||
</view>
|
</view>
|
||||||
@@ -218,7 +251,7 @@
|
|||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { computed, ref, watch } from 'vue'
|
import { computed, ref, watch } from 'vue'
|
||||||
import { onShow, onHide, onShareAppMessage, onShareTimeline } from '@dcloudio/uni-app'
|
import { onShow, onHide, onUnload, onShareAppMessage, onShareTimeline } from '@dcloudio/uni-app'
|
||||||
import { useMetronome } from '../hooks/useMetronome'
|
import { useMetronome } from '../hooks/useMetronome'
|
||||||
import CrushCanvas from './components/crush-canvas.vue'
|
import CrushCanvas from './components/crush-canvas.vue'
|
||||||
|
|
||||||
@@ -226,16 +259,26 @@ type PresetId = 'light' | 'medium' | 'heavy'
|
|||||||
interface GripPreset {
|
interface GripPreset {
|
||||||
id: PresetId
|
id: PresetId
|
||||||
bpm: number
|
bpm: number
|
||||||
|
met: number // 运动强度系数(用于估算糖分消耗)
|
||||||
label: string
|
label: string
|
||||||
desc: string
|
desc: string
|
||||||
}
|
}
|
||||||
|
|
||||||
const GRIP_PRESETS: readonly GripPreset[] = [
|
const GRIP_PRESETS: readonly GripPreset[] = [
|
||||||
{ id: 'light', bpm: 60, label: '轻度', desc: '热身 · 恢复' },
|
{ id: 'light', bpm: 60, met: 2.5, label: '轻度', desc: '热身 · 恢复' },
|
||||||
{ id: 'medium', bpm: 80, label: '中度', desc: '日常 · 锻炼' },
|
{ id: 'medium', bpm: 80, met: 3.5, label: '中度', desc: '日常 · 锻炼' },
|
||||||
{ id: 'heavy', bpm: 100, label: '重度', desc: '强化 · 挑战' },
|
{ id: 'heavy', bpm: 100, met: 4.5, label: '重度', desc: '强化 · 挑战' },
|
||||||
]
|
]
|
||||||
|
|
||||||
|
// 训练功效介绍(专业文案)
|
||||||
|
const TRAINING_BENEFIT = {
|
||||||
|
muscles: ['前臂屈肌', '手部小肌群', '握力'],
|
||||||
|
effect: '增强握力与前臂肌肉耐力,促进手部血液循环,缓解手指与腕部僵硬,适合日常碎片化锻炼及手部功能康复。',
|
||||||
|
}
|
||||||
|
|
||||||
|
// 强度预估参考时长(选择"自由"目标时按此估算)
|
||||||
|
const ESTIMATE_REF_MINUTES = 10
|
||||||
|
|
||||||
const PRESET_ICONS: Record<PresetId, string> = {
|
const PRESET_ICONS: Record<PresetId, string> = {
|
||||||
light: '🌱',
|
light: '🌱',
|
||||||
medium: '💪',
|
medium: '💪',
|
||||||
@@ -347,6 +390,16 @@ const timerInterval = ref<number | null>(null)
|
|||||||
// 获取当前档位配置
|
// 获取当前档位配置
|
||||||
const preset = computed(() => GRIP_PRESETS.find(p => p.id === currentPreset.value) || GRIP_PRESETS[1])
|
const preset = computed(() => GRIP_PRESETS.find(p => p.id === currentPreset.value) || GRIP_PRESETS[1])
|
||||||
const currentBpm = computed(() => preset.value.bpm)
|
const currentBpm = computed(() => preset.value.bpm)
|
||||||
|
const currentMet = computed(() => preset.value.met)
|
||||||
|
const benefitExpanded = ref(false)
|
||||||
|
|
||||||
|
// 当前强度预估消耗文案: 按选中目标时长(自由→10分钟参考)估算
|
||||||
|
const estimateText = computed(() => {
|
||||||
|
const mins = targetMinutes.value > 0 ? targetMinutes.value : ESTIMATE_REF_MINUTES
|
||||||
|
const sugar = (currentMet.value * 60 * (mins / 60)) / 4
|
||||||
|
const suffix = targetMinutes.value > 0 ? '' : '(按 10 分钟估算)'
|
||||||
|
return `${preset.value.label}训练 ${mins} 分钟,约消耗 ${sugar.toFixed(1)}g 糖分${suffix}`
|
||||||
|
})
|
||||||
|
|
||||||
const metronome = useMetronome({
|
const metronome = useMetronome({
|
||||||
initialBpm: currentBpm.value,
|
initialBpm: currentBpm.value,
|
||||||
@@ -440,14 +493,12 @@ function onBeat() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 计算消耗糖分
|
// 计算消耗糖分(随训练强度变化)
|
||||||
// 握力环训练 MET ≈ 3.5, 消耗卡路里 = MET × 体重(kg) × 时长(小时)
|
// 消耗卡路里 = MET × 体重(kg) × 时长(小时); 1g 糖分 ≈ 4 kcal
|
||||||
// 1g 糖分 ≈ 4 kcal, 所以 糖分(g) = 卡路里 / 4
|
|
||||||
function calculateSugar(seconds: number): number {
|
function calculateSugar(seconds: number): number {
|
||||||
const hours = seconds / 3600
|
const hours = seconds / 3600
|
||||||
const weight = 60 // 默认体重60kg
|
const weight = 60 // 默认体重60kg
|
||||||
const met = 3.5
|
const calories = currentMet.value * weight * hours
|
||||||
const calories = met * weight * hours
|
|
||||||
return calories / 4 // 转换为糖分(克)
|
return calories / 4 // 转换为糖分(克)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -676,21 +727,25 @@ onShow(() => {
|
|||||||
onShareAppMessage(() => ({
|
onShareAppMessage(() => ({
|
||||||
title: shareTitle.value,
|
title: shareTitle.value,
|
||||||
path: '/training/pages/grip-ring',
|
path: '/training/pages/grip-ring',
|
||||||
|
imageUrl: TUTORIAL_POSTER_URL,
|
||||||
}))
|
}))
|
||||||
|
|
||||||
// 分享到朋友圈
|
// 分享到朋友圈
|
||||||
onShareTimeline(() => ({
|
onShareTimeline(() => ({
|
||||||
title: shareTitle.value,
|
title: shareTitle.value,
|
||||||
|
imageUrl: TUTORIAL_POSTER_URL,
|
||||||
}))
|
}))
|
||||||
|
|
||||||
onHide(() => {
|
// 切出/卸载页面时强制释放所有媒体(含 BGM + 节拍 + 示范视频)
|
||||||
// 切出页面 → 自动暂停训练 + 强制停掉所有音频
|
function cleanupAllMedia() {
|
||||||
// 不依赖 isPlaying 判断: 暂停/结算态也可能有未释放的音频实例
|
|
||||||
// requiredBackgroundModes:['audio'] 下,InnerAudioContext.pause 不一定立即生效,这里用 stop+destroy 兜底
|
|
||||||
try { metronome.stop() } catch (_) {}
|
try { metronome.stop() } catch (_) {}
|
||||||
stopTimer()
|
stopTimer()
|
||||||
uni.setKeepScreenOn({ keepScreenOn: false })
|
uni.setKeepScreenOn({ keepScreenOn: false })
|
||||||
|
|
||||||
|
try {
|
||||||
|
uni.createVideoContext('gripDemoVideo')?.pause()
|
||||||
|
} catch (_) {}
|
||||||
|
|
||||||
if (bgmAudioCtx.value) {
|
if (bgmAudioCtx.value) {
|
||||||
try { bgmAudioCtx.value.stop() } catch (_) {}
|
try { bgmAudioCtx.value.stop() } catch (_) {}
|
||||||
try { bgmAudioCtx.value.destroy() } catch (_) {}
|
try { bgmAudioCtx.value.destroy() } catch (_) {}
|
||||||
@@ -701,7 +756,10 @@ onHide(() => {
|
|||||||
try { crushAudioCtx.value.destroy() } catch (_) {}
|
try { crushAudioCtx.value.destroy() } catch (_) {}
|
||||||
crushAudioCtx.value = null
|
crushAudioCtx.value = null
|
||||||
}
|
}
|
||||||
})
|
}
|
||||||
|
|
||||||
|
onHide(cleanupAllMedia)
|
||||||
|
onUnload(cleanupAllMedia)
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
@@ -1378,35 +1436,159 @@ $shadow-sm: 0 4rpx 12rpx rgba(15, 23, 42, 0.04);
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* ============================================================
|
/* ============================================================
|
||||||
* 控制面板底部操作(仅暂停时显示)
|
* 强度预估消耗
|
||||||
* ============================================================ */
|
* ============================================================ */
|
||||||
.action-bar {
|
.intensity-estimate {
|
||||||
margin-top: 18rpx;
|
margin-top: 14rpx;
|
||||||
padding: 14rpx 4rpx 2rpx;
|
padding: 16rpx 20rpx;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 10rpx;
|
||||||
|
background: $brand-soft;
|
||||||
|
border-radius: 14rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.estimate-icon {
|
||||||
|
font-size: 30rpx;
|
||||||
|
line-height: 1;
|
||||||
|
flex-shrink: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.estimate-text {
|
||||||
|
font-size: 24rpx;
|
||||||
|
font-weight: 600;
|
||||||
|
color: $brand-deep;
|
||||||
|
letter-spacing: 0.5rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ============================================================
|
||||||
|
* 训练功效(可折叠)
|
||||||
|
* ============================================================ */
|
||||||
|
.benefit-block {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
}
|
||||||
|
|
||||||
|
.benefit-header {
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
justify-content: space-between;
|
justify-content: space-between;
|
||||||
gap: 12rpx;
|
padding: 4rpx;
|
||||||
border-top: 2rpx dashed rgba(15, 23, 42, 0.06);
|
|
||||||
}
|
|
||||||
|
|
||||||
.paused-hint-text {
|
|
||||||
flex: 1;
|
|
||||||
font-size: 22rpx;
|
|
||||||
color: $text-3;
|
|
||||||
letter-spacing: 1rpx;
|
|
||||||
}
|
|
||||||
|
|
||||||
.end-link {
|
|
||||||
flex-shrink: 0;
|
|
||||||
padding: 8rpx 4rpx;
|
|
||||||
font-size: 24rpx;
|
|
||||||
color: $text-2;
|
|
||||||
font-weight: 500;
|
|
||||||
letter-spacing: 1rpx;
|
|
||||||
|
|
||||||
&:active {
|
&:active {
|
||||||
color: $text-1;
|
opacity: 0.7;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.benefit-title {
|
||||||
|
font-size: 26rpx;
|
||||||
|
font-weight: 700;
|
||||||
|
color: $text-1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.benefit-toggle {
|
||||||
|
font-size: 22rpx;
|
||||||
|
color: $brand-deep;
|
||||||
|
font-weight: 600;
|
||||||
|
}
|
||||||
|
|
||||||
|
.benefit-content {
|
||||||
|
margin-top: 14rpx;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 16rpx;
|
||||||
|
padding: 20rpx;
|
||||||
|
background: #f8fafc;
|
||||||
|
border-radius: 16rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.benefit-row {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 10rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.benefit-label {
|
||||||
|
font-size: 22rpx;
|
||||||
|
font-weight: 700;
|
||||||
|
color: $text-2;
|
||||||
|
}
|
||||||
|
|
||||||
|
.muscle-tags {
|
||||||
|
display: flex;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
gap: 10rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.muscle-tag {
|
||||||
|
padding: 6rpx 18rpx;
|
||||||
|
font-size: 22rpx;
|
||||||
|
font-weight: 600;
|
||||||
|
color: $brand-deep;
|
||||||
|
background: $brand-soft;
|
||||||
|
border-radius: 999rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.benefit-effect {
|
||||||
|
font-size: 24rpx;
|
||||||
|
line-height: 1.7;
|
||||||
|
color: $text-2;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ============================================================
|
||||||
|
* 暂停态大按钮(老年友好,醒目易点)
|
||||||
|
* ============================================================ */
|
||||||
|
.pause-actions {
|
||||||
|
margin-top: 20rpx;
|
||||||
|
display: flex;
|
||||||
|
gap: 16rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.big-btn {
|
||||||
|
flex: 1;
|
||||||
|
height: 104rpx;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
gap: 10rpx;
|
||||||
|
border-radius: 20rpx;
|
||||||
|
border: none;
|
||||||
|
padding: 0;
|
||||||
|
line-height: 1;
|
||||||
|
|
||||||
|
&::after {
|
||||||
|
border: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
&:active {
|
||||||
|
transform: scale(0.97);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.big-btn-icon {
|
||||||
|
font-size: 30rpx;
|
||||||
|
line-height: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.big-btn-text {
|
||||||
|
font-size: 34rpx;
|
||||||
|
font-weight: 800;
|
||||||
|
letter-spacing: 2rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.big-btn-resume {
|
||||||
|
background: $brand;
|
||||||
|
color: #fff;
|
||||||
|
box-shadow: 0 8rpx 20rpx rgba(20, 184, 166, 0.32);
|
||||||
|
}
|
||||||
|
|
||||||
|
.big-btn-end {
|
||||||
|
background: #fef2f2;
|
||||||
|
color: #dc2626;
|
||||||
|
border: 2rpx solid rgba(220, 38, 38, 0.3);
|
||||||
|
|
||||||
|
.big-btn-icon {
|
||||||
|
font-size: 26rpx;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -86,7 +86,7 @@
|
|||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { computed, onMounted, onUnmounted, ref } from 'vue'
|
import { computed, onMounted, onUnmounted, ref } from 'vue'
|
||||||
import { onShow, onHide } from '@dcloudio/uni-app'
|
import { onShow, onHide, onUnload } from '@dcloudio/uni-app'
|
||||||
import { useMetronome } from '../hooks/useMetronome'
|
import { useMetronome } from '../hooks/useMetronome'
|
||||||
import WalkerCanvas from './components/walker-canvas.vue'
|
import WalkerCanvas from './components/walker-canvas.vue'
|
||||||
|
|
||||||
@@ -206,15 +206,15 @@ onShow(() => {
|
|||||||
fg.preload()
|
fg.preload()
|
||||||
})
|
})
|
||||||
|
|
||||||
onHide(() => {
|
function cleanupMetronome() {
|
||||||
fg.stop()
|
fg.stop()
|
||||||
uni.setKeepScreenOn({ keepScreenOn: false })
|
uni.setKeepScreenOn({ keepScreenOn: false })
|
||||||
})
|
}
|
||||||
|
|
||||||
onUnmounted(() => {
|
onHide(cleanupMetronome)
|
||||||
fg.stop()
|
onUnload(cleanupMetronome)
|
||||||
uni.setKeepScreenOn({ keepScreenOn: false })
|
|
||||||
})
|
onUnmounted(cleanupMetronome)
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user