Authored by qxm

修复黄色悬浮圆球,我的训练青色圆球,官方和我的模板选择页面,去训练和添加模板弹窗

... ... @@ -50,15 +50,15 @@
}
},
{
"path": "pages/xunji/xunji-wode-moban",
"path": "pages/xunji/wode-xinjian-moban",
"style": {
"navigationBarTitleText": "我的模版"
"navigationBarTitleText": "新建我的模版"
}
},
{
"path": "pages/xunji/xunji-rili-tianjia",
"path": "pages/xunji/xunji-wode-moban",
"style": {
"navigationBarTitleText": "日历添加训练动作"
"navigationBarTitleText": "我的模版"
}
},
{
... ... @@ -113,6 +113,14 @@
"navigationBarTitleText": "新增超级组"
}
},
{
"path": "pages/xunji/wode-jihua-paike",
"style": {
"navigationBarTitleText": "我的计划详情的排课设置"
}
},
{
"path": "pages/xunji/dongzuo-muluguanli",
"style": {
... ... @@ -131,6 +139,12 @@
"style": {
"navigationBarTitleText": ""
}
},
{
"path": "pages/xunji/xunji-wode-jihua",
"style": {
"navigationBarTitleText": ""
}
}
]
},
... ...
... ... @@ -41,8 +41,8 @@ onMounted(() => {
<style lang="scss" scoped>
.floating-train-btn {
position: fixed;
right: 20rpx;
bottom: 200rpx;
right: 11rpx;
bottom: 304rpx;
display: flex;
align-items: center;
background-color: #39d353;
... ...
<template>
<view class="my-page">
<!-- 登录头部区 -->
<view
v-if="userStore.isLogin"
class="section-card user-header"
hover-class="card-hover"
@tap="goMyPersonalData"
>
<image
:src="
userInfo.avatar ||
<view v-if="userStore.isLogin" class="section-card user-header" hover-class="card-hover" @tap="goMyPersonalData">
<image :src="userInfo.avatar ||
'https://fitness-hcxtec-bucket.oss-cn-shenzhen.aliyuncs.com/20260526/默认头像_1779779926983.png'
"
mode="aspectFill"
class="avatar"
/>
" mode="aspectFill" class="avatar" />
<view class="info-content">
<view class="name-row">
<text class="nickname">{{ userInfo.nickname || '微信用户' }}</text>
... ... @@ -48,13 +38,8 @@
<!-- 课程状态快速入口 -->
<view class="section-card quick-entry">
<view
v-for="entry in quickEntryConfig"
:key="entry.type"
class="entry-item"
hover-class="opacity-hover"
@click="handleQuickEntry(entry.type)"
>
<view v-for="entry in quickEntryConfig" :key="entry.type" class="entry-item" hover-class="opacity-hover"
@click="handleQuickEntry(entry.type)">
<text class="num">{{ userInfo[entry.key] || 0 }}</text>
<text class="label">{{ entry.label }}</text>
</view>
... ... @@ -62,21 +47,14 @@
<!-- 广告位 -->
<view class="banner-box" @click="goJiamen">
<image
src="https://fitness-hcxtec-bucket.oss-cn-shenzhen.aliyuncs.com/20260316/4_1773627891703.png"
mode="aspectFill"
class="banner-img"
/>
<image src="https://fitness-hcxtec-bucket.oss-cn-shenzhen.aliyuncs.com/20260316/4_1773627891703.png"
mode="aspectFill" class="banner-img" />
</view>
<!-- 核心应用区 -->
<view class="section-card apply-section">
<view
v-for="(item, index) in APPLY_CONFIG_LIST"
:key="index"
class="apply-item"
@click="authNavigateTo(item.url)"
>
<view v-for="(item, index) in APPLY_CONFIG_LIST" :key="index" class="apply-item"
@click="authNavigateTo(item.url)">
<view class="icon-bg">
<image :src="item.icon" class="img" mode="aspectFit" />
</view>
... ... @@ -87,12 +65,7 @@
<!-- 资产账户网格区 -->
<view v-if="userStore.isLogin" class="section-card">
<view class="account-grid">
<view
v-for="(acc, idx) in accountConfig"
:key="idx"
class="account-item"
@click="authNavigateTo(acc.url)"
>
<view v-for="(acc, idx) in accountConfig" :key="idx" class="account-item" @click="authNavigateTo(acc.url)">
<text class="acc-lab">{{ acc.label }}</text>
<text class="acc-val">
{{ formatAccountValue(userInfo[acc.key], acc.isFloat) }}
... ... @@ -105,12 +78,8 @@
<!-- 功能矩阵九宫格 -->
<view class="section-card icon-grid-box">
<view class="icon-grid">
<view
v-for="(item, index) in FUNCTION_CONFIG_LIST"
:key="index"
class="icon-item"
@click="handleGridItemClick(item)"
>
<view v-for="(item, index) in FUNCTION_CONFIG_LIST" :key="index" class="icon-item"
@click="handleGridItemClick(item)">
<view class="icon-img-wrap">
<image :src="item.icon" mode="aspectFit" class="icon-img" />
... ... @@ -120,11 +89,7 @@
</view>
<text class="icon-text">{{ item.text }}</text>
<button
v-if="item.text === '联系客服'"
open-type="contact"
class="mp-contact-overlay-btn"
/>
<button v-if="item.text === '联系客服'" open-type="contact" class="mp-contact-overlay-btn" />
</view>
</view>
</view>
... ... @@ -142,51 +107,57 @@
</view>
<Tabbar />
<TrainingFloating />
</view>
</template>
<script setup>
import { ref } from 'vue';
import UserApi from '@/sheep/api/member/user';
import MemberApi from '@/sheep/api/member/member';
import useUserStore from '@/sheep/store/user';
import { onShow } from '@dcloudio/uni-app';
// 响应式数据挂载
const userStore = useUserStore();
const userInfo = ref({});
const memberLevelName = ref('');
// 固定的 UI 配置
const APPLY_CONFIG_LIST = [];
const FUNCTION_CONFIG_LIST = [];
// 课程计数状态配置映射
const quickEntryConfig = [
import { ref } from 'vue';
import UserApi from '@/sheep/api/member/user';
import MemberApi from '@/sheep/api/member/member';
import useUserStore from '@/sheep/store/user';
import { onShow } from '@dcloudio/uni-app';
import TrainingFloating from '@/pages/TrainingFloating.vue'
import { useTrainingStore } from '@/sheep/store/trainingStore';
const trainingStore = useTrainingStore();
// 响应式数据挂载
const userStore = useUserStore();
const userInfo = ref({});
const memberLevelName = ref('');
// 固定的 UI 配置
const APPLY_CONFIG_LIST = [];
const FUNCTION_CONFIG_LIST = [];
// 课程计数状态配置映射
const quickEntryConfig = [
{ type: 1, key: 'courseNum', label: '待上课' },
{ type: 2, key: 'courseWaitNum', label: '等待中' },
{ type: 3, key: 'courseEvaluationWaitNum', label: '历史课程' },
];
];
// 资产账户字段清洗配置映射 (对应接口数据类型:number 与 integer)
const accountConfig = [];
// 资产账户字段清洗配置映射 (对应接口数据类型:number 与 integer)
const accountConfig = [];
/**
/**
* JSDoc 核心资产数值洗涤函数
* @param {number|undefined} val 原始金钱/数量值
* @param {boolean} isFloat 是否需要保留两位小数
* @returns {string|number} 格式化后的安全渲染字符串
*/
const formatAccountValue = (val, isFloat) => {
const formatAccountValue = (val, isFloat) => {
if (val === undefined || val === null) return isFloat ? '0.00' : 0;
return isFloat ? Number(val).toFixed(2) : Math.floor(val);
};
};
/**
/**
* 路由守卫拦截转发
* @param {string} url 目标绝对/相对地址
*/
const authNavigateTo = (url) => {
const authNavigateTo = (url) => {
if (!userStore.isLogin) {
goLogin();
return;
... ... @@ -195,13 +166,13 @@
url,
fail: (err) => console.error(`[Router] 页面跳转失败 ${url}: `, err),
});
};
};
/**
/**
* 统一处理功能网格的点击分发
* @param {Object} item 节点配置项
*/
const handleGridItemClick = (item) => {
const handleGridItemClick = (item) => {
if (item.text === '联系客服') {
// #ifndef MP-WEIXIN
// 兜底非微信小程序平台(如H5、App),可以正常走原来的普通客服页面路由
... ... @@ -212,13 +183,13 @@
// 其他正常功能,正常走路由拦截守卫
authNavigateTo(item.url);
};
};
/**
/**
* 异步高内聚合并请求
* 解决因先后触发 setData 导致微信小程序底层 AppService 与 WebView 之间高频拥堵卡顿的问题
*/
const fetchPageData = async () => {
const fetchPageData = async () => {
try {
const [userRes, levelRes] = await Promise.all([
UserApi.getUserInfo(),
... ... @@ -239,34 +210,35 @@
} catch (error) {
console.error('[API Error] 拉取个人资产信息流失败:', error);
}
};
};
onShow(() => {
onShow(() => {
if (userStore.isLogin) {
fetchPageData();
} else {
userInfo.value = {};
memberLevelName.value = '';
}
});
});
// 路由跳转原子原子层
const goLogin = () => uni.navigateTo({ url: '/pages7/pages/index/login' });
const goMyPersonalData = () => authNavigateTo('/pages5/pages/user/wode-geren-ziliao');
const goAddVip = () => authNavigateTo('/pages5/pages/user/wode-hongxing-huiyuan');
// 路由跳转原子原子层
const goLogin = () => uni.navigateTo({ url: '/pages7/pages/index/login' });
const goMyPersonalData = () => authNavigateTo('/pages5/pages/user/wode-geren-ziliao');
const goAddVip = () => authNavigateTo('/pages5/pages/user/wode-hongxing-huiyuan');
const goJiamen = () => uni.navigateTo({ url: '/pages7/pages/index/shouye-jiamen-hongxing' });
const handleQuickEntry = (type) => authNavigateTo(`/pages5/pages/user/wode-shangke?type=${type}`);
const goJiamen = () => uni.navigateTo({ url: '/pages7/pages/index/shouye-jiamen-hongxing' });
const handleQuickEntry = (type) => authNavigateTo(`/pages5/pages/user/wode-shangke?type=${type}`);
</script>
<style scoped lang="scss">
$brand-color: #ff6b00;
$page-bg: #f8f8f8;
$brand-color: #ff6b00;
$page-bg: #f8f8f8;
.my-page {
.my-page {
min-height: 100vh;
background-color: $page-bg;
padding: 20rpx 28rpx calc(40rpx + env(safe-area-inset-bottom)); /* 解决部分 iOS 底部 Tabbar 高度塌陷 */
padding: 20rpx 28rpx calc(40rpx + env(safe-area-inset-bottom));
/* 解决部分 iOS 底部 Tabbar 高度塌陷 */
box-sizing: border-box;
.section-card {
... ... @@ -281,6 +253,7 @@
display: flex;
align-items: center;
padding: 34rpx 30rpx;
.avatar {
width: 110rpx;
height: 110rpx;
... ... @@ -288,17 +261,21 @@
background: #f0f0f0;
border: 4rpx solid #fff;
}
.info-content {
margin-left: 24rpx;
flex: 1;
.name-row {
display: flex;
flex-direction: column;
.nickname {
font-size: 34rpx;
font-weight: bold;
color: #333;
}
.tag {
font-size: 20rpx;
color: $brand-color;
... ... @@ -310,10 +287,12 @@
}
}
}
.right {
display: flex;
align-items: center;
gap: 60rpx;
.img {
width: 60rpx;
height: 60rpx;
... ... @@ -325,17 +304,20 @@
display: flex;
justify-content: space-between;
align-items: center;
.title {
font-size: 32rpx;
font-weight: bold;
color: #333;
}
.desc {
font-size: 22rpx;
color: #999;
margin-top: 4rpx;
display: block;
}
.login-btn {
margin: 0;
background: $brand-color;
... ... @@ -345,9 +327,12 @@
line-height: 64rpx;
border-radius: 32rpx;
padding: 0 30rpx;
&::after {
border: none;
} /* 清理小程序 button 默认黑边线 */
}
/* 清理小程序 button 默认黑边线 */
}
}
... ... @@ -359,15 +344,18 @@
justify-content: space-between;
align-items: center;
margin-bottom: 24rpx;
.vip-info {
display: flex;
align-items: center;
}
.vip-text {
color: #f1c40f;
font-size: 24rpx;
margin-left: 14rpx;
}
.vip-btn {
background: linear-gradient(90deg, #f1c40f, #f39c12);
color: #333;
... ... @@ -381,13 +369,16 @@
.quick-entry {
display: flex;
justify-content: space-around;
.entry-item {
text-align: center;
.num {
font-size: 38rpx;
font-weight: bold;
color: #333;
}
.label {
font-size: 22rpx;
color: #999;
... ... @@ -402,6 +393,7 @@
margin-bottom: 24rpx;
border-radius: 20rpx;
overflow: hidden;
.banner-img {
width: 100%;
height: 100%;
... ... @@ -411,10 +403,12 @@
.apply-section {
display: grid;
grid-template-columns: repeat(5, 1fr);
.apply-item {
display: flex;
flex-direction: column;
align-items: center;
.icon-bg {
width: 80rpx;
height: 80rpx;
... ... @@ -424,11 +418,13 @@
align-items: center;
justify-content: center;
margin-bottom: 12rpx;
.img {
width: 44rpx;
height: 44rpx;
}
}
.text {
font-size: 22rpx;
color: #666;
... ... @@ -440,14 +436,17 @@
display: grid;
grid-template-columns: repeat(4, 1fr);
row-gap: 34rpx;
.account-item {
display: flex;
flex-direction: column;
align-items: center;
.acc-val {
font-size: 30rpx;
font-weight: bold;
color: #333;
.unit {
font-size: 20rpx;
font-weight: normal;
... ... @@ -455,6 +454,7 @@
margin-left: 2rpx;
}
}
.acc-lab {
font-size: 22rpx;
color: #999;
... ... @@ -467,22 +467,27 @@
display: grid;
grid-template-columns: repeat(4, 1fr);
row-gap: 40rpx;
.icon-item {
display: flex;
flex-direction: column;
align-items: center;
position: relative;
.icon-img-wrap {
position: relative;
margin-bottom: 12rpx;
.icon-img {
width: 46rpx;
height: 46rpx;
}
.badge {
position: absolute;
top: -12rpx;
right: -42rpx; /* 适当拓宽右移,容纳后端多字文本 */
right: -42rpx;
/* 适当拓宽右移,容纳后端多字文本 */
background: #ff4d4f;
color: #fff;
font-size: 18rpx;
... ... @@ -490,6 +495,7 @@
border-radius: 16rpx;
white-space: nowrap;
}
/* 未读状态小红点 */
.dot-badge {
position: absolute;
... ... @@ -501,21 +507,25 @@
border-radius: 50%;
}
}
.icon-text {
font-size: 24rpx;
color: #555;
}
.mp-contact-overlay-btn {
position: absolute;
top: 0;
left: 0;
width: 100% !important;
height: 100% !important;
opacity: 0 !important; /* 核心:完全透明 */
opacity: 0 !important;
/* 核心:完全透明 */
border: none !important;
padding: 0 !important;
margin: 0 !important;
z-index: 10; /* 确保盖在图表和文字的最上方 */
z-index: 10;
/* 确保盖在图表和文字的最上方 */
&::after {
border: none !important;
... ... @@ -530,9 +540,11 @@
align-items: center;
padding: 24rpx 0;
border-bottom: 1rpx solid #f9f9f9;
&:last-child {
border-bottom: none;
}
.setting-text {
font-size: 28rpx;
color: #444;
... ... @@ -542,8 +554,9 @@
.opacity-hover {
opacity: 0.7;
}
.card-hover {
background-color: #fcfcfc;
}
}
}
</style>
... ...
... ... @@ -295,7 +295,7 @@ const handleConfirm = async () => {
exerciseId: detail.id,
exerciseName: detail.name,
exerciseType: detail.exerciseType || 1,
urlImage: detail.urlImage || detail.url3dAnimation,
urlImage: detail.url3dAnimation || detail.urlImage,
categoryDescription: detail.categoryDescription,
equipmentDescription: detail.equipmentDescription,
}
... ... @@ -313,7 +313,8 @@ const handleConfirm = async () => {
exerciseId: e.id,
exerciseName: e.name,
exerciseType: e.exerciseType || 1,
urlImage: e.urlImage || e.url3dAnimation,
urlImage: e.url3dAnimation || e.urlImage,
// urlImage: e.urlImage || e.url3dAnimation,
}))
};
}
... ...
... ... @@ -35,17 +35,20 @@
</view>
<view class="close-btn" @click="close">
<text>×</text>
<text>x</text>
</view>
</view>
<WodeJihuaTianjiaTancuang v-model:visible="showPlanPopup" @get-plan-list-length="getPlanListLength" :isAdd="true" />
<!-- 我的计划添加弹窗,显示最新添加的计划的模板列表 传递-->
<WodeJihuaTianjiaTancuang v-model:visible="showPlanPopup" @get-plan-list-length="getPlanListLength" :isAdd="true"
:plan-id="lastPlanId" :is-my-plan="true" />
</view>
</template>
<script setup>
import { ref } from 'vue'
import { ref, onMounted, computed } from 'vue'
import WodeJihuaTianjiaTancuang from '@/pages/xunji/components/wode-jihua-tianjia-tancuang.vue'
import QueryPlanApi from '@/sheep/api/plan/queryplan'
// 控制训练计划弹窗显示
const showPlanPopup = ref(false)
... ... @@ -84,6 +87,38 @@ const handleFreeTraining = () => {
uni.navigateTo({ url: '/pages4/pages/xunji/xunji-dongzuo-lianxi' })
close()
}
// 获取我的计划列表的最后一个planid,传递到WodeJihuaTianjiaTancuang中
// 计划列表
const planList = ref([])
// 获取我的全部训练计划
const fetchMyPlanList = async () => {
try {
const res = await QueryPlanApi.getMyPlan()
if (res.code === 0 && res.data) {
planList.value = res.data
} else {
uni.showToast({ title: '获取计划失败', icon: 'none' })
}
} catch (err) {
console.error('获取计划列表报错:', err)
uni.showToast({ title: '网络异常', icon: 'none' })
}
}
// 计算属性:拿到列表最后一条计划id,无数据返回null
const lastPlanId = computed(() => {
if (!Array.isArray(planList.value) || planList.value.length === 0) return null
const lastPlan = planList.value.at(-1)
return lastPlan?.id ?? null
})
onMounted(() => {
fetchMyPlanList()
})
</script>
<style lang="scss" scoped>
... ... @@ -111,8 +146,8 @@ const handleFreeTraining = () => {
display: flex;
flex-direction: column;
align-items: center;
/* 选项和关闭按钮间距 */
gap: 70rpx;
margin-bottom: 100rpx;
}
/* 选项列表 */
... ...
... ... @@ -33,8 +33,8 @@ const closeAddTrainPopup = () => {
<style lang="scss" scoped>
.float-btn {
position: fixed;
right: 30rpx;
bottom: 10rpx;
right: 11rpx;
bottom: 169rpx;
width: 100rpx;
height: 100rpx;
background-color: #ffcc00;
... ...
... ... @@ -105,10 +105,10 @@
{{ formatSecondsToHms(set.duration) }}
</text>
<text class="set-content" v-if="[4, 5].includes(unit.exercises[0].exerciseType)">
{{ set.weight }}kg x {{ set.reps }}次
{{ set.weight }}kg x {{ set.duration }}s x {{ set.restTime }}
</text>
<text class="set-content" v-if="unit.exercises[0].exerciseType === 6">
{{ formatSecondsToHms(set.duration) }}
{{ set.reps }}次 x {{ formatSecondsToHms(set.duration) }}
</text>
<text class="rest-time" v-if="set.restTime && unit.exercises[0].exerciseType != 6">
{{ set.restTime || 0 }}s
... ... @@ -464,8 +464,8 @@ const handleCompleteCheck = async () => {
try {
// 2. 调用接口
await dailytemplateApi.completeDailyTemplate(currentPlan.value.id)
emit('refreshCalendar');
uni.showToast({ title: '一键打勾成功', icon: 'success' })
closeMorePopup()
// 刷新页面数据
... ... @@ -794,7 +794,7 @@ const startTraining = () => {
uni.navigateTo({
url: `/pages4/pages/xunji/xunji-dongzuo-lianxi?id=${currentPlan.value.templateId}&type=3&dailyTemplateId=${currentPlan.value.id}&isTraining=true`,
});
console.log('开始进入编辑模板页面,模板ID:', currentPlan.value.templateId, '每日模板ID:', currentPlan.value.id);
console.log('去训练开始进入编辑模板页面,模板ID:', currentPlan.value.templateId, '每日模板ID:', currentPlan.value.id);
console.log('打印传递给动作训练页面的模板id', currentPlan.value.templateId);
} else {
... ...
... ... @@ -75,7 +75,7 @@ watch(
if (rtype === 1) {
newUnit = {
unitType: 1, unitId: detail.id, unitName: detail.name,
exercises: [{ exerciseId: detail.id, exerciseName: detail.name, exerciseType: detail.exerciseType, urlImage: detail.urlImage || detail.url3dAnimation, categoryDescription: detail.categoryDescription || '', equipmentDescription: detail.equipmentDescription || '', sets: [] }]
exercises: [{ exerciseId: detail.id, exerciseName: detail.name, exerciseType: detail.exerciseType, urlImage: detail.url3dAnimation || detail.urlImage, categoryDescription: detail.categoryDescription || '', equipmentDescription: detail.equipmentDescription || '', sets: [] }]
}
} else {
newUnit = {
... ... @@ -104,40 +104,71 @@ const currUnit = computed(() => sourceInfo.value.unit || {})
const currUnitIndex = computed(() => sourceInfo.value.unitIndex ?? 0)
// 格式化数据:统一 动作 / 超级组 结构 → 给 dongzuo 组件用
// const formatDongzuoData = (unit) => {
// if (!unit) return {}
// console.log('++每日模板的unit++', unit);
// if (unit.unitType === 1) {
// const ex = unit.exercises?.[0] || {}
// return {
// id: ex.exerciseId,
// name: ex.exerciseName,
// urlImage: ex.url3dAnimation,
// exerciseType: ex.exerciseType,
// categoryDescription: ex.categoryDescription || '',
// equipmentDescription: ex.equipmentDescription || '',
// }
// }
// if (unit.unitType === 2) {
// return {
// id: unit.unitId,
// name: unit.unitName || '超级组',
// exercises: unit.exercises?.map(ex => ({
// id: ex.exerciseId,
// name: ex.exerciseName,
// urlImage: ex.url3dAnimation,
// exerciseType: ex.exerciseType,
// })) || []
// }
// }
// return {}
// }
const formatDongzuoData = (unit) => {
if (!unit) return {}
console.log('++每日模板的unit++', unit);
let result = {} // 定义接收结果的变量
// 1. 普通动作 type=1
if (unit.unitType === 1) {
const ex = unit.exercises?.[0] || {}
return {
result = {
id: ex.exerciseId,
name: ex.exerciseName,
urlImage: ex.urlImage,
urlImage: ex.url3dAnimation,
exerciseType: ex.exerciseType,
categoryDescription: ex.categoryDescription || '',
equipmentDescription: ex.equipmentDescription || '',
}
}
// 2. 超级组 type=2
if (unit.unitType === 2) {
return {
result = {
id: unit.unitId,
name: unit.unitName || '超级组',
// 超级组需要把子动作全部格式化
exercises: unit.exercises?.map(ex => ({
id: ex.exerciseId,
name: ex.exerciseName,
urlImage: ex.urlImage,
urlImage: ex.url3dAnimation,
exerciseType: ex.exerciseType,
})) || []
}
}
return {}
console.log('格式化后结果:', result) // 打印最终数据
return result
}
const handleDeleteAction = () => {
console.log('父组件处理删除动作')
needDeleteUnit.value = true
... ... @@ -442,7 +473,7 @@ defineExpose({ open })
// padding: 0 20rpx 120rpx;
margin: 0 20rpx;
height: calc(100vh - 120rpx);
background: #f5b5b5;
background: #f5f5f5;
max-height: 70vh;
}
</style>
... ...
<template>
<!-- 具体计划的模板列表(在模板详情和我的计划,还有黄色小球中挂载) -->
<!-- 具体计划的模板列表(在模板详情和我的计划,还有黄色小球中挂载) 如果没有输入计划id,就是显示最后一个添加的计划-->
<up-popup :show="props.visible" mode="bottom" round="24rpx" @close="emit('update:visible', false)">
<view class="up-popup-contain">
<!-- 顶部滑块 -->
... ... @@ -50,6 +50,7 @@
</view>
</up-popup>
<!-- 计划列表弹窗,显示计划列表,选择后会回到当前计划包含的模板列表,可以去训练或者添加模板到日历 -->
<WodeJihuaLibiaoTancuang v-if="showPlanList && isAdd" ref="planListRef" @close="showPlanList = false"
:show="showPlanList" :MyPlanList=MyPlanList @select="onSelectPlan" />
... ... @@ -81,6 +82,10 @@ const props = defineProps({
planId: {
type: Number,
default: null
},
isMyPlan: {
type: Boolean,
default: false
}
})
const emit = defineEmits(['update:visible', 'getPlanListLength'])
... ... @@ -91,9 +96,17 @@ const MyPlanDetail = ref({})
// ====================== 核心修复:获取计划详情 ======================
const getMyPlanDetail = async (planId) => {
if (!planId) return;
let res;
try {
const res = await QueryPlanApi.getMyPlanDetail(planId);
console.log('✅ 计划详情获取成功 planId=', planId, res.data);
if (props.isMyPlan) {
res = await QueryPlanApi.getMyPlanDetail(planId);
console.log('✅ 我的计划详情获取成功 planId=', planId, res.data);
}
else {
res = await QueryPlanApi.getPlanDetail(planId);
console.log('✅ 不是我的计划,官方计划,详情获取成功 planId=', planId, res.data);
}
if (res.data) {
MyPlanDetail.value = res.data;
} else {
... ... @@ -176,6 +189,8 @@ const getMyPlanList = async () => {
onMounted(() => {
getMyPlanList();
// console.log('props.planId=', planId);
});
</script>
... ...
... ... @@ -380,7 +380,7 @@ onMounted(() => {
padding-bottom: 20rpx;
// #ifdef MP-WEIXIN
// 微信小程序端可能需要更多底部空间
padding-bottom: 100rpx;
padding-bottom: 200rpx;
// #endif
.nav-item {
... ...
... ... @@ -178,11 +178,14 @@ const loadPlans = async (year, month) => {
const nextYear = month + 1 > 12 ? year + 1 : year;
// 并行请求三个月数据
const [prevRes, currRes, nextRes] = await Promise.all([
DailyTemplateApi.getCalendarPlans(prevYear, prevMonth),
DailyTemplateApi.getCalendarPlans(year, month),
DailyTemplateApi.getCalendarPlans(nextYear, nextMonth),
]);
// const [prevRes, currRes, nextRes] = await Promise.all([
// DailyTemplateApi.getCalendarPlans(prevYear, prevMonth),
// DailyTemplateApi.getCalendarPlans(year, month),
// DailyTemplateApi.getCalendarPlans(nextYear, nextMonth),
// ]);
const prevRes = await DailyTemplateApi.getCalendarPlans(prevYear, prevMonth);
const currRes = await DailyTemplateApi.getCalendarPlans(year, month);
const nextRes = await DailyTemplateApi.getCalendarPlans(nextYear, nextMonth);
// 合并三个月数据
const allPlans = [
... ... @@ -315,10 +318,7 @@ const selectDate = async (date) => {
selectedDate.value = date.dateKey;
// ShowGridCellPopup.value = true;
await nextTick()
console.log('AAAAAAAAAAAAAAAAAAAAAAAAAAA');
gridPopupRef.value?.openPopup();
console.log('BBBBBBBBBBBBBBBBBB');
};
</script>
... ...
... ... @@ -5,26 +5,20 @@
<view class="banner-section">
<!-- 跳转有问题 -->
<view class="item" @click="goToActionLibrary">
<image
src="https://fitness-hcxtec-bucket.oss-cn-shenzhen.aliyuncs.com/20260316/21_1773626442072.png"
class="img"
></image>
<image src="https://fitness-hcxtec-bucket.oss-cn-shenzhen.aliyuncs.com/20260316/21_1773626442072.png"
class="img"></image>
<view class="title">动作库</view>
<view class="desc">真人视频讲解</view>
</view>
<view class="item">
<image
src="https://fitness-hcxtec-bucket.oss-cn-shenzhen.aliyuncs.com/20260316/22_1773626449583.png"
class="img"
></image>
<image src="https://fitness-hcxtec-bucket.oss-cn-shenzhen.aliyuncs.com/20260316/22_1773626449583.png"
class="img"></image>
<view class="title">训练计划</view>
<view class="desc">周期性目标达成</view>
</view>
<view class="item">
<image
src="https://fitness-hcxtec-bucket.oss-cn-shenzhen.aliyuncs.com/20260316/23_1773627239158.png"
class="img"
></image>
<image src="https://fitness-hcxtec-bucket.oss-cn-shenzhen.aliyuncs.com/20260316/23_1773627239158.png"
class="img"></image>
<view class="title">训练模板</view>
<view class="desc">精选课程模板</view>
</view>
... ... @@ -37,12 +31,7 @@
</view>
<view class="plan-list">
<!-- 点击可跳转 -->
<view
v-for="(item, index) in planList"
:key="index"
class="plan-item"
@tap="goPlanDetail(item)"
>
<view v-for="(item, index) in planList" :key="index" class="plan-item" @tap="goPlanDetail(item)">
<image :src="item.cover" mode="aspectFill" class="plan-cover" />
<view class="plan-desc">
<text class="plan-tag" :class="item.tagClass">{{ item.tag }}</text>
... ... @@ -58,35 +47,19 @@
<view class="recommend-header">
<text class="header-title">为你推荐</text>
<view class="tabs">
<button
class="tab-btn"
:class="{ active: currentTab === 'recommend' }"
@tap="switchTab('recommend')"
>
<button class="tab-btn" :class="{ active: currentTab === 'recommend' }" @tap="switchTab('recommend')">
推荐
</button>
<button
class="tab-btn"
:class="{ active: currentTab === 'group' }"
@tap="switchTab('group')"
>
<button class="tab-btn" :class="{ active: currentTab === 'group' }" @tap="switchTab('group')">
团课
</button>
<button
class="tab-btn"
:class="{ active: currentTab === 'private' }"
@tap="switchTab('private')"
>
<button class="tab-btn" :class="{ active: currentTab === 'private' }" @tap="switchTab('private')">
私教
</button>
<!-- <button class="tab-btn" :class="{ active: currentTab === 'small' }" @tap="switchTab('small')">
小班课
</button> -->
<button
class="tab-btn"
:class="{ active: currentTab === 'follow' }"
@tap="switchTab('follow')"
>
<button class="tab-btn" :class="{ active: currentTab === 'follow' }" @tap="switchTab('follow')">
关注
</button>
</view>
... ... @@ -96,21 +69,12 @@
<view class="coach-section">
<view class="coach-list">
<view
class="coach-item"
v-for="(item, index) in currentRecommendList"
:key="item.id"
@click="navigateToDetail(item)"
>
<view class="coach-item" v-for="(item, index) in currentRecommendList" :key="item.id"
@click="navigateToDetail(item)">
<!-- 1. 如果有视频 -->
<template v-if="item.video">
<video
:src="item.video"
:controls="false"
:show-fullscreen-btn="false"
:show-center-play-btn="false"
class="video"
></video>
<video :src="item.video" :controls="false" :show-fullscreen-btn="false" :show-center-play-btn="false"
class="video"></video>
<up-icon name="play-right" size="20" class="icon" color="#fff"></up-icon>
</template>
<!-- 2. 如果没有视频 -->
... ... @@ -122,12 +86,8 @@
<view class="coach-meta">
<image :src="item.coachAvatar" mode="aspectFill" class="coach-avatar" />
<text class="coach-name">{{ item.coachName }}</text>
<up-icon
name="thumb-up"
:color="item.isLike ? '#D96248' : '#666'"
size="20"
@click="handleDynamicLike(item, index)"
></up-icon>
<up-icon name="thumb-up" :color="item.isLike ? '#D96248' : '#666'" size="20"
@click="handleDynamicLike(item, index)"></up-icon>
</view>
</view>
</view>
... ... @@ -162,46 +122,48 @@
</template>
<script setup>
import { ref, computed, onMounted } from 'vue';
import QueryPlanApi from '@/sheep/api/plan/queryplan';
import coachUpdatesApi from '@/sheep/api/Coach/CoachUpdates'; // 请确认路径正确
import useUserStore from '@/sheep/store/user';
const userStore = useUserStore();
// ====== Tab 状态 ======
const currentTab = ref('recommend');
const tabData = ref({
import { ref, computed, onMounted } from 'vue';
import QueryPlanApi from '@/sheep/api/plan/queryplan';
import coachUpdatesApi from '@/sheep/api/Coach/CoachUpdates'; // 请确认路径正确
import useUserStore from '@/sheep/store/user';
import floatYellowBtn from '@/pages/xunji/components/rili-components/float-yellow-btn.vue';
const userStore = useUserStore();
// ====== Tab 状态 ======
const currentTab = ref('recommend');
const tabData = ref({
// finished: false → 还有没有更多数据可以加载?false代表还有更多数据可以加载
recommend: { list: [], pageNo: 1, finished: false },
group: { list: [], pageNo: 1, finished: false },
private: { list: [], pageNo: 1, finished: false },
small: { list: [], pageNo: 1, finished: false },
follow: { list: [], pageNo: 1, finished: false },
});
const loading = ref(false);
});
const loading = ref(false);
// 当前显示的列表(computed)
const currentRecommendList = computed(() => {
// 当前显示的列表(computed)
const currentRecommendList = computed(() => {
return tabData.value[currentTab.value]?.list || [];
});
});
const finished = computed(() => {
const finished = computed(() => {
return tabData.value[currentTab.value]?.finished || false;
});
});
// 获取 storeId(请根据你项目实际情况调整)
const storeId = userStore.initUser.storeId;
// 切换 Tab
const switchTab = (type) => {
// 获取 storeId(请根据你项目实际情况调整)
const storeId = userStore.initUser.storeId;
// 切换 Tab
const switchTab = (type) => {
if (currentTab.value === type) return;
currentTab.value = type;
// 如果该 tab 还没加载过,触发加载
if (tabData.value[type].list.length === 0 && !tabData.value[type].finished) {
loadRecommendData();
}
};
};
// 加载推荐数据
const loadRecommendData = async () => {
// 加载推荐数据
const loadRecommendData = async () => {
const tab = currentTab.value;
const tabInfo = tabData.value[tab];
if (loading.value || tabInfo.finished) return;
... ... @@ -242,18 +204,18 @@
} finally {
loading.value = false;
}
};
};
// 上拉加载更多
const onScrollToLower = () => {
// 上拉加载更多
const onScrollToLower = () => {
if (!finished.value && !loading.value) {
loadRecommendData();
}
};
};
const planList = ref([]);
// 新手第一课接口,如果有数据就循环显示数据,没有就展示默认暂无新手计划
const loadPlans = async () => {
const planList = ref([]);
// 新手第一课接口,如果有数据就循环显示数据,没有就展示默认暂无新手计划
const loadPlans = async () => {
try {
const res = await QueryPlanApi.getPlanList();
const allPlans = res.data || [];
... ... @@ -271,8 +233,7 @@
'https://fitness-hcxtec-bucket.oss-cn-shenzhen.aliyuncs.com/20260316/order-empty_1773628059920.png',
tag: '火爆',
tagClass: 'hot-tag',
meta: ` ${difficultyText[targetPlan.difficultyLevel] || '初阶'} · ${
targetPlan.enrollmentCount
meta: ` ${difficultyText[targetPlan.difficultyLevel] || '初阶'} · ${targetPlan.enrollmentCount
}人练过`,
},
];
... ... @@ -301,25 +262,25 @@
},
];
}
};
};
// 跳转方法
const goPlanDetail = (item) => {
// 跳转方法
const goPlanDetail = (item) => {
uni.navigateTo({
url: `/pages4/pages/xunji/xunji-xunlian-jihua?planid= ${item.id}`,
});
};
// 这是一个【跳转函数】,点击推荐里的内容,跳转到动态详情页,并且把当前是 “推荐 / 团课 / 私教 / 小班 / 关注” 这个分类带给下一页。
const goRecommendDetail = (item) => {
};
// 这是一个【跳转函数】,点击推荐里的内容,跳转到动态详情页,并且把当前是 “推荐 / 团课 / 私教 / 小班 / 关注” 这个分类带给下一页。
const goRecommendDetail = (item) => {
// 传递当前 tab 类型,方便目标页初始化
const typeMap = { group: '1', private: '2', small: '3', recommend: '', follow: '' };
const type = typeMap[currentTab.value] || '';
uni.navigateTo({
url: `/pages3/pages/coach/jiaolian-dongtai?type= ${encodeURIComponent(type)}`,
});
};
// 跳转到动态详情
const navigateToDetail = (item) => {
};
// 跳转到动态详情
const navigateToDetail = (item) => {
if (item.photo) {
uni.navigateTo({
url: `/pages3/pages/coach/jiaolian-dongtai?id=${item.id}`,
... ... @@ -329,9 +290,9 @@
url: `/pages3/pages/coach/jiaolian-shipin-dongtai?id=${item.id}`,
});
}
};
// 动态点赞
const handleDynamicLike = async (item, index) => {
};
// 动态点赞
const handleDynamicLike = async (item, index) => {
// await CoachApi.likeCoachDynamic({
// id: item.id,
// status: item.isLike == 1 ? 0 : 1,
... ... @@ -350,23 +311,23 @@
} catch (err) {
console.log('点赞失败', err);
}
};
// 实现动作库跳转,跳转到F:\hongxing-app\hongxing-new\pages\xunji\components\xunji-dongzuo.vue
const goToActionLibrary = () => {
};
// 实现动作库跳转,跳转到F:\hongxing-app\hongxing-new\pages\xunji\components\xunji-dongzuo.vue
const goToActionLibrary = () => {
uni.navigateTo({
url: '/pages/xunji/components/xunji-dongzuo',
});
};
// 实现
// 初始化
onMounted(() => {
};
// 实现
// 初始化
onMounted(() => {
loadPlans();
loadRecommendData(); // 加载默认 tab(推荐)数据
});
});
</script>
<style lang="scss" scoped>
.container {
.container {
width: 100%;
height: 100%;
padding: 20rpx;
... ... @@ -682,5 +643,5 @@
}
}
}
}
}
</style>
... ...
<template>
<view class="home-page" v-if="userStore.isLogin">
<view class="tab-bar" :style="{ paddingTop: menuButtonHeight + topSafeArea + 'px' }">
<view class="tab-item" :class="{ active: currentTab === 0 }" @click="handleTabClick(0)"
>训记</view
>
<view class="tab-item" :class="{ active: currentTab === 1 }" @click="handleTabClick(1)"
>计划</view
>
<view class="tab-item" :class="{ active: currentTab === 2 }" @click="handleTabClick(2)"
>日历</view
>
<view class="tab-item" :class="{ active: currentTab === 3 }" @click="handleTabClick(3)"
>动作</view
>
<view class="tab-item" :class="{ active: currentTab === 4 }" @click="handleTabClick(4)"
>模板</view
>
<view class="tab-item" :class="{ active: currentTab === 5 }" @click="handleTabClick(5)"
>数据</view
>
<view class="tab-item" :class="{ active: currentTab === 0 }" @click="handleTabClick(0)">训记</view>
<view class="tab-item" :class="{ active: currentTab === 1 }" @click="handleTabClick(1)">计划</view>
<view class="tab-item" :class="{ active: currentTab === 2 }" @click="handleTabClick(2)">日历</view>
<view class="tab-item" :class="{ active: currentTab === 3 }" @click="handleTabClick(3)">动作</view>
<view class="tab-item" :class="{ active: currentTab === 4 }" @click="handleTabClick(4)">模板</view>
<view class="tab-item" :class="{ active: currentTab === 5 }" @click="handleTabClick(5)">数据</view>
<view class="menu-btn" @click="openDrawer">
<uni-icons type="bars" size="20"></uni-icons>
</view>
... ... @@ -38,24 +26,17 @@
<uni-drawer ref="drawer" mode="right" :mask="true" :width="280">
<view class="drawer-content" :style="{ paddingTop: menuButtonHeight + topSafeArea + 'px' }">
<view class="user-header">
<image
class="avatar"
:src="
userInfo.avatar ||
<image class="avatar" :src="userInfo.avatar ||
'https://fitness-hcxtec-bucket.oss-cn-shenzhen.aliyuncs.com/20260526/默认头像_1779779926983.png'
"
mode="aspectFill"
></image>
" mode="aspectFill"></image>
<view class="user-info">
<text class="nickname">{{ userInfo.nickname || '未登录' }}</text>
</view>
</view>
<image
class="ad-banner"
<image class="ad-banner"
src="https://fitness-hcxtec-bucket.oss-cn-shenzhen.aliyuncs.com/20260316/37_1773628025534.png"
mode="aspectFill"
></image>
mode="aspectFill"></image>
<view class="menu-list">
<view class="menu-item" @click="navigateTo('/pages4/pages/xunji/xunji-wode-zhuye')">
... ... @@ -96,47 +77,53 @@
</view>
</view>
</uni-drawer>
<TrainingFloating />
</view>
</template>
<script setup>
import { ref, shallowRef, computed, onMounted } from 'vue';
import { onLoad, onHide } from '@dcloudio/uni-app';
import useUserStore from '@/sheep/store/user';
import { getMenuButtonHeight, getTopSafeArea } from '@/utils/safeArea';
// 组件导入
import xunjiRili from '@/pages/xunji/components/xunji-rili.vue';
import xunjiDongzuo from '@/pages/xunji/components/xunji-dongzuo.vue';
import xunjiMoban from '@/pages/xunji/components/xunji-moban.vue';
import xunjiShuju from '@/pages/xunji/components/xunji-shuju.vue';
import xunjiXunji from '@/pages/xunji/components/xunji-xunji.vue';
import xunjiXunlianjihua from '@/pages/xunji/components/xunji-xunlianjihua.vue';
import TrainingFloating from '@/pages/TrainingFloating.vue';
// 状态管理
const userStore = useUserStore();
// --- 补全缺失的响应式变量定义 ---
const currentTab = ref(0);
const currentComponent = shallowRef(xunjiXunji); // 用于 H5 端动态组件切换(如保留原功能逻辑)
const drawer = ref(null); // uni-drawer 的组件实例引用
// 安全区域相关变量(从工具函数异步或同步获取)
const menuButtonHeight = ref(getMenuButtonHeight ? getMenuButtonHeight() : 0);
const topSafeArea = ref(getTopSafeArea ? getTopSafeArea() : 0);
// 用户信息计算属性(防止 store 异步更新时报错)
const userInfo = computed(() => userStore.userInfo || {});
// --- 原有页面生命周期维护 ---
onHide(() => {
import { ref, shallowRef, computed, onMounted } from 'vue';
import { onLoad, onHide } from '@dcloudio/uni-app';
import useUserStore from '@/sheep/store/user';
import { getMenuButtonHeight, getTopSafeArea } from '@/utils/safeArea';
// 组件导入
import xunjiRili from '@/pages/xunji/components/xunji-rili.vue';
import xunjiDongzuo from '@/pages/xunji/components/xunji-dongzuo.vue';
import xunjiMoban from '@/pages/xunji/components/xunji-moban.vue';
import xunjiShuju from '@/pages/xunji/components/xunji-shuju.vue';
import xunjiXunji from '@/pages/xunji/components/xunji-xunji.vue';
import xunjiXunlianjihua from '@/pages/xunji/components/xunji-xunlianjihua.vue';
import TrainingFloating from '@/pages/TrainingFloating.vue'
import { useTrainingStore } from '@/sheep/store/trainingStore';
const trainingStore = useTrainingStore();
// 状态管理
const userStore = useUserStore();
// --- 补全缺失的响应式变量定义 ---
const currentTab = ref(0);
const currentComponent = shallowRef(xunjiXunji); // 用于 H5 端动态组件切换(如保留原功能逻辑)
const drawer = ref(null); // uni-drawer 的组件实例引用
// 安全区域相关变量(从工具函数异步或同步获取)
const menuButtonHeight = ref(getMenuButtonHeight ? getMenuButtonHeight() : 0);
const topSafeArea = ref(getTopSafeArea ? getTopSafeArea() : 0);
// 用户信息计算属性(防止 store 异步更新时报错)
const userInfo = computed(() => userStore.userInfo || {});
// --- 原有页面生命周期维护 ---
onHide(() => {
if (drawer.value) {
drawer.value.close();
}
});
});
onLoad((options) => {
onLoad((options) => {
if (!userStore.isLogin) {
uni.redirectTo({
url: '/pages7/pages/index/login',
... ... @@ -147,24 +134,24 @@
if (options && options.currentTab) {
currentTab.value = Number(options.currentTab);
}
});
});
// --- 原有业务方法补充与修复 ---
// --- 原有业务方法补充与修复 ---
// 打开抽屉
const openDrawer = () => {
// 打开抽屉
const openDrawer = () => {
if (drawer.value) {
drawer.value.open();
}
};
};
// 修复模板直接调用 uni.navigateTo 的多端兼容问题
const navigateTo = (url) => {
// 修复模板直接调用 uni.navigateTo 的多端兼容问题
const navigateTo = (url) => {
uni.navigateTo({ url });
};
};
// 处理标签点击
const handleTabClick = (index) => {
// 处理标签点击
const handleTabClick = (index) => {
currentTab.value = index;
// #ifdef H5
switch (index) {
... ... @@ -190,18 +177,18 @@
currentComponent.value = xunjiXunlianjihua;
}
// #endif
};
};
// 空实现占位(防止模板点击报错,保持你原有的未给出的方法定义)
const goWidgetLib = () => {
// 空实现占位(防止模板点击报错,保持你原有的未给出的方法定义)
const goWidgetLib = () => {
uni.navigateTo({ url: '/pages4/pages/xunji/widget' });
};
const goFeedback = () => {};
const goUserGroup = () => {};
const goTutorial = () => {};
};
const goFeedback = () => { };
const goUserGroup = () => { };
const goTutorial = () => { };
</script>
<style scoped lang="scss">
.home-page {
.home-page {
width: 100%;
height: 100vh;
// #ifdef H5
... ... @@ -222,9 +209,9 @@
padding-top: 200rpx;
// #endif
}
}
}
.tab-bar {
.tab-bar {
display: flex;
align-items: flex-end;
justify-content: space-between;
... ... @@ -238,36 +225,36 @@
right: 0;
z-index: 999;
box-sizing: border-box;
}
}
/* 标签项:默认样式 */
.tab-item {
/* 标签项:默认样式 */
.tab-item {
font-size: 16px;
color: #666;
padding: 5px 0;
padding-top: 30rpx;
}
}
/* 激活态标签:下划线+深色文字 */
.tab-item.active {
/* 激活态标签:下划线+深色文字 */
.tab-item.active {
color: #333;
border-bottom: 2px solid #000;
font-weight: 500;
}
}
/* 菜单按钮:样式 */
.menu-btn {
/* 菜单按钮:样式 */
.menu-btn {
font-size: 20px;
color: #666;
}
}
.card-subtitle {
.card-subtitle {
font-size: 24rpx;
color: #666;
margin-bottom: 10rpx;
}
}
.plan-btn {
.plan-btn {
width: 100%;
height: 50rpx;
background-color: #2eaa8a;
... ... @@ -278,95 +265,95 @@
line-height: 50rpx;
text-align: center;
margin-top: 10rpx;
}
}
.card-value {
.card-value {
font-size: 36rpx;
color: #333;
margin-bottom: 10rpx;
}
}
.card-desc {
.card-desc {
font-size: 24rpx;
color: #666;
}
}
/* 抽屉样式 */
.drawer-content {
/* 抽屉样式 */
.drawer-content {
background-color: #ffffff;
height: 100%;
padding: 20rpx;
box-sizing: border-box;
}
}
/* 用户头像和信息区域 */
.user-header {
/* 用户头像和信息区域 */
.user-header {
display: flex;
align-items: center;
padding: 20rpx 0;
border-bottom: 1px solid #f0f0f0;
}
}
.user-header .avatar {
.user-header .avatar {
width: 80rpx;
height: 80rpx;
border-radius: 50%;
margin-right: 20rpx;
margin-top: 0;
justify-content: flex-start;
}
}
.user-info {
.user-info {
display: flex;
flex-direction: column;
}
}
.nickname {
.nickname {
font-size: 28rpx;
font-weight: 500;
color: #333333;
margin-bottom: 8rpx;
}
}
.user-id {
.user-id {
font-size: 24rpx;
color: #999999;
}
}
/* 广告横幅 */
.ad-banner {
/* 广告横幅 */
.ad-banner {
width: 100%;
height: 200rpx;
margin: 20rpx 0;
border-radius: 12rpx;
}
}
/* 菜单列表 */
.menu-list {
/* 菜单列表 */
.menu-list {
margin-top: 20rpx;
}
}
.menu-item {
.menu-item {
display: flex;
align-items: center;
justify-content: space-between;
padding: 30rpx 0;
border-bottom: 1px solid #f0f0f0;
}
}
.menu-item:last-child {
.menu-item:last-child {
border-bottom: none;
}
}
.menu-text {
.menu-text {
font-size: 28rpx;
color: #333333;
margin-left: 20rpx;
flex: 1;
}
}
/* 覆盖uni-icons默认颜色 */
:deep(.uni-icons) {
/* 覆盖uni-icons默认颜色 */
:deep(.uni-icons) {
color: #666666;
}
}
</style>
... ...
... ... @@ -145,7 +145,7 @@
{{ detail.reps }}次
</view>
<view class="detail-value" v-if="unit.exercises[0].exerciseType === 3">
{{ detail.duration }}次
{{ formatSeconds(detail.duration) }}
</view>
<view class="detail-value" v-if="unit.exercises[0].exerciseType === 6">
{{ detail.duration }}组 x {{ formatSeconds(detail.duration) }}
... ... @@ -192,7 +192,7 @@
{{ ex.sets[idx - 1].reps }}次
</text>
<text v-if="ex.exerciseType === 3">
{{ ex.sets[idx - 1].duration }}次
{{ formatSeconds(ex.sets[idx - 1].duration) }}
</text>
<text v-if="ex.exerciseType === 6">
{{ ex.sets[idx - 1].duration }}组 x {{ formatSeconds(ex.sets[idx - 1].duration) }}
... ... @@ -425,7 +425,7 @@ const startDaiTemplateTraining = () => {
uni.navigateTo({
url: `/pages4/pages/xunji/xunji-dongzuo-lianxi?id=${TemplateDetail.value.id}&type=3&dailyTemplateId=${TemplateDetail.value.dailyTemplateId}&isTraining=true`,
});
console.log('开始进入编辑模板页面,模板ID:', TemplateDetail.value.id, '每日模板ID:', TemplateDetail.value.dailyTemplateId);
console.log('开始进入每日moan训练页面,模板ID:', TemplateDetail.value.id, '每日模板ID:', TemplateDetail.value.dailyTemplateId);
console.log('打印传递给动作训练页面的模板id', TemplateDetail.value.id);
... ...
... ... @@ -66,11 +66,9 @@
</scroll-view>
<view class="v-else">
<view v-else>
<!-- 文件夹 -->
<!-- 个人模板 -->
<scroll-view scroll-y="true" class="template-list personal-template-list">
<view class="grid-container">
... ... @@ -160,7 +158,7 @@ const getPartCategories = async () => {
const switchTab = async (tab) => {
activeTab.value = tab;
if (tab === 'official') {
TemplatesList();
getTemplatesList();
} else {
doFilter();
}
... ... @@ -203,7 +201,7 @@ const doFilter = async () => {
isFiltering.value = false;
// 官方回到模板大类
if (activeTab.value === 'official') {
TemplatesList();
getTemplatesList();
} else {
getMyTemplates();
}
... ... @@ -221,12 +219,14 @@ const doFilter = async () => {
res = await TemplatesApi.queryCustTemplate(0, muscleId, sceneId);
}
templateList.value = res.data || [];
console.log('templateList.value', templateList.value);
} catch (err) {
console.log('筛选失败', err);
}
};
const TemplatesList = async () => {
const getTemplatesList = async () => {
try {
const response = await TemplatesApi.getTemplates();
templateList.value = response.data;
... ... @@ -238,44 +238,13 @@ const TemplatesList = async () => {
// 获取我的模板(复用同一个 templateList)
const getMyTemplates = async () => {
// try {
// // 调用你自己的“我的模板”接口
// const res = await TemplatesApi.individualTemplates();
// console.log('打印个人模板res=', res);
// templateList.value = res.data;
// } catch (err) {
// console.log('我的模板加载失败', err);
// }
// 获取我的模板(现在用模拟数据,不影响你原来代码)
templateList.value = [
{
id: 1001,
name: "胸部基础训练",
urlCover: "https://picsum.photos/400/300?1",
exerciseCount: 6,
totalSets: 18,
totalWeight: 50,
primaryMuscleNames: ["胸肌", "三头肌"]
},
{
id: 1002,
name: "腿部力量训练",
urlCover: "https://picsum.photos/400/300?2",
exerciseCount: 5,
totalSets: 15,
totalWeight: 120,
primaryMuscleNames: ["股四头", "臀部"]
},
{
id: 1003,
name: "背部塑形计划",
urlCover: "https://picsum.photos/400/300?3",
exerciseCount: 7,
totalSets: 21,
totalWeight: 70,
primaryMuscleNames: ["背阔肌"]
try {
const res = await TemplatesApi.individualTemplates();
console.log('打印个人模板res=', res);
templateList.value = res.data;
} catch (err) {
console.log('我的模板加载失败', err);
}
];
};
// 返回上一页
... ... @@ -294,7 +263,7 @@ const goToPersonalDetail = (item) => {
// 跳转到模板详情页
const goToTemplate = (item) => {
uni.navigateTo({
url: `/pages4/pages/xunji/xunji-moban?id=${item.id}`
url: `/pages4/pages/xunji/xunji-moban?id=${item.id}&isBigTemOffice=true`
});
};
... ... @@ -305,7 +274,7 @@ const menuButtonInfo = ref({
});
onMounted(() => {
TemplatesList();
getTemplatesList();
getPartCategories();
// 获取小程序胶囊位置信息,实现导航栏与胶囊完美对齐
... ...
<template>
<view class="calendar-page">
<!-- 顶部标签栏 -->
<view class="top-tabs">
<text
v-for="(tab, index) in topTabs"
:key="index"
class="tab-item"
:class="{ active: activeTab === tab }"
@click="switchTab(tab)"
>
{{ tab }}
</text>
</view>
<!-- 年月选择器 -->
<view class="year-month-picker">
<button class="picker-btn" @click="showYearMonthPicker"> {{ currentMonth }} ▼ </button>
</view>
<!-- 功能按钮 -->
<view class="action-buttons">
<button class="action-btn">分享</button>
<button class="action-btn">周/月报</button>
<button class="action-btn">说明</button>
</view>
<!-- 日历网格 -->
<view class="calendar-grid">
<!-- 星期标题 -->
<view class="week-header">
<text v-for="(day, index) in weekDays" :key="index" class="week-day">{{ day }}</text>
</view>
<!-- 日期网格 -->
<view class="date-grid">
<view
v-for="(date, index) in dates"
:key="index"
class="date-cell"
:class="{ today: date.today }"
@click="selectDate"
>
<text class="date-number">{{ date.day }}</text>
<text v-if="date.today" class="today-text">今</text>
</view>
</view>
</view>
<!-- 底部 TabBar -->
<view class="bottom-tabbar">
<navigator url="/pages/xunji/xunji" class="tab-item">
<image
class="tab-icon"
src="https://fitness-hcxtec-bucket.oss-cn-shenzhen.aliyuncs.com/20260316/order-empty_1773628059920.png"
mode="aspectFill"
></image>
<text class="tab-text">首页</text>
</navigator>
<navigator url="/pages/course/course" class="tab-item">
<image
class="tab-icon"
src="https://fitness-hcxtec-bucket.oss-cn-shenzhen.aliyuncs.com/20260316/order-empty_1773628059920.png"
mode="aspectFill"
></image>
<text class="tab-text">课程</text>
</navigator>
<navigator url="/pages/enter-gym/enter-gym" class="tab-item active">
<image
class="tab-icon"
src="https://fitness-hcxtec-bucket.oss-cn-shenzhen.aliyuncs.com/20260316/order-empty_1773628059920.png"
mode="aspectFill"
></image>
<text class="tab-text">进馆</text>
</navigator>
<navigator url="/pages/training-log/training-log" class="tab-item">
<image
class="tab-icon"
src="https://fitness-hcxtec-bucket.oss-cn-shenzhen.aliyuncs.com/20260316/order-empty_1773628059920.png"
mode="aspectFill"
></image>
<text class="tab-text">训记</text>
</navigator>
<navigator url="/pages/my/my" class="tab-item">
<image
class="tab-icon"
src="https://fitness-hcxtec-bucket.oss-cn-shenzhen.aliyuncs.com/20260316/order-empty_1773628059920.png"
mode="aspectFill"
></image>
<text class="tab-text">我的</text>
</navigator>
</view>
</view>
</template>
<script setup>
import { ref } from 'vue';
// 响应式数据
const activeTab = ref('日历');
const currentMonth = ref('2025.10月');
const weekDays = ref(['一', '二', '三', '四', '五', '六', '日']);
const topTabs = ref(['概要', '计划', '日历', '动作', '模板', '数据']);
const dates = ref([
{ day: 29, today: false },
{ day: 30, today: false },
{ day: 1, today: false },
{ day: 2, today: false },
{ day: 3, today: false },
{ day: 4, today: false },
{ day: 5, today: false },
{ day: 6, today: false },
{ day: 7, today: false },
{ day: 8, today: false },
{ day: 9, today: false },
{ day: 10, today: false },
{ day: 11, today: false },
{ day: 12, today: false },
{ day: 13, today: false },
{ day: 14, today: false },
{ day: 15, today: false },
{ day: 16, today: true },
{ day: 17, today: false },
{ day: 18, today: false },
{ day: 19, today: false },
{ day: 20, today: false },
{ day: 21, today: false },
{ day: 22, today: false },
{ day: 23, today: false },
{ day: 24, today: false },
{ day: 25, today: false },
{ day: 26, today: false },
{ day: 27, today: false },
{ day: 28, today: false },
{ day: 29, today: false },
{ day: 30, today: false },
{ day: 31, today: false },
{ day: 1, today: false },
{ day: 2, today: false },
]);
// 方法
const switchTab = (tab) => {
activeTab.value = tab;
};
const showYearMonthPicker = () => {
uni.showActionSheet({
itemList: ['2025.10月', '2025.11月', '2025.12月'],
success: (res) => {
if (res.tapIndex === 0) {
currentMonth.value = '2025.10月';
} else if (res.tapIndex === 1) {
currentMonth.value = '2025.11月';
} else {
currentMonth.value = '2025.12月';
}
},
});
};
const selectDate = () => {
uni.navigateTo({
url: '/pages4/pages/xunji/xunji-rili-tianjia',
});
};
</script>
<style scoped lang="scss">
.calendar-page {
background-color: white;
min-height: 100vh;
}
.top-tabs {
display: flex;
justify-content: space-around;
padding: 20rpx 0;
border-bottom: 1px solid #eee;
font-size: 28rpx;
color: #333;
}
.tab-item {
padding: 10rpx 0;
border-bottom: 2rpx solid transparent;
}
.tab-item.active {
color: #ffd700;
border-bottom-color: #ffd700;
}
.year-month-picker {
padding: 20rpx;
display: flex;
justify-content: flex-start;
}
.picker-btn {
background-color: white;
border: 1px solid #ddd;
border-radius: 20rpx;
padding: 10rpx 20rpx;
font-size: 26rpx;
color: #333;
}
.action-buttons {
display: flex;
justify-content: flex-end;
padding: 20rpx;
gap: 20rpx;
}
.action-btn {
background-color: white;
border: 1px solid #ddd;
border-radius: 20rpx;
padding: 10rpx 20rpx;
font-size: 24rpx;
color: #333;
}
.calendar-grid {
margin: 20rpx;
}
.week-header {
display: flex;
justify-content: space-between;
padding: 20rpx 0;
font-size: 26rpx;
color: #999;
}
.week-day {
width: 40rpx;
text-align: center;
}
.date-grid {
display: grid;
grid-template-columns: repeat(7, 1fr);
gap: 10rpx;
}
.date-cell {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
height: 80rpx;
border: 1px solid #eee;
border-radius: 8rpx;
font-size: 26rpx;
color: #333;
position: relative;
}
.date-cell.today {
background-color: #f5f5f5;
color: #ffd700;
}
.today-text {
position: absolute;
bottom: 10rpx;
font-size: 20rpx;
color: #ffd700;
}
.bottom-tabbar {
display: flex;
justify-content: space-around;
padding: 20rpx;
background-color: white;
border-top: 1px solid #eee;
position: fixed;
bottom: 0;
left: 0;
right: 0;
z-index: 999;
}
.tab-item {
display: flex;
flex-direction: column;
align-items: center;
font-size: 24rpx;
color: #333;
}
.tab-item.active {
color: #ffd700;
}
.tab-icon {
width: 40rpx;
height: 40rpx;
margin-bottom: 6rpx;
}
</style>
... ... @@ -57,7 +57,7 @@
<text>结束这个计划</text>
</view> -->
<WodeJihuaTianjiaTancuang v-if="showPlanPopup" v-model:visible="showPlanPopup" :isAdd="false"
:plan-title="'选择课程立即开始训练'" :plan-id="selectPlanId" />
:plan-title="'选择课程立即开始训练'" :plan-id="selectPlanId" :is-my-plan="true" />
</view>
... ...
... ... @@ -176,7 +176,7 @@
</view>
</template>
</view>
<!-- 加入计划的弹窗 -->
<WeekSelectPopup v-model:visible="showWeekPopup" :max-count="plandetail.frequencyPerWeek" :plan-detail="plandetail"
@success="loadDetail" :is-update="isUpdate" />
... ... @@ -184,9 +184,12 @@
<AddToCalendarPopup ref="calendarPopupRef" :plan-id="plandetail.id" :template-id="currentTemplateId"
@success="handleCalendarSuccess" />
<!-- 去训练弹窗 -->
<!-- 去训练弹窗,显示当前计划的所有模板,可以直接跳转到训练页面 -->
<template v-if="plandetail?.id">
<WodeJihuaTianjiaTancuang v-if="showPlanPopup" v-model:visible="showPlanPopup" :isAdd="false"
:plan-title="'选择课程立即开始训练'" :plan-id="plandetail.id" />
:plan-title="'选择课程立即开始训练'" :plan-id="plandetail.id" :is-my-plan="false"/>
</template>
</view>
</template>
... ...
... ... @@ -2,13 +2,73 @@ import request from '@/sheep/request';
const dailytemplateApi = {
//获取每日模板
getdailytemplate:(date)=>{
getdailytemplate: (date) => {
return request({
url:'/app/daily/template/DailyTemplates',
method:'GET',
params:{date}
url: '/app/daily/template/DailyTemplates',
method: 'GET',
params: { date },
});
}
},
// 删除当日模板
deleteDailyTemplate: (id) => {
return request({
url: `/app/daily/template/${id}`,
method: 'DELETE',
});
},
// 更新或者添加日期备注颜色
AddOrUpdateDateNote: (data) => {
return request({
url: `/app/daily/template/note`,
method: 'POST',
data,
});
},
// 删除日期备注
deleteDateNote: (date) => {
return request({
url: `/app/daily/template/note`,
method: 'DELETE',
params: { date },
});
},
// 获得日期备注详情
getNoteDetail: (id) => {
return request({
url: `/app/daily/template/note/${id}`,
method: 'GET',
});
},
// 更新日期备注详情
updateNote: (data) => {
return request({
url: `/app/daily/template/note`,
method: 'PUT',
data,
});
},
//
backgroundColor: (data) => {
return request({
url: '/app/daily/template/backgroundColor',
method: 'PUT',
data,
});
},
completeDailyTemplate: (id) => {
return request({
url: `/app/daily/template/complete/${id}`,
method: 'POST',
});
},
// 更新每日模板
updateDailyTemplate: (data) => {
return request({
url: `/app/daily/template`,
method: 'PUT',
data,
});
},
};
export default dailytemplateApi;
... ...
... ... @@ -8,6 +8,7 @@ const TemplatesApi = {
method: 'GET',
});
},
// 获得模板大类列表(官方)
getTemplates: () => {
return request({
url: '/app/templates/selectGroup',
... ... @@ -15,27 +16,60 @@ const TemplatesApi = {
});
},
//获得模板详情
getTemplateDetail: (id)=>{
// 获得个人模板列表
individualTemplates: () => {
return request({
url:'/app/templates/getTemplateDetail',
method:'GET',
params:{id}
url: '/app/templates/getCustTemplate',
method: 'GET',
});
},
// 条件查询个人列表
queryCustTemplate: (groupId, muscleId, sceneId) => {
return request({
url: '/app/templates/queryCustTemplate',
method: 'GET',
params: {
groupId,
muscleId,
sceneId,
},
});
},
// 条件查询官方模板
getOfficeTemplates: (muscleId, sceneId) => {
return request({
url: '/app/templates/queryTemplatesByCondition',
method: 'GET',
params: {
muscleId,
sceneId,
},
});
},
//获得官方模板详情
getTemplateDetail: (id) => {
return request({
url: '/app/templates/getTemplateDetail',
method: 'GET',
params: { id },
});
},
// 获得所有的部位
getPartAllCategories: ()=> {
getPartAllCategories: () => {
return request({
url:'/app/motion/categories/sub/get',
method:'GET',
})
url: '/app/motion/categories/sub/get',
method: 'GET',
});
},
// 根据场景和部位筛选模板
queryTemplatesByCondition: (params) => {
return request({
url: '/app/templates/queryTemplatesByCondition',
method: 'GET',
params: params //
params: params, //
});
},
//获得细分锻炼部位列表
... ... @@ -44,7 +78,117 @@ const TemplatesApi = {
url: '/app/motion/exercises/sub-categories',
method: 'GET',
});
}
},
// 创建个人模板
createCustTemplate: (data) => {
return request({
url: '/app/templates/createCustTemplate',
method: 'POST',
data,
});
},
// 更新个人模板
updateCustTemplate: (data) => {
return request({
url: '/app/templates/updateCustTemplate',
method: 'PUT',
data,
});
},
// 删除个人模板
deleteCustTemplate: (templateId) => {
return request({
url: '/app/templates/deleteCustTemplate',
method: 'DELETE',
params: { templateId: templateId },
});
},
// 获得个人模板详情
getCustTemplateDetail: (id) => {
return request({
url: '/app/templates/getCustTemplateDetail',
method: 'GET',
params: { id: id },
});
},
// 创建模板文件夹
createGroup: (name) => {
return request({
url: '/app/templates/createGroup',
method: 'POST',
data: {
name: name,
},
});
},
// 获得模板文件夹列表
getTemplateFileList: () => {
return request({
url: '/app/templates/getCustTemplateGroup',
method: 'GET',
});
},
// 删除模板文件夹
deleteCustTemplateGroup: (groupId) => {
return request({
url: '/app/templates/deleteCustTemplateGroup',
method: 'DELETE',
params: { groupId: groupId },
});
},
// 更新模板文件夹
updateTemplateGroup: (groupId, templateId) => {
return request({
url: '/app/templates/updateTemplateGroup',
method: 'PUT',
data: {
groupId,
templateId,
},
});
},
// 更新个人模板文件夹名称
updateTemplateGroupName: (data) => {
return request({
url: '/app/templates/updateTemplateGroup/name',
method: 'PUT',
data,
});
},
// 获得个人模板文件夹名称
getTemplateGroupNname: (groupId) => {
return request({
url: '/app/templates/getTemplateGroup/name',
method: 'GET',
params: {
groupId: groupId,
},
});
},
// 设置日历颜色
putCalendarColor: (templateId, backgroundColor) => {
return request({
url: '/app/daily/template/template/calendarColor',
method: 'PUT',
data: {
templateId,
backgroundColor,
},
});
},
// 是否添加计划
isAddPlan: (id) => {
return request({
url: '/app/plan/isAdd',
method: 'GET',
params: {
id,
},
});
},
};
export default TemplatesApi;
... ...
... ... @@ -2,7 +2,7 @@ import request from '@/sheep/request';
const TrainingApi = {
//创建训练历史
creatTrainHistory: (data) => {
createTrainHistory: (data) => {
return request({
url: '/app/training/history',
method: 'POST',
... ...
... ... @@ -165,7 +165,7 @@ const ExercisesApi = {
return request({
url: `/app/motion/exercises/notes/add`,
method: 'POST',
data
data,
});
},
};
... ...
import request from '@/sheep/request';
import { method } from 'lodash';
// 查询计划API
const QueryPlanApi = {
... ... @@ -7,7 +8,7 @@ const QueryPlanApi = {
url: '/app/plan/queryPlan',
method: 'GET', // 匹配文档的GET请求方式
params: {
categoryId
categoryId,
}, // 传递query参数(可选)
});
},
... ... @@ -23,10 +24,33 @@ const QueryPlanApi = {
url: '/app/plan/getPlanDetail',
method: 'GET',
params: {
id
id,
},
});
},
// 获取我的计划详情(含课程)
getMyPlanDetail: (id) => {
return request({
url: '/app/plan/getmyPlanDetail',
method: 'GET',
params: {
id,
},
});
},
// 根据每日模板ID获取模板详情
getDailyTemplateDetail: (id) => {
return request({
url: '/app/plan/getDailyTemplateDetail',
method: 'GET',
params: {
id,
},
});
},
// 根据筛选条件获得当前计划分类下的计划列表
getFilteredPlanList: (params) => {
return request({
... ... @@ -49,39 +73,119 @@ const QueryPlanApi = {
return request({
url: '/app/plan/arrangePlan',
method: 'POST',
data
data,
});
},
// 重新开始计划
reStartPlan: (data) => {
return request({
url: '/app/plan/rearrangePlan',
method: 'POST',
data,
});
},
// 获得本周计划
getWeekPlan: (id) => {
return request({
url: `/app/plan/getWeekPlan`,
method: 'GET',
params: {
id,
},
});
},
// 添加计划
addPlan: (id) => {
return request({
url:`/app/plan/addPlan`,
url: `/app/plan/addPlan`,
method: 'GET',
params: {
id
}
})
id,
},
});
},
// 是否添加计划
isAddPlan: (id) => {
return request({
url:`/app/plan/isAdd`,
url: `/app/plan/isAdd`,
method: 'GET',
params: {
id
}
})
id,
},
});
},
// 添加计划到日历
addPlanToCalendar: (data) => {
return request ({
return request({
url: `/app/daily/template`,
method: 'POST',
data
})
}
data,
});
},
// 获得我的计划列表
getMyPlan: () => {
return request({
url: '/app/plan/getMyPlan',
method: 'GET',
});
},
// 结束这个计划
deletePlan: (id) => {
return request({
url: '/app/plan/deletePlan',
method: 'DELETE',
params: {
id,
},
});
},
// 获得个人模板详情
getMyPlanDetail: (id) => {
return request({
url: '/app/plan/getmyPlanDetail',
method: 'GET',
params: {
id,
},
});
},
// 获取计划日历数据(本月+下月)
getPlanArrangeCalendar: (Id) => {
return request({
url: '/app/plan/getCalendar',
method: 'GET',
params: {
Id,
},
});
},
// 移动到
updateDailyTemplateDate: (data) => {
return request({
url: '/app/plan/updateDailyTemplateDate',
method: 'POST',
data,
});
},
}
// 收藏-取消收藏计划
toggleFavorite: (planId, status) => {
return request({
url: '/app/plan/favorite/toggle',
method: 'POST',
data: { planId, status },
});
},
// 检查是否已收藏计划
checkFavorite: (planId) => {
return request({
url: `/app/plan/favorite/check/${planId}`,
method: 'GET',
});
},
};
export default QueryPlanApi;
... ...
... ... @@ -38,13 +38,17 @@ export const useTrainingStore = defineStore('training', {
let res;
if (type === 1) {
res = await ExercisesApi.getExerciseById(id);
console.log('动作详情:', res);
} else if (type === 2) {
res = await SupersetsApi.getSupersetsInfo(id);
console.log('超级组详情:', res);
} else if (type === 3) {
if (this.isSystem === 1) {
res = await TemplatesApi.getTemplateDetail(id);
console.log('官方模板详情:', res);
} else {
res = await TemplatesApi.getCustTemplateDetail(id);
console.log('个人模板详情:', res);
}
console.log('pinia中打开模板数据:', res);
}
... ... @@ -63,12 +67,12 @@ export const useTrainingStore = defineStore('training', {
},
loadDailyTemplateForEdit(fullDailyPlan) {
// 2. 🔥 核心:把【完整每日模板数据】直接赋值给 actionDetail
// 动作、顺序、超级组、组数、全部保留,不请求接口
console.log('fullDailyPlan', fullDailyPlan);
this.actionDetail = { ...fullDailyPlan };
console.log('每日模板编辑:已赋值完整模板数据到 actionDetail', this.actionDetail);
console.log('每日模板编辑:已赋值完整模板数据到 actionDetail', this.actionDetail);
// 3. 固定类型为模板
this.type = 3;
... ... @@ -79,7 +83,7 @@ export const useTrainingStore = defineStore('training', {
// 5. 初始化训练记录(重量、次数、完成状态)
this.unitRecords = {};
const units = this.actionDetail?.units || [];
console.log('每日模板的unit',units);
console.log('每日模板的unit', units);
units.forEach((unit, unitIndex) => {
let records = {};
... ... @@ -99,8 +103,6 @@ export const useTrainingStore = defineStore('training', {
// 初始化模板自带的训练数据到 unitRecords
initTemplateRecords() {
console.log('✅=================== 我执行了!开始初始化模板数据');
console.log('EEEEEEEEEEEEEEEEEEEEEE');
// 只在空的时候初始化(避免重复覆盖)
if (Object.keys(this.unitRecords).length > 0) return;
if (this.dailyTemplateId) return;
... ... @@ -201,13 +203,13 @@ export const useTrainingStore = defineStore('training', {
// ✅ 工具方法放到这里
// ======================
convertUnitToActionDetail(unit) {
//转为动作
//超级组转为动作
const convertExercises = (list) => {
return (list || []).map((item) => ({
id: item.exerciseId,
name: item.exerciseName,
// urlImage: item.exerciseCover || item.url3dAnimation,
urlImage: item.url3dAnimation || item.urlImage,
urlImage: item.url3dAnimation || item.exerciseCover || item.urlImage,
exerciseType: item.exerciseType,
}));
};
... ... @@ -221,10 +223,12 @@ export const useTrainingStore = defineStore('training', {
}
if (unit.unitType === 1) {
const act = (unit.exercises || [])[0] || {};
console.log('------------act=', act);
return {
id: act.exerciseId,
name: act.exerciseName,
urlImage: act.exerciseCover || act.url3dAnimation,
urlImage: act.exerciseCover || act.url3dAnimation || act.urlImage,
// urlImage
exerciseType: act.exerciseType,
categoryDescription: act.categoryDescription,
equipmentDescription: act.equipmentDescription,
... ... @@ -260,7 +264,8 @@ export const useTrainingStore = defineStore('training', {
exerciseId: this.actionDetail.id,
exerciseName: this.actionDetail.name,
exerciseType: this.actionDetail.exerciseType,
urlImage: this.actionDetail.urlImage || this.actionDetail.url3dAnimation,
// urlImage: this.actionDetail.urlImage || this.actionDetail.url3dAnimation,
urlImage: this.actionDetail.url3dAnimation || this.actionDetail.urlImage,
categoryDescription: this.actionDetail.categoryDescription,
equipmentDescription: this.actionDetail.equipmentDescription,
},
... ...