|
1
|
<template>
|
1
|
<template>
|
|
2
|
<view class="action-container" @click="closeDifficulty">
|
2
|
<view class="action-container" @click="closeDifficulty">
|
|
3
|
<view class="action-list" v-if="deleteActionShow === false">
|
3
|
<view class="action-list" v-if="deleteActionShow === false">
|
|
4
|
- <view class="card">
|
4
|
+ <view class="card" :class="{ 'unit-active': isUnitActive }">
|
|
5
|
<view class="card-top" @click.stop="isExpanded = !isExpanded">
|
5
|
<view class="card-top" @click.stop="isExpanded = !isExpanded">
|
|
6
|
<view v-if="type === 1">
|
6
|
<view v-if="type === 1">
|
|
7
|
<image class="action-image" :src="actionDetail?.urlImage || lostImage" mode="aspectFill"></image>
|
7
|
<image class="action-image" :src="actionDetail?.urlImage || lostImage" mode="aspectFill"></image>
|
|
@@ -12,11 +12,9 @@ |
|
@@ -12,11 +12,9 @@ |
|
12
|
mode="aspectFill"></image>
|
12
|
mode="aspectFill"></image>
|
|
13
|
</view>
|
13
|
</view>
|
|
14
|
<view class="action-info">
|
14
|
<view class="action-info">
|
|
15
|
- <!-- 动作的 -->
|
|
|
|
16
|
<text class="name">{{ actionDetail?.name }}</text>
|
15
|
<text class="name">{{ actionDetail?.name }}</text>
|
|
17
|
<text class="tags" v-if="type === 1">{{ actionDetail?.categoryDescription }} {{
|
16
|
<text class="tags" v-if="type === 1">{{ actionDetail?.categoryDescription }} {{
|
|
18
|
actionDetail?.equipmentDescription }}</text>
|
17
|
actionDetail?.equipmentDescription }}</text>
|
|
19
|
- <!-- 这里还缺kg/要搞个计算属性 -->
|
|
|
|
20
|
<text class="tags" v-if="type === 2">超级组</text>
|
18
|
<text class="tags" v-if="type === 2">超级组</text>
|
|
21
|
<view class="dot-list" v-if="!isExpanded">
|
19
|
<view class="dot-list" v-if="!isExpanded">
|
|
22
|
<view class="dot" v-for="(item, index) in recordList" :key="'dot-' + index"></view>
|
20
|
<view class="dot" v-for="(item, index) in recordList" :key="'dot-' + index"></view>
|
|
@@ -34,16 +32,12 @@ |
|
@@ -34,16 +32,12 @@ |
|
34
|
</view>
|
32
|
</view>
|
|
35
|
|
33
|
|
|
36
|
<view class="main" v-if="isExpanded">
|
34
|
<view class="main" v-if="isExpanded">
|
|
37
|
- <!-- 当类型为4,5时,显示体重输入框 -->
|
|
|
|
38
|
- <!--动作的 recordList 的输入控制 -->
|
|
|
|
39
|
<template v-if="type === 1">
|
35
|
<template v-if="type === 1">
|
|
40
|
<view class="userWeight" v-if="[4, 5].includes(actionDetail.exerciseType)">
|
36
|
<view class="userWeight" v-if="[4, 5].includes(actionDetail.exerciseType)">
|
|
41
|
<view class="row" hover-class="none" hover-stop-propagation="false">
|
37
|
<view class="row" hover-class="none" hover-stop-propagation="false">
|
|
42
|
<text class="label">体重</text>
|
38
|
<text class="label">体重</text>
|
|
43
|
<view class="userWeight-values" @click="openWeightPicker">
|
39
|
<view class="userWeight-values" @click="openWeightPicker">
|
|
44
|
- <text class="weight-text" style="color: #fbdc00; font-size: 20rpx;">
|
|
|
|
45
|
- {{ displayWeight }}
|
|
|
|
46
|
- </text>
|
40
|
+ <text class="weight-text">{{ displayWeight }}</text>
|
|
47
|
<up-icon name="edit-pen" color="#8e8e93" size="20"></up-icon>
|
41
|
<up-icon name="edit-pen" color="#8e8e93" size="20"></up-icon>
|
|
48
|
</view>
|
42
|
</view>
|
|
49
|
</view>
|
43
|
</view>
|
|
@@ -54,38 +48,27 @@ |
|
@@ -54,38 +48,27 @@ |
|
54
|
该动作为自重减重,根据你的体重减去辅助器械重量计算容量,下方的填写重量为辅助器械重量。
|
48
|
该动作为自重减重,根据你的体重减去辅助器械重量计算容量,下方的填写重量为辅助器械重量。
|
|
55
|
</view>
|
49
|
</view>
|
|
56
|
</view>
|
50
|
</view>
|
|
57
|
- <!-- 导入子组件 -->
|
|
|
|
58
|
<action-set-input v-for="(item, index) in recordList" :key="index"
|
51
|
<action-set-input v-for="(item, index) in recordList" :key="index"
|
|
59
|
:exercise-type="actionDetail.exerciseType" :record="item" :index="index" :is-editing="isEditing"
|
52
|
:exercise-type="actionDetail.exerciseType" :record="item" :index="index" :is-editing="isEditing"
|
|
60
|
@openPicker="openPicker" @openQuickTimer="openQuickTimer" @toggleActive="toggleActive" @addRow="addRow"
|
53
|
@openPicker="openPicker" @openQuickTimer="openQuickTimer" @toggleActive="toggleActive" @addRow="addRow"
|
|
61
|
@deleteRow="deleteRow" :user-weight="userWeight" @change-weight="userWeight = $event" />
|
54
|
@deleteRow="deleteRow" :user-weight="userWeight" @change-weight="userWeight = $event" />
|
|
62
|
</template>
|
55
|
</template>
|
|
63
|
- <!-- 超级组的训练数据控制 -->
|
56
|
+
|
|
64
|
<template v-else-if="type === 2">
|
57
|
<template v-else-if="type === 2">
|
|
65
|
<view class="super-group">
|
58
|
<view class="super-group">
|
|
66
|
<view class="img-list" v-if="type === 2">
|
59
|
<view class="img-list" v-if="type === 2">
|
|
67
|
<image v-for="item in (actionDetail?.exercises || [])" :key="item.id" :src="item?.urlImage || lostImage"
|
60
|
<image v-for="item in (actionDetail?.exercises || [])" :key="item.id" :src="item?.urlImage || lostImage"
|
|
68
|
class="img"></image>
|
61
|
class="img"></image>
|
|
69
|
</view>
|
62
|
</view>
|
|
70
|
- <!-- 超级组:如果内部包含自重加重/减重,显示体重输入v-if="hasWeightExercise" -->
|
|
|
|
71
|
<view class="userWeight" v-if="hasWeightExercise">
|
63
|
<view class="userWeight" v-if="hasWeightExercise">
|
|
72
|
<view class="row">
|
64
|
<view class="row">
|
|
73
|
<text class="label">体重</text>
|
65
|
<text class="label">体重</text>
|
|
74
|
<view class="userWeight-values" @click="openWeightPicker">
|
66
|
<view class="userWeight-values" @click="openWeightPicker">
|
|
75
|
- <text class="weight-text" style="color: #fbdc00; font-size: 20rpx;">
|
|
|
|
76
|
- {{ displayWeight }}
|
|
|
|
77
|
- </text>
|
67
|
+ <text class="weight-text">{{ displayWeight }}</text>
|
|
78
|
<up-icon name="edit-pen" color="#8e8e93" size="20"></up-icon>
|
68
|
<up-icon name="edit-pen" color="#8e8e93" size="20"></up-icon>
|
|
79
|
</view>
|
69
|
</view>
|
|
80
|
</view>
|
70
|
</view>
|
|
81
|
- <!-- <view class="explain" v-if="actionDetail?.exerciseType === 4">
|
|
|
|
82
|
- 该动作为自重加重,根据你的体重加上辅助器械重量计算容量,下方的填写重量为辅助器械重量。
|
|
|
|
83
|
- </view>
|
|
|
|
84
|
- <view class="explain" v-if="actionDetail?.exerciseType === 5">
|
|
|
|
85
|
- 该动作为自重减重,根据你的体重减去辅助器械重量计算容量,下方的填写重量为辅助器械重量。
|
|
|
|
86
|
- </view> -->
|
|
|
|
87
|
</view>
|
71
|
</view>
|
|
88
|
- <!-- 外层:循环【每一组】 -->
|
|
|
|
89
|
<view class="set-group" v-for="(setItem, setIndex) in superTotalSets" :key="setIndex">
|
72
|
<view class="set-group" v-for="(setItem, setIndex) in superTotalSets" :key="setIndex">
|
|
90
|
<view class="set-header">
|
73
|
<view class="set-header">
|
|
91
|
<view class="index-box">{{ setIndex + 1 }}</view>
|
74
|
<view class="index-box">{{ setIndex + 1 }}</view>
|
|
@@ -94,48 +77,39 @@ |
|
@@ -94,48 +77,39 @@ |
|
94
|
{{ String.fromCharCode(65 + idx) }} {{ sub.name }}
|
77
|
{{ String.fromCharCode(65 + idx) }} {{ sub.name }}
|
|
95
|
</text>
|
78
|
</text>
|
|
96
|
</view>
|
79
|
</view>
|
|
97
|
- <!-- 休息时间选择 -->
|
|
|
|
98
|
<view class="timer-selector" @click.stop="openSuperQuickTimer(setIndex)" v-if="!isEditing">
|
80
|
<view class="timer-selector" @click.stop="openSuperQuickTimer(setIndex)" v-if="!isEditing">
|
|
99
|
<text class="text">{{ superGroupSetData(setIndex).quickTimeDisplay || '60s' }}</text>
|
81
|
<text class="text">{{ superGroupSetData(setIndex).quickTimeDisplay || '60s' }}</text>
|
|
100
|
<up-icon name="arrow-down" color="#8e8e93" size="10"></up-icon>
|
82
|
<up-icon name="arrow-down" color="#8e8e93" size="10"></up-icon>
|
|
101
|
</view>
|
83
|
</view>
|
|
102
|
- <!-- 勾选框 -->
|
|
|
|
103
|
- <view class="icon" @click.stop="toggleSuperSetActive(setIndex)"
|
84
|
+ <view class="check-icon" @click.stop="toggleSuperSetActive(setIndex)"
|
|
104
|
:class="{ active: superGroupSetData(setIndex).isActive }" v-if="!isEditing">
|
85
|
:class="{ active: superGroupSetData(setIndex).isActive }" v-if="!isEditing">
|
|
105
|
<up-icon name="checkmark" :color="superGroupSetData(setIndex).isActive ? '#000' : '#919191'"
|
86
|
<up-icon name="checkmark" :color="superGroupSetData(setIndex).isActive ? '#000' : '#919191'"
|
|
106
|
size="20" bold></up-icon>
|
87
|
size="20" bold></up-icon>
|
|
107
|
</view>
|
88
|
</view>
|
|
108
|
- <!-- 新增和删除按钮 -->
|
|
|
|
109
|
- <view class="icons" v-if="isEditing">
|
|
|
|
110
|
- <view class="icon" @click.stop="addSuperSet">
|
89
|
+ <view class="action-icons" v-if="isEditing">
|
|
|
|
90
|
+ <view class="action-icon" @click.stop="addSuperSet">
|
|
111
|
<up-icon name="plus-circle" color="#fff" size="20" bold></up-icon>
|
91
|
<up-icon name="plus-circle" color="#fff" size="20" bold></up-icon>
|
|
112
|
</view>
|
92
|
</view>
|
|
113
|
- <view class="icon del" @click.stop="deleteSuperSet(setIndex)">
|
93
|
+ <view class="action-icon icon-del" @click.stop="deleteSuperSet(setIndex)">
|
|
114
|
<up-icon name="trash" color="#e63e1e" size="20" bold></up-icon>
|
94
|
<up-icon name="trash" color="#e63e1e" size="20" bold></up-icon>
|
|
115
|
</view>
|
95
|
</view>
|
|
116
|
</view>
|
96
|
</view>
|
|
117
|
</view>
|
97
|
</view>
|
|
118
|
-
|
|
|
|
119
|
- <!-- 内层:循环【组内的每个子动作A/B】 -->
|
|
|
|
120
|
<super-set-input v-for="(sub, idx) in actionDetail.exercises" :key="sub.id"
|
98
|
<super-set-input v-for="(sub, idx) in actionDetail.exercises" :key="sub.id"
|
|
121
|
:sub-exercise-type="sub.exerciseType" :set-index="setIndex" :sub-index="idx" :user-weight="userWeight"
|
99
|
:sub-exercise-type="sub.exerciseType" :set-index="setIndex" :sub-index="idx" :user-weight="userWeight"
|
|
122
|
:data="getSubActionData(setIndex, sub.id)" @open-time-picker="openSuperPicker(setIndex, sub.id)" />
|
100
|
:data="getSubActionData(setIndex, sub.id)" @open-time-picker="openSuperPicker(setIndex, sub.id)" />
|
|
123
|
</view>
|
101
|
</view>
|
|
124
|
</view>
|
102
|
</view>
|
|
125
|
</template>
|
103
|
</template>
|
|
126
|
-
|
|
|
|
127
|
</view>
|
104
|
</view>
|
|
128
|
|
105
|
|
|
129
|
<view class="button-group" v-if="isExpanded">
|
106
|
<view class="button-group" v-if="isExpanded">
|
|
130
|
<view class="btn-item" @click.stop="addGroup">加一组</view>
|
107
|
<view class="btn-item" @click.stop="addGroup">加一组</view>
|
|
131
|
<view class="btn-item" @click="openHistory(props?.id)">历史</view>
|
108
|
<view class="btn-item" @click="openHistory(props?.id)">历史</view>
|
|
132
|
- <!-- 历史弹窗 -->
|
|
|
|
133
|
<actionHistory ref="historyPopupRef" :actionName="actionDetail.name" :historyType="props.type" />
|
109
|
<actionHistory ref="historyPopupRef" :actionName="actionDetail.name" :historyType="props.type" />
|
|
134
|
- <!-- 动作难度选择弹窗 -->
|
|
|
|
135
|
<view class="btn-item" @click.stop="showDifficulty = !showDifficulty">
|
110
|
<view class="btn-item" @click.stop="showDifficulty = !showDifficulty">
|
|
136
|
<text :style="{ color: currentDifficulty.color }">{{ currentDifficulty.label }}</text>
|
111
|
<text :style="{ color: currentDifficulty.color }">{{ currentDifficulty.label }}</text>
|
|
137
|
<up-icon name="arrow-down" size="8" color="#fff"></up-icon>
|
112
|
<up-icon name="arrow-down" size="8" color="#fff"></up-icon>
|
|
138
|
-
|
|
|
|
139
|
<view class="difficulty-pop" v-if="showDifficulty">
|
113
|
<view class="difficulty-pop" v-if="showDifficulty">
|
|
140
|
<view class="difficulty-item" @click.stop="selectDifficulty('轻松', '#b2f055')">
|
114
|
<view class="difficulty-item" @click.stop="selectDifficulty('轻松', '#b2f055')">
|
|
141
|
<text :style="{ color: '#b2f055' }">轻松</text>
|
115
|
<text :style="{ color: '#b2f055' }">轻松</text>
|
|
@@ -154,7 +128,6 @@ |
|
@@ -154,7 +128,6 @@ |
|
154
|
</view>
|
128
|
</view>
|
|
155
|
</view>
|
129
|
</view>
|
|
156
|
</view>
|
130
|
</view>
|
|
157
|
-
|
|
|
|
158
|
<view class="btn-item" @click.stop="isEditing = !isEditing">
|
131
|
<view class="btn-item" @click.stop="isEditing = !isEditing">
|
|
159
|
{{ isEditing ? '完成' : '编辑' }}
|
132
|
{{ isEditing ? '完成' : '编辑' }}
|
|
160
|
</view>
|
133
|
</view>
|
|
@@ -168,760 +141,639 @@ |
|
@@ -168,760 +141,639 @@ |
|
168
|
<up-picker :show="showQuickPicker" :columns="quickColumns" title="设置休息时长" @confirm="onQuickConfirm"
|
141
|
<up-picker :show="showQuickPicker" :columns="quickColumns" title="设置休息时长" @confirm="onQuickConfirm"
|
|
169
|
@cancel="showQuickPicker = false" closeOnClickOverlay popupClass="custom-picker"></up-picker>
|
142
|
@cancel="showQuickPicker = false" closeOnClickOverlay popupClass="custom-picker"></up-picker>
|
|
170
|
|
143
|
|
|
171
|
- <!-- 备注弹窗组件(可创建备注成功,但无法显示到动作详情弹窗组件) -->
|
|
|
|
172
|
<beizhu ref="showBeizhuRef" @saveSuccess="handleNoteSave" />
|
144
|
<beizhu ref="showBeizhuRef" @saveSuccess="handleNoteSave" />
|
|
173
|
- <!-- 动作替换弹窗 -->
|
|
|
|
174
|
<replaceActionPopup :show="replacePopupShow" :unitIndex="unitIndex" @close="replacePopupShow = false" />
|
145
|
<replaceActionPopup :show="replacePopupShow" :unitIndex="unitIndex" @close="replacePopupShow = false" />
|
|
175
|
|
146
|
|
|
176
|
- <!-- 体重选择器 -->
|
|
|
|
177
|
<up-picker :show="showWeightPicker" :columns="weightColumns" :defaultIndex="defaultWeightIndex" title="设置体重"
|
147
|
<up-picker :show="showWeightPicker" :columns="weightColumns" :defaultIndex="defaultWeightIndex" title="设置体重"
|
|
178
|
@confirm="onWeightConfirm" @cancel="showWeightPicker = false" closeOnClickOverlay
|
148
|
@confirm="onWeightConfirm" @cancel="showWeightPicker = false" closeOnClickOverlay
|
|
179
|
popupClass="custom-picker"></up-picker>
|
149
|
popupClass="custom-picker"></up-picker>
|
|
180
|
-
|
|
|
|
181
|
</view>
|
150
|
</view>
|
|
182
|
</template>
|
151
|
</template>
|
|
183
|
|
152
|
|
|
184
|
<script setup>
|
153
|
<script setup>
|
|
185
|
-import { ref, reactive, watch, computed, nextTick, onMounted } from 'vue';
|
154
|
+import { ref, reactive, watch, computed, nextTick, onMounted, getCurrentInstance } from 'vue';
|
|
|
|
155
|
+import dayjs from 'dayjs';
|
|
|
|
156
|
+import duration from 'dayjs/plugin/duration';
|
|
|
|
157
|
+import { useTrainingStore } from '@/sheep/store/trainingStore'
|
|
186
|
import beizhu from '@/pages/xunji/components/beizhu.vue';
|
158
|
import beizhu from '@/pages/xunji/components/beizhu.vue';
|
|
187
|
-// import actionHistory from '../components/dongzuo-lianxi-history.vue'
|
|
|
|
188
|
import actionHistory from '@/pages/xunji/components/dongzuo-lianxi/dongzuo-lianxi-history.vue'
|
159
|
import actionHistory from '@/pages/xunji/components/dongzuo-lianxi/dongzuo-lianxi-history.vue'
|
|
189
|
-import SupersetsApi from '@/sheep/api/motion/supersets';
|
|
|
|
190
|
-import ExercisesApi from '@/sheep/api/motion/exercises';
|
|
|
|
191
|
-import { getCurrentInstance } from 'vue';
|
|
|
|
192
|
-import { useTrainingStore } from '@/sheep/store/trainingStore'
|
|
|
|
193
|
-// import replaceActionPopup from '../components/replace-action-popup.vue'
|
|
|
|
194
|
import replaceActionPopup from '@/pages/xunji/components/dongzuo-lianxi/replace-action-popup.vue'
|
160
|
import replaceActionPopup from '@/pages/xunji/components/dongzuo-lianxi/replace-action-popup.vue'
|
|
195
|
-// import actionSetInput from '@/pages4/components/action-set-input.vue'
|
|
|
|
196
|
import actionSetInput from '@/pages/xunji/components/dongzuo-lianxi/action-set-input.vue'
|
161
|
import actionSetInput from '@/pages/xunji/components/dongzuo-lianxi/action-set-input.vue'
|
|
197
|
-// import superSetInput from '../components/super-set-input.vue'
|
|
|
|
198
|
import superSetInput from '@/pages/xunji/components/dongzuo-lianxi/super-set-input.vue'
|
162
|
import superSetInput from '@/pages/xunji/components/dongzuo-lianxi/super-set-input.vue'
|
|
|
|
163
|
+import SupersetsApi from '@/sheep/api/motion/supersets';
|
|
|
|
164
|
+import ExercisesApi from '@/sheep/api/motion/exercises';
|
|
199
|
|
165
|
|
|
200
|
-
|
|
|
|
201
|
-const trainingStore = useTrainingStore()
|
|
|
|
202
|
-const deleteActionShow = ref(false)
|
|
|
|
203
|
-const showTips = ref(false);
|
|
|
|
204
|
-const isExpanded = ref(false);
|
|
|
|
205
|
-const isEditing = ref(false);
|
|
|
|
206
|
-const showPicker = ref(false);
|
|
|
|
207
|
-const showQuickPicker = ref(false);
|
|
|
|
208
|
-const activeIndex = ref(0);
|
|
|
|
209
|
-const activeActionId = ref('');
|
|
|
|
210
|
-const emit = defineEmits(['register', 'update:groupCount', 'replace-action', 'deleteAction', 'replaceActionForSave'])
|
|
|
|
211
|
-const lostImage = "https://fitness-hcxtec-bucket.oss-cn-shenzhen.aliyuncs.com/20260316/order-empty_1773628059920.png"
|
|
|
|
212
|
-
|
|
|
|
213
|
-const historyPopupRef = ref(null)
|
|
|
|
214
|
-const showBeizhuRef = ref(null);
|
|
|
|
215
|
-const userWeight = ref(70)
|
|
|
|
216
|
-// 休息时间设置模式:single=单行,all=全部组
|
|
|
|
217
|
-const restEditMode = ref('single');
|
|
|
|
218
|
-const replacePopupShow = ref(false)
|
|
|
|
219
|
-
|
|
|
|
220
|
-// 接收父组件的数据
|
166
|
+// ===================== Props =====================
|
|
221
|
const props = defineProps({
|
167
|
const props = defineProps({
|
|
222
|
id: [Number, String],
|
168
|
id: [Number, String],
|
|
223
|
type: [Number, String],
|
169
|
type: [Number, String],
|
|
224
|
- index: Number, // 新增
|
170
|
+ index: Number,
|
|
225
|
unitIndex: Number,
|
171
|
unitIndex: Number,
|
|
226
|
- actionDetail: {
|
|
|
|
227
|
- type: Object,
|
|
|
|
228
|
- default: () => ({})
|
|
|
|
229
|
- },
|
|
|
|
230
|
- isDailyTemplates: {
|
|
|
|
231
|
- type: Boolean,
|
|
|
|
232
|
- default: false
|
|
|
|
233
|
- }
|
172
|
+ actionDetail: { type: Object, default: () => ({}) },
|
|
|
|
173
|
+ isDailyTemplates: { type: Boolean, default: false },
|
|
|
|
174
|
+ isUnitActive: { type: Boolean, default: false }
|
|
234
|
})
|
175
|
})
|
|
235
|
|
176
|
|
|
236
|
-watch(() => props.id, () => {
|
|
|
|
237
|
- console.log('dongzuo组件 id/type:', props.id, props.type)
|
|
|
|
238
|
- console.log('打印props.actionDetail', props.actionDetail)
|
|
|
|
239
|
- console.log('dongzuo组件 unitIndex:', props.unitIndex)
|
|
|
|
240
|
- if (props.type === 2)
|
|
|
|
241
|
- console.log('打印父组件传过来超级组动作列表的props.actionDetail.exercises', props.actionDetail.exercises);
|
177
|
+// ===================== Emits =====================
|
|
|
|
178
|
+const emit = defineEmits(['register', 'update:groupCount', 'replace-action', 'deleteAction', 'replaceActionForSave', 'startRestTimer', 'cancelRestTimer', 'updateUnitActive'])
|
|
242
|
|
179
|
|
|
243
|
-}, { immediate: true })
|
180
|
+// ===================== 常量 =====================
|
|
|
|
181
|
+dayjs.extend(duration)
|
|
|
|
182
|
+const lostImage = 'https://fitness-hcxtec-bucket.oss-cn-shenzhen.aliyuncs.com/20260316/order-empty_1773628059920.png'
|
|
244
|
|
183
|
|
|
245
|
-emit('register', props.index, getCurrentInstance()?.proxy)
|
184
|
+// ===================== Store =====================
|
|
|
|
185
|
+const trainingStore = useTrainingStore()
|
|
246
|
|
186
|
|
|
247
|
-// 体重选择器
|
|
|
|
248
|
-const displayWeight = computed(() => {
|
|
|
|
249
|
- return `${userWeight.value}kg`
|
|
|
|
250
|
-})
|
187
|
+// ===================== 基础状态 =====================
|
|
|
|
188
|
+const deleteActionShow = ref(false)
|
|
|
|
189
|
+const showTips = ref(false)
|
|
|
|
190
|
+const isExpanded = ref(false)
|
|
|
|
191
|
+const isEditing = ref(false)
|
|
|
|
192
|
+const replacePopupShow = ref(false)
|
|
|
|
193
|
+const historyPopupRef = ref(null)
|
|
|
|
194
|
+const showBeizhuRef = ref(null)
|
|
251
|
|
195
|
|
|
252
|
-// 2. 体重选择器状态
|
196
|
+// ===================== Picker 状态 =====================
|
|
|
|
197
|
+const showPicker = ref(false)
|
|
|
|
198
|
+const showQuickPicker = ref(false)
|
|
|
|
199
|
+const activeIndex = ref(0)
|
|
|
|
200
|
+const activeActionId = ref('')
|
|
|
|
201
|
+const restEditMode = ref('single')
|
|
|
|
202
|
+
|
|
|
|
203
|
+const timeColumns = reactive([
|
|
|
|
204
|
+ Array.from({ length: 24 }, (_, i) => String(i).padStart(2, '0') + '时'),
|
|
|
|
205
|
+ Array.from({ length: 60 }, (_, i) => String(i).padStart(2, '0') + '分'),
|
|
|
|
206
|
+ Array.from({ length: 60 }, (_, i) => String(i).padStart(2, '0') + '秒'),
|
|
|
|
207
|
+])
|
|
|
|
208
|
+const defaultTimeIndex = ref([0, 0, 0])
|
|
|
|
209
|
+
|
|
|
|
210
|
+const quickColumns = reactive([
|
|
|
|
211
|
+ Array.from({ length: 60 }, (_, i) => String(i).padStart(2, '0') + '分'),
|
|
|
|
212
|
+ Array.from({ length: 60 }, (_, i) => String(i).padStart(2, '0') + '秒'),
|
|
|
|
213
|
+])
|
|
|
|
214
|
+
|
|
|
|
215
|
+// ===================== 体重 =====================
|
|
|
|
216
|
+const userWeight = ref(70)
|
|
253
|
const showWeightPicker = ref(false)
|
217
|
const showWeightPicker = ref(false)
|
|
254
|
const weightColumns = reactive([
|
218
|
const weightColumns = reactive([
|
|
255
|
- // 整数部分:10 ~ 250
|
|
|
|
256
|
Array.from({ length: 241 }, (_, i) => (i + 10).toString()),
|
219
|
Array.from({ length: 241 }, (_, i) => (i + 10).toString()),
|
|
257
|
- // 小数部分:0 ~ 9
|
|
|
|
258
|
Array.from({ length: 10 }, (_, i) => i.toString()),
|
220
|
Array.from({ length: 10 }, (_, i) => i.toString()),
|
|
259
|
- ['千克(kg)'] // 第三列固定文字
|
221
|
+ ['千克(kg)']
|
|
260
|
])
|
222
|
])
|
|
261
|
-const defaultWeightIndex = ref([60, 0, 0]) // 默认 70.0kg(10+60=70)
|
223
|
+const defaultWeightIndex = ref([60, 0, 0])
|
|
262
|
|
224
|
|
|
263
|
-// 3. 打开体重选择器
|
|
|
|
264
|
-const openWeightPicker = () => {
|
|
|
|
265
|
- // 直接用数字处理,避免转字符串
|
|
|
|
266
|
- const num = userWeight.value
|
|
|
|
267
|
- const intPart = Math.floor(num)
|
|
|
|
268
|
- const decPart = Math.round((num - intPart) * 10) // 取小数第一位
|
225
|
+// ===================== 难度 =====================
|
|
|
|
226
|
+const showDifficulty = ref(false)
|
|
|
|
227
|
+const initialDifficulty = { label: '难度', color: '#ffffff' }
|
|
|
|
228
|
+const currentDifficulty = ref({ ...initialDifficulty })
|
|
269
|
|
229
|
|
|
270
|
- // 计算索引(整数部分:intPart - 10,小数部分:decPart)
|
|
|
|
271
|
- const intIndex = Math.max(0, Math.min(intPart - 10, 240))
|
|
|
|
272
|
- defaultWeightIndex.value = [intIndex, decPart, 0]
|
|
|
|
273
|
- showWeightPicker.value = true
|
|
|
|
274
|
-}
|
230
|
+// ===================== 训练数据 =====================
|
|
|
|
231
|
+const recordList = ref([{
|
|
|
|
232
|
+ h: '00', m: '00', s: '00', quickTimeDisplay: formatQuickTime(60),
|
|
|
|
233
|
+ distance: '', weight: '', reps: '', duration: '', restTime: '', isActive: false
|
|
|
|
234
|
+}])
|
|
275
|
|
235
|
|
|
276
|
-// 4. 体重选择器确认事件
|
|
|
|
277
|
-const onWeightConfirm = (e) => {
|
|
|
|
278
|
- const intPart = e.value[0] // 整数部分
|
|
|
|
279
|
- const decPart = e.value[1] // 小数部分
|
|
|
|
280
|
- // 拼接成完整体重
|
|
|
|
281
|
- userWeight.value = parseFloat(`${intPart}.${decPart}`)
|
|
|
|
282
|
- showWeightPicker.value = false
|
|
|
|
283
|
-}
|
|
|
|
284
|
-
|
|
|
|
285
|
-// 打开备注弹窗
|
|
|
|
286
|
-const openBeizhu = () => {
|
|
|
|
287
|
- nextTick(() => {
|
|
|
|
288
|
- if (showBeizhuRef.value) {
|
|
|
|
289
|
- showBeizhuRef.value.open(props.actionDetail.id);
|
|
|
|
290
|
- }
|
|
|
|
291
|
- });
|
|
|
|
292
|
-};
|
236
|
+const superRecordMap = ref({})
|
|
293
|
|
237
|
|
|
294
|
-// 接收子组件传过来的备注内容
|
|
|
|
295
|
-const handleNoteSave = async (content) => {
|
|
|
|
296
|
- try {
|
|
|
|
297
|
- if (props.type == 2) {
|
|
|
|
298
|
- await SupersetsApi.addNotes({
|
|
|
|
299
|
- supersetsId: props.id,
|
|
|
|
300
|
- content: content,
|
|
|
|
301
|
- });
|
|
|
|
302
|
- } else {
|
|
|
|
303
|
- await ExercisesApi.addNotes({
|
|
|
|
304
|
- exerciseId: props.id,
|
|
|
|
305
|
- content: content,
|
|
|
|
306
|
- });
|
|
|
|
307
|
- }
|
|
|
|
308
|
- props.actionDetail.userNote = content;
|
|
|
|
309
|
- } catch (e) {
|
|
|
|
310
|
- console.log(e);
|
|
|
|
311
|
- }
|
|
|
|
312
|
-};
|
238
|
+// 向父组件注册组件实例引用
|
|
|
|
239
|
+emit('register', props.index, getCurrentInstance()?.proxy)
|
|
313
|
|
240
|
|
|
314
|
-const toggleTips = () => {
|
|
|
|
315
|
- showTips.value = !showTips.value
|
|
|
|
316
|
-}
|
241
|
+// ===================== Computed =====================
|
|
|
|
242
|
+const displayWeight = computed(() => `${userWeight.value}kg`)
|
|
317
|
|
243
|
|
|
318
|
-// 超级组是否包含间歇类型动作(用来控制组头休息时间选择器的显示)
|
|
|
|
319
|
-const hasIntervalExercise = computed(() => {
|
244
|
+const hasWeightExercise = computed(() => {
|
|
320
|
if (props.type !== 2) return false
|
245
|
if (props.type !== 2) return false
|
|
321
|
- const exercises = props.actionDetail?.exercises || []
|
|
|
|
322
|
- // 只要有一个子动作是间歇类型(6),就不显示组头的休息时间
|
|
|
|
323
|
- return exercises.some(sub => sub.exerciseType === 6)
|
246
|
+ return (props.actionDetail?.exercises || []).some(sub => [4, 5].includes(sub.exerciseType))
|
|
324
|
})
|
247
|
})
|
|
325
|
-// 替换动作
|
|
|
|
326
|
-const handleReplaceAction = () => {
|
|
|
|
327
|
- showTips.value = false
|
|
|
|
328
|
- replacePopupShow.value = true // 打开弹窗
|
|
|
|
329
|
- console.log("✅ 弹窗打开:", replacePopupShow.value)
|
|
|
|
330
|
-}
|
|
|
|
331
|
|
248
|
|
|
332
|
-// 超级组是否包含 4(自重加重) / 5(自重减重)
|
|
|
|
333
|
-const hasWeightExercise = computed(() => {
|
|
|
|
334
|
- if (props.type !== 2) return false
|
249
|
+const superTotalSets = computed(() => {
|
|
|
|
250
|
+ if (props.type !== 2) return 0
|
|
335
|
const exercises = props.actionDetail?.exercises || []
|
251
|
const exercises = props.actionDetail?.exercises || []
|
|
336
|
- return exercises.some(sub => [4, 5].includes(sub.exerciseType))
|
252
|
+ if (exercises.length === 0) return 0
|
|
|
|
253
|
+ return superRecordMap.value[exercises[0].id]?.length || 0
|
|
337
|
})
|
254
|
})
|
|
338
|
|
255
|
|
|
|
|
256
|
+const exerciseNamesWithLabel = computed(() => {
|
|
|
|
257
|
+ return (props.actionDetail?.exercises || []).map((item, index) => {
|
|
|
|
258
|
+ const label = String.fromCharCode(65 + index)
|
|
|
|
259
|
+ return `${label} ${item?.name || '未知动作'}`
|
|
|
|
260
|
+ })
|
|
|
|
261
|
+})
|
|
339
|
|
262
|
|
|
340
|
-// 删除动作
|
|
|
|
341
|
-const deleteAction = () => {
|
|
|
|
342
|
- // 如何是每日模板的就返回一个删除印象
|
|
|
|
343
|
- if (props.isDailyTemplates) {
|
|
|
|
344
|
- showTips.value = false;
|
|
|
|
345
|
- emit('deleteAction');
|
|
|
|
346
|
- // trainingStore.actionDetail.units.splice(props.unitIndex, 1)
|
|
|
|
347
|
- // trainingStore.clearTrainingStore()
|
|
|
|
348
|
- return;
|
263
|
+const exposeRecordList = computed(() => {
|
|
|
|
264
|
+ return recordList.value.filter(item => item.isActive).map(item => ({
|
|
|
|
265
|
+ ...item,
|
|
|
|
266
|
+ weight: getRealWeight(item)
|
|
|
|
267
|
+ }))
|
|
|
|
268
|
+})
|
|
|
|
269
|
+
|
|
|
|
270
|
+const exposeSuperRecordMap = computed(() => {
|
|
|
|
271
|
+ const map = {}
|
|
|
|
272
|
+ for (const key in superRecordMap.value) {
|
|
|
|
273
|
+ const subExercise = props.actionDetail?.exercises?.find(s => s.id == key)
|
|
|
|
274
|
+ map[key] = superRecordMap.value[key]
|
|
|
|
275
|
+ .filter(item => item.isActive)
|
|
|
|
276
|
+ .map(item => ({ ...item, weight: getRealWeight(item, subExercise?.exerciseType) }))
|
|
349
|
}
|
277
|
}
|
|
350
|
- trainingStore.deleteUnitRecord(props.unitIndex);
|
|
|
|
351
|
- console.log('训练类型 type =', trainingStore.type)
|
|
|
|
352
|
- console.log('组件类型 props.type =', props.type)
|
|
|
|
353
|
- console.log('unitIndex =', props.unitIndex)
|
|
|
|
354
|
- deleteActionShow.value = true
|
278
|
+ return map
|
|
|
|
279
|
+})
|
|
355
|
|
280
|
|
|
356
|
- // 1. 如果是【模板训练】,删除对应项
|
|
|
|
357
|
- if (trainingStore.type === 3) {
|
|
|
|
358
|
- console.log('模板训练:删除第', props.unitIndex, '个单元')
|
|
|
|
359
|
- trainingStore.actionDetail.units.splice(props.unitIndex, 1)
|
281
|
+const totalSetCount = computed(() => {
|
|
|
|
282
|
+ if (props.type === 1) return recordList.value.length
|
|
|
|
283
|
+ if (props.type === 2) {
|
|
|
|
284
|
+ const exercises = props.actionDetail?.exercises || []
|
|
|
|
285
|
+ if (exercises.length === 0) return 0
|
|
|
|
286
|
+ return superRecordMap.value[exercises[0].id]?.length || 0
|
|
360
|
}
|
287
|
}
|
|
361
|
- else {
|
|
|
|
362
|
- console.log('单个动作/超级组:清空')
|
|
|
|
363
|
- trainingStore.clearTrainingStore()
|
288
|
+ return 0
|
|
|
|
289
|
+})
|
|
|
|
290
|
+
|
|
|
|
291
|
+const checkedWeight = computed(() => {
|
|
|
|
292
|
+ let sum = 0
|
|
|
|
293
|
+ if (props.type === 1 && recordList.value) {
|
|
|
|
294
|
+ recordList.value.forEach(item => {
|
|
|
|
295
|
+ if (item.isActive) sum += getRealWeight(item) * (Number(item.reps) || 0)
|
|
|
|
296
|
+ })
|
|
364
|
}
|
297
|
}
|
|
365
|
- // 关闭菜单
|
|
|
|
366
|
- showTips.value = false
|
|
|
|
367
|
- console.log('删除完成 ✅')
|
298
|
+ if (props.type === 2 && superRecordMap.value) {
|
|
|
|
299
|
+ for (const actionId in superRecordMap.value) {
|
|
|
|
300
|
+ const subExercise = props.actionDetail?.exercises?.find(s => s.id == actionId)
|
|
|
|
301
|
+ superRecordMap.value[actionId].forEach(item => {
|
|
|
|
302
|
+ if (item.isActive) sum += getRealWeight(item, subExercise?.exerciseType) * (Number(item.reps) || 0)
|
|
|
|
303
|
+ })
|
|
|
|
304
|
+ }
|
|
|
|
305
|
+ }
|
|
|
|
306
|
+ return sum
|
|
|
|
307
|
+})
|
|
368
|
|
308
|
|
|
|
|
309
|
+const totalWeight = computed(() => {
|
|
|
|
310
|
+ let sum = 0
|
|
|
|
311
|
+ if (props.type === 1 && recordList.value) {
|
|
|
|
312
|
+ recordList.value.forEach(item => {
|
|
|
|
313
|
+ sum += getRealWeight(item) * (Number(item.reps) || 0)
|
|
|
|
314
|
+ })
|
|
|
|
315
|
+ }
|
|
|
|
316
|
+ if (props.type === 2 && superRecordMap.value) {
|
|
|
|
317
|
+ for (const actionId in superRecordMap.value) {
|
|
|
|
318
|
+ const subExercise = props.actionDetail?.exercises?.find(s => s.id == actionId)
|
|
|
|
319
|
+ superRecordMap.value[actionId].forEach(item => {
|
|
|
|
320
|
+ sum += getRealWeight(item, subExercise?.exerciseType) * (Number(item.reps) || 0)
|
|
|
|
321
|
+ })
|
|
|
|
322
|
+ }
|
|
|
|
323
|
+ }
|
|
|
|
324
|
+ return sum
|
|
|
|
325
|
+})
|
|
|
|
326
|
+
|
|
|
|
327
|
+// ===================== 工具函数 =====================
|
|
|
|
328
|
+function getRealWeight(item, subExerciseType = null) {
|
|
|
|
329
|
+ const userW = Number(userWeight.value) || 0
|
|
|
|
330
|
+ const inputW = Number(item.weight) || 0
|
|
|
|
331
|
+ const type = subExerciseType ?? props.actionDetail?.exerciseType
|
|
369
|
|
332
|
|
|
|
|
333
|
+ if (type === 0) return inputW
|
|
|
|
334
|
+ if (type === 4) return userW + inputW
|
|
|
|
335
|
+ if (type === 5) return Math.max(0, userW - inputW)
|
|
|
|
336
|
+ return 0
|
|
370
|
}
|
337
|
}
|
|
371
|
|
338
|
|
|
372
|
-// 难度控制逻辑
|
|
|
|
373
|
-const showDifficulty = ref(false);
|
|
|
|
374
|
-const initialDifficulty = { label: '难度', color: '#ffffff' };
|
|
|
|
375
|
-const currentDifficulty = ref({ ...initialDifficulty });
|
339
|
+function superGroupSetData(setIndex) {
|
|
|
|
340
|
+ const firstSub = props.actionDetail?.exercises?.[0]
|
|
|
|
341
|
+ if (!firstSub) return {}
|
|
|
|
342
|
+ return superRecordMap.value[firstSub.id]?.[setIndex] || {}
|
|
|
|
343
|
+}
|
|
376
|
|
344
|
|
|
377
|
-const selectDifficulty = (label, color) => {
|
|
|
|
378
|
- if (currentDifficulty.value.label === label) {
|
|
|
|
379
|
- currentDifficulty.value = { ...initialDifficulty };
|
|
|
|
380
|
- } else {
|
|
|
|
381
|
- currentDifficulty.value = { label, color };
|
345
|
+function getSubActionData(setIndex, actionId) {
|
|
|
|
346
|
+ return superRecordMap.value[actionId]?.[setIndex] || {
|
|
|
|
347
|
+ h: '00', m: '00', s: '00', quickTimeDisplay: formatQuickTime(60),
|
|
|
|
348
|
+ distance: '', weight: '', reps: '', duration: '', restTime: '', isActive: false
|
|
382
|
}
|
349
|
}
|
|
383
|
- showDifficulty.value = false;
|
|
|
|
384
|
-};
|
|
|
|
385
|
-
|
|
|
|
386
|
-// 点击背景关闭所有弹窗
|
|
|
|
387
|
-const closeDifficulty = () => {
|
|
|
|
388
|
- showDifficulty.value = false;
|
|
|
|
389
|
- showTips.value = false;
|
|
|
|
390
|
-};
|
350
|
+}
|
|
391
|
|
351
|
|
|
392
|
-// 超级组数据控制
|
|
|
|
393
|
-const superRecordMap = ref({})
|
|
|
|
394
|
-// 超级组:总组数(计算第一个动作的组数即可)
|
|
|
|
395
|
-const superTotalSets = computed(() => {
|
|
|
|
396
|
- if (props.type !== 2) return 0
|
|
|
|
397
|
- const exercises = props.actionDetail?.exercises || []
|
|
|
|
398
|
- if (exercises.length === 0) return 0
|
|
|
|
399
|
- const firstId = exercises[0].id
|
|
|
|
400
|
- console.log('打印超级组的组数:', superRecordMap.value[firstId]?.length);
|
|
|
|
401
|
- return superRecordMap.value[firstId]?.length || 0
|
|
|
|
402
|
-})
|
352
|
+function formatQuickTime(totalSeconds) {
|
|
|
|
353
|
+ const dur = dayjs.duration(totalSeconds * 1000)
|
|
|
|
354
|
+ const minutes = Math.floor(dur.asMinutes())
|
|
|
|
355
|
+ const seconds = dur.seconds()
|
|
|
|
356
|
+ if (minutes > 0) return `${minutes}分${seconds > 0 ? seconds + '秒' : ''}`
|
|
|
|
357
|
+ return `${seconds}s`
|
|
|
|
358
|
+}
|
|
403
|
|
359
|
|
|
404
|
-onMounted(() => {
|
|
|
|
405
|
- // 从 Pinia 加载当前 unit 的训练数据
|
|
|
|
406
|
- const savedData = trainingStore.getUnitRecord(props.unitIndex);
|
|
|
|
407
|
- // 恢复体重
|
|
|
|
408
|
- userWeight.value = savedData.userWeight || 70;
|
|
|
|
409
|
- console.log('从pinia加载的数据:', savedData);
|
360
|
+function parseQuickTime(display) {
|
|
|
|
361
|
+ if (!display) return 60
|
|
|
|
362
|
+ // 匹配 "X分Y秒" / "X分" / "Ys"
|
|
|
|
363
|
+ const full = display.match(/^(\d+)分(\d+)秒$/)
|
|
|
|
364
|
+ if (full) return parseInt(full[1]) * 60 + parseInt(full[2])
|
|
|
|
365
|
+ const minOnly = display.match(/^(\d+)分$/)
|
|
|
|
366
|
+ if (minOnly) return parseInt(minOnly[1]) * 60
|
|
|
|
367
|
+ const secOnly = display.match(/^(\d+)s$/)
|
|
|
|
368
|
+ if (secOnly) return parseInt(secOnly[1])
|
|
|
|
369
|
+ return 60
|
|
|
|
370
|
+}
|
|
410
|
|
371
|
|
|
411
|
- // 1. 先从 Pinia 恢复已有数据
|
372
|
+function saveToStore() {
|
|
|
|
373
|
+ let records = {}
|
|
412
|
if (props.type === 1) {
|
374
|
if (props.type === 1) {
|
|
413
|
- // 关键:只有当前是初始默认1条,才赋值,不再覆盖watch结果
|
|
|
|
414
|
- if (savedData.records?.[props.actionDetail.id]) {
|
|
|
|
415
|
- recordList.value = [...savedData.records[props.actionDetail.id]]
|
|
|
|
416
|
- console.log('onMounted兜底赋值', recordList.value)
|
|
|
|
417
|
- }
|
375
|
+ records[props.actionDetail.id] = recordList.value
|
|
418
|
} else if (props.type === 2) {
|
376
|
} else if (props.type === 2) {
|
|
419
|
- if (savedData.records && Object.keys(savedData.records).length > 0) {
|
|
|
|
420
|
- superRecordMap.value = { ...savedData.records };
|
|
|
|
421
|
- }
|
377
|
+ records = superRecordMap.value
|
|
422
|
}
|
378
|
}
|
|
423
|
- // 2. 超级组兜底初始化:只要有子动作,且 superRecordMap 为空就初始化
|
|
|
|
424
|
- if (props.type === 2 && props.actionDetail?.exercises?.length) {
|
|
|
|
425
|
- const exercises = props.actionDetail.exercises;
|
|
|
|
426
|
- // 判断:当前超级组还没任何结构 才初始化
|
|
|
|
427
|
- const firstId = exercises[0].id;
|
|
|
|
428
|
- if (!superRecordMap.value[firstId]) {
|
|
|
|
429
|
- const map = {};
|
|
|
|
430
|
- exercises.forEach(item => {
|
|
|
|
431
|
- map[item.id] = [{
|
|
|
|
432
|
- h: '00', m: '00', s: '00', quickTimeDisplay: '60s',
|
|
|
|
433
|
- distance: '', weight: '', reps: '', duration: '', restTime: '', isActive: false
|
|
|
|
434
|
- }];
|
|
|
|
435
|
- });
|
|
|
|
436
|
- superRecordMap.value = map;
|
|
|
|
437
|
- }
|
379
|
+ trainingStore.saveUnitRecord(props.unitIndex, { records, userWeight: userWeight.value })
|
|
|
|
380
|
+}
|
|
|
|
381
|
+
|
|
|
|
382
|
+// ===================== UI 交互 =====================
|
|
|
|
383
|
+function toggleTips() {
|
|
|
|
384
|
+ showTips.value = !showTips.value
|
|
|
|
385
|
+}
|
|
|
|
386
|
+
|
|
|
|
387
|
+function closeDifficulty() {
|
|
|
|
388
|
+ showDifficulty.value = false
|
|
|
|
389
|
+ showTips.value = false
|
|
|
|
390
|
+}
|
|
|
|
391
|
+
|
|
|
|
392
|
+function selectDifficulty(label, color) {
|
|
|
|
393
|
+ if (currentDifficulty.value.label === label) {
|
|
|
|
394
|
+ currentDifficulty.value = { ...initialDifficulty }
|
|
|
|
395
|
+ } else {
|
|
|
|
396
|
+ currentDifficulty.value = { label, color }
|
|
438
|
}
|
397
|
}
|
|
|
|
398
|
+ showDifficulty.value = false
|
|
|
|
399
|
+}
|
|
439
|
|
400
|
|
|
440
|
- nextTick(() => {
|
|
|
|
441
|
- emit('register', props.index, {
|
|
|
|
442
|
- recordList: recordList.value,
|
|
|
|
443
|
- superRecordMap: superRecordMap.value
|
|
|
|
444
|
- })
|
401
|
+function toggleActive(index) {
|
|
|
|
402
|
+ const wasActive = recordList.value[index].isActive
|
|
|
|
403
|
+ recordList.value[index].isActive = !recordList.value[index].isActive
|
|
|
|
404
|
+ const hasAnyActive = recordList.value.some(item => item.isActive)
|
|
|
|
405
|
+ emit('updateUnitActive', hasAnyActive)
|
|
|
|
406
|
+ if (recordList.value[index].isActive) {
|
|
|
|
407
|
+ const seconds = parseQuickTime(recordList.value[index].quickTimeDisplay)
|
|
|
|
408
|
+ emit('startRestTimer', seconds, props.unitIndex)
|
|
|
|
409
|
+ } else if (wasActive) {
|
|
|
|
410
|
+ emit('cancelRestTimer', props.unitIndex)
|
|
|
|
411
|
+ }
|
|
|
|
412
|
+}
|
|
|
|
413
|
+
|
|
|
|
414
|
+function toggleSuperSetActive(setIndex) {
|
|
|
|
415
|
+ const wasActive = superGroupSetData(setIndex).isActive
|
|
|
|
416
|
+ props.actionDetail.exercises.forEach(sub => {
|
|
|
|
417
|
+ const list = superRecordMap.value[sub.id]
|
|
|
|
418
|
+ if (list?.[setIndex]) list[setIndex].isActive = !list[setIndex].isActive
|
|
445
|
})
|
419
|
})
|
|
446
|
-});
|
|
|
|
447
|
-// 动作组数据记录
|
|
|
|
448
|
-const recordList = ref([
|
|
|
|
449
|
- { h: '00', m: '00', s: '00', quickTimeDisplay: '60s', distance: '', weight: '', reps: '', duration: '', restTime: '', isActive: false },
|
|
|
|
450
|
-]);
|
|
|
|
451
|
-
|
|
|
|
452
|
-const saveToStore = () => {
|
|
|
|
453
|
- let records = {};
|
|
|
|
454
|
- if (props.type === 1) {
|
|
|
|
455
|
- // 普通动作
|
|
|
|
456
|
- records[props.actionDetail.id] = recordList.value;
|
|
|
|
457
|
- } else if (props.type === 2) {
|
|
|
|
458
|
- // 超级组
|
|
|
|
459
|
- records = superRecordMap.value;
|
420
|
+ const hasAnyActive = props.actionDetail.exercises.some(sub =>
|
|
|
|
421
|
+ superRecordMap.value[sub.id]?.some(item => item.isActive)
|
|
|
|
422
|
+ )
|
|
|
|
423
|
+ emit('updateUnitActive', hasAnyActive)
|
|
|
|
424
|
+ if (!wasActive) {
|
|
|
|
425
|
+ const restSeconds = parseQuickTime(superGroupSetData(setIndex).quickTimeDisplay)
|
|
|
|
426
|
+ emit('startRestTimer', restSeconds, props.unitIndex)
|
|
|
|
427
|
+ } else {
|
|
|
|
428
|
+ emit('cancelRestTimer', props.unitIndex)
|
|
460
|
}
|
429
|
}
|
|
461
|
- // 调用 Pinia 保存
|
|
|
|
462
|
- trainingStore.saveUnitRecord(props.unitIndex, {
|
|
|
|
463
|
- records: records,
|
|
|
|
464
|
- userWeight: userWeight.value
|
|
|
|
465
|
- });
|
|
|
|
466
|
-};
|
430
|
+}
|
|
467
|
|
431
|
|
|
468
|
-watch(recordList, () => {
|
|
|
|
469
|
- // console.log('recordList变化,发送长度:', recordList.value.length)
|
|
|
|
470
|
- emit('update:groupCount', recordList.value.length)
|
|
|
|
471
|
-}, { deep: true, immediate: true })
|
432
|
+// 供父组件调用:取消该组件内所有勾选
|
|
|
|
433
|
+function resetActiveSets() {
|
|
|
|
434
|
+ recordList.value.forEach(item => { item.isActive = false })
|
|
|
|
435
|
+ for (const key in superRecordMap.value) {
|
|
|
|
436
|
+ superRecordMap.value[key]?.forEach(item => { item.isActive = false })
|
|
|
|
437
|
+ }
|
|
|
|
438
|
+ emit('updateUnitActive', false)
|
|
|
|
439
|
+}
|
|
472
|
|
440
|
|
|
473
|
-watch([recordList, superRecordMap, userWeight], () => {
|
|
|
|
474
|
- saveToStore();
|
|
|
|
475
|
- console.log('+++++++++打印全局训练数据 trainingStore.unitRecords++++++++', trainingStore.unitRecords);
|
|
|
|
476
|
-}, { deep: true, immediate: false });
|
441
|
+// ===================== 体重选择器 =====================
|
|
|
|
442
|
+function openWeightPicker() {
|
|
|
|
443
|
+ const num = userWeight.value
|
|
|
|
444
|
+ const intIndex = Math.max(0, Math.min(Math.floor(num) - 10, 240))
|
|
|
|
445
|
+ const decPart = Math.round((num - Math.floor(num)) * 10)
|
|
|
|
446
|
+ defaultWeightIndex.value = [intIndex, decPart, 0]
|
|
|
|
447
|
+ showWeightPicker.value = true
|
|
|
|
448
|
+}
|
|
477
|
|
449
|
|
|
478
|
-const toggleActive = (index) => {
|
|
|
|
479
|
- recordList.value[index].isActive = !recordList.value[index].isActive;
|
|
|
|
480
|
-};
|
450
|
+function onWeightConfirm(e) {
|
|
|
|
451
|
+ userWeight.value = parseFloat(`${e.value[0]}.${e.value[1]}`)
|
|
|
|
452
|
+ showWeightPicker.value = false
|
|
|
|
453
|
+}
|
|
481
|
|
454
|
|
|
482
|
-// 超级组工具方法
|
|
|
|
483
|
-const superGroupSetData = (setIndex) => {
|
|
|
|
484
|
- const firstSub = props.actionDetail?.exercises?.[0]
|
|
|
|
485
|
- if (!firstSub) return {}
|
|
|
|
486
|
- return superRecordMap.value[firstSub.id]?.[setIndex] || {}
|
455
|
+// ===================== 备注 =====================
|
|
|
|
456
|
+function openBeizhu() {
|
|
|
|
457
|
+ nextTick(() => {
|
|
|
|
458
|
+ if (showBeizhuRef.value) showBeizhuRef.value.open(props.actionDetail.id)
|
|
|
|
459
|
+ })
|
|
487
|
}
|
460
|
}
|
|
488
|
-const getSubActionData = (setIndex, actionId) => {
|
|
|
|
489
|
- return superRecordMap.value[actionId]?.[setIndex] || {
|
|
|
|
490
|
- h: '00', m: '00', s: '00',
|
|
|
|
491
|
- quickTimeDisplay: '60s',
|
|
|
|
492
|
- distance: '',
|
|
|
|
493
|
- weight: '',
|
|
|
|
494
|
- reps: '',
|
|
|
|
495
|
- duration: '',
|
|
|
|
496
|
- restTime: '',
|
|
|
|
497
|
- isActive: false
|
461
|
+
|
|
|
|
462
|
+async function handleNoteSave(content) {
|
|
|
|
463
|
+ try {
|
|
|
|
464
|
+ if (props.type == 2) {
|
|
|
|
465
|
+ await SupersetsApi.addNotes({ supersetsId: props.id, content })
|
|
|
|
466
|
+ } else {
|
|
|
|
467
|
+ await ExercisesApi.addNotes({ exerciseId: props.id, content })
|
|
|
|
468
|
+ }
|
|
|
|
469
|
+ props.actionDetail.userNote = content
|
|
|
|
470
|
+ } catch (e) {
|
|
|
|
471
|
+ // 静默处理
|
|
|
|
472
|
+ }
|
|
|
|
473
|
+}
|
|
|
|
474
|
+
|
|
|
|
475
|
+// ===================== 替换/删除动作 =====================
|
|
|
|
476
|
+function handleReplaceAction() {
|
|
|
|
477
|
+ showTips.value = false
|
|
|
|
478
|
+ replacePopupShow.value = true
|
|
|
|
479
|
+}
|
|
|
|
480
|
+
|
|
|
|
481
|
+function deleteAction() {
|
|
|
|
482
|
+ if (props.isDailyTemplates) {
|
|
|
|
483
|
+ showTips.value = false
|
|
|
|
484
|
+ emit('deleteAction')
|
|
|
|
485
|
+ return
|
|
|
|
486
|
+ }
|
|
|
|
487
|
+ trainingStore.deleteUnitRecord(props.unitIndex)
|
|
|
|
488
|
+ deleteActionShow.value = true
|
|
|
|
489
|
+ if (trainingStore.type === 3) {
|
|
|
|
490
|
+ trainingStore.actionDetail.units.splice(props.unitIndex, 1)
|
|
|
|
491
|
+ } else {
|
|
|
|
492
|
+ trainingStore.clearTrainingStore()
|
|
498
|
}
|
493
|
}
|
|
|
|
494
|
+ showTips.value = false
|
|
|
|
495
|
+}
|
|
|
|
496
|
+
|
|
|
|
497
|
+// ===================== 时间选择器 =====================
|
|
|
|
498
|
+function openPicker(index) {
|
|
|
|
499
|
+ activeIndex.value = index
|
|
|
|
500
|
+ const item = recordList.value[index]
|
|
|
|
501
|
+ defaultTimeIndex.value = [
|
|
|
|
502
|
+ timeColumns[0].indexOf(item.h + '时'),
|
|
|
|
503
|
+ timeColumns[1].indexOf(item.m + '分'),
|
|
|
|
504
|
+ timeColumns[2].indexOf(item.s + '秒')
|
|
|
|
505
|
+ ]
|
|
|
|
506
|
+ showPicker.value = true
|
|
499
|
}
|
507
|
}
|
|
500
|
|
508
|
|
|
501
|
-const openSuperPicker = (setIndex, actionId) => {
|
509
|
+function openQuickTimer(index) {
|
|
|
|
510
|
+ activeIndex.value = index
|
|
|
|
511
|
+ showQuickPicker.value = true
|
|
|
|
512
|
+}
|
|
|
|
513
|
+
|
|
|
|
514
|
+function openAllQuickTimer() {
|
|
|
|
515
|
+ restEditMode.value = 'all'
|
|
|
|
516
|
+ showQuickPicker.value = true
|
|
|
|
517
|
+}
|
|
|
|
518
|
+
|
|
|
|
519
|
+function openSuperPicker(setIndex, actionId) {
|
|
502
|
activeIndex.value = setIndex
|
520
|
activeIndex.value = setIndex
|
|
503
|
- activeActionId.value = actionId; // 保存当前动作ID
|
521
|
+ activeActionId.value = actionId
|
|
504
|
showPicker.value = true
|
522
|
showPicker.value = true
|
|
505
|
}
|
523
|
}
|
|
506
|
-const openSuperQuickTimer = (setIndex) => {
|
524
|
+
|
|
|
|
525
|
+function openSuperQuickTimer(setIndex) {
|
|
507
|
activeIndex.value = setIndex
|
526
|
activeIndex.value = setIndex
|
|
508
|
showQuickPicker.value = true
|
527
|
showQuickPicker.value = true
|
|
509
|
}
|
528
|
}
|
|
510
|
-const toggleSuperSetActive = (setIndex) => {
|
|
|
|
511
|
- props.actionDetail.exercises.forEach(sub => {
|
|
|
|
512
|
- const list = superRecordMap.value[sub.id]
|
|
|
|
513
|
- if (list?.[setIndex]) {
|
|
|
|
514
|
- list[setIndex].isActive = !list[setIndex].isActive
|
|
|
|
515
|
- }
|
|
|
|
516
|
- })
|
|
|
|
517
|
-}
|
|
|
|
518
|
|
529
|
|
|
519
|
-// 合并后的 Picker 逻辑
|
|
|
|
520
|
-const timeColumns = reactive([
|
|
|
|
521
|
- Array.from({ length: 24 }, (_, i) => String(i).padStart(2, '0') + '时'),
|
|
|
|
522
|
- Array.from({ length: 60 }, (_, i) => String(i).padStart(2, '0') + '分'),
|
|
|
|
523
|
- Array.from({ length: 60 }, (_, i) => String(i).padStart(2, '0') + '秒'),
|
|
|
|
524
|
-]);
|
|
|
|
525
|
-const defaultTimeIndex = ref([0, 0, 0]);
|
|
|
|
526
|
-const quickColumns = reactive([
|
|
|
|
527
|
- Array.from({ length: 60 }, (_, i) => String(i).padStart(2, '0') + '分'),
|
|
|
|
528
|
- Array.from({ length: 60 }, (_, i) => String(i).padStart(2, '0') + '秒'),
|
|
|
|
529
|
-]);
|
|
|
|
530
|
-
|
|
|
|
531
|
-const openPicker = (index) => {
|
|
|
|
532
|
- activeIndex.value = index;
|
|
|
|
533
|
- const item = recordList.value[index];
|
|
|
|
534
|
- const hIdx = timeColumns[0].indexOf(item.h + '时');
|
|
|
|
535
|
- const mIdx = timeColumns[1].indexOf(item.m + '分');
|
|
|
|
536
|
- const sIdx = timeColumns[2].indexOf(item.s + '秒');
|
|
|
|
537
|
- defaultTimeIndex.value = [hIdx, mIdx, sIdx];
|
|
|
|
538
|
- showPicker.value = true;
|
|
|
|
539
|
-};
|
|
|
|
540
|
-//
|
|
|
|
541
|
-const openQuickTimer = (index) => {
|
|
|
|
542
|
- activeIndex.value = index;
|
|
|
|
543
|
- showQuickPicker.value = true;
|
|
|
|
544
|
-};
|
|
|
|
545
|
-// 组间休息
|
|
|
|
546
|
-const openAllQuickTimer = () => {
|
|
|
|
547
|
- restEditMode.value = 'all'; // 重点:标记为全部修改
|
|
|
|
548
|
- showQuickPicker.value = true;
|
|
|
|
549
|
-};
|
|
|
|
550
|
-
|
|
|
|
551
|
-const onTimeConfirm = (e) => {
|
|
|
|
552
|
- const rawValues = e.value.map((val) => String(val).replace(/[时分秒]/g, ''))
|
530
|
+function onTimeConfirm(e) {
|
|
|
|
531
|
+ const rawValues = e.value.map(val => String(val).replace(/[时分秒]/g, ''))
|
|
553
|
const setIdx = activeIndex.value
|
532
|
const setIdx = activeIndex.value
|
|
554
|
|
533
|
|
|
555
|
if (props.type === 1) {
|
534
|
if (props.type === 1) {
|
|
556
|
const item = recordList.value[setIdx]
|
535
|
const item = recordList.value[setIdx]
|
|
557
|
- item.h = rawValues[0]
|
|
|
|
558
|
- item.m = rawValues[1]
|
|
|
|
559
|
- item.s = rawValues[2]
|
536
|
+ item.h = rawValues[0]; item.m = rawValues[1]; item.s = rawValues[2]
|
|
560
|
} else if (props.type === 2) {
|
537
|
} else if (props.type === 2) {
|
|
561
|
- // 只修改当前点击的动作,不批量修改所有动作!
|
|
|
|
562
|
- const actionId = activeActionId.value;
|
|
|
|
563
|
- const list = superRecordMap.value[actionId];
|
538
|
+ const list = superRecordMap.value[activeActionId.value]
|
|
564
|
if (list?.[setIdx]) {
|
539
|
if (list?.[setIdx]) {
|
|
565
|
- list[setIdx].h = rawValues[0];
|
|
|
|
566
|
- list[setIdx].m = rawValues[1];
|
|
|
|
567
|
- list[setIdx].s = rawValues[2];
|
540
|
+ list[setIdx].h = rawValues[0]; list[setIdx].m = rawValues[1]; list[setIdx].s = rawValues[2]
|
|
568
|
}
|
541
|
}
|
|
569
|
}
|
542
|
}
|
|
570
|
showPicker.value = false
|
543
|
showPicker.value = false
|
|
571
|
}
|
544
|
}
|
|
572
|
|
545
|
|
|
573
|
-const onQuickConfirm = (e) => {
|
|
|
|
574
|
- const min = parseInt(e.value[0]) || 0
|
|
|
|
575
|
- const sec = parseInt(e.value[1]) || 0
|
|
|
|
576
|
- const totalSeconds = min * 60 + sec
|
546
|
+function onQuickConfirm(e) {
|
|
|
|
547
|
+ const totalSeconds = dayjs.duration({
|
|
|
|
548
|
+ minutes: parseInt(e.value[0]) || 0,
|
|
|
|
549
|
+ seconds: parseInt(e.value[1]) || 0
|
|
|
|
550
|
+ }).asSeconds()
|
|
577
|
const setIdx = activeIndex.value
|
551
|
const setIdx = activeIndex.value
|
|
578
|
|
552
|
|
|
579
|
- // ============== 统一设置所有组 ==============
|
|
|
|
580
|
if (restEditMode.value === 'all') {
|
553
|
if (restEditMode.value === 'all') {
|
|
581
|
- // 普通动作
|
|
|
|
582
|
if (props.type === 1) {
|
554
|
if (props.type === 1) {
|
|
583
|
- recordList.value.forEach(item => {
|
|
|
|
584
|
- item.quickTimeDisplay = totalSeconds + 's'
|
|
|
|
585
|
- })
|
|
|
|
586
|
- }
|
|
|
|
587
|
- // 超级组
|
|
|
|
588
|
- else if (props.type === 2) {
|
555
|
+ recordList.value.forEach(item => { item.quickTimeDisplay = formatQuickTime(totalSeconds) })
|
|
|
|
556
|
+ } else if (props.type === 2) {
|
|
589
|
const firstSub = props.actionDetail?.exercises?.[0]
|
557
|
const firstSub = props.actionDetail?.exercises?.[0]
|
|
590
|
- if (!firstSub) return
|
|
|
|
591
|
- const allSets = superRecordMap.value[firstSub.id]
|
|
|
|
592
|
- if (!allSets) return
|
|
|
|
593
|
- allSets.forEach(set => {
|
|
|
|
594
|
- set.quickTimeDisplay = totalSeconds + 's'
|
|
|
|
595
|
- })
|
558
|
+ if (firstSub) {
|
|
|
|
559
|
+ superRecordMap.value[firstSub.id]?.forEach(set => { set.quickTimeDisplay = formatQuickTime(totalSeconds) })
|
|
|
|
560
|
+ }
|
|
596
|
}
|
561
|
}
|
|
597
|
- }
|
|
|
|
598
|
-
|
|
|
|
599
|
- // ============== 单行修改 ==============
|
|
|
|
600
|
- else {
|
562
|
+ } else {
|
|
601
|
if (props.type === 1) {
|
563
|
if (props.type === 1) {
|
|
602
|
- recordList.value[setIdx].quickTimeDisplay = totalSeconds + 's'
|
564
|
+ recordList.value[setIdx].quickTimeDisplay = formatQuickTime(totalSeconds)
|
|
603
|
} else if (props.type === 2) {
|
565
|
} else if (props.type === 2) {
|
|
604
|
props.actionDetail.exercises.forEach(sub => {
|
566
|
props.actionDetail.exercises.forEach(sub => {
|
|
605
|
const list = superRecordMap.value[sub.id]
|
567
|
const list = superRecordMap.value[sub.id]
|
|
606
|
- if (list?.[setIdx]) {
|
|
|
|
607
|
- list[setIdx].quickTimeDisplay = totalSeconds + 's'
|
|
|
|
608
|
- }
|
568
|
+ if (list?.[setIdx]) list[setIdx].quickTimeDisplay = formatQuickTime(totalSeconds)
|
|
609
|
})
|
569
|
})
|
|
610
|
}
|
570
|
}
|
|
611
|
}
|
571
|
}
|
|
612
|
-
|
|
|
|
613
|
restEditMode.value = 'single'
|
572
|
restEditMode.value = 'single'
|
|
614
|
showQuickPicker.value = false
|
573
|
showQuickPicker.value = false
|
|
615
|
}
|
574
|
}
|
|
616
|
|
575
|
|
|
617
|
-
|
|
|
|
618
|
-// 单动作的增加/删除
|
|
|
|
619
|
-const addRow = () => {
|
576
|
+// ===================== 增删行/组 =====================
|
|
|
|
577
|
+function addRow() {
|
|
620
|
recordList.value.push({
|
578
|
recordList.value.push({
|
|
621
|
- h: '00', m: '00', s: '00',
|
|
|
|
622
|
- quickTimeDisplay: '60s',
|
|
|
|
623
|
- distance: '', weight: '', reps: '', duration: '',
|
|
|
|
624
|
- restTime: '', isActive: false,
|
|
|
|
625
|
- });
|
|
|
|
626
|
-};
|
|
|
|
627
|
-
|
|
|
|
628
|
-// 删除单动作行数,至少保留一行,提示。
|
|
|
|
629
|
-const deleteRow = (index) => {
|
579
|
+ h: '00', m: '00', s: '00', quickTimeDisplay: formatQuickTime(60),
|
|
|
|
580
|
+ distance: '', weight: '', reps: '', duration: '', restTime: '', isActive: false
|
|
|
|
581
|
+ })
|
|
|
|
582
|
+}
|
|
|
|
583
|
+
|
|
|
|
584
|
+function deleteRow(index) {
|
|
630
|
if (recordList.value.length > 1) {
|
585
|
if (recordList.value.length > 1) {
|
|
631
|
- recordList.value.splice(index, 1);
|
586
|
+ recordList.value.splice(index, 1)
|
|
632
|
} else {
|
587
|
} else {
|
|
633
|
- uni.showToast({
|
|
|
|
634
|
- title: '至少保留一行数据',
|
|
|
|
635
|
- icon: 'none'
|
|
|
|
636
|
- })
|
588
|
+ uni.showToast({ title: '至少保留一行数据', icon: 'none' })
|
|
637
|
}
|
589
|
}
|
|
638
|
-};
|
590
|
+}
|
|
639
|
|
591
|
|
|
640
|
-// 增加超级组的set组数
|
|
|
|
641
|
-const addSuperSet = () => {
|
|
|
|
642
|
- const exercises = props.actionDetail?.exercises || []
|
|
|
|
643
|
- exercises.forEach(sub => {
|
592
|
+function addSuperSet() {
|
|
|
|
593
|
+ (props.actionDetail?.exercises || []).forEach(sub => {
|
|
644
|
if (superRecordMap.value[sub.id]) {
|
594
|
if (superRecordMap.value[sub.id]) {
|
|
645
|
superRecordMap.value[sub.id].push({
|
595
|
superRecordMap.value[sub.id].push({
|
|
646
|
- h: '00', m: '00', s: '00',
|
|
|
|
647
|
- quickTimeDisplay: '60s',
|
|
|
|
648
|
- distance: '',
|
|
|
|
649
|
- weight: '',
|
|
|
|
650
|
- reps: '',
|
|
|
|
651
|
- duration: '',
|
|
|
|
652
|
- restTime: '',
|
|
|
|
653
|
- isActive: false
|
596
|
+ h: '00', m: '00', s: '00', quickTimeDisplay: formatQuickTime(60),
|
|
|
|
597
|
+ distance: '', weight: '', reps: '', duration: '', restTime: '', isActive: false
|
|
654
|
})
|
598
|
})
|
|
655
|
}
|
599
|
}
|
|
656
|
})
|
600
|
})
|
|
657
|
}
|
601
|
}
|
|
658
|
-// 删除超级组的组数
|
|
|
|
659
|
-const deleteSuperSet = (setIndex) => {
|
602
|
+
|
|
|
|
603
|
+function deleteSuperSet(setIndex) {
|
|
660
|
const exercises = props.actionDetail?.exercises || []
|
604
|
const exercises = props.actionDetail?.exercises || []
|
|
661
|
-
|
|
|
|
662
|
- // 没有子动作直接返回
|
|
|
|
663
|
if (!exercises.length) return
|
605
|
if (!exercises.length) return
|
|
664
|
- // 取第一个子动作的组数,所有子动作数组长度保持同步
|
|
|
|
665
|
- const firstSubId = exercises[0].id
|
|
|
|
666
|
- const list = superRecordMap.value[firstSubId] || []
|
|
|
|
667
|
- // 判断只剩一组,弹窗提示并终止删除
|
606
|
+ const list = superRecordMap.value[exercises[0].id] || []
|
|
668
|
if (list.length <= 1) {
|
607
|
if (list.length <= 1) {
|
|
669
|
- uni.showToast({
|
|
|
|
670
|
- title: '至少保留一组数据',
|
|
|
|
671
|
- icon: 'none'
|
|
|
|
672
|
- })
|
608
|
+ uni.showToast({ title: '至少保留一组数据', icon: 'none' })
|
|
673
|
return
|
609
|
return
|
|
674
|
}
|
610
|
}
|
|
675
|
-
|
|
|
|
676
|
exercises.forEach(sub => {
|
611
|
exercises.forEach(sub => {
|
|
677
|
const list = superRecordMap.value[sub.id]
|
612
|
const list = superRecordMap.value[sub.id]
|
|
678
|
- if (list && list.length > 1) {
|
|
|
|
679
|
- list.splice(setIndex, 1)
|
|
|
|
680
|
- }
|
613
|
+ if (list && list.length > 1) list.splice(setIndex, 1)
|
|
681
|
})
|
614
|
})
|
|
682
|
}
|
615
|
}
|
|
683
|
|
616
|
|
|
684
|
-const addGroup = () => {
|
|
|
|
685
|
- if (props.type === 1) {
|
|
|
|
686
|
- addRow()
|
|
|
|
687
|
- } else if (props.type === 2) {
|
|
|
|
688
|
- addSuperSet()
|
|
|
|
689
|
- }
|
617
|
+function addGroup() {
|
|
|
|
618
|
+ if (props.type === 1) addRow()
|
|
|
|
619
|
+ else if (props.type === 2) addSuperSet()
|
|
690
|
}
|
620
|
}
|
|
691
|
|
621
|
|
|
692
|
-// 历史
|
|
|
|
693
|
-const openHistory = (id) => {
|
|
|
|
694
|
- if (historyPopupRef.value && historyPopupRef.value.openHistoryPopup) {
|
|
|
|
695
|
- historyPopupRef.value.openHistoryPopup(id);
|
622
|
+// ===================== 历史 =====================
|
|
|
|
623
|
+function openHistory(id) {
|
|
|
|
624
|
+ if (historyPopupRef.value?.openHistoryPopup) {
|
|
|
|
625
|
+ historyPopupRef.value.openHistoryPopup(id)
|
|
696
|
}
|
626
|
}
|
|
697
|
}
|
627
|
}
|
|
698
|
|
628
|
|
|
699
|
-// 动作名称渲染
|
|
|
|
700
|
-const exerciseNamesWithLabel = computed(() => {
|
|
|
|
701
|
- const exercises = props.actionDetail?.exercises || []
|
|
|
|
702
|
- return exercises.map((item, index) => {
|
|
|
|
703
|
- const label = String.fromCharCode(65 + index)
|
|
|
|
704
|
- return `${label} ${item?.name || '未知动作'}`
|
|
|
|
705
|
- })
|
|
|
|
706
|
-})
|
|
|
|
707
|
-
|
|
|
|
708
|
-// 获得真正的重量(支持普通动作 + 超级组)
|
|
|
|
709
|
-const getRealWeight = (item, subExerciseType = null) => {
|
|
|
|
710
|
- const userW = Number(userWeight.value) || 0
|
|
|
|
711
|
- const inputW = Number(item.weight) || 0
|
|
|
|
712
|
- // 重要:超级组子动作会传入自己的 exerciseType
|
|
|
|
713
|
- let type = subExerciseType ?? props.actionDetail?.exerciseType
|
|
|
|
714
|
-
|
|
|
|
715
|
- // console.log('【重量计算】', {
|
|
|
|
716
|
- // 动作类型: type,
|
|
|
|
717
|
- // 体重: userW,
|
|
|
|
718
|
- // 输入重量: inputW,
|
|
|
|
719
|
- // 最终重量:
|
|
|
|
720
|
- // type === 0 ? inputW :
|
|
|
|
721
|
- // type === 4 ? userW + inputW :
|
|
|
|
722
|
- // type === 5 ? userW - inputW : 0
|
|
|
|
723
|
- // })
|
|
|
|
724
|
- let realWeight = 0;
|
|
|
|
725
|
- if (type === 0) {
|
|
|
|
726
|
- realWeight = inputW;
|
|
|
|
727
|
- } else if (type === 4) {
|
|
|
|
728
|
- realWeight = userW + inputW;
|
|
|
|
729
|
- } else if (type === 5) {
|
|
|
|
730
|
- realWeight = userW - inputW;
|
|
|
|
731
|
- // 只做数据兜底修正,不在这里弹提示
|
|
|
|
732
|
- if (realWeight < 0) {
|
|
|
|
733
|
- realWeight = 0;
|
|
|
|
734
|
- }
|
|
|
|
735
|
- }
|
|
|
|
736
|
- return realWeight;
|
|
|
|
737
|
-}
|
|
|
|
738
|
-
|
|
|
|
739
|
-// 只暴露 isActive = true 的数据
|
|
|
|
740
|
-const exposeRecordList = computed(() => {
|
|
|
|
741
|
- return recordList.value.filter(item => item.isActive).map(item => {
|
|
|
|
742
|
- return {
|
|
|
|
743
|
- ...item,
|
|
|
|
744
|
- weight: getRealWeight(item) // 👈 自动计算真实重量
|
|
|
|
745
|
- }
|
|
|
|
746
|
- })
|
|
|
|
747
|
-})
|
|
|
|
748
|
-
|
|
|
|
749
|
-const exposeSuperRecordMap = computed(() => {
|
|
|
|
750
|
- const map = {}
|
|
|
|
751
|
- for (const key in superRecordMap.value) {
|
|
|
|
752
|
- // 找到当前子动作的类型
|
|
|
|
753
|
- const subExercise = props.actionDetail?.exercises?.find(s => s.id == key)
|
|
|
|
754
|
- const subType = subExercise?.exerciseType
|
|
|
|
755
|
- map[key] = superRecordMap.value[key]
|
|
|
|
756
|
- .filter(item => item.isActive)
|
|
|
|
757
|
- .map(item => {
|
|
|
|
758
|
- return {
|
|
|
|
759
|
- ...item,
|
|
|
|
760
|
- weight: getRealWeight(item, subType) // ✅ 传入子动作类型
|
|
|
|
761
|
- }
|
|
|
|
762
|
- })
|
|
|
|
763
|
- }
|
|
|
|
764
|
- return map
|
|
|
|
765
|
-})
|
|
|
|
766
|
-// 总组数
|
|
|
|
767
|
-const totalSetCount = computed(() => {
|
|
|
|
768
|
- // 1. 普通动作 type === 1
|
|
|
|
769
|
- if (props.type === 1) {
|
|
|
|
770
|
- return recordList.value.length
|
|
|
|
771
|
- }
|
|
|
|
772
|
- // 2. 超级组 type === 2
|
|
|
|
773
|
- if (props.type === 2) {
|
|
|
|
774
|
- const exercises = props.actionDetail?.exercises || []
|
|
|
|
775
|
- if (exercises.length === 0) return 0
|
|
|
|
776
|
- const firstId = exercises[0].id
|
|
|
|
777
|
- return superRecordMap.value[firstId]?.length || 0
|
|
|
|
778
|
- }
|
|
|
|
779
|
- return 0
|
|
|
|
780
|
-})
|
|
|
|
781
|
-
|
|
|
|
782
|
-// 重量
|
|
|
|
783
|
-// 1. 已勾选的重量总和(黄色框框)→ 现在 = 真实重量 × 次数
|
|
|
|
784
|
-const checkedWeight = computed(() => {
|
|
|
|
785
|
- let sum = 0
|
|
|
|
786
|
- // 普通动作
|
|
|
|
787
|
- if (props.type === 1 && recordList.value) {
|
|
|
|
788
|
- recordList.value.forEach(item => {
|
|
|
|
789
|
- if (item.isActive) {
|
|
|
|
790
|
- const realWeight = getRealWeight(item) // 👈 真实重量(自重/加重/减重)
|
|
|
|
791
|
- const reps = Number(item.reps) || 0 // 👈 次数
|
|
|
|
792
|
- sum += realWeight * reps // 👈 重量 × 次数
|
|
|
|
793
|
- }
|
|
|
|
794
|
- })
|
|
|
|
795
|
- }
|
|
|
|
796
|
- // 超级组
|
|
|
|
797
|
- if (props.type === 2 && superRecordMap.value) {
|
|
|
|
798
|
- for (const actionId in superRecordMap.value) {
|
|
|
|
799
|
- // 拿到子动作类型
|
|
|
|
800
|
- const subExercise = props.actionDetail?.exercises?.find(s => s.id == actionId)
|
|
|
|
801
|
- const subType = subExercise?.exerciseType
|
|
|
|
802
|
-
|
|
|
|
803
|
- superRecordMap.value[actionId].forEach(item => {
|
|
|
|
804
|
- if (item.isActive) {
|
|
|
|
805
|
- const realWeight = getRealWeight(item, subType)
|
|
|
|
806
|
- const reps = Number(item.reps) || 0
|
|
|
|
807
|
- sum += realWeight * reps
|
|
|
|
808
|
- }
|
|
|
|
809
|
- })
|
|
|
|
810
|
- }
|
|
|
|
811
|
- }
|
|
|
|
812
|
- return sum
|
|
|
|
813
|
-})
|
|
|
|
814
|
-
|
|
|
|
815
|
-// 2. 所有组的重量总和(不管勾没勾)→ 现在 = 真实重量 × 次数
|
|
|
|
816
|
-const totalWeight = computed(() => {
|
|
|
|
817
|
- let sum = 0
|
|
|
|
818
|
- if (props.type === 1 && recordList.value) {
|
|
|
|
819
|
- recordList.value.forEach(item => {
|
|
|
|
820
|
- const realWeight = getRealWeight(item)
|
|
|
|
821
|
- const reps = Number(item.reps) || 0
|
|
|
|
822
|
- sum += realWeight * reps
|
|
|
|
823
|
- })
|
|
|
|
824
|
- }
|
|
|
|
825
|
- if (props.type === 2 && superRecordMap.value) {
|
|
|
|
826
|
- for (const actionId in superRecordMap.value) {
|
|
|
|
827
|
- const subExercise = props.actionDetail?.exercises?.find(s => s.id == actionId)
|
|
|
|
828
|
- const subType = subExercise?.exerciseType
|
629
|
+// ===================== Watchers =====================
|
|
|
|
630
|
+watch(recordList, () => {
|
|
|
|
631
|
+ emit('update:groupCount', recordList.value.length)
|
|
|
|
632
|
+}, { deep: true, immediate: true })
|
|
829
|
|
633
|
|
|
830
|
- superRecordMap.value[actionId].forEach(item => {
|
|
|
|
831
|
- const realWeight = getRealWeight(item, subType)
|
|
|
|
832
|
- const reps = Number(item.reps) || 0
|
|
|
|
833
|
- sum += realWeight * reps
|
|
|
|
834
|
- })
|
|
|
|
835
|
- }
|
|
|
|
836
|
- }
|
|
|
|
837
|
- return sum
|
|
|
|
838
|
-})
|
634
|
+watch([recordList, superRecordMap, userWeight], saveToStore, { deep: true })
|
|
839
|
|
635
|
|
|
840
|
-// ==============================================
|
|
|
|
841
|
-// 统一监听:普通动作 + 超级组 的自重减重(type=5)
|
|
|
|
842
|
-// ==============================================
|
|
|
|
843
|
watch(
|
636
|
watch(
|
|
844
|
() => [recordList.value, superRecordMap.value],
|
637
|
() => [recordList.value, superRecordMap.value],
|
|
845
|
() => {
|
638
|
() => {
|
|
846
|
- const userW = userWeight.value || 0;
|
|
|
|
847
|
-
|
|
|
|
848
|
- // --------------------------
|
|
|
|
849
|
- // 1. 监听【普通动作】
|
|
|
|
850
|
- // --------------------------
|
639
|
+ const userW = userWeight.value || 0
|
|
851
|
if (props.type === 1 && props.actionDetail?.exerciseType === 5) {
|
640
|
if (props.type === 1 && props.actionDetail?.exerciseType === 5) {
|
|
852
|
- recordList.value.forEach((item) => {
|
|
|
|
853
|
- const inputW = Number(item.weight) || 0;
|
|
|
|
854
|
- if (inputW > userW) {
|
|
|
|
855
|
- item.weight = "";
|
|
|
|
856
|
- uni.showToast({
|
|
|
|
857
|
- title: "辅助重量不能超过体重",
|
|
|
|
858
|
- icon: "none",
|
|
|
|
859
|
- duration: 2000,
|
|
|
|
860
|
- });
|
641
|
+ recordList.value.forEach(item => {
|
|
|
|
642
|
+ if ((Number(item.weight) || 0) > userW) {
|
|
|
|
643
|
+ item.weight = ''
|
|
|
|
644
|
+ uni.showToast({ title: '辅助重量不能超过体重', icon: 'none', duration: 2000 })
|
|
861
|
}
|
645
|
}
|
|
862
|
- });
|
646
|
+ })
|
|
863
|
}
|
647
|
}
|
|
864
|
-
|
|
|
|
865
|
- // --------------------------
|
|
|
|
866
|
- // 2. 监听【超级组】(包含多个子动作)
|
|
|
|
867
|
- // --------------------------
|
|
|
|
868
|
if (props.type === 2) {
|
648
|
if (props.type === 2) {
|
|
869
|
- // 遍历超级组里的所有子动作
|
|
|
|
870
|
- props.actionDetail?.exercises?.forEach((sub) => {
|
|
|
|
871
|
- // 只校验 自重减重 type=5
|
649
|
+ props.actionDetail?.exercises?.forEach(sub => {
|
|
872
|
if (sub.exerciseType === 5) {
|
650
|
if (sub.exerciseType === 5) {
|
|
873
|
- const sets = superRecordMap.value[sub.id] || [];
|
|
|
|
874
|
- sets.forEach((item) => {
|
|
|
|
875
|
- const inputW = Number(item.weight) || 0;
|
|
|
|
876
|
- if (inputW > userW) {
|
|
|
|
877
|
- item.weight = "";
|
|
|
|
878
|
- uni.showToast({
|
|
|
|
879
|
- title: "辅助重量不能超过体重",
|
|
|
|
880
|
- icon: "none",
|
|
|
|
881
|
- duration: 2000,
|
|
|
|
882
|
- });
|
651
|
+ (superRecordMap.value[sub.id] || []).forEach(item => {
|
|
|
|
652
|
+ if ((Number(item.weight) || 0) > userW) {
|
|
|
|
653
|
+ item.weight = ''
|
|
|
|
654
|
+ uni.showToast({ title: '辅助重量不能超过体重', icon: 'none', duration: 2000 })
|
|
883
|
}
|
655
|
}
|
|
884
|
- });
|
656
|
+ })
|
|
885
|
}
|
657
|
}
|
|
886
|
- });
|
658
|
+ })
|
|
887
|
}
|
659
|
}
|
|
888
|
},
|
660
|
},
|
|
889
|
{ deep: true }
|
661
|
{ deep: true }
|
|
890
|
-);
|
662
|
+)
|
|
891
|
|
663
|
|
|
892
|
-defineExpose({
|
|
|
|
893
|
- recordList: exposeRecordList, // 过滤后
|
|
|
|
894
|
- superRecordMap: exposeSuperRecordMap, // 过滤后
|
|
|
|
895
|
- totalSetCount, //全部的组数
|
|
|
|
896
|
- checkedWeight, // 已勾选重量
|
|
|
|
897
|
- totalWeight // 全部重量
|
|
|
|
898
|
-})
|
664
|
+// ===================== Lifecycle =====================
|
|
|
|
665
|
+onMounted(() => {
|
|
|
|
666
|
+ const savedData = trainingStore.getUnitRecord(props.unitIndex)
|
|
|
|
667
|
+ userWeight.value = savedData.userWeight || 70
|
|
899
|
|
668
|
|
|
900
|
-// 打开备注弹窗
|
|
|
|
901
|
-// const openBeizhu = () => {
|
|
|
|
902
|
-// console.log('传递到备注组件的id', actionId.value)
|
|
|
|
903
|
-// showBeizhuRef.value.open(actionId.value)
|
|
|
|
904
|
-// }
|
669
|
+ if (props.type === 1) {
|
|
|
|
670
|
+ if (savedData.records?.[props.actionDetail.id]) {
|
|
|
|
671
|
+ recordList.value = [...savedData.records[props.actionDetail.id]]
|
|
|
|
672
|
+ }
|
|
|
|
673
|
+ } else if (props.type === 2) {
|
|
|
|
674
|
+ if (savedData.records && Object.keys(savedData.records).length > 0) {
|
|
|
|
675
|
+ superRecordMap.value = { ...savedData.records }
|
|
|
|
676
|
+ }
|
|
|
|
677
|
+ }
|
|
905
|
|
678
|
|
|
906
|
-watch(() => props.actionDetail, () => {
|
|
|
|
907
|
- console.log('actionDetail.exercises:', props.actionDetail?.exercises)
|
|
|
|
908
|
-}, { immediate: true })
|
679
|
+ // 超级组兜底初始化
|
|
|
|
680
|
+ if (props.type === 2 && props.actionDetail?.exercises?.length) {
|
|
|
|
681
|
+ const exercises = props.actionDetail.exercises
|
|
|
|
682
|
+ if (!superRecordMap.value[exercises[0].id]) {
|
|
|
|
683
|
+ const map = {}
|
|
|
|
684
|
+ exercises.forEach(item => {
|
|
|
|
685
|
+ map[item.id] = [{
|
|
|
|
686
|
+ h: '00', m: '00', s: '00', quickTimeDisplay: formatQuickTime(60),
|
|
|
|
687
|
+ distance: '', weight: '', reps: '', duration: '', restTime: '', isActive: false
|
|
|
|
688
|
+ }]
|
|
|
|
689
|
+ })
|
|
|
|
690
|
+ superRecordMap.value = map
|
|
|
|
691
|
+ }
|
|
|
|
692
|
+ }
|
|
|
|
693
|
+
|
|
|
|
694
|
+ nextTick(() => {
|
|
|
|
695
|
+ emit('register', props.index, {
|
|
|
|
696
|
+ recordList: recordList.value,
|
|
|
|
697
|
+ superRecordMap: superRecordMap.value
|
|
|
|
698
|
+ })
|
|
|
|
699
|
+ })
|
|
|
|
700
|
+})
|
|
909
|
|
701
|
|
|
|
|
702
|
+// ===================== Expose =====================
|
|
|
|
703
|
+defineExpose({
|
|
|
|
704
|
+ recordList: exposeRecordList,
|
|
|
|
705
|
+ superRecordMap: exposeSuperRecordMap,
|
|
|
|
706
|
+ totalSetCount,
|
|
|
|
707
|
+ checkedWeight,
|
|
|
|
708
|
+ totalWeight,
|
|
|
|
709
|
+ resetActiveSets
|
|
|
|
710
|
+})
|
|
910
|
</script>
|
711
|
</script>
|
|
911
|
|
712
|
|
|
912
|
<style lang="scss" scoped>
|
713
|
<style lang="scss" scoped>
|
|
|
|
714
|
+// ===================== 变量 =====================
|
|
913
|
$bg-black: #303030;
|
715
|
$bg-black: #303030;
|
|
914
|
$card-bg: #1c1c1e;
|
716
|
$card-bg: #1c1c1e;
|
|
915
|
$item-bg: #2c2c2e;
|
717
|
$item-bg: #2c2c2e;
|
|
|
|
718
|
+$input-bg: #1f1f1f;
|
|
|
|
719
|
+$popup-bg: #3e3e3e;
|
|
916
|
$text-main: #ffffff;
|
720
|
$text-main: #ffffff;
|
|
917
|
$text-gray: #8e8e93;
|
721
|
$text-gray: #8e8e93;
|
|
|
|
722
|
+$text-dim: #929292;
|
|
918
|
$theme-yellow: #f8d714;
|
723
|
$theme-yellow: #f8d714;
|
|
919
|
|
724
|
|
|
|
|
725
|
+// ===================== 公共:序号框 =====================
|
|
|
|
726
|
+@mixin index-box {
|
|
|
|
727
|
+ width: 50rpx;
|
|
|
|
728
|
+ height: 70rpx;
|
|
|
|
729
|
+ background: $input-bg;
|
|
|
|
730
|
+ border-radius: 10rpx;
|
|
|
|
731
|
+ display: flex;
|
|
|
|
732
|
+ align-items: center;
|
|
|
|
733
|
+ justify-content: center;
|
|
|
|
734
|
+ font-size: 30rpx;
|
|
|
|
735
|
+ color: $text-main;
|
|
|
|
736
|
+}
|
|
|
|
737
|
+
|
|
|
|
738
|
+// ===================== 公共:计时选择器 =====================
|
|
|
|
739
|
+@mixin timer-selector {
|
|
|
|
740
|
+ width: 75rpx;
|
|
|
|
741
|
+ height: 75rpx;
|
|
|
|
742
|
+ display: flex;
|
|
|
|
743
|
+ flex-direction: column;
|
|
|
|
744
|
+ align-items: center;
|
|
|
|
745
|
+ justify-content: center;
|
|
|
|
746
|
+ border-radius: 50%;
|
|
|
|
747
|
+ border: 1rpx solid #a4a4a4;
|
|
|
|
748
|
+
|
|
|
|
749
|
+ .text {
|
|
|
|
750
|
+ font-size: 20rpx;
|
|
|
|
751
|
+ color: $text-gray;
|
|
|
|
752
|
+ }
|
|
|
|
753
|
+}
|
|
|
|
754
|
+
|
|
|
|
755
|
+// ===================== 公共:操作图标按钮 =====================
|
|
|
|
756
|
+@mixin action-icon-base {
|
|
|
|
757
|
+ width: 70rpx;
|
|
|
|
758
|
+ height: 70rpx;
|
|
|
|
759
|
+ background-color: $input-bg;
|
|
|
|
760
|
+ border-radius: 12rpx;
|
|
|
|
761
|
+ display: flex;
|
|
|
|
762
|
+ align-items: center;
|
|
|
|
763
|
+ justify-content: center;
|
|
|
|
764
|
+
|
|
|
|
765
|
+ &.active {
|
|
|
|
766
|
+ background-color: $theme-yellow;
|
|
|
|
767
|
+ }
|
|
|
|
768
|
+}
|
|
|
|
769
|
+
|
|
|
|
770
|
+// ===================== 容器 =====================
|
|
920
|
.action-container {
|
771
|
.action-container {
|
|
921
|
width: 100%;
|
772
|
width: 100%;
|
|
922
|
- /* 确保容器足够高以接收点击事件 */
|
|
|
|
923
|
background-color: $bg-black;
|
773
|
background-color: $bg-black;
|
|
924
|
|
774
|
|
|
|
|
775
|
+
|
|
|
|
776
|
+
|
|
925
|
.action-list {
|
777
|
.action-list {
|
|
926
|
width: 100%;
|
778
|
width: 100%;
|
|
927
|
|
779
|
|
|
@@ -930,6 +782,10 @@ $theme-yellow: #f8d714; |
|
@@ -930,6 +782,10 @@ $theme-yellow: #f8d714; |
|
930
|
margin-bottom: 20rpx;
|
782
|
margin-bottom: 20rpx;
|
|
931
|
padding-bottom: 20rpx;
|
783
|
padding-bottom: 20rpx;
|
|
932
|
|
784
|
|
|
|
|
785
|
+ &.unit-active {
|
|
|
|
786
|
+ background-color: #4c4d3b;
|
|
|
|
787
|
+ }
|
|
|
|
788
|
+
|
|
933
|
.card-top {
|
789
|
.card-top {
|
|
934
|
display: flex;
|
790
|
display: flex;
|
|
935
|
align-items: center;
|
791
|
align-items: center;
|
|
@@ -992,7 +848,7 @@ $theme-yellow: #f8d714; |
|
@@ -992,7 +848,7 @@ $theme-yellow: #f8d714; |
|
992
|
.tips {
|
848
|
.tips {
|
|
993
|
position: absolute;
|
849
|
position: absolute;
|
|
994
|
color: #fff;
|
850
|
color: #fff;
|
|
995
|
- background-color: #3e3e3e;
|
851
|
+ background-color: $popup-bg;
|
|
996
|
z-index: 6;
|
852
|
z-index: 6;
|
|
997
|
right: 10rpx;
|
853
|
right: 10rpx;
|
|
998
|
top: 20rpx;
|
854
|
top: 20rpx;
|
|
@@ -1029,18 +885,6 @@ $theme-yellow: #f8d714; |
|
@@ -1029,18 +885,6 @@ $theme-yellow: #f8d714; |
|
1029
|
}
|
885
|
}
|
|
1030
|
}
|
886
|
}
|
|
1031
|
|
887
|
|
|
1032
|
- // .userWeight-values {
|
|
|
|
1033
|
- // display: flex;
|
|
|
|
1034
|
- // align-items: center;
|
|
|
|
1035
|
- // gap: 8rpx; // 控制“体重文本”和“编辑图标”的间距
|
|
|
|
1036
|
- // padding: 8rpx;
|
|
|
|
1037
|
-
|
|
|
|
1038
|
- // .weight-text {
|
|
|
|
1039
|
- // color: #fadc00;
|
|
|
|
1040
|
- // font-size: 20rpx;
|
|
|
|
1041
|
- // }
|
|
|
|
1042
|
- // }
|
|
|
|
1043
|
-
|
|
|
|
1044
|
.userWeight {
|
888
|
.userWeight {
|
|
1045
|
padding: 16rpx 32rpx;
|
889
|
padding: 16rpx 32rpx;
|
|
1046
|
gap: 16rpx;
|
890
|
gap: 16rpx;
|
|
@@ -1059,7 +903,7 @@ $theme-yellow: #f8d714; |
|
@@ -1059,7 +903,7 @@ $theme-yellow: #f8d714; |
|
1059
|
.userWeight-values {
|
903
|
.userWeight-values {
|
|
1060
|
display: flex;
|
904
|
display: flex;
|
|
1061
|
align-items: center;
|
905
|
align-items: center;
|
|
1062
|
- gap: 8rpx; // 控制“体重文本”和“编辑图标”的间距
|
906
|
+ gap: 8rpx;
|
|
1063
|
padding: 8rpx;
|
907
|
padding: 8rpx;
|
|
1064
|
|
908
|
|
|
1065
|
.weight-text {
|
909
|
.weight-text {
|
|
@@ -1071,242 +915,16 @@ $theme-yellow: #f8d714; |
|
@@ -1071,242 +915,16 @@ $theme-yellow: #f8d714; |
|
1071
|
|
915
|
|
|
1072
|
.explain {
|
916
|
.explain {
|
|
1073
|
font-size: 20rpx;
|
917
|
font-size: 20rpx;
|
|
1074
|
- color: #fff;
|
918
|
+ color: $text-main;
|
|
1075
|
}
|
919
|
}
|
|
1076
|
}
|
920
|
}
|
|
1077
|
|
921
|
|
|
1078
|
- .record-row {
|
|
|
|
1079
|
- display: flex;
|
|
|
|
1080
|
- align-items: flex-start;
|
|
|
|
1081
|
- justify-content: space-between;
|
|
|
|
1082
|
- padding: 10rpx 30rpx;
|
|
|
|
1083
|
- box-sizing: border-box;
|
|
|
|
1084
|
-
|
|
|
|
1085
|
- &.active {
|
|
|
|
1086
|
- background-color: #4c4d3b;
|
|
|
|
1087
|
- }
|
|
|
|
1088
|
-
|
|
|
|
1089
|
- .left {
|
|
|
|
1090
|
- display: flex;
|
|
|
|
1091
|
- flex-direction: column;
|
|
|
|
1092
|
- gap: 10rpx;
|
|
|
|
1093
|
-
|
|
|
|
1094
|
- .left-header {
|
|
|
|
1095
|
- display: flex;
|
|
|
|
1096
|
- align-items: center;
|
|
|
|
1097
|
- gap: 20rpx;
|
|
|
|
1098
|
-
|
|
|
|
1099
|
- .index-box {
|
|
|
|
1100
|
- width: 50rpx;
|
|
|
|
1101
|
- height: 70rpx;
|
|
|
|
1102
|
- background: #1f1f1f;
|
|
|
|
1103
|
- border-radius: 10rpx;
|
|
|
|
1104
|
- display: flex;
|
|
|
|
1105
|
- align-items: center;
|
|
|
|
1106
|
- justify-content: center;
|
|
|
|
1107
|
- font-size: 30rpx;
|
|
|
|
1108
|
- color: $text-main;
|
|
|
|
1109
|
- }
|
|
|
|
1110
|
-
|
|
|
|
1111
|
- .input-col,
|
|
|
|
1112
|
- .distance {
|
|
|
|
1113
|
- height: 70rpx;
|
|
|
|
1114
|
- background: #1f1f1f;
|
|
|
|
1115
|
- border-radius: 10rpx;
|
|
|
|
1116
|
- padding: 5rpx 10rpx;
|
|
|
|
1117
|
- display: flex;
|
|
|
|
1118
|
- flex-direction: column;
|
|
|
|
1119
|
- justify-content: center;
|
|
|
|
1120
|
-
|
|
|
|
1121
|
- .label {
|
|
|
|
1122
|
- font-size: 15rpx;
|
|
|
|
1123
|
- color: $text-gray;
|
|
|
|
1124
|
- margin-bottom: 2rpx;
|
|
|
|
1125
|
- }
|
|
|
|
1126
|
-
|
|
|
|
1127
|
- .values {
|
|
|
|
1128
|
- display: flex;
|
|
|
|
1129
|
- align-items: baseline;
|
|
|
|
1130
|
-
|
|
|
|
1131
|
- .num {
|
|
|
|
1132
|
- font-size: 32rpx;
|
|
|
|
1133
|
- color: $text-main;
|
|
|
|
1134
|
- }
|
|
|
|
1135
|
-
|
|
|
|
1136
|
- .unit {
|
|
|
|
1137
|
- font-size: 15rpx;
|
|
|
|
1138
|
- color: $text-gray;
|
|
|
|
1139
|
- margin: 0 5rpx;
|
|
|
|
1140
|
- }
|
|
|
|
1141
|
- }
|
|
|
|
1142
|
- }
|
|
|
|
1143
|
-
|
|
|
|
1144
|
- .distance {
|
|
|
|
1145
|
- min-width: 100rpx;
|
|
|
|
1146
|
-
|
|
|
|
1147
|
- :deep(.u-input) {
|
|
|
|
1148
|
- padding: 0 !important;
|
|
|
|
1149
|
- }
|
|
|
|
1150
|
-
|
|
|
|
1151
|
- .u-input__content__field {
|
|
|
|
1152
|
- font-size: 32rpx !important;
|
|
|
|
1153
|
- color: $text-main !important;
|
|
|
|
1154
|
- }
|
|
|
|
1155
|
- }
|
|
|
|
1156
|
-
|
|
|
|
1157
|
- .timer-selector {
|
|
|
|
1158
|
- width: 75rpx;
|
|
|
|
1159
|
- height: 75rpx;
|
|
|
|
1160
|
- display: flex;
|
|
|
|
1161
|
- flex-direction: column;
|
|
|
|
1162
|
- align-items: center;
|
|
|
|
1163
|
- justify-content: center;
|
|
|
|
1164
|
- border-radius: 50%;
|
|
|
|
1165
|
- border: 1rpx solid #a4a4a4;
|
|
|
|
1166
|
-
|
|
|
|
1167
|
- .text {
|
|
|
|
1168
|
- font-size: 20rpx;
|
|
|
|
1169
|
- color: $text-gray;
|
|
|
|
1170
|
- }
|
|
|
|
1171
|
- }
|
|
|
|
1172
|
- }
|
|
|
|
1173
|
-
|
|
|
|
1174
|
- .exercise-name-list {
|
|
|
|
1175
|
- display: flex;
|
|
|
|
1176
|
- flex-direction: column;
|
|
|
|
1177
|
- gap: 8rpx;
|
|
|
|
1178
|
- flex: 1;
|
|
|
|
1179
|
- }
|
|
|
|
1180
|
-
|
|
|
|
1181
|
- .exercise-name {
|
|
|
|
1182
|
- font-size: 26rpx;
|
|
|
|
1183
|
- color: $text-main;
|
|
|
|
1184
|
- line-height: 1.2;
|
|
|
|
1185
|
- }
|
|
|
|
1186
|
-
|
|
|
|
1187
|
- .goal-list {
|
|
|
|
1188
|
- width: 100%;
|
|
|
|
1189
|
- margin-top: 10rpx;
|
|
|
|
1190
|
-
|
|
|
|
1191
|
- .goal-item {
|
|
|
|
1192
|
- display: flex;
|
|
|
|
1193
|
- align-items: center;
|
|
|
|
1194
|
- gap: 20rpx;
|
|
|
|
1195
|
-
|
|
|
|
1196
|
- border-radius: 10rpx;
|
|
|
|
1197
|
-
|
|
|
|
1198
|
- .serial {
|
|
|
|
1199
|
- width: 50rpx;
|
|
|
|
1200
|
- height: 70rpx;
|
|
|
|
1201
|
- display: flex;
|
|
|
|
1202
|
- align-items: center;
|
|
|
|
1203
|
- justify-content: center;
|
|
|
|
1204
|
- font-size: 30rpx;
|
|
|
|
1205
|
- color: #929292;
|
|
|
|
1206
|
- font-weight: bold;
|
|
|
|
1207
|
- }
|
|
|
|
1208
|
-
|
|
|
|
1209
|
- .goal-input-box {
|
|
|
|
1210
|
- display: flex;
|
|
|
|
1211
|
- flex-direction: column;
|
|
|
|
1212
|
- justify-content: center;
|
|
|
|
1213
|
- background-color: #1f1f1f;
|
|
|
|
1214
|
- width: 100rpx;
|
|
|
|
1215
|
- height: 70rpx;
|
|
|
|
1216
|
- border-radius: 10rpx;
|
|
|
|
1217
|
-
|
|
|
|
1218
|
- .values {
|
|
|
|
1219
|
- display: flex;
|
|
|
|
1220
|
- align-items: flex-end;
|
|
|
|
1221
|
- padding-left: 10rpx;
|
|
|
|
1222
|
- box-sizing: border-box;
|
|
|
|
1223
|
-
|
|
|
|
1224
|
- :deep(.uni-input-input[type='number']) {
|
|
|
|
1225
|
- text-align: center;
|
|
|
|
1226
|
- }
|
|
|
|
1227
|
-
|
|
|
|
1228
|
- .num {
|
|
|
|
1229
|
- font-size: 32rpx;
|
|
|
|
1230
|
- color: $text-main;
|
|
|
|
1231
|
- }
|
|
|
|
1232
|
-
|
|
|
|
1233
|
- .unit {
|
|
|
|
1234
|
- font-size: 15rpx;
|
|
|
|
1235
|
- color: $text-gray;
|
|
|
|
1236
|
- margin: 0 5rpx;
|
|
|
|
1237
|
- }
|
|
|
|
1238
|
-
|
|
|
|
1239
|
- // 确保 up-input 内部文字样式一致
|
|
|
|
1240
|
- }
|
|
|
|
1241
|
- }
|
|
|
|
1242
|
-
|
|
|
|
1243
|
- }
|
|
|
|
1244
|
-
|
|
|
|
1245
|
- // 新增的间歇运动样式
|
|
|
|
1246
|
- .interval {
|
|
|
|
1247
|
- display: flex;
|
|
|
|
1248
|
- gap: 20rpx;
|
|
|
|
1249
|
- margin-top: 10rpx;
|
|
|
|
1250
|
-
|
|
|
|
1251
|
- .goal-input-box {
|
|
|
|
1252
|
- flex: none;
|
|
|
|
1253
|
- width: 120rpx;
|
|
|
|
1254
|
-
|
|
|
|
1255
|
- .label {
|
|
|
|
1256
|
- font-size: 15rpx;
|
|
|
|
1257
|
- color: $text-gray;
|
|
|
|
1258
|
- margin-bottom: 2rpx;
|
|
|
|
1259
|
- }
|
|
|
|
1260
|
- }
|
|
|
|
1261
|
- }
|
|
|
|
1262
|
- }
|
|
|
|
1263
|
- }
|
|
|
|
1264
|
-
|
|
|
|
1265
|
- .icons {
|
|
|
|
1266
|
- display: flex;
|
|
|
|
1267
|
- gap: 20rpx;
|
|
|
|
1268
|
-
|
|
|
|
1269
|
- .icon {
|
|
|
|
1270
|
- width: 70rpx;
|
|
|
|
1271
|
- height: 70rpx;
|
|
|
|
1272
|
- background-color: #1f1f1f;
|
|
|
|
1273
|
- border-radius: 12rpx;
|
|
|
|
1274
|
- display: flex;
|
|
|
|
1275
|
- align-items: center;
|
|
|
|
1276
|
- justify-content: center;
|
|
|
|
1277
|
-
|
|
|
|
1278
|
- &.active {
|
|
|
|
1279
|
- background-color: $theme-yellow;
|
|
|
|
1280
|
- }
|
|
|
|
1281
|
- }
|
|
|
|
1282
|
-
|
|
|
|
1283
|
- .del {
|
|
|
|
1284
|
- background-color: #58372d;
|
|
|
|
1285
|
- }
|
|
|
|
1286
|
- }
|
922
|
+ .super-group {
|
|
|
|
923
|
+ width: 100%;
|
|
1287
|
}
|
924
|
}
|
|
1288
|
}
|
925
|
}
|
|
1289
|
|
926
|
|
|
1290
|
- // 新增超级组样式
|
|
|
|
1291
|
- .super-group {
|
|
|
|
1292
|
- width: 100%;
|
|
|
|
1293
|
- }
|
|
|
|
1294
|
-
|
|
|
|
1295
|
- .super-record-row {
|
|
|
|
1296
|
- align-items: center;
|
|
|
|
1297
|
- background-color: red;
|
|
|
|
1298
|
- min-height: 100rpx;
|
|
|
|
1299
|
- }
|
|
|
|
1300
|
-
|
|
|
|
1301
|
- .super-left {
|
|
|
|
1302
|
- flex-direction: row !important;
|
|
|
|
1303
|
- align-items: center;
|
|
|
|
1304
|
- gap: 20rpx;
|
|
|
|
1305
|
- }
|
|
|
|
1306
|
-
|
|
|
|
1307
|
-
|
|
|
|
1308
|
-
|
|
|
|
1309
|
-
|
927
|
+ // 超级组:每组标题行
|
|
1310
|
.set-group {
|
928
|
.set-group {
|
|
1311
|
margin-bottom: 30rpx;
|
929
|
margin-bottom: 30rpx;
|
|
1312
|
}
|
930
|
}
|
|
@@ -1317,35 +935,8 @@ $theme-yellow: #f8d714; |
|
@@ -1317,35 +935,8 @@ $theme-yellow: #f8d714; |
|
1317
|
padding: 10rpx 30rpx;
|
935
|
padding: 10rpx 30rpx;
|
|
1318
|
gap: 20rpx;
|
936
|
gap: 20rpx;
|
|
1319
|
|
937
|
|
|
1320
|
- .icons {
|
|
|
|
1321
|
- display: flex;
|
|
|
|
1322
|
- gap: 20rpx;
|
|
|
|
1323
|
-
|
|
|
|
1324
|
- .icon {
|
|
|
|
1325
|
- width: 70rpx;
|
|
|
|
1326
|
- height: 70rpx;
|
|
|
|
1327
|
- background-color: #1f1f1f;
|
|
|
|
1328
|
- border-radius: 12rpx;
|
|
|
|
1329
|
- display: flex;
|
|
|
|
1330
|
- align-items: center;
|
|
|
|
1331
|
- justify-content: center;
|
|
|
|
1332
|
- }
|
|
|
|
1333
|
-
|
|
|
|
1334
|
- .del {
|
|
|
|
1335
|
- background-color: #58372d;
|
|
|
|
1336
|
- }
|
|
|
|
1337
|
- }
|
|
|
|
1338
|
-
|
|
|
|
1339
|
.index-box {
|
938
|
.index-box {
|
|
1340
|
- width: 50rpx;
|
|
|
|
1341
|
- height: 70rpx;
|
|
|
|
1342
|
- background: #1f1f1f;
|
|
|
|
1343
|
- border-radius: 10rpx;
|
|
|
|
1344
|
- display: flex;
|
|
|
|
1345
|
- align-items: center;
|
|
|
|
1346
|
- justify-content: center;
|
|
|
|
1347
|
- font-size: 30rpx;
|
|
|
|
1348
|
- color: #fff;
|
939
|
+ @include index-box;
|
|
1349
|
}
|
940
|
}
|
|
1350
|
|
941
|
|
|
1351
|
.set-action-names {
|
942
|
.set-action-names {
|
|
@@ -1356,73 +947,44 @@ $theme-yellow: #f8d714; |
|
@@ -1356,73 +947,44 @@ $theme-yellow: #f8d714; |
|
1356
|
|
947
|
|
|
1357
|
text {
|
948
|
text {
|
|
1358
|
font-size: 26rpx;
|
949
|
font-size: 26rpx;
|
|
1359
|
- color: #fff;
|
950
|
+ color: $text-main;
|
|
1360
|
}
|
951
|
}
|
|
1361
|
}
|
952
|
}
|
|
1362
|
|
953
|
|
|
1363
|
.timer-selector {
|
954
|
.timer-selector {
|
|
1364
|
- width: 75rpx;
|
|
|
|
1365
|
- height: 75rpx;
|
|
|
|
1366
|
- display: flex;
|
|
|
|
1367
|
- flex-direction: column;
|
|
|
|
1368
|
- align-items: center;
|
|
|
|
1369
|
- justify-content: center;
|
|
|
|
1370
|
- border-radius: 50%;
|
|
|
|
1371
|
- border: 1rpx solid #a4a4a4;
|
955
|
+ @include timer-selector;
|
|
|
|
956
|
+ }
|
|
1372
|
|
957
|
|
|
1373
|
- .text {
|
|
|
|
1374
|
- font-size: 20rpx;
|
|
|
|
1375
|
- color: #8e8e93;
|
|
|
|
1376
|
- }
|
958
|
+ .check-icon {
|
|
|
|
959
|
+ @include action-icon-base;
|
|
1377
|
}
|
960
|
}
|
|
1378
|
|
961
|
|
|
1379
|
- .icon {
|
|
|
|
1380
|
- width: 70rpx;
|
|
|
|
1381
|
- height: 70rpx;
|
|
|
|
1382
|
- background-color: #1f1f1f;
|
|
|
|
1383
|
- border-radius: 12rpx;
|
962
|
+ .action-icons {
|
|
1384
|
display: flex;
|
963
|
display: flex;
|
|
1385
|
- align-items: center;
|
|
|
|
1386
|
- justify-content: center;
|
964
|
+ gap: 20rpx;
|
|
|
|
965
|
+
|
|
|
|
966
|
+ .action-icon {
|
|
|
|
967
|
+ @include action-icon-base;
|
|
1387
|
|
968
|
|
|
1388
|
- &.active {
|
|
|
|
1389
|
- background-color: $theme-yellow;
|
969
|
+ &.icon-del {
|
|
|
|
970
|
+ background-color: #58372d;
|
|
|
|
971
|
+ }
|
|
1390
|
}
|
972
|
}
|
|
1391
|
}
|
973
|
}
|
|
1392
|
}
|
974
|
}
|
|
1393
|
|
975
|
|
|
1394
|
- .serial {
|
|
|
|
1395
|
- width: 50rpx;
|
|
|
|
1396
|
- height: 70rpx;
|
|
|
|
1397
|
- display: flex;
|
|
|
|
1398
|
- align-items: center;
|
|
|
|
1399
|
- justify-content: center;
|
|
|
|
1400
|
- font-size: 30rpx;
|
|
|
|
1401
|
- color: #929292;
|
|
|
|
1402
|
- font-weight: bold;
|
|
|
|
1403
|
- }
|
|
|
|
1404
|
-
|
|
|
|
1405
|
- .super-action-item {
|
|
|
|
1406
|
- margin-bottom: 30rpx;
|
|
|
|
1407
|
- }
|
|
|
|
1408
|
-
|
|
|
|
1409
|
- .super-action-title {
|
|
|
|
1410
|
- font-size: 28rpx;
|
|
|
|
1411
|
- color: #fff;
|
|
|
|
1412
|
- padding: 10rpx 30rpx;
|
|
|
|
1413
|
- font-weight: bold;
|
|
|
|
1414
|
- }
|
|
|
|
1415
|
-
|
976
|
+ // 按钮组
|
|
1416
|
.button-group {
|
977
|
.button-group {
|
|
1417
|
display: flex;
|
978
|
display: flex;
|
|
1418
|
justify-content: space-between;
|
979
|
justify-content: space-between;
|
|
1419
|
padding: 30rpx;
|
980
|
padding: 30rpx;
|
|
1420
|
box-sizing: border-box;
|
981
|
box-sizing: border-box;
|
|
|
|
982
|
+ gap: 10rpx;
|
|
1421
|
|
983
|
|
|
1422
|
.btn-item {
|
984
|
.btn-item {
|
|
1423
|
- background-color: #1f1f1f;
|
985
|
+ background-color: $input-bg;
|
|
1424
|
font-size: 26rpx;
|
986
|
font-size: 26rpx;
|
|
1425
|
- color: #fff;
|
987
|
+ color: $text-main;
|
|
1426
|
padding: 15rpx 35rpx;
|
988
|
padding: 15rpx 35rpx;
|
|
1427
|
border-radius: 50rpx;
|
989
|
border-radius: 50rpx;
|
|
1428
|
display: flex;
|
990
|
display: flex;
|
|
@@ -1435,7 +997,7 @@ $theme-yellow: #f8d714; |
|
@@ -1435,7 +997,7 @@ $theme-yellow: #f8d714; |
|
1435
|
bottom: 80rpx;
|
997
|
bottom: 80rpx;
|
|
1436
|
left: 50%;
|
998
|
left: 50%;
|
|
1437
|
transform: translateX(-50%);
|
999
|
transform: translateX(-50%);
|
|
1438
|
- background-color: #3e3e3e;
|
1000
|
+ background-color: $popup-bg;
|
|
1439
|
border-radius: 16rpx;
|
1001
|
border-radius: 16rpx;
|
|
1440
|
overflow: hidden;
|
1002
|
overflow: hidden;
|
|
1441
|
z-index: 99;
|
1003
|
z-index: 99;
|
|
@@ -1465,6 +1027,5 @@ $theme-yellow: #f8d714; |
|
@@ -1465,6 +1027,5 @@ $theme-yellow: #f8d714; |
|
1465
|
}
|
1027
|
}
|
|
1466
|
}
|
1028
|
}
|
|
1467
|
}
|
1029
|
}
|
|
1468
|
-
|
|
|
|
1469
|
}
|
1030
|
}
|
|
1470
|
</style> |
1031
|
</style> |