|
|
|
<template>
|
|
|
|
<up-popup
|
|
|
|
:show="actionShow"
|
|
|
|
mode="bottom"
|
|
|
|
minHeight="90vh"
|
|
|
|
@close="actionShow = false"
|
|
|
|
bgColor="#1a1a1a"
|
|
|
|
>
|
|
|
|
<scroll-view class="action-container" scroll-y>
|
|
|
|
<view class="header" v-if="type == 1">
|
|
|
|
<view class="explain">
|
|
|
|
<image
|
|
|
|
v-if="modeTab < 2"
|
|
|
|
:src="modeTab == 0 ? actionDetail.url3dAnimation : actionDetail.urlRealPerson"
|
|
|
|
class="media-content"
|
|
|
|
mode="aspectFill"
|
|
|
|
/>
|
|
|
|
<view class="video" v-else @click="playVideo(actionDetail.urlTutorial)">
|
|
|
|
<video
|
|
|
|
:src="actionDetail.urlTutorial"
|
|
|
|
class="media-content"
|
|
|
|
:autoplay="false"
|
|
|
|
:show-center-play-btn="false"
|
|
|
|
:controls="false"
|
|
|
|
/>
|
|
|
|
<view class="play-icon">
|
|
|
|
<up-icon name="play-right" size="28" class="icon" color="#fff"></up-icon>
|
|
|
|
</view>
|
|
|
|
</view>
|
|
|
|
</view>
|
|
|
|
|
|
|
|
<view class="mode-tabs" v-if="actionDetail.urlRealPerson || actionDetail.urlTutorial">
|
|
|
|
<view
|
|
|
|
class="tab-item"
|
|
|
|
v-if="actionDetail.url3dAnimation"
|
|
|
|
:class="{ active: modeTab == 0 }"
|
|
|
|
@click="switchModeTab(0)"
|
|
|
|
>
|
|
|
|
3D
|
|
|
|
</view>
|
|
|
|
<view
|
|
|
|
class="tab-item"
|
|
|
|
v-if="actionDetail.urlRealPerson"
|
|
|
|
:class="{ active: modeTab == 1 }"
|
|
|
|
@click="switchModeTab(1)"
|
|
|
|
>
|
|
|
|
真人
|
|
|
|
</view>
|
|
|
|
<view
|
|
|
|
class="tab-item"
|
|
|
|
v-if="actionDetail.urlTutorial"
|
|
|
|
:class="{ active: modeTab == 2 }"
|
|
|
|
@click="switchModeTab(2)"
|
|
|
|
>
|
|
|
|
讲解
|
|
|
|
</view>
|
|
|
|
</view>
|
|
|
|
</view>
|
|
|
|
|
|
|
|
<view class="main">
|
|
|
|
<view class="main-header">
|
|
|
|
<view class="title-bar">
|
|
|
|
<text class="title">{{ actionDetail?.name }}</text>
|
|
|
|
<view class="action-icons">
|
|
|
|
<!-- <up-icon name="share-square" color="#fff" size="24"></up-icon> -->
|
|
|
|
<button class="share-btn" open-type="share">
|
|
|
|
<uni-icons type="paperplane" size="24" color="#fff"></uni-icons>
|
|
|
|
</button>
|
|
|
|
<up-icon
|
|
|
|
:name="isFavorite ? 'star-fill' : 'star'"
|
|
|
|
:color="isFavorite ? '#fedc1f' : '#fff'"
|
|
|
|
size="24"
|
|
|
|
@click="toggleCollect"
|
|
|
|
></up-icon>
|
|
|
|
<!-- <FavoriteBtn :id="actionId" :type="type" /> -->
|
|
|
|
</view>
|
|
|
|
</view>
|
|
|
|
<!-- 要点,历史,平替动作标签 -->
|
|
|
|
<view class="content-tabs">
|
|
|
|
<view class="tab-item" :class="{ active: contentTab === 0 }" @click="contentTab = 0">
|
|
|
|
要点
|
|
|
|
</view>
|
|
|
|
<view class="tab-item" :class="{ active: contentTab === 1 }" @click="contentTab = 1">
|
|
|
|
历史
|
|
|
|
</view>
|
|
|
|
<view
|
|
|
|
class="tab-item"
|
|
|
|
:class="{ active: contentTab === 2 }"
|
|
|
|
@click="contentTab = 2"
|
|
|
|
v-if="type === 1"
|
|
|
|
>
|
|
|
|
平替动作
|
|
|
|
</view>
|
|
|
|
</view>
|
|
|
|
</view>
|
|
|
|
|
|
|
|
<view class="main-content">
|
|
|
|
<!-- 1 要点 -->
|
|
|
|
<view v-if="contentTab === 0" class="tab-pane slide-up">
|
|
|
|
<view class="section" v-if="actionDetail.urlTutorial">
|
|
|
|
<view class="section-title">视频讲解</view>
|
|
|
|
<view class="video-grid">
|
|
|
|
<!-- <view class="video-card" v-for="i in 2" :key="i"></view> -->
|
|
|
|
<view class="video-card" @click="playVideo(actionDetail.urlTutorial)">
|
|
|
|
<video
|
|
|
|
:src="actionDetail.urlTutorial"
|
|
|
|
class="video"
|
|
|
|
:autoplay="false"
|
|
|
|
:show-center-play-btn="false"
|
|
|
|
:controls="false"
|
|
|
|
/>
|
|
|
|
<view class="play-overlay"
|
|
|
|
><up-icon name="play-circle-fill" color="#fff" size="30"></up-icon
|
|
|
|
></view>
|
|
|
|
</view>
|
|
|
|
</view>
|
|
|
|
</view>
|
|
|
|
|
|
|
|
<view class="memo-box" @click="openBeizhu">
|
|
|
|
<view class="section-title">训练备注</view>
|
|
|
|
<up-textarea
|
|
|
|
class="textarea"
|
|
|
|
v-model="actionDetail.userNote"
|
|
|
|
placeholder="点击填写备注"
|
|
|
|
autoHeight
|
|
|
|
customStyle="background: transparent; border: none; padding: 10rpx 0;"
|
|
|
|
placeholderStyle="color: #666"
|
|
|
|
disabled
|
|
|
|
border="none"
|
|
|
|
></up-textarea>
|
|
|
|
</view>
|
|
|
|
<!-- 动作列表,只有超级组才有 -->
|
|
|
|
<view class="section" v-if="type === 2">
|
|
|
|
<view class="section-title">动作列表</view>
|
|
|
|
<view class="action-list">
|
|
|
|
<!-- 动作循环列表 -->
|
|
|
|
<view
|
|
|
|
class="action-item"
|
|
|
|
v-for="item in actionDetail?.exercises"
|
|
|
|
:key="item.id"
|
|
|
|
@click="openActionItem(item)"
|
|
|
|
>
|
|
|
|
<image :src="item.url3dAnimation || lostImage" mode="aspectFill" class="img" />
|
|
|
|
<view class="middle">
|
|
|
|
<view class="name">{{ item.name }}</view>
|
|
|
|
<view class="tips">
|
|
|
|
<!-- 渲染主练肌肉标签 -->
|
|
|
|
<view class="tip" v-for="p in item.primaryMuscles" :key="p">
|
|
|
|
{{ p }}
|
|
|
|
</view>
|
|
|
|
<view v-for="s in item.secondaryMuscles" :key="s">{{ s }}</view>
|
|
|
|
</view>
|
|
|
|
</view>
|
|
|
|
<up-icon name="arrow-right" color="#fff" size="16"></up-icon>
|
|
|
|
</view>
|
|
|
|
</view>
|
|
|
|
</view>
|
|
|
|
|
|
|
|
<view class="section" v-if="type == 1">
|
|
|
|
<view class="section-title">步骤</view>
|
|
|
|
<view class="steps-list">
|
|
|
|
<rich-text class="step-text" :nodes="actionDetail.stepDescription"></rich-text>
|
|
|
|
</view>
|
|
|
|
</view>
|
|
|
|
|
|
|
|
<view class="section">
|
|
|
|
<view class="section-title">训练部位</view>
|
|
|
|
<image :src="actionDetail.urlImage" mode="widthFix" class="muscle-map" />
|
|
|
|
<view class="legend">
|
|
|
|
<view class="legend-item">
|
|
|
|
<view class="legend-color primary"></view>
|
|
|
|
<text class="legend-text">主要部位</text>
|
|
|
|
</view>
|
|
|
|
<view class="legend-item">
|
|
|
|
<view class="legend-color secondary"></view>
|
|
|
|
<text class="legend-text">次要部位</text>
|
|
|
|
</view>
|
|
|
|
</view>
|
|
|
|
</view>
|
|
|
|
</view>
|
|
|
|
<!-- 2 历史 -->
|
|
|
|
<view v-if="contentTab === 1" class="tab-pane slide-up">
|
|
|
|
<!-- <view class="stat-card highlight">
|
|
|
|
<text class="label">最长时长</text>
|
|
|
|
<text class="value">01:02:03</text>
|
|
|
|
<text class="date">记录于 2026/03/04</text>
|
|
|
|
</view> -->
|
|
|
|
|
|
|
|
<!-- <view class="chart-container" v-if="chartData && chartData.series">
|
|
|
|
<qiun-data-charts type="line" :opts="chartOpts" :chartData="chartData" />
|
|
|
|
</view> -->
|
|
|
|
|
|
|
|
<view class="history-list">
|
|
|
|
<template v-if="historyList.length > 0">
|
|
|
|
<view class="history-item" v-for="item in historyList" :key="item.id">
|
|
|
|
<view class="item-header">
|
|
|
|
<text class="date">{{ formatDate(item.date) }}</text>
|
|
|
|
<text class="tag">{{ item.name }}</text>
|
|
|
|
</view>
|
|
|
|
<view class="item-body">
|
|
|
|
<view class="count">
|
|
|
|
<view>共 {{ item.setCount }} 组训练</view>
|
|
|
|
<view class="dot">· </view>
|
|
|
|
<!-- <view class="difficulty">困难</view> -->
|
|
|
|
<view class="difficulty">{{
|
|
|
|
item.weight ? item.weight + 'kg' : '无负重'
|
|
|
|
}}</view>
|
|
|
|
</view>
|
|
|
|
<view class="group-chips">
|
|
|
|
<view class="chip" v-for="(set, index) in item.setConfigList" :key="index">
|
|
|
|
<view class="idx">{{ index + 1 }}</view>
|
|
|
|
<view class="group-data">
|
|
|
|
{{ formatSetData(set) }}
|
|
|
|
</view>
|
|
|
|
</view>
|
|
|
|
</view>
|
|
|
|
</view>
|
|
|
|
</view>
|
|
|
|
</template>
|
|
|
|
<template v-else>
|
|
|
|
<up-empty text="暂无训练历史"> </up-empty>
|
|
|
|
</template>
|
|
|
|
</view>
|
|
|
|
</view>
|
|
|
|
<!-- 3 平替动作(只有动作组才有) -->
|
|
|
|
<view v-if="contentTab === 2 && type === 1" class="tab-pane slide-up">
|
|
|
|
<view class="substitute-list">
|
|
|
|
<view
|
|
|
|
class="sub-item"
|
|
|
|
v-for="item in alternativeActions"
|
|
|
|
:key="item.id"
|
|
|
|
@click="openActionItem(item)"
|
|
|
|
>
|
|
|
|
<image :src="item.urlImage || lostImage" mode="aspectFill" class="img" />
|
|
|
|
<view class="sub-info">
|
|
|
|
<text class="name">{{ item.name }}</text>
|
|
|
|
|
|
|
|
<text class="meta">练过{{ item.trainingReps }}次</text>
|
|
|
|
</view>
|
|
|
|
<up-icon name="arrow-right" color="#666" size="16"></up-icon>
|
|
|
|
</view>
|
|
|
|
</view>
|
|
|
|
</view>
|
|
|
|
</view>
|
|
|
|
</view>
|
|
|
|
<view class="footer">
|
|
|
|
<view class="btn" @click="startTraining">开始训练</view>
|
|
|
|
</view>
|
|
|
|
</scroll-view>
|
|
|
|
<!-- 备注弹窗组件 -->
|
|
|
|
<beizhu ref="showBeizhuRef" @saveSuccess="handleNoteSave" />
|
|
|
|
</up-popup>
|
|
|
|
</template>
|
|
|
|
|
|
|
|
<script setup>
|
|
|
|
import { onMounted, ref, nextTick } from 'vue';
|
|
|
|
import ExercisesApi from '@/sheep/api/motion/exercises';
|
|
|
|
import beizhu from '@/pages/xunji/components/beizhu.vue';
|
|
|
|
import SupersetsApi from '@/sheep/api/motion/supersets';
|
|
|
|
import TrainingApi from '@/sheep/api/Training/traininghistory';
|
|
|
|
import { onShareAppMessage } from '@dcloudio/uni-app';
|
|
|
|
|
|
|
|
// 静态配置
|
|
|
|
|
|
|
|
const alternativeActions = ref([]); // 平替动作列表接口数据
|
|
|
|
|
|
|
|
// 响应式状态
|
|
|
|
const actionShow = ref(false);
|
|
|
|
const modeTab = ref(0);
|
|
|
|
const contentTab = ref(0);
|
|
|
|
const isFavorite = ref(false);
|
|
|
|
|
|
|
|
// 记录当前动作的详细数据
|
|
|
|
const actionDetail = ref({});
|
|
|
|
// 记录当前动作的id
|
|
|
|
const actionId = ref(0);
|
|
|
|
// 记录是超级组还是动作组 1=动作组,2=超级组
|
|
|
|
const type = ref(0);
|
|
|
|
const showBeizhuRef = ref(null);
|
|
|
|
const historyList = ref([]); // 训练历史列表接口数据
|
|
|
|
const lostImage =
|
|
|
|
'https://fitness-hcxtec-bucket.oss-cn-shenzhen.aliyuncs.com/20260316/order-empty_1773628059920.png';
|
|
|
|
|
|
|
|
// 切换图表模式
|
|
|
|
const switchModeTab = (index) => {
|
|
|
|
modeTab.value = index;
|
|
|
|
};
|
|
|
|
|
|
|
|
// 跳转到视频播放的页面
|
|
|
|
const playVideo = (url) => {
|
|
|
|
uni.navigateTo({
|
|
|
|
url: '/pages4/pages/xunji/xunji-shiping?url=' + url,
|
|
|
|
});
|
|
|
|
};
|
|
|
|
// 获取动作收藏状态
|
|
|
|
const checkExerciseFavorited = async () => {
|
|
|
|
try {
|
|
|
|
const res = await ExercisesApi.checkExerciseFavorited(actionId.value);
|
|
|
|
isFavorite.value = res.data;
|
|
|
|
} catch (err) {
|
|
|
|
console.log(err);
|
|
|
|
}
|
|
|
|
};
|
|
|
|
// 收藏
|
|
|
|
const toggleCollect = async () => {
|
|
|
|
try {
|
|
|
|
const status = isFavorite.value ? 0 : 1;
|
|
|
|
if (type == 1) {
|
|
|
|
await ExercisesApi.toggleFavorite(actionId.value, status);
|
|
|
|
} else {
|
|
|
|
await SupersetsApi.toggleFavorite(actionId.value, status);
|
|
|
|
}
|
|
|
|
|
|
|
|
isFavorite.value = !isFavorite.value;
|
|
|
|
} catch (err) {
|
|
|
|
console.log(err);
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
// 获取超级组收藏状态
|
|
|
|
const checkSupersetFavorited = async () => {
|
|
|
|
try {
|
|
|
|
const res = await SupersetsApi.checkSupersetFavorited(actionId.value);
|
|
|
|
isFavorite.value = res.data;
|
|
|
|
} catch (err) {
|
|
|
|
console.log(err);
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
const startTraining = () => {
|
|
|
|
uni.navigateTo({
|
|
|
|
url: `/pages4/pages/xunji/xunji-dongzuo-lianxi?id=${actionId.value}&type=${type.value}`,
|
|
|
|
});
|
|
|
|
};
|
|
|
|
|
|
|
|
const open = (id, typeData) => {
|
|
|
|
actionId.value = Number(id);
|
|
|
|
|
|
|
|
type.value = typeData;
|
|
|
|
contentTab.value = 0;
|
|
|
|
// 如何判断是动作还是超级组
|
|
|
|
if (typeData == 1) {
|
|
|
|
loadexercisedetail(actionId.value);
|
|
|
|
loadAlternativeActions(actionId.value);
|
|
|
|
checkExerciseFavorited();
|
|
|
|
} else {
|
|
|
|
loadsuperdetail(actionId.value);
|
|
|
|
checkSupersetFavorited();
|
|
|
|
}
|
|
|
|
|
|
|
|
loadTrainHistoryDetail(actionId.value);
|
|
|
|
actionShow.value = true;
|
|
|
|
};
|
|
|
|
// 打开备注弹窗
|
|
|
|
const openBeizhu = () => {
|
|
|
|
nextTick(() => {
|
|
|
|
if (showBeizhuRef.value) {
|
|
|
|
showBeizhuRef.value.open(actionId.value);
|
|
|
|
}
|
|
|
|
});
|
|
|
|
};
|
|
|
|
|
|
|
|
// 接收子组件传过来的备注内容
|
|
|
|
const handleNoteSave = async (content) => {
|
|
|
|
try {
|
|
|
|
if (type.value == 2) {
|
|
|
|
await SupersetsApi.addNotes({
|
|
|
|
supersetsId: actionId.value,
|
|
|
|
content: content,
|
|
|
|
});
|
|
|
|
} else {
|
|
|
|
await ExercisesApi.addNotes({
|
|
|
|
exerciseId: actionId.value,
|
|
|
|
content: content,
|
|
|
|
});
|
|
|
|
}
|
|
|
|
actionDetail.value.userNote = content;
|
|
|
|
} catch (e) {
|
|
|
|
console.log(e);
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
// 启用分享菜单
|
|
|
|
// #ifdef MP-WEIXIN
|
|
|
|
wx.showShareMenu({
|
|
|
|
withShareTicket: true,
|
|
|
|
menus: ['shareAppMessage', 'shareTimeline'],
|
|
|
|
});
|
|
|
|
// #endif
|
|
|
|
// 定义分享内容
|
|
|
|
onShareAppMessage((res) => {
|
|
|
|
// res.from 可区分触发来源:'button'(按钮触发)或 'menu'(右上角菜单触发)[reference:3]
|
|
|
|
console.log('分享触发来源:', res.from);
|
|
|
|
return {
|
|
|
|
title: actionDetail.value.name || '健身动作分享', // 分享标题
|
|
|
|
// path: `/pages4/pages/xunji/xunji-dongzuo-xiangqing?id=${id.value}`, // 分享路径
|
|
|
|
path: `/pages/xunji/xunji?currentTab=${3}`,
|
|
|
|
imageUrl: actionDetail.value.urlImage || lostImage, // 分享图片
|
|
|
|
};
|
|
|
|
});
|
|
|
|
|
|
|
|
// 加载单个动作详情
|
|
|
|
const loadexercisedetail = async (id) => {
|
|
|
|
const response = await ExercisesApi.getExerciseById(id);
|
|
|
|
actionDetail.value = response.data;
|
|
|
|
if (actionDetail.value.url3dAnimation) {
|
|
|
|
modeTab.value = 0;
|
|
|
|
} else if (actionDetail.value.urlRealPerson) {
|
|
|
|
modeTab.value = 1;
|
|
|
|
} else {
|
|
|
|
modeTab.value = 2;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
// 加载超级组详情
|
|
|
|
const loadsuperdetail = async (id) => {
|
|
|
|
const response = await SupersetsApi.getSupersetsInfo(id);
|
|
|
|
actionDetail.value = response.data;
|
|
|
|
console.log('显示超级组详情:', actionDetail.value);
|
|
|
|
};
|
|
|
|
// 2. 加载平替动作的函数
|
|
|
|
const loadAlternativeActions = async (id) => {
|
|
|
|
if (!id || isNaN(Number(id))) {
|
|
|
|
console.warn('平替动作id非法,跳过请求:', id);
|
|
|
|
alternativeActions.value = [];
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
try {
|
|
|
|
const res = await ExercisesApi.getalternatives(id);
|
|
|
|
if (res.code === 0 && res.data) {
|
|
|
|
alternativeActions.value = Array.isArray(res.data) ? res.data : [];
|
|
|
|
} else {
|
|
|
|
alternativeActions.value = [];
|
|
|
|
}
|
|
|
|
} catch (error) {
|
|
|
|
console.error('加载平替动作失败:', error);
|
|
|
|
alternativeActions.value = [];
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
// 加载训练历史
|
|
|
|
const loadTrainHistoryDetail = async (id) => {
|
|
|
|
try {
|
|
|
|
const res = await TrainingApi.getTrainHistoryList(id);
|
|
|
|
historyList.value = res.data;
|
|
|
|
console.log('训练历史列表接口返回结果historyList.value', historyList.value);
|
|
|
|
} catch (error) {
|
|
|
|
console.error('加载训练历史失败:', error);
|
|
|
|
}
|
|
|
|
};
|
|
|
|
// 格式化时间
|
|
|
|
const formatDate = (dateArr) => {
|
|
|
|
if (!Array.isArray(dateArr) || dateArr.length < 3) return '';
|
|
|
|
const [year, month, day] = dateArr;
|
|
|
|
const date = new Date(year, month - 1, day);
|
|
|
|
const weekArr = ['周日', '周一', '周二', '周三', '周四', '周五', '周六'];
|
|
|
|
const week = weekArr[date.getDay()];
|
|
|
|
return `${year}/${String(month).padStart(2, '0')}/${String(day).padStart(2, '0')} ${week}`;
|
|
|
|
};
|
|
|
|
|
|
|
|
// 格式化每组数据:自动拼接 weight/reps/duration/distance
|
|
|
|
const formatSetData = (set) => {
|
|
|
|
const parts = [];
|
|
|
|
|
|
|
|
// 重量
|
|
|
|
if (set.weight != null && set.weight !== '') {
|
|
|
|
parts.push(`${set.weight}kg`);
|
|
|
|
}
|
|
|
|
|
|
|
|
// 次数
|
|
|
|
if (set.reps != null && set.reps !== '') {
|
|
|
|
parts.push(`${set.reps}次`);
|
|
|
|
}
|
|
|
|
|
|
|
|
// 时长(自动转 时:分:秒)
|
|
|
|
if (set.duration != null && set.duration !== '') {
|
|
|
|
parts.push(formatTime(set.duration));
|
|
|
|
}
|
|
|
|
|
|
|
|
// 距离
|
|
|
|
if (set.distance != null && set.distance !== '') {
|
|
|
|
parts.push(`${set.distance}m`);
|
|
|
|
}
|
|
|
|
|
|
|
|
return parts.length > 0 ? parts.join(' × ') : '无数据';
|
|
|
|
};
|
|
|
|
|
|
|
|
// 新增:秒数转 00:00:00 格式
|
|
|
|
const formatTime = (seconds) => {
|
|
|
|
const h = Math.floor(seconds / 3600);
|
|
|
|
const m = Math.floor((seconds % 3600) / 60);
|
|
|
|
const s = seconds % 60;
|
|
|
|
|
|
|
|
const hh = h > 0 ? String(h).padStart(2, '0') + ':' : '';
|
|
|
|
const mm = String(m).padStart(2, '0') + ':';
|
|
|
|
const ss = String(s).padStart(2, '0');
|
|
|
|
|
|
|
|
return hh + mm + ss;
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
// 点击超级组内部的动作 → 打开动作详情(复用同一个组件)
|
|
|
|
const openActionItem = (item) => {
|
|
|
|
open(item.id, 1);
|
|
|
|
};
|
|
|
|
|
|
|
|
defineExpose({ open });
|
|
|
|
|
|
|
|
onMounted(() => {});
|
|
|
|
</script>
|
|
|
|
|
|
|
|
<style lang="scss" scoped>
|
|
|
|
.action-container {
|
|
|
|
width: 100%;
|
|
|
|
height: 80vh;
|
|
|
|
background-color: #1a1a1a;
|
|
|
|
color: #ffffff;
|
|
|
|
|
|
|
|
.header {
|
|
|
|
width: 100%;
|
|
|
|
height: 50vh;
|
|
|
|
position: relative;
|
|
|
|
|
|
|
|
.explain {
|
|
|
|
width: 100%;
|
|
|
|
height: 100%;
|
|
|
|
|
|
|
|
.media-content {
|
|
|
|
width: 100%;
|
|
|
|
height: 100%;
|
|
|
|
}
|
|
|
|
.video {
|
|
|
|
width: 100%;
|
|
|
|
height: 100%;
|
|
|
|
display: flex;
|
|
|
|
justify-content: center;
|
|
|
|
align-items: center;
|
|
|
|
position: relative;
|
|
|
|
.play-icon {
|
|
|
|
width: 50px;
|
|
|
|
height: 50px;
|
|
|
|
background-color: rgb(216, 209, 209, 0.8);
|
|
|
|
display: flex;
|
|
|
|
justify-content: center;
|
|
|
|
align-items: center;
|
|
|
|
border-radius: 50%;
|
|
|
|
position: absolute;
|
|
|
|
z-index: 10;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
.mode-tabs {
|
|
|
|
position: absolute;
|
|
|
|
bottom: 30rpx;
|
|
|
|
left: 30rpx;
|
|
|
|
display: flex;
|
|
|
|
background: rgba(0, 0, 0, 0.6);
|
|
|
|
padding: 6rpx;
|
|
|
|
border-radius: 12rpx;
|
|
|
|
backdrop-filter: blur(10px);
|
|
|
|
z-index: 99;
|
|
|
|
.tab-item {
|
|
|
|
padding: 8rpx 24rpx;
|
|
|
|
font-size: 24rpx;
|
|
|
|
color: #999;
|
|
|
|
transition: all 0.3s;
|
|
|
|
|
|
|
|
&.active {
|
|
|
|
background: #444;
|
|
|
|
color: #fff;
|
|
|
|
border-radius: 8rpx;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
.main {
|
|
|
|
.main-header {
|
|
|
|
position: sticky;
|
|
|
|
top: 0;
|
|
|
|
z-index: 10;
|
|
|
|
background: #1a1a1a;
|
|
|
|
padding: 30rpx 30rpx 0;
|
|
|
|
|
|
|
|
.title-bar {
|
|
|
|
display: flex;
|
|
|
|
justify-content: space-between;
|
|
|
|
align-items: center;
|
|
|
|
margin-bottom: 30rpx;
|
|
|
|
|
|
|
|
.title {
|
|
|
|
font-size: 48rpx;
|
|
|
|
font-weight: bold;
|
|
|
|
}
|
|
|
|
|
|
|
|
.action-icons {
|
|
|
|
display: flex;
|
|
|
|
gap: 30rpx;
|
|
|
|
|
|
|
|
.share-btn {
|
|
|
|
background: transparent;
|
|
|
|
border: none;
|
|
|
|
padding: 0;
|
|
|
|
margin: 0;
|
|
|
|
line-height: 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
.content-tabs {
|
|
|
|
display: flex;
|
|
|
|
gap: 60rpx;
|
|
|
|
border-bottom: 1rpx solid #333;
|
|
|
|
|
|
|
|
.tab-item {
|
|
|
|
padding-bottom: 20rpx;
|
|
|
|
font-size: 30rpx;
|
|
|
|
color: #666;
|
|
|
|
position: relative;
|
|
|
|
|
|
|
|
&.active {
|
|
|
|
color: #fff;
|
|
|
|
font-weight: 500;
|
|
|
|
|
|
|
|
&::after {
|
|
|
|
content: '';
|
|
|
|
position: absolute;
|
|
|
|
bottom: 0;
|
|
|
|
left: 0;
|
|
|
|
width: 100%;
|
|
|
|
height: 4rpx;
|
|
|
|
background: #fedc1f;
|
|
|
|
border-radius: 2rpx;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
.main-content {
|
|
|
|
padding: 40rpx 30rpx 160rpx;
|
|
|
|
|
|
|
|
.section {
|
|
|
|
margin-bottom: 40rpx;
|
|
|
|
}
|
|
|
|
|
|
|
|
.section-title {
|
|
|
|
font-size: 32rpx;
|
|
|
|
font-weight: bold;
|
|
|
|
margin-bottom: 24rpx;
|
|
|
|
color: #ddd;
|
|
|
|
}
|
|
|
|
|
|
|
|
.action-list {
|
|
|
|
.action-item {
|
|
|
|
display: flex;
|
|
|
|
align-items: center;
|
|
|
|
justify-content: space-between;
|
|
|
|
padding: 20rpx;
|
|
|
|
box-sizing: border-box;
|
|
|
|
gap: 15rpx;
|
|
|
|
background-color: #262626;
|
|
|
|
border-radius: 10rpx;
|
|
|
|
margin-bottom: 15rpx;
|
|
|
|
|
|
|
|
.img {
|
|
|
|
width: 120rpx;
|
|
|
|
height: 120rpx;
|
|
|
|
border-radius: 5rpx;
|
|
|
|
}
|
|
|
|
|
|
|
|
.middle {
|
|
|
|
flex: 1;
|
|
|
|
height: 120rpx;
|
|
|
|
|
|
|
|
.name {
|
|
|
|
margin-bottom: 20rpx;
|
|
|
|
}
|
|
|
|
|
|
|
|
.tips {
|
|
|
|
display: flex;
|
|
|
|
gap: 10rpx;
|
|
|
|
align-items: center;
|
|
|
|
flex-wrap: wrap;
|
|
|
|
font-size: 20rpx;
|
|
|
|
|
|
|
|
.tip {
|
|
|
|
color: #fedc1f;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// 要点板块样式
|
|
|
|
.video-grid {
|
|
|
|
display: grid;
|
|
|
|
grid-template-columns: 1fr 1fr;
|
|
|
|
gap: 20rpx;
|
|
|
|
margin-bottom: 40rpx;
|
|
|
|
|
|
|
|
.video-card {
|
|
|
|
height: 360rpx;
|
|
|
|
position: relative;
|
|
|
|
border-radius: 16rpx;
|
|
|
|
overflow: hidden;
|
|
|
|
background: #333;
|
|
|
|
|
|
|
|
.video {
|
|
|
|
width: 100%;
|
|
|
|
height: 100%;
|
|
|
|
}
|
|
|
|
|
|
|
|
.play-overlay {
|
|
|
|
position: absolute;
|
|
|
|
top: 20rpx;
|
|
|
|
right: 20rpx;
|
|
|
|
|
|
|
|
pointer-events: none;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
.memo-box {
|
|
|
|
background: #262626;
|
|
|
|
padding: 24rpx;
|
|
|
|
border-radius: 16rpx;
|
|
|
|
margin-bottom: 40rpx;
|
|
|
|
|
|
|
|
.textarea {
|
|
|
|
height: 50rpx;
|
|
|
|
|
|
|
|
:deep(.u-textarea--disabled) {
|
|
|
|
background-color: #262626;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
.steps-list {
|
|
|
|
display: flex;
|
|
|
|
flex-direction: column;
|
|
|
|
gap: 16rpx;
|
|
|
|
background: #262626;
|
|
|
|
padding: 20rpx;
|
|
|
|
box-sizing: border-box;
|
|
|
|
border-radius: 16rpx;
|
|
|
|
|
|
|
|
.step-text {
|
|
|
|
font-size: 26rpx;
|
|
|
|
line-height: 1.6;
|
|
|
|
color: #bbb;
|
|
|
|
list-style: none;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
.muscle-map {
|
|
|
|
width: 100%;
|
|
|
|
border-radius: 16rpx;
|
|
|
|
}
|
|
|
|
|
|
|
|
.legend {
|
|
|
|
display: flex;
|
|
|
|
justify-content: flex-end;
|
|
|
|
align-items: center;
|
|
|
|
gap: 20rpx;
|
|
|
|
margin-top: 20rpx;
|
|
|
|
}
|
|
|
|
|
|
|
|
.legend-item {
|
|
|
|
display: flex;
|
|
|
|
align-items: center;
|
|
|
|
gap: 10rpx;
|
|
|
|
}
|
|
|
|
|
|
|
|
.legend-color {
|
|
|
|
width: 16rpx;
|
|
|
|
height: 16rpx;
|
|
|
|
border-radius: 4rpx;
|
|
|
|
}
|
|
|
|
|
|
|
|
.legend-color.primary {
|
|
|
|
background-color: #ffd700;
|
|
|
|
}
|
|
|
|
|
|
|
|
.legend-color.secondary {
|
|
|
|
background-color: #999;
|
|
|
|
}
|
|
|
|
|
|
|
|
.legend-text {
|
|
|
|
font-size: 24rpx;
|
|
|
|
color: #fff;
|
|
|
|
}
|
|
|
|
|
|
|
|
// 历史记录样式
|
|
|
|
.stat-card {
|
|
|
|
background: linear-gradient(135deg, #333, #222);
|
|
|
|
padding: 40rpx;
|
|
|
|
border-radius: 20rpx;
|
|
|
|
display: flex;
|
|
|
|
flex-direction: column;
|
|
|
|
align-items: center;
|
|
|
|
border: 1rpx solid #444;
|
|
|
|
|
|
|
|
.label {
|
|
|
|
font-size: 24rpx;
|
|
|
|
color: #888;
|
|
|
|
}
|
|
|
|
|
|
|
|
.value {
|
|
|
|
font-size: 60rpx;
|
|
|
|
font-weight: bold;
|
|
|
|
color: #fedc1f;
|
|
|
|
margin: 10rpx 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
.date {
|
|
|
|
font-size: 22rpx;
|
|
|
|
color: #666;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
.chart-container {
|
|
|
|
height: 450rpx;
|
|
|
|
margin: 40rpx 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
.history-item {
|
|
|
|
background: #262626;
|
|
|
|
border-radius: 16rpx;
|
|
|
|
padding: 30rpx;
|
|
|
|
margin-bottom: 20rpx;
|
|
|
|
|
|
|
|
.count {
|
|
|
|
display: flex;
|
|
|
|
gap: 10rpx;
|
|
|
|
}
|
|
|
|
|
|
|
|
.item-header {
|
|
|
|
display: flex;
|
|
|
|
flex-direction: column;
|
|
|
|
justify-content: space-between;
|
|
|
|
margin-bottom: 20rpx;
|
|
|
|
|
|
|
|
.date {
|
|
|
|
font-size: 24rpx;
|
|
|
|
color: #888;
|
|
|
|
}
|
|
|
|
|
|
|
|
.tag {
|
|
|
|
// font-size: 20rpx;
|
|
|
|
// background: #444;
|
|
|
|
margin: 5rpx 5rpx;
|
|
|
|
border-radius: 4rpx;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
.group-chips {
|
|
|
|
display: flex;
|
|
|
|
flex-direction: column;
|
|
|
|
flex-wrap: wrap;
|
|
|
|
gap: 16rpx;
|
|
|
|
margin-top: 20rpx;
|
|
|
|
|
|
|
|
.chip {
|
|
|
|
// background: #333;
|
|
|
|
padding: 8rpx 20rpx;
|
|
|
|
font-size: 24rpx;
|
|
|
|
display: flex;
|
|
|
|
align-items: center;
|
|
|
|
gap: 10rpx;
|
|
|
|
|
|
|
|
.idx {
|
|
|
|
background: #444;
|
|
|
|
font-weight: bold;
|
|
|
|
border-radius: 30rpx;
|
|
|
|
padding: 4rpx 10rpx;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// 平替动作样式
|
|
|
|
.sub-item {
|
|
|
|
display: flex;
|
|
|
|
align-items: center;
|
|
|
|
background: #262626;
|
|
|
|
padding: 24rpx;
|
|
|
|
border-radius: 16rpx;
|
|
|
|
margin-bottom: 20rpx;
|
|
|
|
|
|
|
|
.img {
|
|
|
|
width: 120rpx;
|
|
|
|
height: 120rpx;
|
|
|
|
border-radius: 12rpx;
|
|
|
|
margin-right: 24rpx;
|
|
|
|
}
|
|
|
|
|
|
|
|
.sub-info {
|
|
|
|
flex: 1;
|
|
|
|
|
|
|
|
.name {
|
|
|
|
font-size: 30rpx;
|
|
|
|
font-weight: 500;
|
|
|
|
display: block;
|
|
|
|
}
|
|
|
|
|
|
|
|
.meta {
|
|
|
|
font-size: 22rpx;
|
|
|
|
color: #666;
|
|
|
|
margin-top: 8rpx;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
.footer {
|
|
|
|
width: 100%;
|
|
|
|
display: flex;
|
|
|
|
justify-content: center;
|
|
|
|
align-items: center;
|
|
|
|
position: fixed;
|
|
|
|
bottom: 0;
|
|
|
|
height: 120rpx;
|
|
|
|
background-color: #242424;
|
|
|
|
z-index: 999;
|
|
|
|
.btn {
|
|
|
|
width: 80%;
|
|
|
|
height: 80rpx;
|
|
|
|
background-color: #fedc1f;
|
|
|
|
color: #333;
|
|
|
|
border-radius: 12rpx;
|
|
|
|
text-align: center;
|
|
|
|
line-height: 80rpx;
|
|
|
|
border-radius: 50rpx;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// 动画
|
|
|
|
.slide-up {
|
|
|
|
animation: slideUp 0.4s ease-out;
|
|
|
|
}
|
|
|
|
|
|
|
|
@keyframes slideUp {
|
|
|
|
from {
|
|
|
|
opacity: 0;
|
|
|
|
transform: translateY(20rpx);
|
|
|
|
}
|
|
|
|
|
|
|
|
to {
|
|
|
|
opacity: 1;
|
|
|
|
transform: translateY(0);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
</style> |
...
|
...
|
|