|
@@ -1,23 +1,25 @@
|
|
|
import { CommonModule } from '@angular/common';
|
|
|
import { Component } from '@angular/core';
|
|
|
import { IonTextarea } from '@ionic/angular/standalone';
|
|
|
-import {
|
|
|
+import {
|
|
|
ModalController,
|
|
|
IonHeader,IonNote,IonChip, IonToolbar, IonTitle, IonButtons, IonButton, IonIcon,
|
|
|
IonContent, IonCard, IonCardHeader, IonCardTitle, IonCardSubtitle,
|
|
|
IonCardContent, IonProgressBar, IonGrid, IonRow, IonCol, IonListHeader,
|
|
|
- IonLabel, IonList, IonItem, IonAvatar, IonBadge, IonFab, IonFabButton
|
|
|
+ IonLabel, IonList, IonItem, IonAvatar, IonBadge, IonFab, IonFabButton,IonSkeletonText
|
|
|
} from '@ionic/angular/standalone';
|
|
|
import { addIcons } from 'ionicons';
|
|
|
-import {
|
|
|
+import {
|
|
|
notificationsOutline, calendarNumber, checkmarkCircle, ellipseOutline,
|
|
|
timeOutline, barbell, body, walk, add, refresh, fitness,
|
|
|
- flame, bicycle, trophy
|
|
|
+ flame, bicycle, trophy,
|
|
|
+ ellipsisHorizontal
|
|
|
} from 'ionicons/icons';
|
|
|
|
|
|
// 引用fmode-ng智能体组件
|
|
|
-import { ChatPanelOptions, FmChatModalInput, FmodeChat, FmodeChatMessage, openChatPanelModal } from 'fmode-ng';
|
|
|
+import { ChatPanelOptions, FmodeChat, FmodeChatMessage, openChatPanelModal } from 'fmode-ng';
|
|
|
import Parse from "parse";
|
|
|
+import { CloudObject, CloudQuery, CloudUser } from 'src/lib/ncloud';
|
|
|
|
|
|
@Component({
|
|
|
selector: 'app-tab2',
|
|
@@ -31,7 +33,7 @@ import Parse from "parse";
|
|
|
IonHeader, IonToolbar, IonTitle, IonButtons, IonButton, IonIcon,
|
|
|
IonContent, IonCard, IonCardHeader, IonCardTitle, IonCardSubtitle,
|
|
|
IonCardContent, IonProgressBar, IonGrid, IonRow, IonCol, IonListHeader,
|
|
|
- IonLabel, IonList, IonItem, IonAvatar, IonBadge, IonFab, IonFabButton
|
|
|
+ IonLabel, IonList, IonItem, IonAvatar, IonBadge, IonFab, IonFabButton,IonSkeletonText
|
|
|
]
|
|
|
})
|
|
|
export class Tab2Page {
|
|
@@ -83,46 +85,46 @@ export class Tab2Page {
|
|
|
{
|
|
|
cate:"有氧",img:"/assets/icon/yy.jpg",
|
|
|
messageList:[
|
|
|
- "有氧运动多久才能有效减脂?",
|
|
|
- "跑步和游泳哪个减肥效果更好?",
|
|
|
- "空腹有氧真的更燃脂吗?",
|
|
|
- "有氧运动会不会掉肌肉?",
|
|
|
- "心率控制在多少才能高效燃脂?",
|
|
|
- "每天做有氧运动会不会过度疲劳?",
|
|
|
- "有氧运动前要不要吃东西?",
|
|
|
- "椭圆机和跑步机哪个更适合新手?",
|
|
|
- "跳绳会不会伤膝盖?",
|
|
|
- "有氧运动后怎么补充能量?"
|
|
|
+ "有氧运动多久才能有效减脂?",
|
|
|
+ "跑步和游泳哪个减肥效果更好?",
|
|
|
+ "空腹有氧真的更燃脂吗?",
|
|
|
+ "有氧运动会不会掉肌肉?",
|
|
|
+ "心率控制在多少才能高效燃脂?",
|
|
|
+ "每天做有氧运动会不会过度疲劳?",
|
|
|
+ "有氧运动前要不要吃东西?",
|
|
|
+ "椭圆机和跑步机哪个更适合新手?",
|
|
|
+ "跳绳会不会伤膝盖?",
|
|
|
+ "有氧运动后怎么补充能量?"
|
|
|
]
|
|
|
},
|
|
|
{
|
|
|
cate:"减脂",img:"/assets/icon/jz.jpg",
|
|
|
messageList:[
|
|
|
- "减脂一定要做有氧吗?",
|
|
|
- "为什么体重没变但看起来瘦了?",
|
|
|
- "局部减脂(如瘦肚子)真的存在吗?",
|
|
|
- "减脂期每天应该吃多少热量?",
|
|
|
- "低碳饮食和低脂饮食哪个更适合减脂?",
|
|
|
- "为什么运动后体重反而增加了?",
|
|
|
- "减脂期可以吃零食吗?",
|
|
|
- "平台期怎么突破?",
|
|
|
- "晚上吃东西会不会更容易长胖?",
|
|
|
- "减脂期要不要计算蛋白质摄入?"
|
|
|
+ "减脂一定要做有氧吗?",
|
|
|
+ "为什么体重没变但看起来瘦了?",
|
|
|
+ "局部减脂(如瘦肚子)真的存在吗?",
|
|
|
+ "减脂期每天应该吃多少热量?",
|
|
|
+ "低碳饮食和低脂饮食哪个更适合减脂?",
|
|
|
+ "为什么运动后体重反而增加了?",
|
|
|
+ "减脂期可以吃零食吗?",
|
|
|
+ "平台期怎么突破?",
|
|
|
+ "晚上吃东西会不会更容易长胖?",
|
|
|
+ "减脂期要不要计算蛋白质摄入?"
|
|
|
]
|
|
|
},
|
|
|
{
|
|
|
cate:"增肌",img:"/assets/icon/zj.jpg",
|
|
|
messageList: [
|
|
|
- "增肌一定要喝蛋白粉吗?",
|
|
|
- "为什么练了很久肌肉不长?",
|
|
|
- "增肌期可以同时减脂吗?",
|
|
|
- "训练后多久补充蛋白质最有效?",
|
|
|
- "增肌需要每天练同一个部位吗?",
|
|
|
- "徒手训练(如俯卧撑)能有效增肌吗?",
|
|
|
- "增肌期体重不增长是怎么回事?",
|
|
|
- "肌肉酸痛还能继续练吗?",
|
|
|
- "增肌训练每组做多少次最合适?",
|
|
|
- "睡眠对增肌的影响有多大?"
|
|
|
+ "增肌一定要喝蛋白粉吗?",
|
|
|
+ "为什么练了很久肌肉不长?",
|
|
|
+ "增肌期可以同时减脂吗?",
|
|
|
+ "训练后多久补充蛋白质最有效?",
|
|
|
+ "增肌需要每天练同一个部位吗?",
|
|
|
+ "徒手训练(如俯卧撑)能有效增肌吗?",
|
|
|
+ "增肌期体重不增长是怎么回事?",
|
|
|
+ "肌肉酸痛还能继续练吗?",
|
|
|
+ "增肌训练每组做多少次最合适?",
|
|
|
+ "睡眠对增肌的影响有多大?"
|
|
|
]
|
|
|
},
|
|
|
]
|
|
@@ -183,23 +185,13 @@ export class Tab2Page {
|
|
|
constructor(
|
|
|
private modalCtrl:ModalController,
|
|
|
) {
|
|
|
- addIcons({
|
|
|
+ addIcons({
|
|
|
notificationsOutline, calendarNumber, checkmarkCircle, ellipseOutline,
|
|
|
timeOutline, barbell, body, walk, add, refresh, fitness,
|
|
|
- flame, bicycle, trophy
|
|
|
+ flame, bicycle, trophy, ellipsisHorizontal
|
|
|
});
|
|
|
}
|
|
|
|
|
|
- // 周训练数据
|
|
|
- weekDays = [
|
|
|
- { shortName: '周一', name: 'Monday', trained: true, active: false },
|
|
|
- { shortName: '周二', name: 'Tuesday', trained: false, active: true },
|
|
|
- { shortName: '周三', name: 'Wednesday', trained: true, active: false },
|
|
|
- { shortName: '周四', name: 'Thursday', trained: false, active: false },
|
|
|
- { shortName: '周五', name: 'Friday', trained: false, active: false },
|
|
|
- { shortName: '周六', name: 'Saturday', trained: false, active: false },
|
|
|
- { shortName: '周日', name: 'Sunday', trained: false, active: false }
|
|
|
- ];
|
|
|
|
|
|
// 计算属性
|
|
|
get completedWorkouts(): number {
|
|
@@ -239,41 +231,109 @@ export class Tab2Page {
|
|
|
}
|
|
|
];
|
|
|
|
|
|
- // 我的计划
|
|
|
- myPlans = [
|
|
|
- {
|
|
|
- name: '30天减脂挑战',
|
|
|
- progress: 65,
|
|
|
- nextTime: '明天 7:00',
|
|
|
- remaining: 12,
|
|
|
- icon: 'flame'
|
|
|
- },
|
|
|
- {
|
|
|
- name: '上肢力量训练',
|
|
|
- progress: 30,
|
|
|
- nextTime: '后天 19:30',
|
|
|
- remaining: 5,
|
|
|
- icon: 'barbell'
|
|
|
- },
|
|
|
- {
|
|
|
- name: '晨跑计划',
|
|
|
- progress: 80,
|
|
|
- nextTime: '今天 6:00',
|
|
|
- remaining: 3,
|
|
|
- icon: 'walk'
|
|
|
- }
|
|
|
+
|
|
|
+
|
|
|
+ // 动态加载数据
|
|
|
+ async ngOnInit() {
|
|
|
+ await this.loadUserData();
|
|
|
+ }
|
|
|
+ isLoading = true;
|
|
|
+ currentUser: CloudUser | null = null;
|
|
|
+ myPlans: any[] = [];
|
|
|
+ planTasks: any[] = [];
|
|
|
+
|
|
|
+ // 周训练数据
|
|
|
+ weekDays = [
|
|
|
+ { shortName: '周一', name: 'Monday', trained: true, active: false },
|
|
|
+ { shortName: '周二', name: 'Tuesday', trained: false, active: true },
|
|
|
+ { shortName: '周三', name: 'Wednesday', trained: true, active: false },
|
|
|
+ { shortName: '周四', name: 'Thursday', trained: false, active: false },
|
|
|
+ { shortName: '周五', name: 'Friday', trained: false, active: false },
|
|
|
+ { shortName: '周六', name: 'Saturday', trained: false, active: false },
|
|
|
+ { shortName: '周日', name: 'Sunday', trained: false, active: false }
|
|
|
];
|
|
|
+ async loadUserData() {
|
|
|
+ this.isLoading = true;
|
|
|
+
|
|
|
+ try {
|
|
|
+ // 获取当前用户
|
|
|
+ this.currentUser = new CloudUser();
|
|
|
+
|
|
|
+ if (this.currentUser.id) {
|
|
|
+ // 加载用户的训练计划
|
|
|
+ await this.loadTrainingPlans();
|
|
|
+ }
|
|
|
+ } catch (error) {
|
|
|
+ console.error('加载用户数据失败:', error);
|
|
|
+ } finally {
|
|
|
+ this.isLoading = false;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ async loadTrainingPlans() {
|
|
|
+ if (!this.currentUser?.id) return;
|
|
|
+
|
|
|
+ const query = new CloudQuery('TrainingPlan');
|
|
|
+ query.equalTo('user', this.currentUser.toPointer());
|
|
|
+
|
|
|
+ const plans = await query.find();
|
|
|
+ console.log("this.loadTrainingPlans()",plans)
|
|
|
+ this.myPlans = plans.map(plan => ({
|
|
|
+ id: plan.id,
|
|
|
+ name: plan.get('planName') || '未命名计划',
|
|
|
+ progress: 0, // 这里可以根据实际完成情况计算
|
|
|
+ nextTime: this.getNextTrainingTime(plan),
|
|
|
+ remaining: this.getRemainingDays(plan),
|
|
|
+ icon: this.getPlanIcon(plan.get('fitnessGoals')),
|
|
|
+ description: plan.get('description'),
|
|
|
+ durationInWeeks: plan.get('durationInWeeks'),
|
|
|
+ difficultyLevel: plan.get('difficultyLevel')
|
|
|
+ }));
|
|
|
|
|
|
+ // 加载每个计划的任务
|
|
|
+ for (const plan of plans) {
|
|
|
+ if(typeof plan.id == "string"){
|
|
|
+ await this.loadPlanTasks(plan.id);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ async loadPlanTasks(planId: string) {
|
|
|
+ const query = new CloudQuery('TrainingTask');
|
|
|
+ query.equalTo('plan', planId);
|
|
|
+
|
|
|
+ const tasks = await query.find();
|
|
|
+ console.log("tasks",tasks)
|
|
|
+ this.planTasks = tasks
|
|
|
+ }
|
|
|
+
|
|
|
+ getNextTrainingTime(plan: CloudObject): string {
|
|
|
+ // 简单实现 - 实际应根据计划schedule计算
|
|
|
+ return '明天 7:00';
|
|
|
+ }
|
|
|
+
|
|
|
+ getRemainingDays(plan: CloudObject): number {
|
|
|
+ // 简单实现 - 实际应根据计划duration和开始日期计算
|
|
|
+ return Math.floor(Math.random() * 30) + 1;
|
|
|
+ }
|
|
|
+
|
|
|
+ getPlanIcon(goals: string[] = []): string {
|
|
|
+ if (goals.includes('减脂')) return 'flame';
|
|
|
+ if (goals.includes('增肌')) return 'barbell';
|
|
|
+ if (goals.includes('跑步')) return 'walk';
|
|
|
+ return 'fitness';
|
|
|
+ }
|
|
|
|
|
|
- refreshPlans() {
|
|
|
- console.log('刷新计划数据');
|
|
|
+ async refreshPlans() {
|
|
|
+ await this.loadUserData();
|
|
|
}
|
|
|
|
|
|
openPlan(plan: any) {
|
|
|
- console.log('打开计划:', plan.name);
|
|
|
+ console.log('打开计划:', plan);
|
|
|
+ // 这里可以导航到计划详情页,传入plan和this.planTasks[plan.id]
|
|
|
}
|
|
|
|
|
|
createNewPlan() {
|
|
|
console.log('创建新计划');
|
|
|
}
|
|
|
-}
|
|
|
+}
|