Merge branch 'feature/qxm'
Showing
5 changed files
with
203 additions
and
289 deletions
| @@ -449,23 +449,15 @@ const recordList = ref([ | @@ -449,23 +449,15 @@ const recordList = ref([ | ||
| 449 | { h: '00', m: '00', s: '00', quickTimeDisplay: '60s', distance: '', weight: '', reps: '', duration: '', restTime: '', isActive: false }, | 449 | { h: '00', m: '00', s: '00', quickTimeDisplay: '60s', distance: '', weight: '', reps: '', duration: '', restTime: '', isActive: false }, |
| 450 | ]); | 450 | ]); |
| 451 | 451 | ||
| 452 | -watch(recordList, () => { | ||
| 453 | - // console.log('recordList变化,发送长度:', recordList.value.length) | ||
| 454 | - emit('update:groupCount', recordList.value.length) | ||
| 455 | -}, { deep: true, immediate: true }) | ||
| 456 | - | ||
| 457 | const saveToStore = () => { | 452 | const saveToStore = () => { |
| 458 | let records = {}; | 453 | let records = {}; |
| 459 | - | ||
| 460 | if (props.type === 1) { | 454 | if (props.type === 1) { |
| 461 | // 普通动作 | 455 | // 普通动作 |
| 462 | records[props.actionDetail.id] = recordList.value; | 456 | records[props.actionDetail.id] = recordList.value; |
| 463 | - | ||
| 464 | } else if (props.type === 2) { | 457 | } else if (props.type === 2) { |
| 465 | // 超级组 | 458 | // 超级组 |
| 466 | records = superRecordMap.value; | 459 | records = superRecordMap.value; |
| 467 | } | 460 | } |
| 468 | - | ||
| 469 | // 调用 Pinia 保存 | 461 | // 调用 Pinia 保存 |
| 470 | trainingStore.saveUnitRecord(props.unitIndex, { | 462 | trainingStore.saveUnitRecord(props.unitIndex, { |
| 471 | records: records, | 463 | records: records, |
| @@ -473,6 +465,11 @@ const saveToStore = () => { | @@ -473,6 +465,11 @@ const saveToStore = () => { | ||
| 473 | }); | 465 | }); |
| 474 | }; | 466 | }; |
| 475 | 467 | ||
| 468 | +watch(recordList, () => { | ||
| 469 | + // console.log('recordList变化,发送长度:', recordList.value.length) | ||
| 470 | + emit('update:groupCount', recordList.value.length) | ||
| 471 | +}, { deep: true, immediate: true }) | ||
| 472 | + | ||
| 476 | watch([recordList, superRecordMap, userWeight], () => { | 473 | watch([recordList, superRecordMap, userWeight], () => { |
| 477 | saveToStore(); | 474 | saveToStore(); |
| 478 | console.log('+++++++++打印全局训练数据 trainingStore.unitRecords++++++++', trainingStore.unitRecords); | 475 | console.log('+++++++++打印全局训练数据 trainingStore.unitRecords++++++++', trainingStore.unitRecords); |
| @@ -63,13 +63,13 @@ | @@ -63,13 +63,13 @@ | ||
| 63 | </view> | 63 | </view> |
| 64 | <!-- 要点,历史,平替动作标签 --> | 64 | <!-- 要点,历史,平替动作标签 --> |
| 65 | <view class="content-tabs"> | 65 | <view class="content-tabs"> |
| 66 | - <view class="tab-item" :class="{ active: contentTab === 0 }" @click="contentTab = 0"> | 66 | + <view class="tab-item" :class="{ active: contentTab === 0 }" @click="switchContentTab(0)"> |
| 67 | 要点 | 67 | 要点 |
| 68 | </view> | 68 | </view> |
| 69 | - <view class="tab-item" :class="{ active: contentTab === 1 }" @click="contentTab = 1"> | 69 | + <view class="tab-item" :class="{ active: contentTab === 1 }" @click="switchContentTab(1)"> |
| 70 | 历史 | 70 | 历史 |
| 71 | </view> | 71 | </view> |
| 72 | - <view class="tab-item" :class="{ active: contentTab === 2 }" @click="contentTab = 2" v-if="type === 1"> | 72 | + <view class="tab-item" :class="{ active: contentTab === 2 }" @click="switchContentTab(2)" v-if="type === 1"> |
| 73 | 平替动作 | 73 | 平替动作 |
| 74 | </view> | 74 | </view> |
| 75 | </view> | 75 | </view> |
| @@ -167,7 +167,7 @@ | @@ -167,7 +167,7 @@ | ||
| 167 | <!-- <view class="difficulty">困难</view> --> | 167 | <!-- <view class="difficulty">困难</view> --> |
| 168 | <view class="difficulty">{{ | 168 | <view class="difficulty">{{ |
| 169 | item.weight ? item.weight + 'kg' : '无负重' | 169 | item.weight ? item.weight + 'kg' : '无负重' |
| 170 | - }}</view> | 170 | + }}</view> |
| 171 | </view> | 171 | </view> |
| 172 | <view class="group-chips"> | 172 | <view class="group-chips"> |
| 173 | <view class="chip" v-for="(set, index) in item.setConfigList" :key="index"> | 173 | <view class="chip" v-for="(set, index) in item.setConfigList" :key="index"> |
| @@ -189,7 +189,7 @@ | @@ -189,7 +189,7 @@ | ||
| 189 | <view v-if="contentTab === 2 && type === 1" class="tab-pane slide-up"> | 189 | <view v-if="contentTab === 2 && type === 1" class="tab-pane slide-up"> |
| 190 | <view class="substitute-list"> | 190 | <view class="substitute-list"> |
| 191 | <view class="sub-item" v-for="item in alternativeActions" :key="item.id" @click="openActionItem(item)"> | 191 | <view class="sub-item" v-for="item in alternativeActions" :key="item.id" @click="openActionItem(item)"> |
| 192 | - <image :src="item.urlImage || lostImage" mode="aspectFill" class="img" /> | 192 | + <image :src="item.url3dAnimation || lostImage" mode="aspectFill" class="img" /> |
| 193 | <view class="sub-info"> | 193 | <view class="sub-info"> |
| 194 | <text class="name">{{ item.name }}</text> | 194 | <text class="name">{{ item.name }}</text> |
| 195 | 195 | ||
| @@ -221,6 +221,8 @@ import { onShareAppMessage } from '@dcloudio/uni-app'; | @@ -221,6 +221,8 @@ import { onShareAppMessage } from '@dcloudio/uni-app'; | ||
| 221 | // 静态配置 | 221 | // 静态配置 |
| 222 | 222 | ||
| 223 | const alternativeActions = ref([]); // 平替动作列表接口数据 | 223 | const alternativeActions = ref([]); // 平替动作列表接口数据 |
| 224 | +const loadedHistory = ref(false) | ||
| 225 | +const loadedAlternative = ref(false) | ||
| 224 | 226 | ||
| 225 | // 响应式状态 | 227 | // 响应式状态 |
| 226 | const actionShow = ref(false); | 228 | const actionShow = ref(false); |
| @@ -300,25 +302,42 @@ const startTraining = () => { | @@ -300,25 +302,42 @@ const startTraining = () => { | ||
| 300 | }); | 302 | }); |
| 301 | }; | 303 | }; |
| 302 | 304 | ||
| 303 | -const open = (id, typeData) => { | 305 | +const switchContentTab = async (chooseTab) => { |
| 306 | + contentTab.value = chooseTab; | ||
| 307 | + // 切历史 | ||
| 308 | + if (chooseTab === 1 && !loadedHistory.value) { | ||
| 309 | + await loadTrainHistoryDetail(actionId.value, type.value) | ||
| 310 | + loadedHistory.value = true; | ||
| 311 | + } | ||
| 312 | + // 切平替 | ||
| 313 | + if (chooseTab === 2 && type.value === 1 && !loadedAlternative.value) { | ||
| 314 | + await loadAlternativeActions(actionId.value) | ||
| 315 | + loadedAlternative.value = true; | ||
| 316 | + } | ||
| 317 | +} | ||
| 318 | + | ||
| 319 | +const open = async (id, typeData) => { | ||
| 304 | actionId.value = Number(id); | 320 | actionId.value = Number(id); |
| 305 | type.value = typeData; | 321 | type.value = typeData; |
| 306 | contentTab.value = 0; | 322 | contentTab.value = 0; |
| 307 | console.log('动作详情页面接收id和类型:', actionId.value, type.value); | 323 | console.log('动作详情页面接收id和类型:', actionId.value, type.value); |
| 308 | // 如何判断是动作还是超级组 | 324 | // 如何判断是动作还是超级组 |
| 309 | if (typeData == 1) { | 325 | if (typeData == 1) { |
| 310 | - loadexercisedetail(actionId.value); | ||
| 311 | - loadAlternativeActions(actionId.value); | ||
| 312 | - checkExerciseFavorited(); | 326 | + await loadexercisedetail(actionId.value); |
| 327 | + // await loadAlternativeActions(actionId.value); | ||
| 328 | + await checkExerciseFavorited(); | ||
| 313 | } else { | 329 | } else { |
| 314 | - loadsuperdetail(actionId.value); | ||
| 315 | - checkSupersetFavorited(); | 330 | + await loadsuperdetail(actionId.value); |
| 331 | + await checkSupersetFavorited(); | ||
| 316 | } | 332 | } |
| 317 | 333 | ||
| 318 | console.log('请求参数actionId/typeData', actionId.value, type.value); | 334 | console.log('请求参数actionId/typeData', actionId.value, type.value); |
| 319 | 335 | ||
| 336 | + // 重置加载训练历史列表和平替动作列表标记 | ||
| 337 | + loadedHistory.value = false | ||
| 338 | + loadedAlternative.value = false | ||
| 320 | 339 | ||
| 321 | - loadTrainHistoryDetail(actionId.value, type.value); | 340 | + // loadTrainHistoryDetail(actionId.value, type.value); |
| 322 | actionShow.value = true; | 341 | actionShow.value = true; |
| 323 | }; | 342 | }; |
| 324 | // 打开备注弹窗 | 343 | // 打开备注弹窗 |
| @@ -280,7 +280,7 @@ | @@ -280,7 +280,7 @@ | ||
| 280 | <CalendarColorPicker v-model:visible="showColorPopup" :daily-template-id="selectedPlanId" | 280 | <CalendarColorPicker v-model:visible="showColorPopup" :daily-template-id="selectedPlanId" |
| 281 | :current-color="currentPlan?.templateBackgroundColor || '#ffffff'" @success="calendarColorPickerSuccess" /> | 281 | :current-color="currentPlan?.templateBackgroundColor || '#ffffff'" @success="calendarColorPickerSuccess" /> |
| 282 | 282 | ||
| 283 | - <MeiRiMoBanXiuGai ref="meirimobanRef" @saveSuccess="loaddailytemplate(selectedDate)" /> | 283 | + <MeiRiMoBanXiuGai ref="meirimobanRef" @saveSuccess="handleRenderSuccess" /> |
| 284 | </view> | 284 | </view> |
| 285 | </up-popup> | 285 | </up-popup> |
| 286 | </template> | 286 | </template> |
| @@ -446,6 +446,12 @@ const loaddailytemplate = async () => { | @@ -446,6 +446,12 @@ const loaddailytemplate = async () => { | ||
| 446 | } | 446 | } |
| 447 | }; | 447 | }; |
| 448 | 448 | ||
| 449 | +const handleRenderSuccess = async () => { | ||
| 450 | + | ||
| 451 | + await loaddailytemplate(); | ||
| 452 | + await nextTick() | ||
| 453 | +} | ||
| 454 | + | ||
| 449 | const switchPlan = (index) => { | 455 | const switchPlan = (index) => { |
| 450 | currentPlanIndex.value = index; | 456 | currentPlanIndex.value = index; |
| 451 | console.log('【切换标签后 - currentPlan】', currentPlan.value); | 457 | console.log('【切换标签后 - currentPlan】', currentPlan.value); |
| @@ -43,20 +43,18 @@ const isRenderDongzuo = ref(false) | @@ -43,20 +43,18 @@ const isRenderDongzuo = ref(false) | ||
| 43 | // 标记是否需要删除当前动作组 | 43 | // 标记是否需要删除当前动作组 |
| 44 | const needDeleteUnit = ref(false) | 44 | const needDeleteUnit = ref(false) |
| 45 | 45 | ||
| 46 | -// watch( | ||
| 47 | -// () => templateStore.replaceId, | ||
| 48 | -// (id) => { | ||
| 49 | -// if (id) { | ||
| 50 | -// needReplaceUnit.value = true | ||
| 51 | -// uni.showToast({ | ||
| 52 | -// title: '已标记替换', | ||
| 53 | -// icon: 'success' | ||
| 54 | -// }) | ||
| 55 | -// } | ||
| 56 | -// } | ||
| 57 | -// ) | ||
| 58 | - | ||
| 59 | -// 原watch不动,补充拉取新数据、替换source.unit | 46 | +// 缓存打开弹窗传入的数据 |
| 47 | +let sourceInfo = ref({ | ||
| 48 | + unit: null, | ||
| 49 | + unitIndex: null, | ||
| 50 | + dailyTemplate: null | ||
| 51 | +}) | ||
| 52 | +// 当前操作的unit和下标 | ||
| 53 | +const currUnit = computed(() => sourceInfo.value.unit || {}) | ||
| 54 | +const currUnitIndex = computed(() => sourceInfo.value.unitIndex ?? 0) | ||
| 55 | + | ||
| 56 | +//当替换动作的时候, 原watch不动,补充拉取新数据、替换source.unit | ||
| 57 | +const replaceCacheUnit = ref(null) | ||
| 60 | watch( | 58 | watch( |
| 61 | () => templateStore.replaceId, | 59 | () => templateStore.replaceId, |
| 62 | async (id) => { | 60 | async (id) => { |
| @@ -97,7 +95,29 @@ watch( | @@ -97,7 +95,29 @@ watch( | ||
| 97 | } | 95 | } |
| 98 | console.log('newUnit', newUnit); | 96 | console.log('newUnit', newUnit); |
| 99 | } | 97 | } |
| 98 | + | ||
| 99 | + // ============【新增改动】缓存拼装好的替换单元,保存复用============ | ||
| 100 | + replaceCacheUnit.value = newUnit | ||
| 101 | + // ================================================================= | ||
| 102 | + | ||
| 103 | + | ||
| 100 | sourceInfo.value.unit = newUnit | 104 | sourceInfo.value.unit = newUnit |
| 105 | + | ||
| 106 | + // ========== 新增:同步初始化当前unitIndex的Pinia训练记录 ========== | ||
| 107 | + const unitIdx = sourceInfo.value.unitIndex | ||
| 108 | + const exercises = newUnit.exercises || [] | ||
| 109 | + let records = {} | ||
| 110 | + exercises.forEach(ex => { | ||
| 111 | + // 新动作无历史sets,给默认空白一组(和open初始化逻辑统一) | ||
| 112 | + records[ex.exerciseId] = [{ | ||
| 113 | + h: '00', m: '00', s: '00', quickTimeDisplay: '60s', | ||
| 114 | + distance: '', weight: '', reps: '', duration: '', restTime: '', isActive: false | ||
| 115 | + }] | ||
| 116 | + }) | ||
| 117 | + // 覆盖当前unitIndex的仓库记录 | ||
| 118 | + trainingStore.saveUnitRecord(unitIdx, { records, userWeight: 70 }) | ||
| 119 | + // ================================================================= | ||
| 120 | + | ||
| 101 | // 销毁重建dongzuo实现刷新 | 121 | // 销毁重建dongzuo实现刷新 |
| 102 | isRenderDongzuo.value = false | 122 | isRenderDongzuo.value = false |
| 103 | await nextTick() | 123 | await nextTick() |
| @@ -106,49 +126,7 @@ watch( | @@ -106,49 +126,7 @@ watch( | ||
| 106 | } | 126 | } |
| 107 | ) | 127 | ) |
| 108 | 128 | ||
| 109 | - | ||
| 110 | -// 缓存打开弹窗传入的数据 | ||
| 111 | -let sourceInfo = ref({ | ||
| 112 | - unit: null, | ||
| 113 | - unitIndex: null, | ||
| 114 | - dailyTemplate: null | ||
| 115 | -}) | ||
| 116 | -// 当前操作的unit和下标 | ||
| 117 | -const currUnit = computed(() => sourceInfo.value.unit || {}) | ||
| 118 | -const currUnitIndex = computed(() => sourceInfo.value.unitIndex ?? 0) | ||
| 119 | - | ||
| 120 | -// 格式化数据:统一 动作 / 超级组 结构 → 给 dongzuo 组件用 | ||
| 121 | -// const formatDongzuoData = (unit) => { | ||
| 122 | -// if (!unit) return {} | ||
| 123 | -// console.log('++每日模板的unit++', unit); | ||
| 124 | - | ||
| 125 | -// if (unit.unitType === 1) { | ||
| 126 | -// const ex = unit.exercises?.[0] || {} | ||
| 127 | -// return { | ||
| 128 | -// id: ex.exerciseId, | ||
| 129 | -// name: ex.exerciseName, | ||
| 130 | -// urlImage: ex.url3dAnimation, | ||
| 131 | -// exerciseType: ex.exerciseType, | ||
| 132 | -// categoryDescription: ex.categoryDescription || '', | ||
| 133 | -// equipmentDescription: ex.equipmentDescription || '', | ||
| 134 | -// } | ||
| 135 | -// } | ||
| 136 | - | ||
| 137 | -// if (unit.unitType === 2) { | ||
| 138 | -// return { | ||
| 139 | -// id: unit.unitId, | ||
| 140 | -// name: unit.unitName || '超级组', | ||
| 141 | -// exercises: unit.exercises?.map(ex => ({ | ||
| 142 | -// id: ex.exerciseId, | ||
| 143 | -// name: ex.exerciseName, | ||
| 144 | -// urlImage: ex.url3dAnimation, | ||
| 145 | -// exerciseType: ex.exerciseType, | ||
| 146 | -// })) || [] | ||
| 147 | -// } | ||
| 148 | -// } | ||
| 149 | - | ||
| 150 | -// return {} | ||
| 151 | -// } | 129 | +// 格式化传入动作组件的unit |
| 152 | const formatDongzuoData = (unit) => { | 130 | const formatDongzuoData = (unit) => { |
| 153 | if (!unit) return {} | 131 | if (!unit) return {} |
| 154 | console.log('++每日模板的unit++', unit); | 132 | console.log('++每日模板的unit++', unit); |
| @@ -183,6 +161,8 @@ const formatDongzuoData = (unit) => { | @@ -183,6 +161,8 @@ const formatDongzuoData = (unit) => { | ||
| 183 | console.log('格式化后结果:', result) // 打印最终数据 | 161 | console.log('格式化后结果:', result) // 打印最终数据 |
| 184 | return result | 162 | return result |
| 185 | } | 163 | } |
| 164 | + | ||
| 165 | +// | ||
| 186 | const handleDeleteAction = () => { | 166 | const handleDeleteAction = () => { |
| 187 | console.log('父组件处理删除动作') | 167 | console.log('父组件处理删除动作') |
| 188 | needDeleteUnit.value = true | 168 | needDeleteUnit.value = true |
| @@ -262,10 +242,12 @@ const closePop = () => { | @@ -262,10 +242,12 @@ const closePop = () => { | ||
| 262 | 242 | ||
| 263 | // 【保存修改:核心,组装参数调用更新接口】 | 243 | // 【保存修改:核心,组装参数调用更新接口】 |
| 264 | const saveEdit = async () => { | 244 | const saveEdit = async () => { |
| 265 | - if (!dongzuoSingleRef.value) return uni.showToast({ title: '获取数据失败', icon: 'none' }) | 245 | + if (!dongzuoSingleRef.value) |
| 246 | + return uni.showToast({ title: '获取数据失败', icon: 'none' }) | ||
| 247 | + | ||
| 266 | const { unit, unitIndex, dailyTemplate } = sourceInfo.value | 248 | const { unit, unitIndex, dailyTemplate } = sourceInfo.value |
| 267 | 249 | ||
| 268 | - // ================== 新增:删除逻辑 ================== | 250 | + // ================== 删除逻辑 ================== |
| 269 | if (needDeleteUnit.value) { | 251 | if (needDeleteUnit.value) { |
| 270 | // 1. 复制所有 unit,删掉当前这个 | 252 | // 1. 复制所有 unit,删掉当前这个 |
| 271 | const allUnits = [...dailyTemplate.units] | 253 | const allUnits = [...dailyTemplate.units] |
| @@ -290,112 +272,19 @@ const saveEdit = async () => { | @@ -290,112 +272,19 @@ const saveEdit = async () => { | ||
| 290 | // 直接 return,不执行后面的修改逻辑 | 272 | // 直接 return,不执行后面的修改逻辑 |
| 291 | return | 273 | return |
| 292 | } | 274 | } |
| 293 | - // ==================================================== | ||
| 294 | 275 | ||
| 295 | - // ========================替换 | ||
| 296 | - if (needReplaceUnit.value) { | ||
| 297 | - const replaceId = templateStore.replaceId | ||
| 298 | - const replaceType = templateStore.replaceType | 276 | + // ========================替换================== |
| 277 | + // =========【新增:替换动作分支,覆盖基础unit】========= | ||
| 278 | + let baseUnit = { ...unit } | ||
| 299 | 279 | ||
| 300 | - if (!replaceId || !replaceType) { | ||
| 301 | - uni.showToast({ title: '替换异常', icon: 'none' }) | ||
| 302 | - return | ||
| 303 | - } | ||
| 304 | - | ||
| 305 | - try { | ||
| 306 | - let detail = null | ||
| 307 | - | ||
| 308 | - // ====================== | ||
| 309 | - // 👇 完全移植你现成的接口逻辑(动作替换) | ||
| 310 | - // ====================== | ||
| 311 | - if (replaceType === 1) { | ||
| 312 | - // 普通动作 | ||
| 313 | - const res = await ExercisesApi.getExerciseById(replaceId) | ||
| 314 | - detail = res.data | ||
| 315 | - console.log('detail=', detail); | ||
| 316 | - | ||
| 317 | - } else if (replaceType === 2) { | ||
| 318 | - // 超级组 | ||
| 319 | - const res = await SupersetsApi.getSupersetsInfo(replaceId) | ||
| 320 | - detail = res.data | ||
| 321 | - console.log('detail=', detail); | ||
| 322 | - } | ||
| 323 | - | ||
| 324 | - if (!detail) { | ||
| 325 | - uni.showToast({ title: '获取动作详情失败', icon: 'none' }) | ||
| 326 | - return | ||
| 327 | - } | ||
| 328 | - | ||
| 329 | - // ====================== | ||
| 330 | - // 组装 newUnit | ||
| 331 | - // ====================== | ||
| 332 | - let newUnit = null | ||
| 333 | - if (replaceType === 1) { | ||
| 334 | - newUnit = { | ||
| 335 | - unitType: 1, | ||
| 336 | - unitId: detail.id, | ||
| 337 | - unitName: detail.name, | ||
| 338 | - exercises: [ | ||
| 339 | - { | ||
| 340 | - exerciseId: detail.id, | ||
| 341 | - exerciseName: detail.name, | ||
| 342 | - exerciseType: detail.exerciseType, | ||
| 343 | - urlImage: detail.url3dAnimation || detail.exerciseCover, | ||
| 344 | - // urlImage: detail.urlImage || detail.url3dAnimation, | ||
| 345 | - categoryDescription: detail.categoryDescription || '', | ||
| 346 | - equipmentDescription: detail.equipmentDescription || '', | ||
| 347 | - sets: [] | ||
| 348 | - } | ||
| 349 | - ] | ||
| 350 | - } | ||
| 351 | - } else if (replaceType === 2) { | ||
| 352 | - newUnit = { | ||
| 353 | - unitType: 2, | ||
| 354 | - unitId: detail.id, | ||
| 355 | - unitName: detail.name, | ||
| 356 | - exercises: detail.exercises.map(e => ({ | ||
| 357 | - exerciseId: e.id, | ||
| 358 | - exerciseName: e.name, | ||
| 359 | - exerciseType: e.exerciseType, | ||
| 360 | - urlImage: e.url3dAnimation || e.exerciseCover, | ||
| 361 | - sets: [] | ||
| 362 | - })) | ||
| 363 | - } | ||
| 364 | - } | ||
| 365 | - | ||
| 366 | - // ====================== | ||
| 367 | - // 替换到模板数组 | ||
| 368 | - // ====================== | ||
| 369 | - const allUnits = [...dailyTemplate.units] | ||
| 370 | - allUnits[unitIndex] = newUnit | ||
| 371 | - | ||
| 372 | - console.log('allUnits[unitIndex]=', allUnits[unitIndex]); | ||
| 373 | - | ||
| 374 | - await dailytemplateApi.updateDailyTemplate({ | ||
| 375 | - dailyTemplateId: dailyTemplate.id, | ||
| 376 | - units: allUnits | ||
| 377 | - }) | ||
| 378 | - | ||
| 379 | - uni.showToast({ title: '替换成功', icon: 'success' }) | ||
| 380 | - needReplaceUnit.value = false | ||
| 381 | - emit('saveSuccess') | ||
| 382 | - closePop() | ||
| 383 | - return | ||
| 384 | - | ||
| 385 | - } catch (err) { | ||
| 386 | - uni.showToast({ title: '替换失败', icon: 'none' }) | ||
| 387 | - } finally { | ||
| 388 | - // 最后清空 | ||
| 389 | - templateStore.clearReplaceAction() | ||
| 390 | - } | 280 | + if (needReplaceUnit.value && replaceCacheUnit.value) { |
| 281 | + // 使用watch提前缓存好的替换单元作为基础载体 | ||
| 282 | + baseUnit = { ...replaceCacheUnit.value } | ||
| 391 | } | 283 | } |
| 284 | + // ===================================================== | ||
| 392 | 285 | ||
| 393 | 286 | ||
| 394 | - | ||
| 395 | - | ||
| 396 | - // 动作替换 | ||
| 397 | - | ||
| 398 | - let targetExercises = [...unit.exercises] | 287 | + let targetExercises = [...baseUnit.exercises] |
| 399 | if (unit.unitType === 1) { | 288 | if (unit.unitType === 1) { |
| 400 | // 单动作:exercises只有1个 | 289 | // 单动作:exercises只有1个 |
| 401 | const exItem = targetExercises[0] | 290 | const exItem = targetExercises[0] |
| 1 | <template> | 1 | <template> |
| 2 | - <!-- 历史按钮 + 弹窗 全部封装 --> | ||
| 3 | - <view> | ||
| 4 | - <!-- 历史按钮 --> | ||
| 5 | - <button class="history-btn" @click="openPopup">历史</button> | ||
| 6 | - | ||
| 7 | - <!-- 弹窗(组件内部管理) --> | ||
| 8 | - <u-popup :show="showPopup" mode="bottom" :mask-click="false" :safe-area-inset-bottom="true" | ||
| 9 | - @update:modelValue="showPopup = $event"> | ||
| 10 | - <view class="history-section"> | ||
| 11 | - <view class="popup-header"> | ||
| 12 | - <u-icon name="close" size="24" color="#333" @click="closePopup"></u-icon> | ||
| 13 | - </view> | ||
| 14 | - | ||
| 15 | - <view v-if="historyList.length > 0" class="history-list"> | ||
| 16 | - <view v-for="(item, index) in historyList" :key="index" class="history-card"> | ||
| 17 | - <view class="card-date"> | ||
| 18 | - <text class="date-text">{{ item.date ? `${item.date[0]}/${item.date[1]}/${item.date[2]}` : | ||
| 19 | - '未知日期' }}</text> | ||
| 20 | - </view> | ||
| 21 | - <view class="card-body"> | ||
| 22 | - <view class="card-header"> | ||
| 23 | - <text class="history-name">{{ item.name }}</text> | ||
| 24 | - <text class="history-set">{{ item.setCount }}组</text> | ||
| 25 | - </view> | ||
| 26 | - <view class="card-config"> | ||
| 27 | - <text class="config-text">配置数: {{ item.setConfigList?.length || 0 }}</text> | ||
| 28 | - </view> | ||
| 29 | - </view> | ||
| 30 | - </view> | ||
| 31 | - </view> | ||
| 32 | - | ||
| 33 | - <view v-else class="empty-container"> | ||
| 34 | - <image :src="lostImage" class="empty-img"></image> | ||
| 35 | - <text class="empty-text">暂无历史数据</text> | ||
| 36 | - </view> | 2 | + <!-- 历史按钮 + 弹窗 全部封装 --> |
| 3 | + <view> | ||
| 4 | + <!-- 历史按钮 --> | ||
| 5 | + <button class="history-btn" @click="openPopup">历史</button> | ||
| 6 | + | ||
| 7 | + <!-- 弹窗(组件内部管理) --> | ||
| 8 | + <u-popup :show="showPopup" mode="bottom" :mask-click="false" :safe-area-inset-bottom="true" | ||
| 9 | + @update:modelValue="showPopup = $event"> | ||
| 10 | + <view class="history-section"> | ||
| 11 | + <view class="popup-header"> | ||
| 12 | + <u-icon name="close" size="24" color="#333" @click="closePopup"></u-icon> | ||
| 13 | + </view> | ||
| 14 | + | ||
| 15 | + <view v-if="historyList.length > 0" class="history-list"> | ||
| 16 | + <view v-for="(item, index) in historyList" :key="index" class="history-card"> | ||
| 17 | + <view class="card-date"> | ||
| 18 | + <text class="date-text">{{ item.date ? `${item.date[0]}/${item.date[1]}/${item.date[2]}` : | ||
| 19 | + '未知日期' }}</text> | ||
| 37 | </view> | 20 | </view> |
| 38 | - </u-popup> | ||
| 39 | - </view> | 21 | + <view class="card-body"> |
| 22 | + <view class="card-header"> | ||
| 23 | + <text class="history-name">{{ item.name }}</text> | ||
| 24 | + <text class="history-set">{{ item.setCount }}组</text> | ||
| 25 | + </view> | ||
| 26 | + <view class="card-config"> | ||
| 27 | + <text class="config-text">配置数: {{ item.setConfigList?.length || 0 }}</text> | ||
| 28 | + </view> | ||
| 29 | + </view> | ||
| 30 | + </view> | ||
| 31 | + </view> | ||
| 32 | + | ||
| 33 | + <view v-else class="empty-container"> | ||
| 34 | + <image :src="lostImage" class="empty-img"></image> | ||
| 35 | + <text class="empty-text">暂无历史数据</text> | ||
| 36 | + </view> | ||
| 37 | + </view> | ||
| 38 | + </u-popup> | ||
| 39 | + </view> | ||
| 40 | </template> | 40 | </template> |
| 41 | 41 | ||
| 42 | <script setup> | 42 | <script setup> |
| @@ -45,10 +45,13 @@ import TrainingApi from '@/sheep/api/Training/traininghistory'; | @@ -45,10 +45,13 @@ import TrainingApi from '@/sheep/api/Training/traininghistory'; | ||
| 45 | 45 | ||
| 46 | // 接收外部传入的 动作ID | 46 | // 接收外部传入的 动作ID |
| 47 | const props = defineProps({ | 47 | const props = defineProps({ |
| 48 | - exerciseId: { | ||
| 49 | - type: [String, Number], | ||
| 50 | - required: true | ||
| 51 | - } | 48 | + exerciseId: { |
| 49 | + type: [String, Number], | ||
| 50 | + required: true | ||
| 51 | + }, | ||
| 52 | + historyType: { | ||
| 53 | + type: String | ||
| 54 | + } | ||
| 52 | }); | 55 | }); |
| 53 | 56 | ||
| 54 | // 内部状态(页面完全不需要知道) | 57 | // 内部状态(页面完全不需要知道) |
| @@ -58,126 +61,126 @@ const lostImage = ref('https://fitness-hcxtec-bucket.oss-cn-shenzhen.aliyuncs.co | @@ -58,126 +61,126 @@ const lostImage = ref('https://fitness-hcxtec-bucket.oss-cn-shenzhen.aliyuncs.co | ||
| 58 | 61 | ||
| 59 | // 打开弹窗 + 加载数据 | 62 | // 打开弹窗 + 加载数据 |
| 60 | const openPopup = async () => { | 63 | const openPopup = async () => { |
| 61 | - showPopup.value = true; | ||
| 62 | - await loadHistory(); // 打开时才加载,不打开不请求 | 64 | + showPopup.value = true; |
| 65 | + await loadHistory(); // 打开时才加载,不打开不请求 | ||
| 63 | }; | 66 | }; |
| 64 | 67 | ||
| 65 | // 关闭弹窗 | 68 | // 关闭弹窗 |
| 66 | const closePopup = () => { | 69 | const closePopup = () => { |
| 67 | - showPopup.value = false; | 70 | + showPopup.value = false; |
| 68 | }; | 71 | }; |
| 69 | 72 | ||
| 70 | // 组件自己加载历史记录(核心!你页面彻底不用管) | 73 | // 组件自己加载历史记录(核心!你页面彻底不用管) |
| 71 | const loadHistory = async () => { | 74 | const loadHistory = async () => { |
| 72 | - try { | ||
| 73 | - const res = await TrainingApi.getTrainHistoryList(props.exerciseId); | ||
| 74 | - historyList.value = res.data || []; | ||
| 75 | - } catch (err) { | ||
| 76 | - console.error('加载历史失败', err); | ||
| 77 | - historyList.value = []; | ||
| 78 | - } | 75 | + try { |
| 76 | + const res = await TrainingApi.getTrainHistoryList(props.exerciseId); | ||
| 77 | + historyList.value = res.data || []; | ||
| 78 | + } catch (err) { | ||
| 79 | + console.error('加载历史失败', err); | ||
| 80 | + historyList.value = []; | ||
| 81 | + } | ||
| 79 | }; | 82 | }; |
| 80 | </script> | 83 | </script> |
| 81 | 84 | ||
| 82 | <style scoped lang="scss"> | 85 | <style scoped lang="scss"> |
| 83 | /* 按钮样式和你原来完全一样 */ | 86 | /* 按钮样式和你原来完全一样 */ |
| 84 | .history-btn { | 87 | .history-btn { |
| 85 | - flex: 1; | ||
| 86 | - height: 60rpx; | ||
| 87 | - background-color: #eaeaea; | ||
| 88 | - color: #333; | ||
| 89 | - font-size: 28rpx; | ||
| 90 | - border-radius: 30rpx; | ||
| 91 | - border: none; | ||
| 92 | - display: flex; | ||
| 93 | - align-items: center; | ||
| 94 | - justify-content: center; | 88 | + flex: 1; |
| 89 | + height: 60rpx; | ||
| 90 | + background-color: #eaeaea; | ||
| 91 | + color: #333; | ||
| 92 | + font-size: 28rpx; | ||
| 93 | + border-radius: 30rpx; | ||
| 94 | + border: none; | ||
| 95 | + display: flex; | ||
| 96 | + align-items: center; | ||
| 97 | + justify-content: center; | ||
| 95 | } | 98 | } |
| 96 | 99 | ||
| 97 | /* 下面是你原来的全部弹窗样式,完整保留 */ | 100 | /* 下面是你原来的全部弹窗样式,完整保留 */ |
| 98 | .history-section { | 101 | .history-section { |
| 99 | - width: 100%; | ||
| 100 | - margin-top: 0; | ||
| 101 | - background-color: #ffffff; | ||
| 102 | - padding: 30rpx; | ||
| 103 | - box-sizing: border-box; | 102 | + width: 100%; |
| 103 | + margin-top: 0; | ||
| 104 | + background-color: #ffffff; | ||
| 105 | + padding: 30rpx; | ||
| 106 | + box-sizing: border-box; | ||
| 104 | } | 107 | } |
| 105 | 108 | ||
| 106 | .popup-header { | 109 | .popup-header { |
| 107 | - display: flex; | ||
| 108 | - justify-content: space-between; | ||
| 109 | - align-items: center; | ||
| 110 | - padding: 30rpx 0; | 110 | + display: flex; |
| 111 | + justify-content: space-between; | ||
| 112 | + align-items: center; | ||
| 113 | + padding: 30rpx 0; | ||
| 111 | } | 114 | } |
| 112 | 115 | ||
| 113 | .history-list { | 116 | .history-list { |
| 114 | - width: 100%; | ||
| 115 | - display: flex; | ||
| 116 | - flex-direction: column; | ||
| 117 | - gap: 20rpx; | 117 | + width: 100%; |
| 118 | + display: flex; | ||
| 119 | + flex-direction: column; | ||
| 120 | + gap: 20rpx; | ||
| 118 | } | 121 | } |
| 119 | 122 | ||
| 120 | .history-card { | 123 | .history-card { |
| 121 | - width: 100%; | ||
| 122 | - box-sizing: border-box; | ||
| 123 | - background: #f0f0f0; | ||
| 124 | - border-radius: 16rpx; | ||
| 125 | - padding: 30rpx; | ||
| 126 | - border: 1rpx solid #e5e5e5; | 124 | + width: 100%; |
| 125 | + box-sizing: border-box; | ||
| 126 | + background: #f0f0f0; | ||
| 127 | + border-radius: 16rpx; | ||
| 128 | + padding: 30rpx; | ||
| 129 | + border: 1rpx solid #e5e5e5; | ||
| 127 | } | 130 | } |
| 128 | 131 | ||
| 129 | .card-date { | 132 | .card-date { |
| 130 | - margin-bottom: 16rpx; | 133 | + margin-bottom: 16rpx; |
| 131 | } | 134 | } |
| 132 | 135 | ||
| 133 | .date-text { | 136 | .date-text { |
| 134 | - font-size: 28rpx; | ||
| 135 | - color: #333333; | ||
| 136 | - font-weight: 500; | 137 | + font-size: 28rpx; |
| 138 | + color: #333333; | ||
| 139 | + font-weight: 500; | ||
| 137 | } | 140 | } |
| 138 | 141 | ||
| 139 | .card-header { | 142 | .card-header { |
| 140 | - display: flex; | ||
| 141 | - justify-content: space-between; | ||
| 142 | - align-items: center; | ||
| 143 | - margin-bottom: 12rpx; | 143 | + display: flex; |
| 144 | + justify-content: space-between; | ||
| 145 | + align-items: center; | ||
| 146 | + margin-bottom: 12rpx; | ||
| 144 | } | 147 | } |
| 145 | 148 | ||
| 146 | .history-name { | 149 | .history-name { |
| 147 | - font-size: 32rpx; | ||
| 148 | - color: #333333; | ||
| 149 | - font-weight: bold; | 150 | + font-size: 32rpx; |
| 151 | + color: #333333; | ||
| 152 | + font-weight: bold; | ||
| 150 | } | 153 | } |
| 151 | 154 | ||
| 152 | .history-set { | 155 | .history-set { |
| 153 | - font-size: 26rpx; | ||
| 154 | - color: #ffd700; | ||
| 155 | - padding: 6rpx 14rpx; | ||
| 156 | - border-radius: 8rpx; | 156 | + font-size: 26rpx; |
| 157 | + color: #ffd700; | ||
| 158 | + padding: 6rpx 14rpx; | ||
| 159 | + border-radius: 8rpx; | ||
| 157 | } | 160 | } |
| 158 | 161 | ||
| 159 | .card-config .config-text { | 162 | .card-config .config-text { |
| 160 | - font-size: 26rpx; | ||
| 161 | - color: #666666; | 163 | + font-size: 26rpx; |
| 164 | + color: #666666; | ||
| 162 | } | 165 | } |
| 163 | 166 | ||
| 164 | .empty-container { | 167 | .empty-container { |
| 165 | - display: flex; | ||
| 166 | - flex-direction: column; | ||
| 167 | - align-items: center; | ||
| 168 | - justify-content: center; | ||
| 169 | - padding: 60rpx 0; | 168 | + display: flex; |
| 169 | + flex-direction: column; | ||
| 170 | + align-items: center; | ||
| 171 | + justify-content: center; | ||
| 172 | + padding: 60rpx 0; | ||
| 170 | } | 173 | } |
| 171 | 174 | ||
| 172 | .empty-img { | 175 | .empty-img { |
| 173 | - width: 200rpx; | ||
| 174 | - height: 200rpx; | ||
| 175 | - margin-bottom: 30rpx; | ||
| 176 | - opacity: 0.6; | 176 | + width: 200rpx; |
| 177 | + height: 200rpx; | ||
| 178 | + margin-bottom: 30rpx; | ||
| 179 | + opacity: 0.6; | ||
| 177 | } | 180 | } |
| 178 | 181 | ||
| 179 | .empty-text { | 182 | .empty-text { |
| 180 | - font-size: 28rpx; | ||
| 181 | - color: #999999; | 183 | + font-size: 28rpx; |
| 184 | + color: #999999; | ||
| 182 | } | 185 | } |
| 183 | </style> | 186 | </style> |
-
Please register or login to post a comment