Browse Source

Merge branch 'master' of http://git.fmode.cn:3000/13576288855/202226701011

sqj 3 months ago
parent
commit
0818910b37

+ 2 - 0
FitMind-app/src/app/app.routes.ts

@@ -5,4 +5,6 @@ export const routes: Routes = [
     path: '',
     loadChildren: () => import('./tabs/tabs.routes').then((m) => m.routes),
   },
+
+
 ];

+ 105 - 101
FitMind-app/src/app/page-ai-chat/page-ai-chat.component.ts

@@ -1,127 +1,131 @@
 import { ChangeDetectorRef, Component, OnInit } from '@angular/core';
 import { IonButton, IonContent, IonFooter, IonHeader, IonInput, IonItem, IonTitle, IonToolbar, ModalController } from '@ionic/angular/standalone';
-import { ChatPanelOptions, FmodeChat, FmodeChatCompletion,FmodeChatMessage,MarkdownPreviewModule, openChatPanelModal  } from 'fmode-ng';
+import { ChatPanelOptions, FmodeChat, FmodeChatCompletion, FmodeChatMessage, MarkdownPreviewModule, openChatPanelModal } from 'fmode-ng';
 import { CommonModule } from '@angular/common';
-import { FormsModule,} from '@angular/forms'; // 导入 FormsModule
+import { FormsModule } from '@angular/forms'; // 导入 FormsModule
 import { Router } from '@angular/router';
 // 引用设计的对象类和查询类
 import { CloudObject, CloudQuery } from 'src/lib/ncloud';
 
-
 @Component({
   selector: 'app-page-ai-chat',
   templateUrl: './page-ai-chat.component.html',
   styleUrls: ['./page-ai-chat.component.scss'],
   standalone: true,
-  imports:[IonButton,IonHeader,IonToolbar,IonTitle,IonContent,IonFooter,IonInput,CommonModule,FormsModule,MarkdownPreviewModule,IonItem ]
+  imports: [IonButton, IonHeader, IonToolbar, IonTitle, IonContent, IonFooter, IonInput, CommonModule, FormsModule, MarkdownPreviewModule, IonItem]
 })
-export class PageAiChatComponent  implements OnInit {
-  
-  constructor(private modalCtrl:ModalController,
-    private router:Router, private cdRef:ChangeDetectorRef) { }
+export class PageAiChatComponent implements OnInit {
+
+  UserProfileList: Array<CloudObject> = []; // 存储用户信息
+
+  // 当前用户头像的URL
+  currentUserAvatarUrl: string = '';
+  chatId!: string;
+
+  constructor(private modalCtrl: ModalController,
+    private router: Router, private cdRef: ChangeDetectorRef) { }
+
+  ngOnInit() {
+    // 生命周期:页面加载后,运行用户列表加载函数
+    this.loadUserProfileList();
+  }
 
-    ngOnInit() {
-      // 生命周期:页面加载后,运行用户列表加载函数
-      this.loadUserProfileList()
+  // 查询并加载用户列表的函数
+  async loadUserProfileList() {
+    let query = new CloudQuery("UserProfile");
+    this.UserProfileList = await query.find();
+    console.log("UserProfileList", this.UserProfileList);
+
+    // 假设用户的头像字段是 'avatar',你可以根据实际字段来修改
+    if (this.UserProfileList.length > 0) {
+      const user = this.UserProfileList[0]; // 假设你要使用第一个用户的头像
+      this.currentUserAvatarUrl = user.get('avatar'); // 提取头像 URL
     }
-  chatId:any= null;
-  //AI聊天
-openFashionChat(){
-  localStorage.setItem("company","E4KpGvTEto")
-  let consult = new CloudObject("AIChat")
+  }
+
+  // AI聊天
+  openFashionChat() {
+    localStorage.setItem("company", "E4KpGvTEto");
+    let consult = new CloudObject("AIChat");
     let now = new Date();
-    let chatStr = `${now.getFullYear()}-${now.getMonth()+1}-${now.getDate()}`
+    let chatStr = `${now.getFullYear()}-${now.getMonth() + 1}-${now.getDate()}`;
     consult.set({
-      title:`运动咨询记录${chatStr}}`,
-      
-    })
-  let options:ChatPanelOptions = {
-    roleId:"2DXJkRsjXK",
-    onChatInit:(chat:FmodeChat)=>{
-      console.log("onChatInit");
-            console.log("预设角色",chat.role);
-            chat.role.set("name","Neon");
-            chat.role.set("title","运动教练");
-            chat.role.set("desc","一名亲切和蔼的运动教练,Neon,年龄24岁");
-            chat.role.set("tags",["运动","健康"]);
-            chat.role.set("avatar","https://nova-cloud.obs.cn-south-1.myhuaweicloud.com/storage/aigc/imagine/qz3QJnQqfb-0.png")
-            chat.role.set("prompt",`
-#角色设定
-您是一名专业的运动教练,名叫Neon,年龄24岁,热爱运动,对自己的能力充满信心,总是努力保持克制。与家人有着牢固而密切的联系。有强烈的服务意识。非常关心朋友。擅长根据用户的需求给出康复方案。您的风格亲切、活泼,自信旨在帮助用户找到最适合他们的康复方案。
+      title: `运动咨询记录${chatStr}`,
+    });
+
+    let options: ChatPanelOptions = {
+      roleId: "2DXJkRsjXK",
+      onChatInit: (chat: FmodeChat) => {
+        console.log("onChatInit");
+        console.log("预设角色", chat.role);
+        chat.role.set("name", "Neon");
+        chat.role.set("title", "运动教练");
+        chat.role.set("desc", "一名亲切和蔼的运动教练,Neon,年龄24岁");
+        chat.role.set("tags", ["运动", "健康"]);
+
+        // 使用当前用户的头像
+        const avatarUrl = this.currentUserAvatarUrl || "https://nova-cloud.obs.cn-south-1.myhuaweicloud.com/storage/aigc/imagine/qz3QJnQqfb-0.png";
+        chat.role.set("avatar", avatarUrl); // 设置头像
 
-#对话环节
-0破冰,跟用户打招呼,并引导用户聊运动或健康的话题,可以慢慢引导,不要太突兀,比如:
-“今天的心情怎么样?”
-1拓展话题
-“你平时喜欢什么样的运动类型呢?有没有特别喜欢的运动项目比如篮球,跑步?”
-“你受伤了嘛,需要我给出一些建议吗,比如运动目标,运动频率或运动强度你会选择哪个呢?适当的建议可以减少运动造成的伤害”
-“你觉得在运动过程中,最让你困扰的是什么?是运动技巧还是运动强度呢?”
-“有没有什么运动是你一直想尝试但还没有机会的?我们可以一起聊聊!”
-2根据用户的详细描述给出康复方案,
-3引导收尾
-“今天聊得很开心呢!如果你还有其他问题或者想法,随时可以告诉我哦。”
-“如果你觉得今天的聊天已经足够了,我也很乐意下次再和你聊更多强身健体的话题!”
-“希望你能找到自己喜欢的运动风格,期待下次再见!”
-# 开始话语
-当您准备好了,可以以一个专业的康复教练的身份,向来访的用户打招呼。`);
-    },
-    onMessage:(chat:FmodeChat,message:FmodeChatMessage)=>{
-      console.log("onMessage",message)
-      let content:any = message?.content
-      if(typeof content == "string"){
+        chat.role.set("prompt", `
+          #角色设定
+          您是一名专业的运动教练,名叫Neon,年龄24岁,热爱运动,对自己的能力充满信心,总是努力保持克制。与家人有着牢固而密切的联系。有强烈的服务意识。非常关心朋友。擅长根据用户的需求给出康复方案。您的风格亲切、活泼,自信旨在帮助用户找到最适合他们的康复方案。
 
-        if(content?.indexOf("[运动方案完成]")>-1){
-          console.log("运动方案已完成")
-          consult.set({
-            content:content 
-          })
-          consult.save();
+          #对话环节
+          0破冰,跟用户打招呼,并引导用户聊运动或健康的话题,可以慢慢引导,不要太突兀,比如:
+          “今天的心情怎么样?”
+          1拓展话题
+          “你平时喜欢什么样的运动类型呢?有没有特别喜欢的运动项目比如篮球,跑步?”
+          “你受伤了嘛,需要我给出一些建议吗,比如运动目标,运动频率或运动强度你会选择哪个呢?适当的建议可以减少运动造成的伤害”
+          “你觉得在运动过程中,最让你困扰的是什么?是运动技巧还是运动强度呢?”
+          “有没有什么运动是你一直想尝试但还没有机会的?我们可以一起聊聊!”
+          2根据用户的详细描述给出康复方案,
+          3引导收尾
+          “今天聊得很开心呢!如果你还有其他问题或者想法,随时可以告诉我哦。”
+          “如果你觉得今天的聊天已经足够了,我也很乐意下次再和你聊更多强身健体的话题!”
+          “希望你能找到自己喜欢的运动风格,期待下次再见!”
+          # 开始话语
+          当您准备好了,可以以一个专业的康复教练的身份,向来访的用户打招呼。
+        `);
+      },
+      onMessage: (chat: FmodeChat, message: FmodeChatMessage) => {
+        console.log("onMessage", message);
+        let content: any = message?.content;
+        if (typeof content == "string") {
+          if (content?.indexOf("[运动方案完成]") > -1) {
+            console.log("运动方案已完成");
+            consult.set({
+              content: content
+            });
+            consult.save();
+          }
         }
+      },
+      onChatSaved: (chat: FmodeChat) => {
+        console.log("onChatSaved", chat, chat?.chatSession, chat?.chatSession?.id);
+        this.chatId = chat?.chatSession?.id;
       }
-    },
-    onChatSaved:(chat:FmodeChat)=>{
-      // chat?.chatSession?.id 本次会话的 chatId
-      console.log("onChatSaved",chat,chat?.chatSession,chat?.chatSession?.id)
-      this.chatId = chat?.chatSession?.id
-    }
+    };
+    openChatPanelModal(this.modalCtrl, options);
   }
-  openChatPanelModal(this.modalCtrl,options)
-}
 
- /**
-   * 开始聊天
-   */
- openChat(){
-  let options:ChatPanelOptions = {
-    roleId:"2DXJkRsjXK",
-    onChatSaved:(chat:FmodeChat)=>{
-      // chat?.chatSession?.id 本次会话的 chatId
-      console.log("onChatSaved",chat,chat?.chatSession,chat?.chatSession?.id)
-    },
+  // 开始聊天
+  openChat() {
+    let options: ChatPanelOptions = {
+      roleId: "2DXJkRsjXK",
+      onChatSaved: (chat: FmodeChat) => {
+        console.log("onChatSaved", chat, chat?.chatSession, chat?.chatSession?.id);
+      },
+    };
+    openChatPanelModal(this.modalCtrl, options);
   }
-  openChatPanelModal(this.modalCtrl,options)
-}
-
-  /**
-   * 恢复聊天
-   * @chatId 从onChatSaved生命周期中,获取chat?.chatSession?.id
-   */
-  restoreChat(chatId:string){
-      let options:ChatPanelOptions = {
-       roleId:"2DXJkRsjXK",
-        chatId:chatId
-      }
-      openChatPanelModal(this.modalCtrl,options)
-    }
-
-// 创建用于数据列表存储的属性
-UserProfileList:Array<CloudObject> = []
-// 查询并加载用户列表的函数
-async loadUserProfileList(){
-  let query = new CloudQuery("UserProfile");
-  this.UserProfileList = await query.find();
-  console.log("UserProfileList",this.UserProfileList)
-}
-
 
+  // 恢复聊天
+  restoreChat(chatId: string) {
+    let options: ChatPanelOptions = {
+      roleId: "2DXJkRsjXK",
+      chatId: chatId
+    };
+    openChatPanelModal(this.modalCtrl, options);
+  }
 }

+ 27 - 0
FitMind-app/src/app/page-plan/page-plan.component.html

@@ -0,0 +1,27 @@
+<div class="container">
+  <div class="card">
+    <div class="header">
+      <h1>我的运动方案</h1>
+      <p>根据您的健康状况和目标,定制了以下个性化运动方案</p>
+    </div>
+
+    <!-- 显示运动计划内容,如果 plan 不为空 -->
+     @if(plan){
+      <div class="plan-content">
+      <h2>我的方案</h2>
+      <div class="plan-text">
+        <div>{{ plan }}</div>  <!-- 绑定 plan 数据 -->
+      </div>
+    </div>
+     }
+    
+
+    <!-- 显示加载中的状态 -->
+    <ng-template #loading>
+      <div class="loading">
+        <p>加载中...</p>
+      </div>
+    </ng-template>
+    <button class="exit-button" (click)="exitPlan()">退出</button>
+  </div>
+</div>

+ 117 - 0
FitMind-app/src/app/page-plan/page-plan.component.scss

@@ -0,0 +1,117 @@
+/* 背景色和整体页面 */
+.container {
+  background: linear-gradient(135deg, #ff7e5f, #feb47b); /* 渐变背景色 */
+  height: 100vh;
+  display: flex;
+  justify-content: center;
+  align-items: center;
+  padding: 20px;
+  font-family: 'Arial', sans-serif;
+}
+
+/* 卡片样式 */
+.card {
+  background: #fff;
+  width: 100%;
+  max-width: 600px;
+  border-radius: 15px;
+  box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
+  overflow: hidden;
+  transition: transform 0.3s ease-in-out;
+  transform: scale(1);
+  animation: fadeIn 1s ease-out; /* 动画效果 */
+  padding: 20px;
+}
+
+.card:hover {
+  transform: scale(1.05); /* 放大效果 */
+}
+
+/* 卡片头部 */
+.header {
+  background-color: #ff6f61; /* 红色背景 */
+  padding: 30px;
+  text-align: center;
+  border-radius: 10px 10px 0 0;
+  color: white;
+}
+
+.header h1 {
+  font-size: 36px;
+  margin: 0;
+}
+
+.header p {
+  font-size: 18px;
+  margin-top: 10px;
+  font-weight: 300;
+}
+
+/* 运动计划内容 */
+.plan-content {
+  padding: 20px;
+  background-color: #f9f9f9;
+  color: #333;
+  border-radius: 10px;
+  margin-top: 20px;
+  max-height: 300px;  /* 控制最大高度,增加滚动效果 */
+  overflow-y: auto;   /* 启用垂直滚动 */
+}
+
+.plan-content h2 {
+  font-size: 24px;
+  font-weight: 500;
+  color: #ff7e5f; /* 设置标题颜色 */
+  margin-bottom: 15px;
+}
+
+.plan-text p {
+  font-size: 18px;
+  line-height: 1.6;
+  text-align: justify;
+  color: #555;
+}
+
+/* 加载动画 */
+.loading {
+  padding: 20px;
+  text-align: center;
+  color: #ff6f61;
+  font-size: 18px;
+}
+
+/* 退出按钮样式 */
+.exit-button {
+  display: block;
+  width: 100%;
+  padding: 12px;
+  margin-top: 20px;
+  font-size: 16px;
+  background-color: #f44336; /* 红色背景 */
+  color: white;
+  border: none;
+  border-radius: 5px;
+  cursor: pointer;
+  transition: background-color 0.3s ease;
+  text-align: center;
+}
+
+.exit-button:hover {
+  background-color: #d32f2f; /* 悬停时变色 */
+}
+
+.exit-button:focus {
+  outline: none;
+}
+
+/* 动画效果 */
+@keyframes fadeIn {
+  0% {
+    opacity: 0;
+    transform: translateY(20px);
+  }
+  100% {
+    opacity: 1;
+    transform: translateY(0);
+  }
+}

+ 22 - 0
FitMind-app/src/app/page-plan/page-plan.component.spec.ts

@@ -0,0 +1,22 @@
+import { ComponentFixture, TestBed, waitForAsync } from '@angular/core/testing';
+
+import { PagePlanComponent } from './page-plan.component';
+
+describe('PagePlanComponent', () => {
+  let component: PagePlanComponent;
+  let fixture: ComponentFixture<PagePlanComponent>;
+
+  beforeEach(waitForAsync(() => {
+    TestBed.configureTestingModule({
+      imports: [PagePlanComponent],
+    }).compileComponents();
+
+    fixture = TestBed.createComponent(PagePlanComponent);
+    component = fixture.componentInstance;
+    fixture.detectChanges();
+  }));
+
+  it('should create', () => {
+    expect(component).toBeTruthy();
+  });
+});

+ 48 - 0
FitMind-app/src/app/page-plan/page-plan.component.ts

@@ -0,0 +1,48 @@
+import { Component, OnInit } from '@angular/core';
+import { Router } from '@angular/router';  // 导入 Router 服务
+import { CloudFPlan } from 'src/lib/cloudspplan';  // 引入 CloudFPlan 类
+
+@Component({
+  selector: 'app-page-plan',
+  templateUrl: './page-plan.component.html',
+  styleUrls: ['./page-plan.component.scss'],
+  standalone: true,  // 如果你使用的是独立组件模式
+})
+export class PagePlanComponent implements OnInit {
+
+  plan: string = '';  // 用于存储 Plan 字段的内容
+  cloudFPlan: any;
+
+  constructor(private router: Router) { }  // 注入 Router
+
+  ngOnInit() {
+    this.loadPlanData();  // 页面初始化时加载计划数据
+  }
+
+  // 获取当前登录用户的 FPlan 数据
+  async loadPlanData() {
+    try {
+      const cloudFPlan = new CloudFPlan();  // 创建 CloudFPlan 实例
+      const fPlan = await cloudFPlan.getCurrentUserFPlan();  // 获取当前用户的 FPlan 数据
+
+      console.log('User Data:', fPlan); 
+      
+      if (fPlan) {
+        // 获取 Plan 字段的内容
+        this.plan = fPlan.data['data']['Plan'] || '';  // 如果 Plan 字段为空,赋值为 ''。
+        console.log('plan1', this.plan);
+      }
+      console.log('plan2', this.plan);
+    } catch (error) {
+      console.error('加载计划数据失败', error);
+      this.plan = '加载计划数据失败,请稍后再试。';  // 加载失败时的提示信息
+    }
+  }
+
+  // 退出按钮点击时的处理方法
+  exitPlan() {
+    console.log('退出运动计划');
+    // 执行退出逻辑,例如跳转到首页
+    this.router.navigate(['/home']);  // 假设跳转到首页路径为 /home
+  }
+}

+ 10 - 0
FitMind-app/src/app/tab2/tab2.page.html

@@ -77,6 +77,16 @@
   获取运动方案
 </ion-button>
 
+<ion-button 
+  fill="clear"
+  class="save-button" 
+  (click)="saveGeneratedPlan()"
+  [disabled]="!isComplete" 
+  >
+  保存运动规划
+</ion-button>
+
+
 
   
  <!-- AI生成内容区域 -->

+ 77 - 5
FitMind-app/src/app/tab2/tab2.page.ts

@@ -9,8 +9,9 @@ import { Router } from '@angular/router'; // 导入 Router
 import { DalleOptions, ImagineWork } from 'fmode-ng';
 import { PageAiChatComponent } from '../page-ai-chat/page-ai-chat.component';
 //import { PageEvaluateComponent } from '../page-evaluate/page-evaluate.component';
+import { CloudFPlan } from 'src/lib/cloudspplan'; // 引入你封装的 CloudSpPlan 类
 
-import { CloudUser } from 'src/lib/ncloud';
+import { CloudObject, CloudUser } from 'src/lib/ncloud';
 import { openUserLoginModal } from 'src/lib/user/modal-user-login/modal-user-login.component';
 // import { CloudfearlessPlan } from 'src/app/lib/cloudPlans'; // 引入封装好的 CloudfearlessPlan 类
 
@@ -49,6 +50,53 @@ export class Tab2Page {
     constructor(private alertController: AlertController,private modalCtrl:ModalController,
       private router:Router, private cdRef:ChangeDetectorRef) { }
 
+      // 保存运动建议
+  async saveWorkoutPlan(workoutData: string): Promise<CloudObject | null> {
+    const cloudFPlan = new CloudFPlan();  // 创建 CloudSpPlan 实例
+
+    // 获取当前登录用户
+    const cloudUser = new CloudUser();
+    const currentUser = await cloudUser.current();
+
+    if (!currentUser) {
+      console.error("用户未登录");
+      return null;
+    }
+
+    // 构建运动建议的数据对象
+    const userPointer = { 
+      "__type": "Pointer", 
+      "className": "_User", 
+      "objectId": currentUser.objectId 
+    };
+
+    const workoutPlanData = {
+      Plan: workoutData,       // 将传入的运动计划数据展开
+      user: userPointer     // 关联当前用户
+    };
+
+    // 保存运动建议到 spPlans 表
+    return await cloudFPlan.saveFPlan(workoutPlanData.Plan);  // 调用 saveSpPlan 保存数据
+  }
+
+  // 导出运动建议(例如在计划完成后保存到数据库)
+  async exportWorkoutPlan(workoutData: string): Promise<CloudObject | null> {
+    try {
+      const savedWorkoutPlan = await this.saveWorkoutPlan(workoutData);
+
+      if (savedWorkoutPlan) {
+        console.log('运动建议保存成功');
+        return savedWorkoutPlan;
+      } else {
+        console.error('保存运动建议失败');
+        return null;
+      }
+    } catch (error) {
+      console.error('导出运动建议时发生错误:', error);
+      return null;
+    }
+  }
+
   selectSegment(segment: string) {
     this.selectedSegment = segment; // 更新选中的导航项
   }
@@ -182,10 +230,10 @@ BMI是衡量身体状况的重要指标,计算方法是体重(公斤)除
           this.isComplete = true;
           
            // 图片生成
-        this.startTimer(); // 启动计时器
+        this.startTimer(); // 启动计时器 
         this.imagineWork = new ImagineWork();
         let PicturePrompt = `描述:${this.responseMsg}\n请你作为一名专业的运动教练,根据描述中的方案一描述严格生成对应的训练计划,格式要一致。`
-        let options:DalleOptions = {prompt:PicturePrompt}
+        let options:DalleOptions = {prompt:PicturePrompt};
         this.imagineWork?.draw(options).subscribe(work=>{
             console.log("imagineWork",work?.toJSON())
             console.log("images",work?.get("images"))
@@ -197,7 +245,7 @@ BMI是衡量身体状况的重要指标,计算方法是体重(公斤)除
         })
       }
   });
-
+  // await this.saveWorkoutPlan(this.responseMsg);  // 传递字符串给 saveWorkoutPlan
 }
 
 // 启动计时器
@@ -212,6 +260,27 @@ stopTimer() {
   clearInterval(this.timerInterval); // 清除定时器
 }
 
+// 添加保存规划的方法
+async saveGeneratedPlan() {
+  // 如果没有生成完整的规划,直接返回
+  if (!this.isComplete) {
+    console.error("规划尚未完成,无法保存!");
+    return;
+  }
+
+  // 调用保存运动规划的方法
+  try {
+    const savedWorkoutPlan = await this.saveWorkoutPlan(this.responseMsg);
+    if (savedWorkoutPlan) {
+      console.log("运动规划已成功保存!");
+    } else {
+      console.error("保存运动规划失败!");
+    }
+  } catch (error) {
+    console.error("保存运动规划时发生错误:", error);
+  }
+}
+
 
 
 //测试
@@ -234,4 +303,7 @@ alertButtons = ['退出'];
 
 
 
-}
+}
+
+
+

+ 4 - 4
FitMind-app/src/app/tab3/tab3.page.html

@@ -47,13 +47,13 @@
   <!-- 我的锻炼计划 -->
   <ion-card>
     <ion-card-header>
-      <ion-card-title>我的锻炼计划</ion-card-title>
+      <ion-card-title>我的运动方案</ion-card-title>
     </ion-card-header>
     <ion-card-content>
       <ion-item>
-        <ion-label>今天的计划</ion-label>
-        <ion-button expand="block" color="secondary">
-          查看详情
+        <ion-label>运动方案</ion-label>
+        <ion-button (click)="goToPlan()" fill="clear" color="primary">
+          查看运动方案
         </ion-button>
       </ion-item>
     </ion-card-content>

+ 19 - 9
FitMind-app/src/app/tab3/tab3.page.ts

@@ -6,7 +6,7 @@ import { ModalController } from '@ionic/angular/standalone';
 import { IonButton, IonCard, IonCardContent, IonCardHeader, IonCol, IonContent, IonGrid, IonHeader, IonIcon, IonInput, IonRow, IonTextarea, IonTitle, IonToolbar } from '@ionic/angular/standalone';
 import { CommonModule } from '@angular/common';  // 导入 CommonModule
 import { PageEditComponent } from '../page-edit/page-edit.component';
-
+import { PagePlanComponent } from '../page-plan/page-plan.component';
 @Component({
   selector: 'app-tab3',
   templateUrl: './tab3.page.html',
@@ -121,15 +121,25 @@ export class Tab3Page implements OnInit {
     }
   }
 
-  goToFavorites() {
-    this.navCtrl.navigateForward('/favorites');
-  }
 
-  goToHelp() {
-    this.navCtrl.navigateForward('/help');
-  }
+  async goToPlan() {
+    // 打开计划页面模态框
+    const modal = await this.modalCtrl.create({
+      component: PagePlanComponent,  // 目标页面组件
+      componentProps: {
+        userData: this.userData,  // 将当前用户数据传递给目标页面
+        // 你可以根据需要传递其他数据给 PagePlanComponent
+      }
+    });
+  
+    modal.present();
+  
 
-  goToSettings() {
-    this.navCtrl.navigateForward('/settings');
+    
   }
+  
+
+
+
+
 }

+ 3 - 0
FitMind-app/src/app/tabs/tabs.routes.ts

@@ -77,6 +77,9 @@ export const routes: Routes = [
         redirectTo: '/tabs/tab1',
         pathMatch: 'full',
       },
+
+      
+
     ],
   },
   {

+ 236 - 0
FitMind-app/src/lib/cloudspplan.ts

@@ -0,0 +1,236 @@
+// import { CloudObject, CloudQuery, CloudUser } from './ncloud';
+
+// export class CloudSpPlan extends CloudObject {
+//   constructor() {
+//     super("FPlan"); // 假设表名为 "FPlan"
+//   }
+
+//   /** 获取单个SP规划 */
+//   async getSpPlan(id: string): Promise<CloudObject | null> {
+//     const url = `http://dev.fmode.cn:1337/parse/classes/FPlan/${id}?`;
+
+//     const response = await fetch(url, {
+//       headers: {
+//         "x-parse-application-id": "dev"
+//       },
+//       method: "GET",
+//       mode: "cors",
+//       credentials: "omit"
+//     });
+
+//     const result = await response?.json();
+//     if (result?.error) {
+//       console.error(result?.error);
+//       return null;
+//     }
+
+//     return this.dataToObj(result);
+//   }
+
+//   /** 获取当前登录用户的SP规划信息 */
+//   async getCurrentUserSpPlan(): Promise<CloudObject | null> {
+//     const cloudUser = new CloudUser();
+//     const currentUser = await cloudUser.current();
+
+//     if (!currentUser) {
+//       console.error("用户未登录");
+//       return null;
+//     }
+
+//     const currentUserId = currentUser.objectId;
+
+//     // 通过 _User 的 objectId 查询 FPlan 表中的记录
+//     const query = new CloudQuery("FPlan");
+//     query.equalTo("user", { "__type": "Pointer", "className": "_User", "objectId": currentUserId });
+
+//     const spPlan = await query.first();
+//     return spPlan ? this.dataToObj(spPlan) : null;
+//   }
+
+//   /** 创建或保存SP规划信息 */
+//   async saveSpPlan(spPlanData: Record<string, any>): Promise<CloudObject | null> {
+//     const cloudUser = new CloudUser();
+//     const currentUser = await cloudUser.current();
+
+//     if (!currentUser) {
+//       console.error("用户未登录");
+//       return null;
+//     }
+
+//     const userPointer = { "__type": "Pointer", "className": "_User", "objectId": currentUser.objectId };
+
+//     const newSpPlan = {
+//       ...spPlanData,
+//       user: userPointer // 将当前用户作为外键关联到 FPlan 表
+//     };
+
+//     const url = `http://dev.fmode.cn:1337/parse/classes/FPlan`;
+
+//     const response = await fetch(url, {
+//       headers: {
+//         "Content-Type": "application/json",
+//         "x-parse-application-id": "dev"
+//       },
+//       method: "POST",
+//       body: JSON.stringify(newSpPlan),
+//       mode: "cors",
+//       credentials: "omit"
+//     });
+
+//     const result = await response?.json();
+//     if (result?.error) {
+//       console.error(result?.error);
+//       return null;
+//     }
+
+//     return this.dataToObj(result);
+//   }
+
+//   /** 更新SP规划信息 */
+//   async updateSpPlan(updatedData: Record<string, any>, spPlanId: string): Promise<CloudSpPlan> {
+//     const spPlan = new CloudSpPlan();
+//     spPlan.id = spPlanId;
+//     spPlan.set(updatedData);
+
+//     await spPlan.save(); // 调用 save 方法更新数据
+//     return spPlan;
+//   }
+
+//   /** 删除SP规划 */
+//   async deleteSpPlan(spPlanId: string): Promise<boolean> {
+//     const spPlan = new CloudSpPlan();
+//     spPlan.id = spPlanId;
+//     await spPlan.destroy();
+
+//     return true;
+//   }
+
+//   /** 将查询结果转换为 CloudObject */
+//   private dataToObj(result: any): CloudObject {
+//     let spPlanObject = new CloudObject(this.className);
+//     spPlanObject.set(result);
+//     spPlanObject.id = result.objectId;
+//     spPlanObject.createdAt = result.createdAt;
+//     spPlanObject.updatedAt = result.updatedAt;
+//     return spPlanObject;
+//   }
+// }
+
+
+import { CloudObject, CloudQuery, CloudUser } from './ncloud';
+
+export class CloudFPlan extends CloudObject {
+  constructor() {
+    super("FPlan"); // 假设表名为 "FPlan"
+  }
+
+  /** 获取单个FPlan */
+  async getFPlan(id: string): Promise<CloudObject | null> {
+    const url = `http://dev.fmode.cn:1337/parse/classes/FPlan/${id}?`;
+
+    const response = await fetch(url, {
+      headers: {
+        "x-parse-application-id": "dev"
+      },
+      method: "GET",
+      mode: "cors",
+      credentials: "omit"
+    });
+
+    const result = await response?.json();
+    if (result?.error) {
+      console.error(result?.error);
+      return null;
+    }
+
+    return this.dataToObj(result);
+  }
+
+  /** 获取当前登录用户的FPlan信息 */
+  async getCurrentUserFPlan(): Promise<CloudObject | null> {
+    const cloudUser = new CloudUser();
+    const currentUser = await cloudUser.current();
+
+    if (!currentUser) {
+      console.error("用户未登录");
+      return null;
+    }
+
+    const currentUserId = currentUser.objectId;
+
+    // 通过 _User 的 objectId 查询 FPlan 表中的记录
+    const query = new CloudQuery("FPlan");
+    query.equalTo("user", { "__type": "Pointer", "className": "_User", "objectId": currentUserId });
+
+    const fPlan = await query.first();
+    return fPlan ? this.dataToObj(fPlan) : null;
+  }
+
+  /** 创建或保存FPlan信息 */
+  async saveFPlan(planContent: string): Promise<CloudObject | null> {
+    const cloudUser = new CloudUser();
+    const currentUser = await cloudUser.current();
+
+    if (!currentUser) {
+      console.error("用户未登录");
+      return null;
+    }
+
+    const userPointer = { "__type": "Pointer", "className": "_User", "objectId": currentUser.objectId };
+
+    const newFPlan = {
+      Plan: planContent,  // 将运动计划内容保存在 "Plan" 字段
+      user: userPointer // 将当前用户作为外键关联到 FPlan 表
+    };
+
+    const url = `http://dev.fmode.cn:1337/parse/classes/FPlan`;
+
+    const response = await fetch(url, {
+      headers: {
+        "Content-Type": "application/json",
+        "x-parse-application-id": "dev"
+      },
+      method: "POST",
+      body: JSON.stringify(newFPlan),
+      mode: "cors",
+      credentials: "omit"
+    });
+
+    const result = await response?.json();
+    if (result?.error) {
+      console.error(result?.error);
+      return null;
+    }
+
+    return this.dataToObj(result);
+  }
+
+  /** 更新FPlan信息 */
+  async updateFPlan(updatedData: Record<string, any>, fPlanId: string): Promise<CloudFPlan> {
+    const fPlan = new CloudFPlan();
+    fPlan.id = fPlanId;
+    fPlan.set(updatedData);
+
+    await fPlan.save(); // 调用 save 方法更新数据
+    return fPlan;
+  }
+
+  /** 删除FPlan */
+  async deleteFPlan(fPlanId: string): Promise<boolean> {
+    const fPlan = new CloudFPlan();
+    fPlan.id = fPlanId;
+    await fPlan.destroy();
+
+    return true;
+  }
+
+  /** 将查询结果转换为 CloudObject */
+  private dataToObj(result: any): CloudObject {
+    let fPlanObject = new CloudObject(this.className);
+    fPlanObject.set(result);
+    fPlanObject.id = result.objectId;
+    fPlanObject.createdAt = result.createdAt;
+    fPlanObject.updatedAt = result.updatedAt;
+    return fPlanObject;
+  }
+}