This commit is contained in:
Your Name
2026-08-11 17:41:36 +08:00
parent cfe4c82c90
commit 03fe4ddf9d
18771 changed files with 3617239 additions and 0 deletions
@@ -0,0 +1,446 @@
"use strict";
const common_vendor = require("../../common/vendor.js");
const TUTORIAL_VIDEO_URL = "https://gz-1349751149.cos.ap-guangzhou.myqcloud.com/uploads/video/20260528/202605281739110fa2d3784.mp4";
const TUTORIAL_POSTER_URL = "https://gz-1349751149.cos.ap-guangzhou.myqcloud.com/uploads/images/20260529/2026052911251785db25125.jpg";
const BGM_URL = "https://gz-1349751149.cos.ap-guangzhou.myqcloud.com/uploads/file/20260528/20260528093709c669f4659.mp3";
const _sfc_defineComponent = common_vendor.defineComponent({
__name: "pilates-ring",
setup(__props) {
const PILATES_PRESETS = [
{ id: "light", bpm: 50, met: 3, label: "轻度", desc: "热身 · 激活" },
{ id: "medium", bpm: 65, met: 4, label: "中度", desc: "日常 · 塑形" },
{ id: "heavy", bpm: 80, met: 5, label: "重度", desc: "强化 · 挑战" }
];
const TARGET_OPTIONS = [
{ minutes: 0, label: "自由" },
{ minutes: 5, label: "5 分钟" },
{ minutes: 10, label: "10 分钟" },
{ minutes: 15, label: "15 分钟" }
];
const MILESTONES = [
{ emoji: "🌸", title: "热身完成", desc: "身体已激活!", minReps: 8, maxReps: 12 },
{ emoji: "💫", title: "核心稳定", desc: "动作很标准!", minReps: 15, maxReps: 20 },
{ emoji: "✨", title: "塑形进阶", desc: "力量感很棒!", minReps: 25, maxReps: 30 },
{ emoji: "🏆", title: "完美收官", desc: "太棒了!", minReps: 40, maxReps: 50 }
];
const FOOD_SUGAR_TABLE = [
{ emoji: "🍬", name: "糖果", sugar: 95, unit: "颗", weight: 5 },
// 1颗糖果约5g
{ emoji: "🍪", name: "饼干", sugar: 65, unit: "块", weight: 10 },
// 1块饼干约10g
{ emoji: "🍫", name: "巧克力", sugar: 51.5, unit: "块", weight: 50 },
// 1块巧克力约50g
{ emoji: "🍎", name: "苹果", sugar: 10.3, unit: "个", weight: 200 },
// 1个苹果约200g
{ emoji: "🍌", name: "香蕉", sugar: 12.2, unit: "根", weight: 120 },
// 1根香蕉约120g
{ emoji: "🍚", name: "米饭", sugar: 25.9, unit: "碗", weight: 150 },
// 1碗米饭约150g
{ emoji: "🥤", name: "可乐", sugar: 10.6, unit: "罐", weight: 330 }
// 1罐可乐330ml
];
const currentPreset = common_vendor.ref("medium");
const targetMinutes = common_vendor.ref(0);
const isPlaying = common_vendor.ref(false);
const beatTimer = common_vendor.ref(null);
const showRewardPopup = common_vendor.ref(false);
const showSummary = common_vendor.ref(false);
const currentReward = common_vendor.ref(MILESTONES[0]);
const bgmAudioCtx = common_vendor.ref(null);
const bgmEnabled = common_vendor.ref(true);
const totalReps = common_vendor.ref(0);
const elapsedSeconds = common_vendor.ref(0);
const totalSugar = common_vendor.ref(0);
const beatCount = common_vendor.ref(0);
const rewardIndex = common_vendor.ref(0);
const nextRewardAt = common_vendor.ref(0);
const startTime = common_vendor.ref(0);
const timerInterval = common_vendor.ref(null);
const preset = common_vendor.computed(() => PILATES_PRESETS.find((p) => p.id === currentPreset.value) || PILATES_PRESETS[1]);
const currentBpm = common_vendor.computed(() => preset.value.bpm);
const currentMet = common_vendor.computed(() => preset.value.met);
const targetExpanded = common_vendor.ref(false);
const currentTargetLabel = common_vendor.computed(() => {
const opt = TARGET_OPTIONS.find((t) => t.minutes === targetMinutes.value);
return opt ? opt.label : "自由";
});
const benefitExpanded = common_vendor.ref(false);
const TRAINING_BENEFIT = {
muscles: ["核心肌群", "盆底肌", "大腿内侧", "臀部"],
effect: "通过持续抗阻收紧核心与盆底肌,强化深层稳定肌群,改善体态、收紧腹部与腿部线条,提升身体协调性与柔韧度。"
};
common_vendor.watch(isPlaying, (playing) => {
const videoCtx = common_vendor.index.createVideoContext("pilatesDemoVideo");
if (!videoCtx)
return;
if (playing) {
videoCtx.play();
} else {
videoCtx.pause();
}
});
const intervalMs = common_vendor.computed(() => 6e4 / currentBpm.value);
const hasStats = common_vendor.computed(() => isPlaying.value || totalReps.value > 0);
const isPaused = common_vendor.computed(() => !isPlaying.value && totalReps.value > 0 && !showSummary.value);
const remainingSeconds = common_vendor.computed(() => {
if (targetMinutes.value === 0)
return null;
const total = targetMinutes.value * 60;
return Math.max(0, total - elapsedSeconds.value);
});
const centerHintText = common_vendor.computed(() => isPaused.value ? "点击继续" : "点击开始");
const statusText = common_vendor.computed(() => {
if (isPlaying.value)
return "训练中";
if (isPaused.value)
return "已暂停";
return "待开始";
});
const shareTitle = common_vendor.computed(() => {
if (totalReps.value === 0)
return "瑜伽环训练 · 一起练起来";
return `刚刚完成 ${totalReps.value} 次瑜伽环训练,约消耗 ${totalSugar.value.toFixed(1)}g 糖分 ✨`;
});
const rootStyle = common_vendor.computed(() => ({
"--beat-duration": `${intervalMs.value}ms`
}));
const sugarComparisons = common_vendor.computed(() => {
if (totalSugar.value === 0)
return [];
const results = [];
for (const food of FOOD_SUGAR_TABLE) {
const foodSugar = food.sugar * food.weight / 100;
const count = totalSugar.value / foodSugar;
if (count >= 0.1 && count <= 50) {
results.push({
emoji: food.emoji,
name: food.name,
count: count >= 10 ? Math.round(count).toString() : count.toFixed(1),
unit: food.unit
});
}
}
return results.slice(0, 3);
});
function onBeat() {
beatCount.value++;
if (beatCount.value % 2 === 0) {
totalReps.value++;
if (totalReps.value >= nextRewardAt.value && rewardIndex.value < MILESTONES.length) {
triggerReward();
}
}
}
function calculateSugar(seconds) {
const hours = seconds / 3600;
const weight = 60;
const calories = currentMet.value * weight * hours;
return calories / 4;
}
function formatTime(seconds) {
const mins = Math.floor(seconds / 60);
const secs = seconds % 60;
return `${mins}:${secs.toString().padStart(2, "0")}`;
}
function triggerReward() {
const reward = MILESTONES[rewardIndex.value];
currentReward.value = reward;
triggerHaptic();
rewardIndex.value++;
if (rewardIndex.value < MILESTONES.length) {
const nextReward = MILESTONES[rewardIndex.value];
const range = nextReward.maxReps - nextReward.minReps;
nextRewardAt.value = totalReps.value + nextReward.minReps + Math.floor(Math.random() * (range + 1));
}
setTimeout(() => {
showRewardPopup.value = true;
}, 400);
}
function closeRewardPopup() {
showRewardPopup.value = false;
}
function triggerHaptic() {
common_vendor.index.vibrateShort({
type: "medium",
fail: () => {
try {
common_vendor.index.vibrateShort({});
} catch (_) {
}
}
});
}
function startRhythm() {
stopRhythm();
isPlaying.value = true;
const beatMs = 6e4 / currentBpm.value;
beatTimer.value = setInterval(onBeat, beatMs);
}
function stopRhythm() {
isPlaying.value = false;
if (beatTimer.value) {
clearInterval(beatTimer.value);
beatTimer.value = null;
}
}
function startBgm() {
if (!bgmEnabled.value)
return;
if (bgmAudioCtx.value) {
try {
bgmAudioCtx.value.play();
} catch (_) {
}
return;
}
bgmAudioCtx.value = common_vendor.index.createInnerAudioContext();
bgmAudioCtx.value.src = BGM_URL;
bgmAudioCtx.value.loop = true;
bgmAudioCtx.value.obeyMuteSwitch = false;
bgmAudioCtx.value.volume = 0.4;
try {
bgmAudioCtx.value.play();
} catch (_) {
}
}
function stopBgm() {
if (bgmAudioCtx.value) {
try {
bgmAudioCtx.value.pause();
} catch (_) {
}
}
}
function toggleBgm() {
bgmEnabled.value = !bgmEnabled.value;
if (bgmEnabled.value && isPlaying.value) {
startBgm();
} else {
stopBgm();
}
}
function onPresetTap(id) {
if (isPlaying.value)
return;
currentPreset.value = id;
if (beatTimer.value) {
stopRhythm();
startRhythm();
}
}
function onTargetTap(minutes) {
if (isPlaying.value)
return;
targetMinutes.value = minutes;
}
function onTogglePlay() {
if (isPlaying.value) {
pauseTraining();
} else {
if (totalReps.value === 0) {
resetStats();
}
startTrainingInternal();
}
}
function startTrainingInternal() {
startRhythm();
startBgm();
startTimer();
common_vendor.index.setKeepScreenOn({ keepScreenOn: true });
}
function pauseTraining() {
stopRhythm();
stopBgm();
stopTimer();
common_vendor.index.setKeepScreenOn({ keepScreenOn: false });
}
function onEndTraining() {
if (totalReps.value === 0)
return;
pauseTraining();
showSummary.value = true;
}
function dismissSummary() {
showSummary.value = false;
resetStats();
}
function onFinish() {
showSummary.value = false;
resetStats();
}
function onRestart() {
showSummary.value = false;
resetStats();
startTrainingInternal();
}
function resetStats() {
totalReps.value = 0;
elapsedSeconds.value = 0;
totalSugar.value = 0;
beatCount.value = 0;
rewardIndex.value = 0;
startTime.value = Date.now();
const firstReward = MILESTONES[0];
const range = firstReward.maxReps - firstReward.minReps;
nextRewardAt.value = firstReward.minReps + Math.floor(Math.random() * (range + 1));
}
function startTimer() {
if (timerInterval.value)
return;
startTime.value = Date.now() - elapsedSeconds.value * 1e3;
timerInterval.value = setInterval(() => {
elapsedSeconds.value = Math.floor((Date.now() - startTime.value) / 1e3);
totalSugar.value = calculateSugar(elapsedSeconds.value);
if (targetMinutes.value > 0 && elapsedSeconds.value >= targetMinutes.value * 60) {
onEndTraining();
}
}, 1e3);
}
function stopTimer() {
if (timerInterval.value) {
clearInterval(timerInterval.value);
timerInterval.value = null;
}
}
common_vendor.onShareAppMessage(() => ({
title: shareTitle.value,
path: "/training/pages/pilates-ring",
imageUrl: TUTORIAL_POSTER_URL
}));
common_vendor.onShareTimeline(() => ({
title: shareTitle.value,
imageUrl: TUTORIAL_POSTER_URL
}));
function cleanupAllMedia() {
var _a;
stopRhythm();
stopTimer();
common_vendor.index.setKeepScreenOn({ keepScreenOn: false });
try {
(_a = common_vendor.index.createVideoContext("pilatesDemoVideo")) == null ? void 0 : _a.pause();
} catch (_) {
}
if (bgmAudioCtx.value) {
try {
bgmAudioCtx.value.stop();
} catch (_) {
}
try {
bgmAudioCtx.value.destroy();
} catch (_) {
}
bgmAudioCtx.value = null;
}
}
common_vendor.onHide(cleanupAllMedia);
common_vendor.onUnload(cleanupAllMedia);
return (_ctx, _cache) => {
return common_vendor.e({
a: common_vendor.t(statusText.value),
b: isPlaying.value ? 1 : "",
c: isPaused.value ? 1 : "",
d: TUTORIAL_VIDEO_URL,
e: TUTORIAL_POSTER_URL,
f: !isPlaying.value
}, !isPlaying.value ? {
g: common_vendor.t(centerHintText.value)
} : {
h: common_vendor.t(currentBpm.value)
}, {
i: common_vendor.o(onTogglePlay, "20"),
j: isPlaying.value ? 1 : "",
k: common_vendor.t(bgmEnabled.value ? "🎵" : "🔇"),
l: common_vendor.o(toggleBgm, "d5"),
m: remainingSeconds.value !== null && hasStats.value
}, remainingSeconds.value !== null && hasStats.value ? {
n: common_vendor.t(formatTime(remainingSeconds.value))
} : {}, {
o: isPlaying.value
}, isPlaying.value ? {} : {}, {
p: common_vendor.f(PILATES_PRESETS, (p, k0, i0) => {
return {
a: common_vendor.t(p.label),
b: common_vendor.t(p.bpm),
c: p.id,
d: currentPreset.value === p.id ? 1 : "",
e: common_vendor.o(($event) => onPresetTap(p.id), p.id)
};
}),
q: isPlaying.value ? 1 : "",
r: common_vendor.t(currentTargetLabel.value),
s: common_vendor.t(targetExpanded.value ? "▲" : "▼"),
t: common_vendor.o(($event) => targetExpanded.value = !targetExpanded.value, "31"),
v: targetExpanded.value
}, targetExpanded.value ? {
w: common_vendor.f(TARGET_OPTIONS, (t, k0, i0) => {
return {
a: common_vendor.t(t.label),
b: t.minutes,
c: targetMinutes.value === t.minutes ? 1 : "",
d: common_vendor.o(($event) => onTargetTap(t.minutes), t.minutes)
};
}),
x: isPlaying.value ? 1 : ""
} : {}, {
y: common_vendor.t(benefitExpanded.value ? "收起 ▲" : "展开 ▼"),
z: common_vendor.o(($event) => benefitExpanded.value = !benefitExpanded.value, "53"),
A: benefitExpanded.value
}, benefitExpanded.value ? {
B: common_vendor.f(TRAINING_BENEFIT.muscles, (m, k0, i0) => {
return {
a: common_vendor.t(m),
b: m
};
}),
C: common_vendor.t(TRAINING_BENEFIT.effect)
} : {}, {
D: isPaused.value
}, isPaused.value ? {
E: common_vendor.o(onTogglePlay, "9c"),
F: common_vendor.o(onEndTraining, "77")
} : {}, {
G: isPlaying.value ? 1 : "",
H: isPaused.value ? 1 : "",
I: common_vendor.s(rootStyle.value),
J: showRewardPopup.value
}, showRewardPopup.value ? {
K: common_vendor.t(currentReward.value.emoji),
L: common_vendor.t(currentReward.value.title),
M: common_vendor.t(currentReward.value.desc),
N: common_vendor.t(totalReps.value),
O: common_vendor.o(closeRewardPopup, "fd"),
P: common_vendor.o(() => {
}, "9e"),
Q: common_vendor.o(closeRewardPopup, "a4")
} : {}, {
R: showSummary.value
}, showSummary.value ? common_vendor.e({
S: common_vendor.t(totalReps.value),
T: common_vendor.t(formatTime(elapsedSeconds.value)),
U: common_vendor.t(totalSugar.value.toFixed(1)),
V: sugarComparisons.value.length > 0
}, sugarComparisons.value.length > 0 ? {
W: common_vendor.f(sugarComparisons.value, (food, idx, i0) => {
return {
a: common_vendor.t(food.emoji),
b: common_vendor.t(food.count),
c: common_vendor.t(food.unit),
d: common_vendor.t(food.name),
e: idx
};
})
} : {}, {
X: common_vendor.o(onRestart, "bc"),
Y: common_vendor.o(onFinish, "90"),
Z: common_vendor.o(() => {
}, "99"),
aa: common_vendor.o(dismissSummary, "b4")
}) : {});
};
}
});
_sfc_defineComponent.__runtimeHooks = 6;
const MiniProgramPage = /* @__PURE__ */ common_vendor._export_sfc(_sfc_defineComponent, [["__scopeId", "data-v-6dc323a3"]]);
wx.createPage(MiniProgramPage);
//# sourceMappingURL=../../../.sourcemap/mp-weixin/training/pages/pilates-ring.js.map