Authored by qxm

Merge branch 'feature/qxm'

@@ -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>