Pārlūkot izejas kodu

feat:查看全部饮食规划及部分css样式

刘嘉轩 7 mēneši atpakaļ
vecāks
revīzija
ed0280a040

+ 49 - 0
smarteat-app/src/app/page-plans/page-plans.component.html

@@ -0,0 +1,49 @@
+<ion-header>
+  <ion-toolbar>
+    <!-- 返回按钮 -->
+    <ion-button (click)="back()" slot="start" >
+      <ion-icon name="arrow-undo-outline" ></ion-icon>
+    </ion-button>
+    <ion-title>饮食规划</ion-title>
+  </ion-toolbar>
+</ion-header>
+
+<ion-content>
+  <!-- 显示加载中的状态 -->
+  @if(loading && !errorMessage && !obtain){
+    <ion-spinner ></ion-spinner>
+  }
+
+  <!-- 显示错误消息 -->
+  @if(errorMessage && !obtain){
+    <div class="error-message">
+      <ion-text color="danger" >{{ errorMessage }}</ion-text>
+    </div>
+  }
+  
+
+  <ion-card class="diet-card">
+    <ion-card-header class="diet-card-header">
+      <ion-card-title class="diet-card-title">
+        <ion-icon  name="leaf-outline"></ion-icon>
+        饮食内容
+      </ion-card-title>
+    </ion-card-header>
+    <ion-card-content class="diet-card-content">
+      
+      @if(obtain){
+      <ion-card-content class="diet-card-content">
+        <div [innerHTML]="responseMsg0"></div>
+      </ion-card-content>
+      }
+     
+    </ion-card-content>
+  </ion-card>
+
+  <!-- 如果没有饮食规划,显示此按钮 -->
+  @if(mealPlans.length === 0){
+    <ion-button  expand="full">您还没有饮食规划</ion-button>
+  }
+  
+
+</ion-content>

+ 116 - 0
smarteat-app/src/app/page-plans/page-plans.component.scss

@@ -0,0 +1,116 @@
+/* 设置饮食规划页面的基本样式 */
+ion-content {
+  background-color: #f7f7f7; /* 背景颜色 */
+  padding: 16px;
+  font-family: 'Arial', sans-serif;
+}
+
+
+/* 设置返回按钮的样式 */
+ion-button {
+  --background: transparent;
+  --border-radius: 50%;
+  --box-shadow: none;
+  padding: 8px;
+  font-size: 20px;
+}
+
+/* 头部标题样式 */
+ion-title {
+  font-size: 20px;
+  font-weight: bold;
+  color: #2c6e4f; /* 深绿色 */
+  background-color: #ffffff; /* 头部背景色 */
+}
+
+/* 显示加载中的状态 */
+ion-spinner {
+  display: block;
+  margin: 40px auto;
+}
+
+/* 错误消息 */
+.error-message {
+  text-align: center;
+  color: #f44336; /* 错误消息为红色 */
+  font-size: 18px;
+  margin-top: 20px;
+}
+
+/* 饮食卡片样式 */
+.diet-card {
+  border-radius: 12px; /* 卡片圆角 */
+  overflow: hidden; /* 防止内容溢出 */
+  box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1); /* 轻微阴影 */
+  margin-bottom: 16px;
+  background-color: #ffffff; /* 白色背景 */
+}
+
+.diet-card-header {
+  background-color: #e6f7e6; /* 淡绿色背景 */
+  padding: 16px;
+  display: flex;
+  align-items: center;
+  border-bottom: 2px solid #4caf50; /* 绿色底边 */
+}
+
+.diet-card-title {
+  font-size: 20px;
+  font-weight: bold;
+  color: #2c6e4f; /* 深绿色 */
+  display: flex;
+  align-items: center;
+  gap: 8px; /* 图标与文字之间的间距 */
+}
+
+.diet-card-content {
+  padding: 16px;
+  color: #555;
+  font-size: 16px;
+  line-height: 1.5;
+}
+
+/* 当没有饮食规划时,按钮样式 */
+ion-button {
+  margin-top: 20px;
+  background-color: #99ffcc;
+  color: white;
+  font-weight: bold;
+  border-radius: 8px;
+  padding: 12px;
+  transition: background-color 0.3s ease;
+}
+
+ion-button:hover {
+  background-color: #e53935; /* 按钮悬停时颜色变化 */
+}
+
+/* 响应式布局调整 */
+@media (max-width: 768px) {
+  ion-header {
+    padding: 8px;
+  }
+
+  ion-title {
+    font-size: 18px;
+  }
+
+  .diet-card {
+    margin: 0 auto;
+    max-width: 90%;
+  }
+
+  .diet-card-header {
+    padding: 12px;
+  }
+
+  .diet-card-content {
+    padding: 12px;
+    font-size: 14px;
+  }
+
+  ion-button {
+    font-size: 14px;
+    padding: 10px;
+  }
+}

+ 22 - 0
smarteat-app/src/app/page-plans/page-plans.component.spec.ts

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

+ 162 - 0
smarteat-app/src/app/page-plans/page-plans.component.ts

@@ -0,0 +1,162 @@
+import { Component, OnInit } from '@angular/core';
+import { IonBackButton, IonButton, IonButtons, IonCard, IonCardContent, IonCardHeader, IonCardTitle, IonContent, IonHeader, IonIcon, IonItem, IonLabel, IonList, IonSpinner, IonText, IonTitle, IonToolbar, LoadingController, ModalController } from '@ionic/angular/standalone';
+import { addIcons } from 'ionicons';
+import { arrowUndoOutline } from 'ionicons/icons';
+import { CloudSeMealPlan } from 'src/lib/cloudplans';
+import { CloudUser } from 'src/lib/ncloud';
+import { CommonModule } from '@angular/common';  // 导入 CommonModule
+import { CloudSeUser } from 'src/lib/cloudSeuser';
+
+// 定义 MealPlan 接口
+interface MealPlan {
+  // id: string;
+  day: string;
+  breakfast: string;
+  lunch: string;
+  dinner: string;
+  notes: string;
+  mark: boolean;
+}
+
+@Component({
+  selector: 'app-page-plans',
+  templateUrl: './page-plans.component.html',
+  styleUrls: ['./page-plans.component.scss'],
+  standalone: true,
+  imports: [
+    IonHeader, IonToolbar, IonTitle, IonContent, IonCardHeader, IonCard, 
+    IonButton, IonIcon,  IonSpinner, IonText, IonCardTitle, IonCardContent,
+    CommonModule  
+  ]
+})
+export class PagePlansComponent implements OnInit {
+  
+  mealPlans: MealPlan[] = [];  // 用来存储饮食规划数据
+  loading: any;
+  errorMessage: string = '';  // 用来存储错误信息
+  planday: number = 0;
+  responseMsg: string = '';
+  responseMsg0: string = '';
+  obtain: boolean=false;
+  currentUser:CloudUser|undefined;
+  cloudSeUser: CloudSeUser;  // 引入CloudSeUser实例
+  
+  constructor(private loadingController: LoadingController, private modalCtrl: ModalController) {
+    addIcons({ arrowUndoOutline });
+    this.currentUser=new CloudUser();
+    this.cloudSeUser = new CloudSeUser();  // 实例化CloudSeUser
+  }
+
+  ngOnInit() {
+    this.loadUserData();
+    this.exportMealPlan();  // 加载饮食规划数据
+  }
+
+  async loadUserData() {
+    const cloudSeUser = new CloudSeUser();
+    const currentUserInfo = await cloudSeUser.getCurrentUserInfo();
+    
+    if (currentUserInfo) {
+      this.planday = currentUserInfo.get('planDays') || null;
+    } else {
+      console.error("未能加载当前用户信息");
+    }
+    }
+
+  // 获取用户的饮食规划数据
+  async exportMealPlan() {
+    this.loading = await this.loadingController.create({
+      message: '加载饮食规划...',
+    });
+    await this.loading.present();
+  
+    this.errorMessage = '';  // 每次加载前清空错误信息
+  
+    try {
+      const cloudSeMealPlan = new CloudSeMealPlan();
+      const cloudSeUser = new CloudSeUser();
+  
+      // 获取当前用户信息
+      const currentUser = await cloudSeUser.getCurrentUserInfo();
+      if (!currentUser) {
+        console.error("未能加载当前用户信息");
+        this.errorMessage = '未能加载当前用户信息';
+        return;
+      }
+  
+      const planDaysFromUserInfo = this.planday || 0;  // 用户的饮食计划天数
+      const plans: MealPlan[] = [];  // 存储所有饮食规划
+  
+      // 通过循环获取用户饮食计划
+      for (let i = 1; i <= planDaysFromUserInfo; i++) {
+        const mealPlanData = await cloudSeMealPlan.getMealPlanForDay(i);  // 获取第 i 天饮食计划
+        console.log("getMealPlanForDay(i)方法获取",mealPlanData)
+        if (mealPlanData && mealPlanData.data) {
+          // 使用 .get() 来访问 CloudObject 的字段
+          console.log("mealPlanData.data:", mealPlanData.data);
+          const mealPlan: MealPlan = {
+            // id: mealPlanData.id,  // CloudObject 会有 id 字段
+            day: mealPlanData.data['data']['day'] || null,
+            breakfast: mealPlanData.data['data']['breakfast'] || null,
+            lunch: mealPlanData.data['data']['lunch'] || null,
+            dinner: mealPlanData.data['data']['dinner'] || null,
+            notes: mealPlanData.data['data']['notes'] || null,
+            mark: mealPlanData.data['data']['mark'] || null
+          };
+          plans.push(mealPlan);
+        } else {
+          console.warn(`未找到第 ${i} 天的饮食计划`);
+        }
+      }
+  
+      console.log("已获取所有饮食规划:", plans);
+      
+  
+      if (plans.length === 0) {
+        this.errorMessage = '没有找到饮食规划';
+        this.obtain = false;
+      }else{
+        this.mealPlans = plans;  // 将获取到的饮食规划赋值给 mealPlans 数组
+        this.responseMsg = JSON.stringify(plans);
+        this.responseMsg0=this.responseMsg;
+    
+        // 1. 替换字段名
+        this.responseMsg0 = this.responseMsg0
+        .replace(/\bday\b/g, '日期')
+        .replace(/\bbreakfast\b/g, '早餐')
+        .replace(/\blunch\b/g, '午餐')
+        .replace(/\bdinner\b/g, '晚餐')
+        .replace(/\bnotes\b/g, '注意事项');
+
+        // 2. 将 " 后面的 , 替换为换行
+        this.responseMsg0 = this.responseMsg0.replace(/",/g, '<br>');
+
+        // 3. 将 } 后面的 , 替换为换行
+        this.responseMsg0 = this.responseMsg0.replace(/},/g, '<br>-------------------<br>');
+
+        // 4. 删除多余的空格(包括首尾空格和中间多余的空格)
+        this.responseMsg0 = this.responseMsg0.replace(/\s+/g, ' ').trim();
+
+        // 5. 删除所有的双引号、方括号、花括号
+        this.responseMsg0 = this.responseMsg0
+        .replace(/["\[\]{}]/g, ''); // 删除双引号、方括号、花括号
+        this.responseMsg0 = this.responseMsg0
+        .replace(/mark:true/g, "已打卡")
+        .replace(/mark:null/g, "未打卡");
+        this.obtain = true;
+        console.log(this.responseMsg0)
+      }
+    } catch (error) {
+      console.error('获取饮食规划失败:', error);
+      this.errorMessage = '加载饮食规划失败,请稍后再试';
+    } finally {
+      this.loading.dismiss();
+    }
+  }
+  
+
+  back() {
+    this.modalCtrl.dismiss();
+  }
+
+}

BIN
smarteat-app/src/app/tab1/image/logo.jpg


+ 13 - 26
smarteat-app/src/app/tab1/tab1.page.html

@@ -1,7 +1,7 @@
 <ion-toolbar>
       <ion-searchbar 
         class="custom-searchbar" 
-        placeholder="搜索食物、食谱、餐厅" 
+        placeholder="搜索食物、食谱" 
         show-clear-button="focus" 
         (ionInput)="setSearchQuery($event.target.value || '')" 
         (ionClear)="searchQuery = ''" 
@@ -95,38 +95,25 @@
 
   <!-- 快速入口 -->
   <ion-grid>
-    <ion-row>
-      <ion-col size="12">
-        <ion-button (click)="goToasf()">
-          <ion-icon slot="start" name="document-outline"></ion-icon>
-          健康目标管理
-        </ion-button>
-      </ion-col>
-    </ion-row>
-    <ion-row>
-      <ion-col size="12">
+
+    <ion-row class="horizontal-row">
+      <ion-col size="6">
         <ion-button (click)="goToasx()">
           <ion-icon slot="start" name="storefront-outline"></ion-icon>
           外卖推荐
         </ion-button>
       </ion-col>
+    
+    
+    
+      <ion-col size="6">
+        <ion-button (click)="goToasy()">
+          <ion-icon slot="start" name="albums-outline"></ion-icon>
+          食谱推荐
+        </ion-button>
+      </ion-col>
     </ion-row>
   </ion-grid>
 
-  <!-- 推荐食谱 -->
-  <ion-card>
-    <ion-card-header>
-      <ion-card-title>
-        <ion-icon slot="start" name="albums-outline"></ion-icon>
-        今日推荐食谱:
-        <div [innerHTML]="dishName"></div>
-      </ion-card-title>
-    </ion-card-header>
-    <ion-card-content>
-      <ion-button (click)="goToasy()">
-        查看推荐食谱
-      </ion-button>
-    </ion-card-content>
-  </ion-card>
 
 </ion-content>

+ 33 - 297
smarteat-app/src/app/tab1/tab1.page.scss

@@ -1,301 +1,23 @@
-// //   /* 设置轮播图区域 */
-// .carousel-container {
-//   position: relative;
-//   overflow: hidden;
-//   width: 100%;
-//   max-width: 600px; /* 可根据需要调整宽度 */
-//   margin: 0 auto;
-// }
-
-// //轮播图描述样式
-// .description.active {
-//   color: black;
-//   font-weight: bold;
-//   /* 确保不会隐藏描述内容 */
-//   display: block;
-//   opacity: 1; 
-//   text-align: center;
-//   display: flex;
-//   justify-content: center;
-//   align-items: center;
-//   flex-direction: column;
-// }
-
-// .carousel {
-//   display: flex;
-//   transition: transform 0.5s ease;
-// }
-
-// .slide {
-//   min-width: 100%;
-//   max-width: 100%;
-// }
-
-// .slide img {
-//   width: 100%;
-//   height: auto;
-//   border-radius: 15px;
-// }
-
-// button {
-//   position: absolute;
-//   top: 50%;
-//   transform: translateY(-50%);
-//   background: rgba(0, 0, 0, 0.5);
-//   color: #fff;
-//   border: none;
-//   padding: 10px;
-//   cursor: pointer;
-//   z-index: 10;
-// }
-
-// button.prev {
-//   left: 10px;
-// }
-
-// button.next {
-//   right: 10px;
-// }
-
-// .dots {
-//   position: absolute;
-//   bottom: 10px;
-//   left: 50%;
-//   transform: translateX(-50%);
-//   display: flex;
-//   justify-content: center;
-// }
-
-// .dot {
-//   width: 10px;
-//   height: 10px;
-//   margin: 0 5px;
-//   background-color: rgba(255, 255, 255, 0.5);
-//   border-radius: 50%;
-//   cursor: pointer;
-// }
-
-// .dot.active {
-//   background-color: #fff;
-// }
-
-
-// /* 设置所有矩形框为圆角矩形 */
-// ion-card {
-//     border-radius: 12px; /* 卡片圆角 */
-//     overflow: hidden; /* 防止内容溢出圆角边界 */
-//     box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1); /* 轻微的阴影效果 */
-//     margin-bottom: 16px; /* 卡片之间的间距 */
-//   }
-  
-//   .custom-searchbar {
-//     --background: #f8f8f8;
-//     --border-radius: 10px; // 可选:调整边角圆滑度
-//     --box-shadow: none; // 可选:去掉阴影
-//   }
-
-//   ion-card-header {
-//     // background: linear-gradient(to bottom, #ccffcc, #00ffcc);
-//     // background-color: #f8f8f8; /* 设置卡片头部背景颜色 */
-//     background: linear-gradient(to right, #ccffcc, #00ffcc), linear-gradient(to bottom, #33ffcc, white);
-//     background-blend-mode: multiply; /* 混合模式,确保两个渐变效果结合 */
-//     border-top-left-radius: 12px; /* 圆角效果 */
-//     border-top-right-radius: 12px; /* 圆角效果 */
-//   }
-  
-//   ion-card-title {
-//     font-weight: bold; /* 标题加粗 */
-//     font-size: 18px;
-//     color: #333; /* 字体颜色 */
-//   }
-  
-//   ion-card-content {
-//     padding: 16px; /* 内容的内边距 */
-//     color: #555; /* 内容字体颜色 */
-//   }
-  
-//   ion-button:hover {
-//     transform: scale(1.05); /* 按钮悬停效果 */
-//   }
-
-
-//   /* 设置所有按钮的样式 */
-//   ion-button {
-//     border-radius: 12px; /* 按钮圆角 */
-//     color: #333; /* 按钮中文字的颜色 */
-//     font-weight: bold; /* 按钮字体加粗 */
-//     text-align: center; /* 确保按钮文字水平居中 */
-//     display: flex; /* 使用 flexbox 布局 */
-//     justify-content: center; /* 水平居中 */
-//     align-items: center; /* 垂直居中 */
-//   }
-  
-  
-//   /* 设置图标的间距 */
-//   ion-icon {
-//     margin-right: 8px; /* 图标与文字之间的间距 */
-//   }
-  
-//   /* 设置搜索框的样式 */
-//   ion-searchbar {
-//     border-radius: 20px; /* 搜索框圆角 */
-//     margin: 10px 0; /* 上下间距 */
-//   }
-  
-//   /* 设置页面布局 */
-//   ion-grid {
-//     padding: 0 16px; /* 网格的内边距 */
-//   }
-  
-//   ion-row {
-//     margin-bottom: 16px; /* 行间距 */
-//   }
-  
-//   ion-col {
-//     padding: 0; /* 去掉每列的默认内边距 */
-//   }
-  
-
-// /* 卡片样式 */
-// .diet-card {
-//   border-radius: 12px; /* 卡片圆角 */
-//   box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1); /* 轻微的阴影效果 */
-//   margin: 20px auto; /* 设置上下外边距 */
-//   max-width: 700px; /* 限制最大宽度 */
-//   background-color: #fff; /* 卡片背景颜色 */
-//   transition: box-shadow 0.3s ease-in-out; /* 平滑的阴影变化 */
-// }
-
-// /* 卡片头部样式 */
-// .diet-card-header {
-//   background-color: #e6f7e6; /* 淡绿色背景 */
-//   padding: 16px 20px; /* 上下和左右内边距 */
-//   border-top-left-radius: 12px;
-//   border-top-right-radius: 12px;
-//   display: flex;
-//   align-items: center; /* 图标与文字垂直居中 */
-//   border-bottom: 2px solid #4caf50; /* 添加底部分隔线 */
-// }
-
-// /* 卡片标题样式 */
-// .diet-card-title {
-//   font-size: 20px;
-//   font-weight: bold;
-//   color: #2c6e4f; /* 深绿色 */
-//   display: flex;
-//   align-items: center; /* 图标与文字垂直居中 */
-//   gap: 8px; /* 图标与文字之间的间距 */
-// }
-
-// /* 卡片内容区域样式 */
-// .diet-card-content {
-//   padding: 16px; /* 内边距 */
-//   color: #555; /* 内容文字颜色 */
-// }
-
-// /* 外层框,包裹整个饮食规划内容 */
-// .diet-plan-container {
-//   border: 2px solid #4caf50; /* 边框颜色 */
-//   padding: 16px;
-//   border-radius: 8px;
-//   margin-bottom: 16px;
-// }
-
-// /* 每餐的框 */
-// .meal-box {
-//   border: 1px solid #4caf50; /* 每餐框的边框颜色 */
-//   padding: 12px;
-//   border-radius: 8px;
-//   margin-bottom: 12px; /* 每餐之间的间距 */
-// }
-
-// /* 早餐、午餐、晚餐的标题 */
-// .meal-title {
-//   font-size: 18px;
-//   font-weight: bold;
-//   margin-top: 10px; /* 减小顶部间距 */
-//   margin-bottom: 5px; /* 减小底部间距 */
-//   color: #4caf50; /* 绿色 */
-// }
-
-// /* 每餐的饮食内容 */
-// .meal-details {
-//   font-size: 16px;
-//   color: #333; /* 内容颜色 */
-//   line-height: 1.6; /* 增加行间距,使内容更易读 */
-//   margin-bottom: 20px; /* 每段内容的间距 */
-// }
-
-// /* 没有饮食规划的提示 */
-// .no-plan {
-//   font-size: 16px;
-//   color: #f44336; /* 红色 */
-//   text-align: center;
-//   padding: 8px;
-//   background-color: #f8d7da;
-//   border-radius: 8px;
-//   margin-bottom: 16px;
-// }
-
-// /* 底部内容区域 */
-// .diet-card-footer {
-//   padding: 16px;
-// }
-
-// /* 加载中消息的样式 */
-// .loading-msg p {
-//   font-size: 16px;
-//   color: #888; /* 灰色文字 */
-//   text-align: center; /* 文字居中 */
-//   margin-top: 10px;
-// }
-
-// /* 登录按钮的样式 */
-// .login-btn {
-//   margin-top: 20px; /* 与上一部分的间距 */
-//   display: block;
-//   width: 100%; /* 按钮宽度占满容器 */
-//   font-size: 16px; /* 按钮文字大小 */
-//   padding: 10px 0; /* 按钮上下内边距 */
-//   border-radius: 12px; /* 按钮圆角 */
-//   transition: background-color 0.3s ease, color 0.3s ease; /* 按钮的平滑过渡效果 */
-// }
-
-// /* 登录按钮的 hover 效果 */
-// .login-btn:hover {
-//   background-color: #3880ff; /* 蓝色背景 */
-//   color: white; /* 按钮文字变为白色 */
-// }
-
-// /* 小屏设备上的样式调整 */
-// @media (max-width: 768px) {
-//   .diet-card {
-//     max-width: 90%; /* 调整卡片最大宽度 */
-//   }
-
-//   .diet-card-header {
-//     padding: 12px 16px; /* 缩小内边距 */
-//   }
-
-//   .diet-card-content,
-//   .diet-card-footer {
-//     padding: 12px; /* 减少内边距 */
-//   }
-
-//   .meal-title {
-//     font-size: 16px; /* 调整字体大小 */
-//   }
-
-//   .meal-details {
-//     font-size: 14px; /* 调整字体大小 */
-//   }
-
-//   .login-btn {
-//     font-size: 14px; /* 调整按钮文字大小 */
-//     padding: 8px 0; /* 减小按钮内边距 */
-//   }
-// }
 
+/* 页面背景和基础样式 */
+ion-content {
+  --background: #fffafa;
+}
+
+/* 搜索框圆角样式 */
+.custom-searchbar {
+  --border-radius: 25px; /* 设置圆角 */
+  --background: #ffffff; /* 背景色 */
+  --padding-start: 16px; /* 内边距,适应圆角 */
+  --padding-end: 16px; /* 内边距,适应圆角 */
+  --box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1); /* 添加轻微阴影 */
+}
+
+/* 搜索框的聚焦效果(增加阴影) */
+.custom-searchbar:focus-within {
+  --box-shadow: 0 0 8px rgba(76, 175, 80, 0.6); /* 聚焦时的阴影效果 */
+  --border-color: #4caf50; /* 聚焦时的边框颜色 */
+}
 
 /* 保持轮播图相关的样式不变 */
 .carousel-container {
@@ -523,3 +245,17 @@ ion-card-content {
     padding: 8px 0; /* 减小按钮内边距 */
   }
 }
+
+.horizontal-row {
+  display: flex;          /* 使用 flexbox 排列 */
+  justify-content: space-between; /* 左右对齐 */
+  align-items: center;    /* 垂直居中对齐 */
+}
+
+.horizontal-row ion-col {
+  padding: 0;  /* 去除默认 padding */
+}
+
+ion-button {
+  width: 100%;  /* 按钮宽度为 100%,确保按钮撑满每个列 */
+}

+ 51 - 7
smarteat-app/src/app/tab1/tab1.page.ts

@@ -4,7 +4,7 @@ import { CloudSeUser } from 'src/lib/cloudSeuser'; // 引入 CloudSeUser 类
 import { FmodeChatCompletion } from 'fmode-ng'; // 引入 FmodeChatCompletion
 import { addIcons } from 'ionicons';
 import { albumsOutline, checkmarkCircleOutline, documentOutline, leafOutline, scanOutline, storefrontOutline } from 'ionicons/icons';
-import { IonButton, IonCard, IonCardContent, IonCardHeader, IonCol, IonContent, IonHeader, IonIcon, IonInput, IonRow, IonTextarea, IonTitle, IonToolbar, IonGrid, IonCardTitle, IonSearchbar, IonProgressBar,  } from '@ionic/angular/standalone'; // 导入 Ionic 组件
+import { IonButton, IonCard, IonCardContent, IonCardHeader, IonCol, IonContent, IonHeader, IonIcon, IonInput, IonRow, IonTextarea, IonTitle, IonToolbar, IonGrid, IonCardTitle, IonSearchbar, IonProgressBar, IonButtons,  } from '@ionic/angular/standalone'; // 导入 Ionic 组件
 import { CommonModule } from '@angular/common'; // 导入 CommonModule
 import { ImagePopupComponent } from '../image-popup/image-popup.component'; // 导入弹窗组件
 import { ModalController, NavController } from '@ionic/angular/standalone';
@@ -15,6 +15,9 @@ import { Image4PopupComponent } from '../image-popup/image4-popup/image4-popup.c
 import { openUserLoginModal } from 'src/lib/user/modal-user-login/modal-user-login.component';
 import { CloudQuery, CloudUser } from 'src/lib/ncloud';
 import { CloudSeMealPlan } from 'src/lib/cloudplans';
+import { MealService } from '../meal/meal.service';
+import { MealSearchComponent } from '../meal-search/meal-search/meal-search.component';
+
 
 @Component({
   selector: 'app-tab1',
@@ -24,12 +27,13 @@ import { CloudSeMealPlan } from 'src/lib/cloudplans';
   imports: [
     CommonModule, IonContent, IonHeader, IonTitle, IonToolbar, 
     IonButton, IonTextarea, IonInput, IonCard, IonCardContent, IonGrid, IonRow, IonCol, IonIcon,
-    IonCardHeader, IonCardTitle, IonSearchbar, IonProgressBar
+    IonCardHeader, IonCardTitle, IonSearchbar, IonProgressBar,IonButtons
   ],
 })
 export class Tab1Page implements OnInit {
   private cloudSeUser: CloudSeUser; // 引入 CloudSeUser 实例
   private cloudSeMealPlan: CloudSeMealPlan; // 引入 CloudSeMealPlan 实例
+  searchQuery: string = '';
 
   userInfo: any = null; // 用户信息
   responseMsg: string = ""; // 用于存储 AI 生成的饮食建议
@@ -44,6 +48,10 @@ export class Tab1Page implements OnInit {
   mark0:boolean=false;
   isComplete:boolean = false;
 
+  isLoading: boolean = false; 
+  dishName:string="";//用于存储菜品名
+  dishPhoto:string="";
+
   // 当前显示的幻灯片索引
   currentSlide: number = 0;
   currentUser:CloudUser|undefined
@@ -70,13 +78,40 @@ export class Tab1Page implements OnInit {
   ];
   
 
-  constructor(private router: Router, private modalCtrl: ModalController,) {
+  constructor(private router: Router, private modalCtrl: ModalController, private mealService: MealService,) {
     addIcons({ scanOutline, documentOutline, storefrontOutline, albumsOutline, leafOutline, checkmarkCircleOutline});
     this.cloudSeUser = new CloudSeUser();
     this.cloudSeMealPlan = new CloudSeMealPlan();
     this.currentUser=new CloudUser()
   }
 
+  //搜索框功能实现
+  // 当输入发生变化时触发
+  setSearchQuery(query: string) {
+    this.searchQuery = query;
+  }
+
+  // 点击搜索按钮时触发的搜索方法
+  async search() {
+    if (this.searchQuery.trim()) {
+      await this.openMealSearchModal();
+    }
+  }
+
+  // 打开弹窗并展示搜索结果
+  async openMealSearchModal() {
+    const modal = await this.modalCtrl.create({
+      component: MealSearchComponent,
+      componentProps: {
+        searchQuery: this.searchQuery,
+      },
+    });
+
+    await modal.present();
+  }
+//搜索框功能实现
+
+
   async ngOnInit(): Promise<void> {
     await this.loadUserData(); // 页面初始化时加载用户数据
     if (this.currentUser?.id) {
@@ -268,10 +303,6 @@ export class Tab1Page implements OnInit {
       }
     }
 
-    // setToday() {
-    //   const nextDay = new Date(this.currentDate);
-    //   this.today = nextDay.toISOString().split('T')[0];
-    //   }
 
     async check() {
     
@@ -299,5 +330,18 @@ export class Tab1Page implements OnInit {
         console.log('未找到今日饮食规划,无法打卡');
       }
     }
+
+
+    goToasy() {
+      this.router.navigate([`/tabs/asy`]);
+    }
+
+    goToasf(){
+      this.router.navigate([`/tabs/asf`]);
+    }
+
+    goToasx(){
+      this.router.navigate([`/tabs/asx`]);
+    }
     
 }

+ 1 - 1
smarteat-app/src/app/tab2/tab2.page.scss

@@ -5,7 +5,7 @@ ion-header {
   }
   
   ion-toolbar {
-    --background: #00ffcc; /* 设置工具栏背景色 */
+    --background: #99ffcc; /* 设置工具栏背景色 */
   }
   
   ion-title {

+ 52 - 4
smarteat-app/src/app/tab2/tab2.page.ts

@@ -3,9 +3,10 @@ import { CloudSeMealPlan } from 'src/lib/cloudplans'; // 引入封装好的 Clou
 import { FmodeChatCompletion, MarkdownPreviewModule } from 'fmode-ng';
 import { CloudSeUser } from 'src/lib/cloudSeuser'; // 引入 CloudSeUser 类
 
-import { IonButton, IonContent, IonHeader, IonInput, IonSelect, IonSelectOption, IonTextarea, IonTitle, IonToolbar, ModalController } from '@ionic/angular/standalone';
+import { AlertController, IonButton, IonContent, IonHeader, IonInput, IonSelect, IonSelectOption, IonTextarea, IonTitle, IonToolbar, ModalController } from '@ionic/angular/standalone';
 import { CloudUser } from 'src/lib/ncloud';
 import { openUserLoginModal } from 'src/lib/user/modal-user-login/modal-user-login.component';
+import { PageEditComponent } from '../page-edit/page-edit.component';
 @Component({
 selector: 'app-tab2',
 templateUrl: 'tab2.page.html',
@@ -19,7 +20,7 @@ MarkdownPreviewModule,
 })
 export class Tab2Page {
 
-constructor(private modalCtrl: ModalController) {
+constructor(private modalCtrl: ModalController, private alertCtrl: AlertController) {
   this.currentUser=new CloudUser();
 }
 
@@ -43,6 +44,7 @@ dietPreference: string = '';
 dietGroup: string = '';
 avatar: string | null = null;
 allergies: string = '';
+xinxi:boolean = true;
 
 responseMsg: string = "";
 responseMsg0: string = "";
@@ -65,6 +67,8 @@ if (currentUserInfo) {
   this.allergies = currentUserInfo.get('allergies') || '';
 } else {
   console.error("未能加载当前用户信息");
+  this.xinxi=false
+ 
 }
 }
 
@@ -82,8 +86,9 @@ promptInput(ev: any) {
 this.userPrompt = ev.detail.value;
 }
 
-sendMessage() {
-console.log("create");
+async sendMessage() {
+  if(this.xinxi){
+    console.log("create");
 
 this.responseMsg = "";
 this.responseMsg0="";
@@ -153,6 +158,29 @@ completion.sendCompletion().subscribe((message: any) => {
 
   }
 });
+  }else{
+     // 弹出提醒用户填写个人信息的弹窗
+  const alert = await this.alertCtrl.create({
+    header: '信息缺失',
+    message: '未能加载您的个人信息,请先填写个人信息。',
+    buttons: [
+      {
+        text: '确定',
+        handler: async () => {
+          const modal = await this.modalCtrl.create({
+            component: PageEditComponent,  // 这里是你要弹出的弹窗组件
+            cssClass: 'my-custom-class',  // 可选:自定义样式
+          });
+
+          // 显示模态框
+          await modal.present();  
+        }
+      }
+    ]
+  });
+  await alert.present();
+  }
+
 }
 
 // 保存饮食规划到数据库
@@ -182,6 +210,16 @@ try {
       // console.log(this.responseMsg)
     }
   }
+
+
+  // 显示保存成功的弹窗
+  const alert = await this.alertCtrl.create({
+    header: '成功',
+    message: '饮食规划已成功导出!',
+    buttons: ['确定']
+  });
+  await alert.present();
+
 } catch (error) {
   console.error('保存饮食规划时发生错误:', error);
 }
@@ -268,6 +306,16 @@ async exportMealPlan() {
         console.error('更新用户计划天数失败');
       }
 
+      // 显示成功导出的弹窗
+      const alert = await this.alertCtrl.create({
+        header: '成功',
+        message: '饮食规划已成功导出并保存!',
+        buttons: ['确定']
+      });
+      await alert.present();
+
+
+
     } catch (error) {
       console.error('导出饮食规划时发生错误:', error);
     }

+ 5 - 5
smarteat-app/src/app/tab3/tab3.page.html

@@ -37,7 +37,7 @@
       }
     </div>
   </ion-item>
-
+  
   <!-- 我的饮食计划 -->
     <ion-card>
       <ion-card-header>
@@ -46,7 +46,7 @@
       <ion-card-content>
         <ion-item>
           <ion-label></ion-label>
-          <ion-button expand="block" color="secondary">
+          <ion-button (click)="goToplans()" expand="block" color="secondary">
             查看详情
           </ion-button>
         </ion-item>
@@ -71,7 +71,7 @@
   
 
  
-    <ion-item button (click)="goToFavorites()">
+    <ion-item button >
       <ion-icon slot="start" name="heart-outline"></ion-icon>
       <ion-label>收藏</ion-label>
     </ion-item>
@@ -79,14 +79,14 @@
 
   <!-- 帮助与反馈按钮 -->
 
-    <ion-item button (click)="goToHelp()">
+    <ion-item button >
       <ion-icon slot="start" name="help-circle-outline"></ion-icon>
       <ion-label>帮助与反馈</ion-label>
     </ion-item>
 
   <!-- 设置按钮 -->
 
-    <ion-item button (click)="goToSettings()">
+    <ion-item button >
       <ion-icon slot="start" name="settings-outline"></ion-icon>
       <ion-label>设置</ion-label>
     </ion-item>

+ 17 - 1
smarteat-app/src/app/tab3/tab3.page.scss

@@ -1,6 +1,22 @@
+ion-header {
+  color: #333; /* 中文字的颜色 */
+  font-weight: bold; /* 按钮字体加粗 */
+  box-shadow: none;
+}
+
+ion-toolbar {
+  --background: #99ffcc; /* 设置工具栏背景色 */
+}
+
+ion-title {
+  // font-size: 1.8em;
+  font-weight: bold;
+  color: white; /* 设置标题文字颜色 */
+}
+
 /* 页面背景和基础样式 */
 ion-content {
-  --background: #f4f5f8;
+  --background: #f2f2f2;
 }
 
 /* 用户信息区 */

+ 28 - 2
smarteat-app/src/app/tab3/tab3.page.ts

@@ -7,6 +7,9 @@ import { CloudSeUser } from 'src/lib/cloudSeuser';
 import { openUserLoginModal } from 'src/lib/user/modal-user-login/modal-user-login.component';
 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 { PagePlansComponent } from '../page-plans/page-plans.component';
+import { addIcons } from 'ionicons';
+import { heartOutline, helpCircleOutline, settingsOutline } from 'ionicons/icons';
 
 interface UserInfo {
   name: string;
@@ -34,6 +37,7 @@ export class Tab3Page implements OnInit {
   };
 
   constructor(private navCtrl: NavController, private modalCtrl: ModalController) {
+    addIcons({settingsOutline, helpCircleOutline, heartOutline})
     this.currentUser=new CloudUser();
   }
   
@@ -103,8 +107,30 @@ export class Tab3Page implements OnInit {
     }
   }
 
-  goToFavorites() {
-    this.navCtrl.navigateForward('/favorites');
+  async goToplans() {
+    // 判断当前是否已登录
+  if (!this.currentUser || !this.currentUser.id) {
+    // 如果没有登录,弹出登录模态框
+    const user = await openUserLoginModal(this.modalCtrl);
+    
+    if (user?.id) {
+      // 登录成功后更新当前用户
+      this.currentUser = user;
+      // 登录后再打开 PagePlansComponent
+      this.openPlansModal();
+    }
+  } else {
+    // 如果已经登录,直接打开 PagePlansComponent
+    this.openPlansModal();
+  }
+}
+
+// 打开 PagePlansComponent 模态框
+private async openPlansModal() {
+  const modal = await this.modalCtrl.create({
+    component: PagePlansComponent,
+  });
+  await modal.present();
   }
 
   goToHelp() {

+ 36 - 0
smarteat-app/src/lib/cloudplans.ts

@@ -47,6 +47,42 @@ export class CloudSeMealPlan extends CloudObject {
     return seMealPlan;
   }
 
+
+  async getMealPlanForDay(i: number) {
+    // 获取当前登录用户的对象 ID
+    const cloudUser = new CloudUser();
+    const currentUser = await cloudUser.current();
+  
+    if (!currentUser) {
+      console.error("用户未登录");
+      return null;
+    }
+  
+    const currentUserId = currentUser.objectId;
+  
+    // 创建查询对象
+    const query = new CloudQuery("seMealPlans");
+  
+    // 通过 _User 的 objectId 查询 seMealPlans 表中的记录
+    query.equalTo("user", { "__type": "Pointer", "className": "_User", "objectId": currentUserId });
+  
+    // 同时根据 No 字段过滤第 i 天的饮食计划
+    query.equalTo("No", i);
+  
+    // 执行查询,获取匹配的饮食计划
+    const mealPlan = await query.first();
+  
+    if (!mealPlan) {
+      console.error(`未找到当前用户的第 ${i} 天饮食规划`);
+      return null;
+    }
+  
+    // 将查询结果转换为 CloudObject
+    return this.dataToObj(mealPlan);
+  }
+  
+
+
   /** 创建或保存饮食规划信息 */
   async saveMealPlan(mealPlanData: Record<string, any>) {
     const cloudUser = new CloudUser();