15179588180 7 ヶ月 前
コミット
6c25310029

+ 4 - 1
seeking-app/angular.json

@@ -126,7 +126,10 @@
     }
   },
   "cli": {
-    "schematicCollections": ["@ionic/angular-toolkit"]
+    "schematicCollections": [
+      "@ionic/angular-toolkit"
+    ],
+    "analytics": false
   },
   "schematics": {
     "@ionic/angular-toolkit:component": {

+ 19 - 0
seeking-app/src/app/models/diet-plan.model.ts

@@ -0,0 +1,19 @@
+export interface DietPlan {
+  goal: string;  // 饮食目标
+  preference: string;  // 饮食偏好
+  duration: number;  // 饮食时长(天数)
+  foodRestrictions: string;  // 食物忌口
+  detailedRequirements: string;  // 详细需求
+  meals: Meal[];  // 餐食列表
+}
+
+export interface Meal {
+  type: string;  // 餐食类型(早餐、午餐、晚餐)
+  foods: FoodItem[];  // 食物列表
+}
+
+export interface FoodItem {
+  food: string;  // 食物名称
+  quantity: string;  // 食物数量
+  calories: number;  // 卡路里
+}

+ 40 - 93
seeking-app/src/app/tab1/tab1.page.html

@@ -1,124 +1,71 @@
 <ion-header [translucent]="true">
-  <ion-toolbar>
-    <ion-title>
-      首页
-    </ion-title>
+  <ion-toolbar color="primary">
+    <ion-title class="left">首页</ion-title>
     <ion-buttons slot="end">
-      <ion-button>
+      <ion-button fill="clear">
         <ion-icon slot="icon-only" name="search"></ion-icon>
       </ion-button>
-      <ion-button>
+      <ion-button fill="clear">
         <ion-icon slot="icon-only" name="notifications"></ion-icon>
       </ion-button>
     </ion-buttons>
   </ion-toolbar>
 </ion-header>
 
-<ion-content [fullscreen]="true">
-  
-  <!-- 饮食计划 -->
-  <ion-card>
+<ion-content [fullscreen]="true" class="ion-padding">
+
+  <!-- 合并饮食计划和打卡进度为一个卡片 -->
+  <ion-card class="custom-card">
     <ion-card-header>
-      <ion-card-title>饮食计划</ion-card-title>
+      <ion-card-title class="ion-text-center">饮食计划与打卡进度</ion-card-title>
     </ion-card-header>
     <ion-card-content>
-      <ion-list>
-        <ion-item>
-          <ion-icon slot="start" name="bread"></ion-icon> <!-- 全麦面包 -->
-          <ion-label>早餐:全麦面包 + 牛奶 + 水果</ion-label>
-        </ion-item>
-        <ion-item>
-          <ion-icon slot="start" name="pizza"></ion-icon> <!-- 鸡胸肉沙拉 -->
-          <ion-label>午餐:鸡胸肉 + 沙拉</ion-label>
-        </ion-item>
-        <ion-item>
-          <ion-icon slot="start" name="fish"></ion-icon> <!-- 蒸鱼 -->
-          <ion-label>晚餐:蒸鱼 + 蔬菜</ion-label>
-        </ion-item>
-      </ion-list>
+
+      <!-- 饮食计划部分 -->
+      <div class="meal-plan">
+        <ion-list lines="full">
+          <ion-item *ngFor="let meal of mealPlan">
+            <ion-img [src]="meal.imageUrl" slot="start" class="meal-image"></ion-img>
+            <ion-icon slot="start" [name]="meal.icon" class="ion-icon-size"></ion-icon>
+            <ion-label>{{ meal.meal }}:{{ meal.food }}</ion-label>
+            <ion-note slot="end" class="calories-text">{{ meal.calories }} kcal</ion-note> <!-- 显示卡路里 -->
+          </ion-item>
+        </ion-list>
+      </div>
+
+      <!-- 打卡进度部分 -->
+      <div class="progress-section">
+        <ion-label class="progress-text">{{ progressText }}</ion-label>
+      </div>
+
     </ion-card-content>
   </ion-card>
 
-  <!-- 运动计划 -->
-  <ion-card>
+  <!-- 食谱推荐部分 -->
+  <ion-card class="custom-card">
     <ion-card-header>
-      <ion-card-title>运动计划</ion-card-title>
+      <ion-card-title class="ion-text-center">今日食谱推荐</ion-card-title>
     </ion-card-header>
     <ion-card-content>
-      <ion-list>
-        <ion-item>
-          <ion-icon slot="start" name="walk"></ion-icon> <!-- 跑步 -->
-          <ion-label>早晨:跑步 30 分钟</ion-label>
-        </ion-item>
-        <ion-item>
-          <ion-icon slot="start" name="bicycle"></ion-icon> <!-- 瑜伽 -->
-          <ion-label>中午:瑜伽 20 分钟</ion-label>
-        </ion-item>
-        <ion-item>
-          <ion-icon slot="start" name="walk"></ion-icon> <!-- 快走 -->
-          <ion-label>晚上:快走 30 分钟</ion-label>
+      <ion-list lines="full">
+        <ion-item *ngFor="let recipe of recipeRecommendations">
+          <ion-img [src]="recipe.imageUrl" slot="start" class="meal-image"></ion-img>
+          <ion-label>{{ recipe.title }}</ion-label>
+          <ion-note slot="end" class="small-text">{{ recipe.description }}</ion-note>
+          <ion-note slot="end" class="calories-text">{{ recipe.calories }} kcal</ion-note> <!-- 显示卡路里 -->
         </ion-item>
       </ion-list>
     </ion-card-content>
   </ion-card>
 
-  <!-- 身体数据 -->
-  <ion-card>
+  <ion-card class="custom-card">
     <ion-card-header>
-      <ion-card-title>身体数据</ion-card-title>
     </ion-card-header>
     <ion-card-content>
-      <ion-grid>
-        <ion-row>
-          <ion-col size="4">
-            <ion-item lines="none">
-              <ion-icon slot="start" name="fitness"></ion-icon> <!-- 体重 -->
-              <ion-label>体重</ion-label>
-              <ion-note slot="end">70kg</ion-note>
-            </ion-item>
-          </ion-col>
-          <ion-col size="4">
-            <ion-item lines="none">
-              <ion-icon slot="start" name="fitness"></ion-icon> <!-- 身高 -->
-              <ion-label>身高</ion-label>
-              <ion-note slot="end">175cm</ion-note>
-            </ion-item>
-          </ion-col>
-          <ion-col size="4">
-            <ion-item lines="none">
-              <ion-icon slot="start" name="fitness"></ion-icon> <!-- 体脂率 -->
-              <ion-label>体脂率</ion-label>
-              <ion-note slot="end">18%</ion-note>
-            </ion-item>
-          </ion-col>
-        </ion-row>
-        <ion-row>
-          <ion-col size="4">
-            <ion-item lines="none">
-              <ion-icon slot="start" name="walk"></ion-icon> <!-- 步数 -->
-              <ion-label>步数</ion-label>
-              <ion-note slot="end">8000步</ion-note>
-            </ion-item>
-          </ion-col>
-          <ion-col size="4">
-            <ion-item lines="none">
-              <ion-icon slot="start" name="flame"></ion-icon> <!-- 卡路里 -->
-              <ion-label>卡路里</ion-label>
-              <ion-note slot="end">500kcal</ion-note>
-            </ion-item>
-          </ion-col>
-          <ion-col size="4">
-            <ion-item lines="none">
-              <ion-icon slot="start" name="water"></ion-icon> <!-- 水分 -->
-              <ion-label>水分</ion-label>
-              <ion-note slot="end">1500ml</ion-note>
-            </ion-item>
-          </ion-col>
-        </ion-row>
-      </ion-grid>
+      <ion-button expand="full" color="secondary" routerLink="/ai-food-analysis" class="custom-button">
+        食材查询
+      </ion-button>
     </ion-card-content>
   </ion-card>
 
-
-
 </ion-content>

+ 43 - 0
seeking-app/src/app/tab1/tab1.page.scss

@@ -0,0 +1,43 @@
+/* 统一的卡片样式 */
+ion-card {
+    margin-bottom: 15px;
+  }
+  
+  /* 饮食计划部分样式 */
+  .meal-plan {
+    margin-bottom: 20px; /* 给饮食计划部分加个下边距,确保进度显示有空隙 */
+  }
+  
+  /* 打卡进度部分样式 */
+  .progress-section {
+    margin-top: 10px; /* 给打卡进度加上顶部间距 */
+    text-align: center; /* 使进度文本居中 */
+  }
+  
+  .progress-text {
+    font-size: 1.4rem;
+    font-weight: bold;
+    color: #4caf50; /* 进度条绿色 */
+  }
+  
+  /* 卡路里文本样式 */
+  .calories-text {
+    font-size: 1rem;
+    color: #888;
+    margin-left: 10px;
+  }
+  
+  /* 饮食计划图标和图片样式 */
+  .meal-image {
+    width: 50px;
+    height: 50px;
+    border-radius: 8px;
+    margin-right: 10px;
+  }
+  
+  ion-card-title {
+    font-size: 1.4rem;
+    font-weight: bold;
+    color: #333;
+  }
+  

+ 30 - 4
seeking-app/src/app/tab1/tab1.page.ts

@@ -18,10 +18,12 @@ import {
   IonRow,
   IonCol,
   IonFooter,
-  IonButtons
-} from '@ionic/angular/standalone';  // 引入所有需要的Ionic组件
+  IonButtons,
+  IonImg,
+  IonCardSubtitle
+} from '@ionic/angular/standalone';
 
-import { ExploreContainerComponent } from '../explore-container/explore-container.component';
+import { CommonModule } from '@angular/common';  // 确保导入 CommonModule
 
 @Component({
   selector: 'app-tab1',
@@ -48,9 +50,33 @@ import { ExploreContainerComponent } from '../explore-container/explore-containe
     IonCol,
     IonFooter,
     IonButtons,
-    ExploreContainerComponent
+    IonImg,
+    IonCardSubtitle,
+    CommonModule
   ],
 })
 export class Tab1Page {
+  totalDays: number = 30;
+  completedDays: number = 6;  // 当前打卡天数
+
+ // 饮食计划数据结构
+mealPlan = [
+  { meal: '早餐', food: '燕麦片', calories: 200, imageUrl: 's202226701038/seeking-prod/img/yanmai.png', icon: 'pizza' },
+  { meal: '午餐', food: '鸡胸肉', calories: 300, imageUrl: 'path/to/image.jpg', icon: 'egg' },
+  { meal: '晚餐', food: '蔬菜沙拉', calories: 150, imageUrl: 'path/to/image.jpg', icon: 'fast-food' }
+];
+
+// 食谱推荐数据结构
+recipeRecommendations = [
+  { title: '鸡肉沙拉', description: '健康美味', calories: 350, imageUrl: 'path/to/image.jpg' },
+  { title: '牛肉炖菜', description: '富含蛋白质', calories: 500, imageUrl: 'path/to/image.jpg' },
+  { title: '水果拼盘', description: '清新爽口', calories: 200, imageUrl: 'path/to/image.jpg' }
+];
+
+
+  get progressText(): string {
+    return `第 ${this.completedDays} / ${this.totalDays} 天`;  // 返回打卡进度文本
+  }
+
   constructor() {}
 }

+ 62 - 8
seeking-app/src/app/tab2/tab2.page.html

@@ -1,17 +1,71 @@
 <ion-header [translucent]="true">
   <ion-toolbar>
     <ion-title>
-      Tab 2
+      饮食计划生成
     </ion-title>
   </ion-toolbar>
 </ion-header>
 
-<ion-content [fullscreen]="true">
-  <ion-header collapse="condense">
-    <ion-toolbar>
-      <ion-title size="large">Tab 2</ion-title>
-    </ion-toolbar>
-  </ion-header>
+<ion-content>
+  <!-- 用户输入饮食目标 -->
+  <ion-item>
+    <ion-label position="floating">饮食目标</ion-label>
+    <ion-input [(ngModel)]="dietGoal" placeholder="例如:减脂、增肌等"></ion-input>
+  </ion-item>
 
-  <app-explore-container name="Tab 2 page"></app-explore-container>
+  <!-- 用户输入食物忌口 -->
+  <ion-item>
+    <ion-label position="floating">食物忌口</ion-label>
+    <ion-input [(ngModel)]="foodRestrictions" placeholder="例如:不吃海鲜、不吃辣等"></ion-input>
+  </ion-item>
+
+  <!-- 用户输入详细需求 -->
+  <ion-item>
+    <ion-label position="floating">详细需求</ion-label>
+    <ion-textarea [(ngModel)]="detailedRequirements" placeholder="例如:每天至少摄入 100 克蛋白质"></ion-textarea>
+  </ion-item>
+
+  <!-- 用户输入饮食偏好 -->
+  <ion-item>
+    <ion-label position="floating">饮食偏好</ion-label>
+    <ion-input [(ngModel)]="dietPreference" placeholder="例如:高蛋白、低碳水"></ion-input>
+  </ion-item>
+
+  <!-- 用户输入饮食计划时长 -->
+  <ion-item>
+    <ion-label position="floating">饮食计划时长</ion-label>
+    <ion-input [(ngModel)]="dietDuration" type="number" placeholder="例如:7、14、30 天"></ion-input>
+  </ion-item>
+
+  <!-- 用户输入需求 -->
+  <ion-textarea 
+    [value]="userPrompt" 
+    (ionInput)="promptInput($event)" 
+    placeholder="输入你的饮食需求,如:高蛋白饮食,低糖饮食等" 
+    autoGrow="true"
+  ></ion-textarea>
+
+  <!-- 按钮:触发饮食计划生成 -->
+  <ion-button (click)="sendMessage()" expand="block">生成饮食计划</ion-button>
+  
+  <!-- 显示生成的饮食计划 -->
+  <div *ngIf="responseMsg" class="response-container">
+    <h2>生成的饮食计划</h2>
+    <p><strong>饮食目标:</strong> {{ responseMsg.goal }}</p>
+    <p><strong>饮食偏好:</strong> {{ responseMsg.preference }}</p>
+    <p><strong>饮食计划时长:</strong> {{ responseMsg.duration }} 天</p>
+    <p><strong>食物忌口:</strong> {{ responseMsg.foodRestrictions }}</p>
+    <p><strong>详细需求:</strong> {{ responseMsg.detailedRequirements }}</p>
+
+    
+    <!-- 遍历每个餐食并展示 -->
+    <div class="meal-plan" *ngFor="let meal of responseMsg.meals">
+      <h3>{{ meal.type }}</h3>
+      <ul>
+        <li *ngFor="let item of meal.foods">
+          <strong>{{ item.food }}</strong>: {{ item.quantity }} ({{ item.calories }} kcal)
+        </li>
+      </ul>
+    </div>
+  </div>
 </ion-content>

+ 66 - 0
seeking-app/src/app/tab2/tab2.page.scss

@@ -0,0 +1,66 @@
+/* 增加页面内的间距 */
+.content {
+  padding: 20px;
+}
+
+/* 为每个输入框设置底部间距 */
+.input-item {
+  margin-bottom: 20px;
+}
+
+/* 设置每个输入框的高度和间距,避免与标签重叠 */
+ion-input, ion-textarea {
+  padding-top: 16px;  /* 增加输入框顶部间距 */
+  padding-bottom: 16px;  /* 增加输入框底部间距 */
+  font-size: 16px;  /* 设置输入框的字体大小 */
+}
+
+/* 设置浮动标签的字体大小和颜色 */
+ion-label {
+  font-size: 16px;
+  color: var(--ion-text-color);
+}
+
+/* 增加浮动标签的间距 */
+ion-label.floating {
+  margin-top: 12px;
+}
+
+/* 设置生成按钮的间距 */
+.generate-button {
+  margin-top: 20px;
+  padding: 12px 0;
+}
+
+/* 设置生成饮食计划标题的间距 */
+.response-title {
+  margin-top: 20px;
+  font-size: 24px;
+  font-weight: bold;
+}
+
+/* 增加生成饮食计划文本的间距 */
+.response-container p {
+  margin-bottom: 15px;
+}
+
+/* 调整餐食列表的间距 */
+.meal-plan {
+  margin-top: 20px;
+}
+
+.meal-plan h3 {
+  font-size: 20px;
+  font-weight: bold;
+  margin-bottom: 10px;
+}
+
+.meal-plan ul {
+  margin-left: 20px;
+  list-style-type: none;
+  padding: 0;
+}
+
+.meal-plan li {
+  margin-bottom: 10px;
+}

+ 81 - 3
seeking-app/src/app/tab2/tab2.page.ts

@@ -1,16 +1,94 @@
 import { Component } from '@angular/core';
-import { IonHeader, IonToolbar, IonTitle, IonContent } from '@ionic/angular/standalone';
+import { IonicModule, LoadingController } from '@ionic/angular';  // 导入 IonicModule
+import { CommonModule } from '@angular/common';  // 导入 CommonModule
+import { FormsModule } from '@angular/forms';  // 导入 FormsModule
 import { ExploreContainerComponent } from '../explore-container/explore-container.component';
+import { FmodeChatCompletion } from 'fmode-ng';  // 假设你在使用 Fmode API 来生成消息
+import { DietPlan } from '../models/diet-plan.model';  // 导入定义好的数据结构
 
 @Component({
   selector: 'app-tab2',
   templateUrl: 'tab2.page.html',
   styleUrls: ['tab2.page.scss'],
   standalone: true,
-  imports: [IonHeader, IonToolbar, IonTitle, IonContent, ExploreContainerComponent]
+  imports: [IonicModule, CommonModule, FormsModule, ExploreContainerComponent]  // 添加 CommonModule 和 FormsModule
 })
 export class Tab2Page {
+  userPrompt: string = "高蛋白饮食,低糖饮食";
+  responseMsg: DietPlan | null = null;
+  isLoading: boolean = false;  // 用于控制加载指示器
 
-  constructor() {}
+  // 用户输入的饮食信息
+  dietGoal: string = '';
+  foodRestrictions: string = '';  // 用户输入的食物忌口
+  detailedRequirements: string = '';  // 用户输入的详细需求
+  dietPreference: string = '';  // 用户输入的饮食偏好
+  dietDuration: number | null = null;  // 用户输入的饮食时长(天数)
 
+  constructor(private loadingController: LoadingController) {}
+
+  // 输入事件处理方法
+  promptInput(ev: any) {
+    this.userPrompt = ev.detail.value;
+  }
+
+  // 发送请求并获取响应
+  async sendMessage() {
+    console.log("生成饮食计划");
+
+    // 显示加载指示器
+    this.isLoading = true;
+    const loading = await this.loadingController.create({
+      message: '生成饮食计划中...',
+      duration: 10000  // 最大等待 10 秒
+    });
+    await loading.present();
+
+    // 创建 AI 提示词
+    const aiPrompt = `
+      请根据以下需求生成饮食计划:
+      目标:${this.dietGoal || '无目标'}
+      食物忌口:${this.foodRestrictions || '无'}
+      详细需求:${this.detailedRequirements || '无详细需求'}
+      偏好:${this.dietPreference || '无'}
+      时长:${this.dietDuration ? this.dietDuration + '天' : '未指定'}
+    `;
+
+    // 构建请求体
+    let completion = new FmodeChatCompletion([
+      { role: "system", content: "你是一个营养师,帮助用户生成饮食计划。" },
+      { role: "user", content: aiPrompt }
+    ]);
+
+    // 获取 AI 响应并更新状态
+    completion.sendCompletion().subscribe(
+      (message: any) => {
+        this.responseMsg = this.formatDietPlan(message.content);  // 格式化并更新饮食计划
+        this.isLoading = false;
+        loading.dismiss();  // 关闭加载指示器
+      },
+      (error) => {
+        console.error("生成饮食计划失败", error);
+        this.isLoading = false;
+        loading.dismiss();  // 关闭加载指示器
+      }
+    );
+  }
+
+  // 格式化返回的饮食计划
+  formatDietPlan(message: string): DietPlan | null {
+    try {
+      const dietPlan: DietPlan = JSON.parse(message);
+
+      // 确保返回的饮食计划包含 foodRestrictions 和 detailedRequirements 字段
+      return {
+        ...dietPlan,
+        foodRestrictions: dietPlan.foodRestrictions || '无',  // 默认值
+        detailedRequirements: dietPlan.detailedRequirements || '无'  // 默认值
+      };
+    } catch (error) {
+      console.error("饮食计划解析失败", error);
+      return null;
+    }
+  }
 }

BIN
seeking-prod/img/yanmai.png