2 Commits ee214ed392 ... 30e3263cee

Autor SHA1 Mensagem Data
  202226701046 30e3263cee 随机食谱生成 7 meses atrás
  202226701046 3ee1c3765c temp 7 meses atrás

+ 11 - 0
smarteat-app/src/app/app.module.ts

@@ -0,0 +1,11 @@
+import { NgModule } from '@angular/core';
+import { BrowserModule } from '@angular/platform-browser';
+import { AppComponent } from './app.component';
+import { NewlineToBrPipe } from './newline-to-br.pipe';  // 导入管道
+
+@NgModule({
+  declarations: [AppComponent, NewlineToBrPipe],  // 声明管道
+  imports: [BrowserModule],
+  bootstrap: [AppComponent],
+})
+export class AppModule {}

+ 4 - 0
smarteat-app/src/app/asf/asf.component.html

@@ -0,0 +1,4 @@
+<p>
+  asf works!
+  <img src="https://app.fmode.cn/dev/jxnu/202226701038/boluogulaorou.jpeg" alt="">
+</p>

+ 0 - 0
smarteat-app/src/app/asf/asf.component.scss


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

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

+ 15 - 0
smarteat-app/src/app/asf/asf.component.ts

@@ -0,0 +1,15 @@
+import { Component, OnInit } from '@angular/core';
+
+@Component({
+  selector: 'app-asf',
+  templateUrl: './asf.component.html',
+  styleUrls: ['./asf.component.scss'],
+  standalone: true,
+})
+export class AsfComponent  implements OnInit {
+
+  constructor() { }
+
+  ngOnInit() {}
+
+}

+ 3 - 0
smarteat-app/src/app/asx/asx.component.html

@@ -0,0 +1,3 @@
+<p>
+  asx works!
+</p>

+ 0 - 0
smarteat-app/src/app/asx/asx.component.scss


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

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

+ 15 - 0
smarteat-app/src/app/asx/asx.component.ts

@@ -0,0 +1,15 @@
+import { Component, OnInit } from '@angular/core';
+
+@Component({
+  selector: 'app-asx',
+  templateUrl: './asx.component.html',
+  styleUrls: ['./asx.component.scss'],
+  standalone: true,
+})
+export class AsxComponent  implements OnInit {
+
+  constructor() { }
+
+  ngOnInit() {}
+
+}

+ 32 - 0
smarteat-app/src/app/asy/asy.component.html

@@ -0,0 +1,32 @@
+<ion-header>
+  <ion-toolbar>
+    <ion-title>{{ dishDetails.title }}</ion-title>
+  </ion-toolbar>
+</ion-header>
+
+<ion-content>
+  <ion-card>
+    <ion-card-header>
+      <ion-card-title>{{ dishDetails.title }}</ion-card-title>
+    </ion-card-header>
+    <ion-card-content>
+      <!-- 食谱图片 -->
+      <ion-img [src]="dishDetails.image_url">
+        <!-- 使用备用的 <img> 元素来处理 alt 属性 -->
+        <img [src]="dishDetails.image_url" [alt]="dishDetails.title">
+      </ion-img>
+      
+      <!-- 食材 -->
+      <h3>食材:</h3>
+      <p [innerHTML]="dishDetails.ingredient"></p> <!-- 使用 [innerHTML] 渲染带 <br> 的 HTML -->
+
+      <!-- 制作方法 -->
+      <h3>制作方法:</h3>
+      <p [innerHTML]="dishDetails.instructions"></p> <!-- 使用 [innerHTML] 渲染带 <br> 的 HTML -->
+
+      <!-- 小贴士 -->
+      <h3>小贴士:</h3>
+      <p [innerHTML]="dishDetails.tips"></p> <!-- 使用 [innerHTML] 渲染带 <br> 的 HTML -->
+    </ion-card-content>
+  </ion-card>
+</ion-content>

+ 0 - 0
smarteat-app/src/app/asy/asy.component.scss


+ 26 - 0
smarteat-app/src/app/asy/asy.component.spec.ts

@@ -0,0 +1,26 @@
+import { ComponentFixture, TestBed, waitForAsync } from '@angular/core/testing';
+
+import { AsyComponent } from './asy.component';
+import { NewlineToBrPipe } from '.././newline-to-br.pipe';  // 导入管道
+
+
+describe('AsyComponent', () => {
+  let component: AsyComponent;
+  let fixture: ComponentFixture<AsyComponent>;
+
+  beforeEach(waitForAsync(() => {
+    TestBed.configureTestingModule({
+      imports: [AsyComponent],
+    }).compileComponents();
+
+    fixture = TestBed.createComponent(AsyComponent);
+    component = fixture.componentInstance;
+    fixture.detectChanges();
+  }));
+
+  it('should create', () => {
+    expect(component).toBeTruthy();
+  });
+});
+
+

+ 54 - 0
smarteat-app/src/app/asy/asy.component.ts

@@ -0,0 +1,54 @@
+import { Component, OnInit } from '@angular/core';
+import { CloudShipu } from '../../lib/cloudshipu';  // 引入 CloudShipu 类
+import { IonButton } from '@ionic/angular/standalone';
+import { CloudQuery } from 'src/lib/ncloud';
+import { NewlineToBrPipe } from '.././newline-to-br.pipe';  // 导入管道
+import { IonicModule } from '@ionic/angular';  // 确保导入 IonicModule
+import { sanitizeIdentifier } from '@angular/compiler';
+
+@Component({
+  selector: 'app-asy',
+  templateUrl: './asy.component.html',
+  styleUrls: ['./asy.component.scss'],
+  standalone: true,
+  imports: [
+    IonButton,
+    IonicModule
+  ],
+})
+export class AsyComponent  implements OnInit {
+
+  private CloudShipu: CloudShipu =new CloudShipu(); // 引入 CloudShipu 实例
+  private shipuData: any = null; // 信息
+
+    // 定义存储食谱详细信息的变量
+    dishDetails: any = {
+      title: '',
+      image_url: '',
+      ingredient: '',
+      instructions: '',
+      tips: '',
+    };
+
+  async ngOnInit(): Promise<void> {
+    await this.loadUserData(); // 页面初始化时加载用户数据
+    console.log(this.shipuData)
+    const randomIndex = Math.floor(Math.random() * this.shipuData.length);
+
+    // 访问这个随机索引的元素
+    this.dishDetails = this.shipuData[randomIndex].data;
+    // this.dishDetails = this.shipuData[1].data
+  }
+  
+  async loadUserData() {
+    try {
+        this.shipuData = await this.CloudShipu.getAllShipu();
+        
+    } catch (error) {
+        console.error('加载用户数据失败', error);
+    }
+  }
+
+  
+}
+

+ 2 - 1
smarteat-app/src/app/image-popup/image1-popup/image1-popup.component.ts

@@ -1,7 +1,8 @@
 import { HttpClient } from '@angular/common/http';
 import { Component, Input } from '@angular/core';
 import { IonButton, IonButtons, IonContent, IonHeader, IonIcon, IonTitle, IonToolbar, ModalController } from '@ionic/angular/standalone';
-import mammoth from 'mammoth';  // 引入 mammoth 库
+import * as mammoth from 'mammoth';
+
 @Component({
   selector: 'app-image1-popup',
   templateUrl: './image1-popup.component.html',

+ 8 - 0
smarteat-app/src/app/newline-to-br.pipe.spec.ts

@@ -0,0 +1,8 @@
+import { NewlineToBrPipe } from './newline-to-br.pipe';
+
+describe('NewlineToBrPipe', () => {
+  it('create an instance', () => {
+    const pipe = new NewlineToBrPipe();
+    expect(pipe).toBeTruthy();
+  });
+});

+ 13 - 0
smarteat-app/src/app/newline-to-br.pipe.ts

@@ -0,0 +1,13 @@
+import { Pipe, PipeTransform } from '@angular/core';
+
+@Pipe({
+  name: 'newlineToBr',
+  standalone: true
+})
+export class NewlineToBrPipe implements PipeTransform {
+
+  transform(value: unknown, ...args: unknown[]): unknown {
+    return null;
+  }
+
+}

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

@@ -54,7 +54,7 @@
   <ion-grid>
     <ion-row>
       <ion-col size="12">
-        <ion-button>
+        <ion-button (click)="goToasf()">
           <ion-icon slot="start" name="document-outline"></ion-icon>
           健康目标管理
         </ion-button>
@@ -62,7 +62,7 @@
     </ion-row>
     <ion-row>
       <ion-col size="12">
-        <ion-button>
+        <ion-button (click)="goToasx()">
           <ion-icon slot="start" name="storefront-outline"></ion-icon>
           外卖推荐
         </ion-button>
@@ -75,14 +75,14 @@
     <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)="viewRecommendedRecipes()">
+      <ion-button (click)="goToasy()">
         查看推荐食谱
       </ion-button>
-      <p>{{ recipeMsg }}</p> <!-- 显示 AI 生成的推荐食谱 -->
     </ion-card-content>
   </ion-card>
 </ion-content>

+ 15 - 26
smarteat-app/src/app/tab1/tab1.page.ts

@@ -32,6 +32,8 @@ export class Tab1Page implements OnInit {
   userInfo: any = null; // 用户信息
   responseMsg: string = ""; // 用于存储 AI 生成的饮食建议
   recipeMsg: string = ""; // 用于存储 AI 生成的推荐食谱
+  dishName:string="";//用于存储菜品名
+  dishPhoto:string="";
 
   // 存储图片的数组
   images = [
@@ -117,30 +119,6 @@ export class Tab1Page implements OnInit {
     });
   }
 
-  // 查看推荐食谱
-  async viewRecommendedRecipes() {
-    if (!this.userInfo) return;
-
-    const { height, weight, activityLevel, dietPreference, dietGroup } = this.userInfo;
-    const newPrompt = `
-      你是一名专业的饮食营养规划师。根据以下用户信息,请推荐今日的食谱:
-      身高:${height} cm
-      体重:${weight} kg
-      活动水平:${activityLevel}
-      饮食偏好:${dietPreference}
-      饮食类型:${dietGroup}
-    `;
-
-    const completion = new FmodeChatCompletion([
-      { role: "system", content: "" },
-      { role: "user", content: newPrompt }
-    ]);
-
-    completion.sendCompletion().subscribe((message: any) => {
-      console.log(message.content);
-      this.recipeMsg = message.content; // 更新推荐食谱
-    });
-  }
 
   // 打开弹窗
   async openImagePopup(imageUrl: string, description: string) {
@@ -207,6 +185,18 @@ export class Tab1Page implements OnInit {
       this.router.navigate([`/tabs/tips`]);
     }
 
+    goToasy() {
+      this.router.navigate([`/tabs/asy`]);
+    }
+
+    goToasf(){
+      this.router.navigate([`/tabs/asf`]);
+    }
+
+    goToasx(){
+      this.router.navigate([`/tabs/asx`]);
+    }
+
     async login(){
       // 弹出登录窗口
       let user = await openUserLoginModal(this.modalCtrl);
@@ -215,5 +205,4 @@ export class Tab1Page implements OnInit {
         await this.loadUserData();// 登录后加载用户信息
       }
     }
-  }
-  
+  }

+ 15 - 0
smarteat-app/src/app/tabs/tabs.routes.ts

@@ -31,6 +31,21 @@ export const routes: Routes = [
         loadComponent: () =>
           import('../health-tips/health-tips.component').then((m) => m.HealthTipsComponent),
       },
+      {
+        path: 'asy',
+        loadComponent: () =>
+          import('../asy/asy.component').then((m) => m.AsyComponent),
+      },
+      {
+        path: 'asf',
+        loadComponent: () =>
+          import('../asf/asf.component').then((m) => m.AsfComponent),
+      },
+      {
+        path: 'asx',
+        loadComponent: () =>
+          import('../asx/asx.component').then((m) => m.AsxComponent),
+      },
       {
         path: '',
         redirectTo: '/tabs/tab1',

+ 133 - 0
smarteat-app/src/lib/cloudshipu.ts

@@ -0,0 +1,133 @@
+import { CloudObject } from "./ncloud";
+
+export class CloudShipu extends CloudObject {
+    constructor() {
+        super("seshipu"); // 假设 seshipu 类在 Parse 中是 "seshipu"
+    }
+
+    /** 获取所有 `seshipu` 信息 */
+    async getAllShipu() {
+        const url = "http://dev.fmode.cn:1337/parse/classes/seshipu";
+
+        const response = await fetch(url, {
+            headers: {
+                "accept": "*/*",
+                "accept-language": "zh-CN,zh;q=0.9",
+                "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 result.results.map((item: any) => this.dataToObj(item)); // 假设返回的数据在 `results` 字段中
+    }
+
+    /** 获取单个 `seshipu` 信息 */
+    async getShipu(id: string) {
+        const url = `http://dev.fmode.cn:1337/parse/classes/seshipu/${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);
+    }
+
+    /** 创建 `seshipu` 信息 */
+    async saveShipuInfo(shipuData: Record<string, any>) {
+        const url = `http://dev.fmode.cn:1337/parse/classes/seshipu`;
+
+        const response = await fetch(url, {
+            headers: {
+                "Content-Type": "application/json",
+                "x-parse-application-id": "dev"
+            },
+            method: "POST",
+            body: JSON.stringify(shipuData),
+            mode: "cors",
+            credentials: "omit"
+        });
+
+        const result = await response?.json();
+        if (result?.error) {
+            console.error(result?.error);
+            return null;
+        }
+
+        return this.dataToObj(result);
+    }
+
+    /** 更新 `seshipu` 信息 */
+    async updateShipuInfo(id: string, updatedData: Record<string, any>) {
+        const url = `http://dev.fmode.cn:1337/parse/classes/seshipu/${id}`;
+
+        const response = await fetch(url, {
+            headers: {
+                "Content-Type": "application/json",
+                "x-parse-application-id": "dev"
+            },
+            method: "PUT",
+            body: JSON.stringify(updatedData),
+            mode: "cors",
+            credentials: "omit"
+        });
+
+        const result = await response?.json();
+        if (result?.error) {
+            console.error(result?.error);
+            return null;
+        }
+
+        return this.dataToObj(result);
+    }
+
+    /** 删除 `seshipu` 信息 */
+    async deleteShipuInfo(id: string) {
+        const url = `http://dev.fmode.cn:1337/parse/classes/seshipu/${id}`;
+
+        const response = await fetch(url, {
+            headers: {
+                "x-parse-application-id": "dev"
+            },
+            method: "DELETE",
+            mode: "cors",
+            credentials: "omit"
+        });
+
+        const result = await response?.json();
+        if (result?.error) {
+            console.error(result?.error);
+            return false;
+        }
+
+        return true;
+    }
+
+    /** 将查询结果转换为 CloudObject */
+    private dataToObj(result: any): CloudObject {
+        let shipuObject = new CloudObject(this.className);
+        shipuObject.set(result);
+        shipuObject.id = result.objectId;
+        shipuObject.createdAt = result.createdAt;
+        shipuObject.updatedAt = result.updatedAt;
+        return shipuObject;
+    }
+}

+ 63 - 0
smarteat-app/src/lib/import-data.js

@@ -72,4 +72,67 @@ fetch("http://dev.fmode.cn:1337/parse/classes/seUser?", {
     "method": "DELETE",
     "mode": "cors",
     "credentials": "omit"
+  });
+
+
+
+
+  fetch("http://dev.fmode.cn:1337/parse/classes/seshipu?", {
+    "headers": {
+      "accept": "*/*",
+      "accept-language": "zh-CN,zh;q=0.9",
+      "x-parse-application-id": "dev"
+    },
+    "referrer": "http://127.0.0.1:4040/",
+    "referrerPolicy": "strict-origin-when-cross-origin",
+    "body": null,
+    "method": "GET",
+    "mode": "cors",
+    "credentials": "omit"
+  });
+
+  fetch("http://dev.fmode.cn:1337/parse/classes/seshipu", {
+    "headers": {
+      "accept": "*/*",
+      "accept-language": "zh-CN,zh;q=0.9",
+      "content-type": "text/plain;charset=UTF-8",
+      "x-parse-application-id": "dev"
+    },
+    "referrer": "http://127.0.0.1:4040/",
+    "referrerPolicy": "strict-origin-when-cross-origin",
+    "body": "",
+    "method": "POST",
+    "mode": "cors",
+    "credentials": "omit"
+  });
+
+
+  fetch("http://dev.fmode.cn:1337/parse/classes/seshipu", {
+    "headers": {
+      "accept": "*/*",
+      "accept-language": "zh-CN,zh;q=0.9",
+      "content-type": "text/plain;charset=UTF-8",
+      "x-parse-application-id": "dev"
+    },
+    "referrer": "http://127.0.0.1:4040/",
+    "referrerPolicy": "strict-origin-when-cross-origin",
+    "body": "",
+    "method": "PUT",
+    "mode": "cors",
+    "credentials": "omit"
+  });
+
+
+  fetch("http://dev.fmode.cn:1337/parse/classes/seshipu", {
+    "headers": {
+      "accept": "*/*",
+      "accept-language": "zh-CN,zh;q=0.9",
+      "x-parse-application-id": "dev"
+    },
+    "referrer": "http://127.0.0.1:4040/",
+    "referrerPolicy": "strict-origin-when-cross-origin",
+    "body": null,
+    "method": "DELETE",
+    "mode": "cors",
+    "credentials": "omit"
   });