Browse Source

Merge branch 'master' of http://git.fmode.cn:3000/4u/workspace

19136808282 3 months ago
parent
commit
faed3c8d29

+ 11 - 18
docs-prod/schema.md

@@ -3,20 +3,7 @@
 ```plantuml
 ' 聊天项目类图英文版
 @startuml
-class ChatAdvice {
-    + objectId: String//建议标识符
-    + title:String//建议标题
-    + contnet:String//建议内容
-    + admin: Pointer<_Admin> // 关联的管理员
-}
 
-class ChatAdmin {
-    + objectId: String // 管理员唯一标识符
-    + password: String // 管理员密码
-    + email: String // 管理员邮箱
-    + realname: String // 管理员真实姓名
-    + manageUser(user: Pointer<_User>): void // 管理用户的方法
-}
 class _User { 
     + objectId: String //用户唯一标识符
     + username: String //用户名
@@ -26,7 +13,6 @@ class _User {
     + age: Number //年龄
     + email: String //用户邮箱
     + avatar: String //用户头像
-    + bio: String //用户个人简介
     + startChat(): void 
     + chooseChatPartner(): String
     + summarizeChatHistory(): void
@@ -58,17 +44,24 @@ class ChatRecord {
     + getChatHistory(): List
 }
 
-class Report {
+class ChatReport {
     + objectId: String //报告唯一标识符
-    - analysisResult: String //分析结果
+    - report: String //分析结果
     + generateReport(): String //生成报告的方法
 }
+class ChatEvaluate{
+    + objectId:String//评论唯一标识符
+    + avater:String//用户头像
+    + content:String//评论内容
+    + rating:Number//评论星星数
+    + user: Pointer<User> //关联的用户对象
+}
 
+_User "*" --> "*" ChatEvaluate
 _User "1" --> "*" ChatRecord     
 ChatPartner "1" --> "*" ChatRecord 
 ChatCompanion "1" --> "*" ChatRecord 
-ChatRecord "1" -- "1" Report
-ChatAdmin "1" --> "*" ChatAdvice      
+ChatRecord "1" --> "1" ChatReport      
 @enduml
 ```
 # 时序图

+ 12 - 0
soul-app/src/app/report-modal/report-modal.component.html

@@ -0,0 +1,12 @@
+<ion-header>
+  <ion-toolbar>
+    <ion-title>聊天记录报告</ion-title>
+    <ion-buttons slot="end">
+      <ion-button (click)="closeModal()">关闭</ion-button>
+    </ion-buttons>
+  </ion-toolbar>
+</ion-header>
+
+<ion-content>
+  <pre>{{ report }}</pre> <!-- 显示报告内容 -->
+</ion-content>

+ 12 - 0
soul-app/src/app/report-modal/report-modal.component.scss

@@ -0,0 +1,12 @@
+ion-content {
+    padding: 16px; // 增加内边距
+  }
+  
+  pre {
+    white-space: pre-wrap; // 允许换行
+    word-wrap: break-word; // 处理长单词
+  }
+  ion-header {
+    background-color: #f8f9fa;
+  }
+  

+ 24 - 0
soul-app/src/app/report-modal/report-modal.component.spec.ts

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

+ 64 - 0
soul-app/src/app/report-modal/report-modal.component.ts

@@ -0,0 +1,64 @@
+import { Component, OnInit,Input } from '@angular/core';
+import { IonButton, IonButtons, IonContent, IonHeader, IonTitle, IonToolbar, ModalController } from '@ionic/angular/standalone';
+
+@Component({
+  selector: 'app-report-modal',
+  templateUrl: './report-modal.component.html',
+  styleUrls: ['./report-modal.component.scss'],
+  standalone: true,
+  imports: [IonHeader,IonToolbar,IonTitle,
+    IonButtons,IonButton,IonContent
+  ],
+})
+export class ReportModalComponent  implements OnInit {
+
+  @Input() report: string=''; // 接收报告内容
+  @Input() consult: any; // 接收 Consult 对象
+
+  constructor(private modalCtrl: ModalController) {}
+
+  async generateReport() {
+    if (!this.consult) {
+      console.error('Consult对象未定义');
+      return;
+    }
+    let chatContent = this.consult.get('content') || [];
+    let report = "聊天记录报告\n\n";
+    
+    if (chatContent.length === 0) {
+      report += "没有聊天记录。\n\n";
+    } else {
+      chatContent.forEach((message: any, index: number) => {
+        report += `消息 ${index + 1}:\n\n`;
+        report += `内容: ${message.content}\n\n`;
+        
+        const sentiment = this.analyzeSentiment(message.content);
+        report += `心晴分析: ${sentiment}\n\n`;
+      });
+    }
+    
+    this.report = report; // 更新报告内容
+  }
+
+  analyzeSentiment(text: string): string {
+    if (text.includes("好") || text.includes("喜欢")) {
+      return "积极";
+    } else if (text.includes("坏") || text.includes("不喜欢")) {
+      return "消极";
+    } else {
+      return "中性";
+    }
+  }
+
+  closeModal() {
+    //this.modalCtrl.dismiss(); // 关闭模态框
+    this.modalCtrl.dismiss({ report: this.report }); // 关闭模态框并返回报告内容
+  }
+
+  ionViewWillEnter() {
+    this.generateReport(); // 页面进入时生成报告
+  }
+
+  ngOnInit() {}
+
+}

+ 5 - 6
soul-app/src/app/tab1/tab1.page.html

@@ -24,7 +24,7 @@
         <ion-item *ngFor="let topic of topics">
           <ion-label>
             <h2>{{ topic.title }}</h2>
-            <p>{{ topic.description }}</p>
+            <p style="font-size: 16px;">{{ topic.description }}</p>
           </ion-label>
           <ion-buttons slot="end">
           <ion-button color="primary" fill="solid" (click)="viewDetails(topic.id)">
@@ -60,14 +60,13 @@
     </ion-card-header>
     <ion-card-content>
       <ion-list>
-        <ion-item *ngFor="let review of reviews">
+        <ion-item *ngFor="let chatevaluate of chatevaluateList">
           <ion-avatar slot="start">
-            <img [src]="review.avatar" alt="用户头像"/>
+            <img [src]="chatevaluate.get('avatar') || '/assets/img/2.png'"/>
           </ion-avatar>
           <ion-label>
-            <p>{{ review.content }}</p>
-            <!--<ion-icon name="star" *ngFor="let star of [].constructor(review.rating); let i = index" [attr.aria-hidden]="true"></ion-icon>-->
-            <ion-icon name="star" *ngFor="let star of createFilledArray(review.rating); let i = index" [attr.aria-hidden]="true"></ion-icon>
+            <p style="font-size: 16px;">{{ chatevaluate.get('content') }}</p>
+            <ion-icon name="star" *ngFor="let star of createFilledArray(chatevaluate.get('rating')); let i = index" [attr.aria-hidden]="true"></ion-icon>
           </ion-label>
         </ion-item>
       </ion-list>

+ 38 - 35
soul-app/src/app/tab1/tab1.page.ts

@@ -7,6 +7,10 @@ import {  TopicDetailComponent } from '../topic-detail/topic-detail.component';
 import { Router } from '@angular/router';
 import { TopicDetail2Component } from '../topic-detail2/topic-detail2.component';
 import { TopicDetail3Component } from '../topic-detail3/topic-detail3.component';
+import { CloudObject, CloudQuery, CloudUser } from 'src/lib/ncloud';
+import { ModalController } from '@ionic/angular/standalone';
+import { openUserEvaModal } from '../user-evaluate/user-evaluate.component';
+import { openUserLoginModal } from 'src/lib/user/modal-user-login/modal-user-login.component';
 @Component({
   selector: 'app-tab1',
   templateUrl: 'tab1.page.html',
@@ -28,13 +32,6 @@ export class Tab1Page {
     console.log('搜索内容:', searchTerm);
     // 在这里添加搜索逻辑,例如过滤列表或导航到搜索结果页面
   }
-  consultants = [
-    {
-      name: '智能心理咨询师',
-      avatar: '/assets/img/2.png',
-      fields: ['焦虑', '抑郁','压力','...']
-    }
-  ];
   topics = [
     {
       id: 1,
@@ -55,27 +52,6 @@ export class Tab1Page {
       detailRoute: 'topic-detail2'
     }
   ];
-  reviews = [
-    {
-      avatar: '/assets/img/4.png',
-      content: '这款APP真的帮助了我,感谢陪聊师!',
-      rating: 4
-    },
-    {
-      avatar: '/assets/img/5.png',
-      content: '非常实用的心理咨询平台!',
-      rating: 5
-    },
-    {
-      avatar: '/assets/img/6.png',
-      content: '我喜欢这里的热门话题!',
-      rating: 5
-    }
-  ];
-
-  constructor(private router: Router) {
-    // 其他构造函数代码
-  }
   
   goPsysurvey() {
     this.router.navigate(['tabs/page-psysurvey'])
@@ -99,17 +75,44 @@ export class Tab1Page {
     // 导航到指定的路由,并可以传递参数
     this.router.navigate([`tabs/${route}`, { id: topicId }]);
   }
-
-  evaluate() {
-    // 处理点击评价的逻辑
-    console.log('用户点击了“进入评价”按钮');
-    // 您可以导航到一个新的页面来让用户填写评价,或者显示一个模态框等。
+  constructor(private router: Router,private modalCtrl: ModalController) {
+    // 其他构造函数代码
   }
+  matchedCounselor: { content: string; rating: number } | null = null;
   review: any = { rating: 5 };  // 示例数据
- 
   // 创建一个方法,用于生成填充了 null 的数组
   createFilledArray(length: number): any[] {
     return Array(length).fill(null);
   }
-  ngOnInit() {}
+  async evaluate() {
+    // 处理点击评价的逻辑
+    // 验证用户登录
+    let currentUser = new CloudUser();
+    let userPrompt = ``
+    if(!currentUser?.id){
+      console.log("用户未登录,请登录后重试")
+      let user = await openUserLoginModal(this.modalCtrl)
+      if(!user?.id){
+        console.log("用户登录失败");
+        return
+      } 
+      else {
+        console.log("当前用户ID:", currentUser.id);
+      }    
+    }
+     // 打开评价模态框
+     const evaluationResult = await openUserEvaModal(this.modalCtrl);
+     // 如果评价成功,重新加载评价列表
+     if (evaluationResult) {
+         await this.loadChatEvaluateList(); // 重新加载评价列表
+     }
+  }
+  ngOnInit() {
+    this.loadChatEvaluateList()
+  }
+  chatevaluateList:Array<CloudObject>=[]
+  async loadChatEvaluateList(){
+    let query = new CloudQuery("ChatEvaluate");
+    this.chatevaluateList = await query.find()
+  }
 }

+ 2 - 1
soul-app/src/app/tab2/tab2.page.html

@@ -12,6 +12,7 @@
   </ion-toolbar>
 </ion-header>
 
+
 <ion-content>
   <!-- 智能陪聊区 -->
   <section>
@@ -28,7 +29,7 @@
             </ion-avatar>
             <ion-label>
               <h2>{{ chatpartner.get('name') }}</h2>
-              <p style="font-size: 15px;">专业领域:{{ chatpartner.get('expertise') }}</p>
+              <p style="font-size: 16px;">专业领域:{{ chatpartner.get('expertise') }}</p>
             </ion-label>
             <ion-button slot="end" (click)="clickToConsult(chatpartner)" style="margin-left: 10px;">开始陪聊</ion-button>
           </ion-item>

+ 121 - 167
soul-app/src/app/tab2/tab2.page.ts

@@ -10,6 +10,7 @@ import { ModalController } from '@ionic/angular/standalone';
 import { CloudObject, CloudQuery, CloudUser } from 'src/lib/ncloud';
 import { openUserLoginModal } from 'src/lib/user/modal-user-login/modal-user-login.component';
 import { CustomerServiceComponent } from '../customer-service/customer-service.component';
+import { ReportModalComponent } from '../report-modal/report-modal.component';
 
 @Component({
   selector: 'app-tab2',
@@ -45,187 +46,141 @@ export class Tab2Page {
     });
     return await modal.present();
   }
-
+  private consult: any; // 这里定义你的 consult 对象
   private modalCtrl: ModalController;
   constructor(private router: Router,modalCtrl: ModalController) {
     this.modalCtrl = modalCtrl;
     // 其他构造函数代码
     this.cyclePlaceholder();
   }
-  async clickToConsult(chatpartner:CloudObject) {
-    // 验证用户登录
-    let currentUser = new CloudUser();
-    let userPrompt = ``
-    if(!currentUser?.id){
-      console.log("用户未登录,请登录后重试")
-      let user = await openUserLoginModal(this.modalCtrl)
-      if(!user?.id){
-        console.log("用户登录失败");
-        return
-      } 
-      else {
-        console.log("当前用户ID:", currentUser.id);
-      }    
-    }
-    if(currentUser?.get("username")){
-      userPrompt += `当前来访的用户,姓名:${currentUser?.get("username")}`
-    }
-    if(currentUser?.get("gender")){
-      userPrompt += `,性别:${currentUser?.get("gender")}`
-    }
-    if(currentUser?.get("age")){
-      userPrompt += `,年龄:${currentUser?.get("age")}`
-    }
-
-
-    // 弹窗形式聊天:开始聊天
-    localStorage.setItem("company","E4KpGvTEto")
-    // 创建聊天记录对象
-    let consult = new CloudObject("ChatRecord")
-    // 设置聊天记录的基本信息
-    let now = new Date();
-    let dateStr = `${now.getFullYear()}-${now.getMonth()+1}-${now.getDate()}`
-    //对象权限的精确制定
-    let ACL:any = {//公开访客 不可读 不可写
-      "*":{read:true,write:true}
-    }
-    if(currentUser?.id){//当前用户 可读 可写
-      ACL[currentUser?.id] = {read:true,write:true}
-    }
-
-    consult.set({
-      title:`${chatpartner.get('expertise') || ""}领域聊天记录${dateStr}-${chatpartner.get('name')}`,
-      chatpartner:chatpartner.toPointer(),
-      user:currentUser.toPointer(),
-      ACL:ACL,
-      content: [], // 初始内容为空
-      createdAt: now, // 可以加上创建时间
-    })
-    // 进入聊天面板
-    let options:ChatPanelOptions = {
-      roleId:"2DXJkRsjXK",
-      onChatInit: (chat: FmodeChat) => {
-        console.log("onChatInit");
-        console.log("预设角色", chat.role);
-        chat.role.set("name", chatpartner.get("name"));
-        chat.role.set("bio",chatpartner.get("bio"));
-        chat.role.set("expertise", chatpartner.get("expertise"));
-        chat.role.set("avatar", chatpartner.get("avatar") || "/assets/img/2.png")//设置陪聊师头像
-        chat.role.set("prompt", `
-        # 角色设定
-        您是${chatpartner.get("name")},一位${chatpartner.get("bio")},${chatpartner.get("expertise")},需要为用户提供陪伴和支持等积极情绪。
-        # 开始话语
-        当您准备好了,可以以一个关心用户的朋友的身份,向来访的用户打招呼。
-        # 对话环节
-        耐心积极的开导用户,给人一种暖心的感觉
-        ${userPrompt}
-        `);
-      },
-
-      onMessage: (chat: FmodeChat, message: FmodeChatMessage) => {
-        console.log("onMessage", message);
-        let content:any = message?.content
-        // 更新 consult 对象的内容
-        consult.set({
-            content: chat.messageList, // 直接存储数组
-        });
-        // 仅在内容发生变化时保存
-        consult.save()
-      },
-        // chat?.chatSession?.id 本次会话的 chatId
-        onChatSaved:(chat:FmodeChat)=>{
-        console.log("onChatSaved",chat,chat?.chatSession,chat?.chatSession?.id)
-      }
-    }
-    openChatPanelModal(this.modalCtrl,options)
-    
-  }
-
   matchedCounselor: { name: string; specialty: string } | null = null;
+  async clickToConsult(chatpartner: CloudObject) {
+      await this.initChat(chatpartner, true);
+  }
 
+  async goChat(chatcompanion: CloudObject) {
+      await this.initChat(chatcompanion, false);
+  }
 
-
-  async goChat(chatcompanion:CloudObject) {
-    // 验证用户登录
-    let currentUser = new CloudUser();
-    let userPrompt = ``
-    if(!currentUser?.id){
-      console.log("用户未登录,请登录后重试")
-      let user = await openUserLoginModal(this.modalCtrl)
-      if(!user?.id){
-        return
-      }     
-    }
-    if(currentUser?.get("username")){
-      userPrompt += `当前来访的用户,姓名:${currentUser?.get("username")}`
+  private async initChat(partner: CloudObject, isConsult: boolean) {
+      // 验证用户登录
+      let currentUser = new CloudUser();
+      let userPrompt = ``;
+      if (!currentUser?.id) {
+          console.log("用户未登录,请登录后重试");
+          let user = await openUserLoginModal(this.modalCtrl);
+          if (!user?.id) {
+              return;
+          }
+      }
+    if (currentUser?.get("username")) {
+        userPrompt += `当前来访的用户,姓名:${currentUser?.get("username")}`;
     }
-    if(currentUser?.get("gender")){
-      userPrompt += `,性别:${currentUser?.get("gender")}`
+    if (currentUser?.get("gender")) {
+        userPrompt += `,性别:${currentUser?.get("gender")}`;
     }
-    if(currentUser?.get("age")){
-      userPrompt += `,年龄:${currentUser?.get("age")}`
+    if (currentUser?.get("age")) {
+        userPrompt += `,年龄:${currentUser?.get("age")}`;
     }
-
     // 弹窗形式聊天:开始聊天
-    localStorage.setItem("company","E4KpGvTEto")
+    localStorage.setItem("company", "E4KpGvTEto");
     // 创建聊天记录对象
-    let consult = new CloudObject("ChatRecord")
+    let consult = new CloudObject("ChatRecord");
     // 设置聊天记录的基本信息
     let now = new Date();
-    let dateStr = `${now.getFullYear()}-${now.getMonth()+1}-${now.getDate()}`
-    //对象权限的精确制定
-    let ACL:any = {//公开访客 不可读 不可写
-      "*":{read:true,write:true}
-    }
-    if(currentUser?.id){//当前用户 可读 可写
-      ACL[currentUser?.id] = {read:true,write:true}
-    }
-    consult.set({
-      title:`${chatcompanion.get('expertise') || ""}领域聊天记录${dateStr}-${chatcompanion.get('name')}`,
-      chatcompanion:chatcompanion.toPointer(),
-      user:currentUser.toPointer(),
-      content: [], // 初始内容为空
-      createdAt: now, // 可以加上创建时间
-      ACL:ACL
-    })
-    let options:ChatPanelOptions = {
-      roleId:"2DXJkRsjXK",
-      onChatInit: (chat: FmodeChat) => {
-        console.log("onChatInit");
-        console.log("预设角色", chat.role);
-        chat.role.set("name", chatcompanion.get("name"));
-        chat.role.set("bio",chatcompanion.get("bio"));
-        chat.role.set("expertise", chatcompanion.get("expertise"));
-        chat.role.set("avatar", chatcompanion.get("avatar") || "/assets/img/2.png")//设置聊天伙伴头像
-        chat.role.set("prompt", `
-        # 角色设定
-        您是${chatcompanion.get("name")},一位${chatcompanion.get("bio")}的聊天伙伴,需要为用户提供陪伴和支持等积极情绪。
-        # 开始话语
-        当您准备好了,可以以一个关心用户的朋友的身份,向来访的用户打招呼。
-        # 对话环节
-        耐心与用户聊天,给人一种暖心陪伴的感觉
-        ${userPrompt}
-        `);
-      },
-      onMessage: (chat: FmodeChat, message: FmodeChatMessage) => {
-        console.log("onMessage", message);
-        let content:any = message?.content
-        // 更新 consult 对象的内容
-        consult.set({
-            content: chat.messageList, // 直接存储数组
-        });
-        // 仅在内容发生变化时保存
-        consult.save()
-      },
-        // chat?.chatSession?.id 本次会话的 chatId
-        onChatSaved:(chat:FmodeChat)=>{
-        console.log("onChatSaved",chat,chat?.chatSession,chat?.chatSession?.id)
-      }
-    }
-    openChatPanelModal(this.modalCtrl,options)
-    
-  }
-
+    let dateStr = `${now.getFullYear()}-${now.getMonth() + 1}-${now.getDate()}`;
+    // 对象权限的精确制定
+    let ACL: any = {
+        "*": { read: true, write: true }
+    };
+    this.consult.set({
+        title: `${partner.get('expertise') || ""}领域聊天记录${dateStr}-${partner.get('name')}`,
+        [isConsult ? 'chatpartner' : 'chatcompanion']: partner.toPointer(),
+        user: currentUser.toPointer(),
+        content: [], // 初始内容为空
+        createdAt: now, // 可以加上创建时间
+        ACL: ACL
+    });
+    let options: ChatPanelOptions = {
+        roleId: "2DXJkRsjXK",
+        onChatInit: (chat: FmodeChat) => {
+            console.log("onChatInit");
+            console.log("预设角色", chat.role);
+            chat.role.set("name", partner.get("name"));
+            chat.role.set("bio", partner.get("bio"));
+            chat.role.set("expertise", partner.get("expertise"));
+            chat.role.set("avatar", partner.get("avatar") || "/assets/img/2.png"); // 设置聊天伙伴头像
+            chat.role.set("prompt", `
+            # 角色设定
+            您是${partner.get("name")},一位${partner.get("bio")}的聊天伙伴,需要为用户提供陪伴和支持等积极情绪。
+            # 开始话语
+            当您准备好了,可以以一个关心用户的朋友的身份,向来访的用户打招呼
+            # 对话环节
+            耐心与用户聊天,给人一种暖心陪伴的感觉
+            ${userPrompt}
+            `);
+        },
+        onMessage: (chat: FmodeChat, message: FmodeChatMessage) => {
+            console.log("onMessage", message);
+            let content: any = message?.content;
+            // 更新 consult 对象的内容
+            consult.set({
+                content: chat.messageList, // 直接存储数组
+            });
+            // 仅在内容发生变化时保存
+            consult.save();
+        },
+        onChatSaved: (chat: FmodeChat) => {
+            console.log("onChatSaved", chat, chat?.chatSession, chat?.chatSession?.id);
+        }
+    };
+    openChatPanelModal(this.modalCtrl, options);
+}
+
+// async generateReport() {
+//   if (!this.consult) {
+//     console.error('Consult对象未定义');
+//     return;
+//   }
+//   let chatContent = this.consult.get('content') || [];
+//   // 检查 chatContent 是否有效
+//   let report = "聊天记录报告\n\n";
+//   if (chatContent.length === 0) {
+//       report += "没有聊天记录。\n\n";
+//   } else {
+//       chatContent.forEach((message: any, index: number) => {
+//           report += `消息 ${index + 1}:\n\n`;
+//           report += `内容: ${message.content}\n\n`;
+          
+//           // 假设有一个情感分析函数 analyzeSentiment
+//           const sentiment = this.analyzeSentiment(message.content);
+//           report += `心晴分析: ${sentiment}\n\n`;
+//       });
+//   }
+//   // 显示报告
+//   await this.showReportModal(report);
+//   }
+//   analyzeSentiment(text:String) {
+//     // 这里可以使用简单的关键词匹配或更复杂的模型来分析情感
+//     if (text.includes("好") || text.includes("喜欢")) {
+//         return "积极";
+//     } else if (text.includes("坏") || text.includes("不喜欢")) {
+//         return "消极";
+//     } else {
+//         return "中性";
+//     }
+//   }
+//   extractKeywords(text:String): string[] {
+//     // 这里可以实现简单的关键词提取逻辑
+//     return text.split(/\s+/).filter(word => word.length > 0); // 示例:提取长度大于0的单词
+//   }
+//   async showReportModal(report: string) {
+//     const modal = await this.modalCtrl.create({
+//       component: ReportModalComponent, // 你需要创建这个组件来显示报告
+//       componentProps: { report }
+//     });
+//     return await modal.present();
+//   }
 
   questions = [
     {
@@ -244,12 +199,10 @@ export class Tab2Page {
       expanded: false,
     },
   ];
-
   ngOnInit() {
     this.loadChatPartnerList(),
     this.loadChatCompanionList()
   }
-
   chatpartnerList:Array<CloudObject>=[]
   async loadChatPartnerList(){
     let query = new CloudQuery("ChatPartner");
@@ -260,4 +213,5 @@ export class Tab2Page {
     let query = new CloudQuery("ChatCompanion");
     this.chatcompanionList = await query.find()
   }
+
 }

+ 8 - 1
soul-app/src/app/tab3/tab3.page.html

@@ -33,7 +33,7 @@
       <ion-card-content>
       @if(!currentUser?.id){
         <div style="display: flex; justify-content: space-between;">
-          <!--<ion-button expand="block"  color="danger" (click)="signup()" style="flex: 1; margin-right: 5px;">注册</ion-button>-->
+          <ion-button expand="block"  color="danger" (click)="signup()" style="flex: 1; margin-right: 5px;">注册</ion-button>
           <ion-button expand="block"  color="danger" (click)="login()" style="flex: 1; margin-left: 5px;">登录</ion-button>
         </div>
       }
@@ -62,6 +62,13 @@
       <ion-icon name="chevron-forward-outline" slot="end"></ion-icon>
     </ion-item>
 
+    <!-- 我的报告 -->
+    <ion-item (click)="openReportModal()">
+      <ion-icon name="heart-outline" slot="start"></ion-icon>
+      <ion-label>我的报告</ion-label>
+      <ion-icon name="chevron-forward-outline" slot="end"></ion-icon>
+    </ion-item>
+
     <!-- 消息通知 -->
     <ion-item>
       <ion-icon name="notifications-outline" slot="start"></ion-icon>

+ 33 - 0
soul-app/src/app/tab3/tab3.page.ts

@@ -8,6 +8,7 @@ import { ModalController } from '@ionic/angular/standalone';
 import { openUserEditModal } from 'src/lib/user/modal-user-edit/modal-user-edit.component';
 import { openInfoModal } from '../info-modal/info-modal.component';
 import { openIdentityVerificationModal } from 'src/lib/user/modal-identity-verification/modal-identity-verification.component';
+import { ReportModalComponent } from '../report-modal/report-modal.component';
 
 @Component({
   selector: 'app-tab3',
@@ -52,4 +53,36 @@ export class Tab3Page {
   identityVerificationModal(){
     openIdentityVerificationModal(this.modalCtrl)
   }
+
+  async openReportModal() {
+    const modal = await this.modalCtrl.create({
+      component: ReportModalComponent,
+      componentProps: {
+        consult: this.getConsultData() // 传递 Consult 对象
+      }
+    });
+    
+    await modal.present();
+    const { data } = await modal.onWillDismiss();
+    if (data) {
+      console.log('生成的报告:', data.report);
+    }
+  }
+
+  getConsultData() {
+    // 这里返回 Consult 对象的逻辑
+    return {
+      get: (key: string) => {
+        // 模拟返回聊天记录
+        if (key === 'content') {
+          return [
+            { content: '我喜欢这项服务!' },
+            { content: '这真是太棒了!' },
+            { content: '我不喜欢这个选项。' }
+          ];
+        }
+        return null;
+      }
+    };
+  }
 }

+ 6 - 7
soul-app/src/app/topic-detail/topic-detail.component.html

@@ -20,15 +20,14 @@
       <ion-list-header>
         <ion-label>管理焦虑的技巧</ion-label>
       </ion-list-header>
-      <ion-item *ngFor="let tip of tips">
+      <ion-item *ngFor="let tip of tips" (click)="tip.expanded = !tip.expanded">
         <ion-label>
           <h2>{{ tip.title }}</h2>
-          <p>{{ tip.description }}</p>
+          <p style="font-size: 16px;">{{ tip.description }}</p>
+          <p *ngIf="tip.expanded" style="text-indent:2em;font-weight: bold;font-size: 16px;">{{tip.details}}</p>
         </ion-label>
-        <ion-icon name="chevron-down" slot="end" (click)="tip.expanded = !tip.expanded"></ion-icon>
-        <ion-item *ngIf="tip.expanded">
-          <ion-label>{{ tip.details }}</ion-label>
-        </ion-item>
+        <ion-icon name="chevron-down" slot="end" *ngIf="!tip.expanded"></ion-icon>
+        <ion-icon name="chevron-up" slot="end" *ngIf="tip.expanded"></ion-icon>
       </ion-item>
     </ion-list>
   </section>
@@ -42,7 +41,7 @@
       <ion-item *ngFor="let tool of tools">
         <ion-label>
           <h2>{{ tool.name }}</h2>
-          <p>{{ tool.description }}</p>
+          <p style="font-size: 16px;">{{ tool.description }}</p>
         </ion-label>
         <ion-button slot="end" [href]="tool.link">{{ tool.buttonText }}</ion-button>
       </ion-item>

+ 4 - 15
soul-app/src/app/topic-detail/topic-detail.component.ts

@@ -22,30 +22,24 @@ export class TopicDetailComponent  implements OnInit {
     {
       title: '深呼吸',
       description: '通过深呼吸来放松身心,缓解焦虑',
-      details: '深呼吸可以帮助你放慢心率,增加氧气摄入,改善心理状态',
+      details: '通过深呼吸,个体能够调节身体的生理反应,促进氧气的充分吸入,从而使身体和大脑得到放松。因此,定期进行深呼吸练习不仅能够有效缓解焦虑,还能提升整体的心理健康和情绪稳定性。',
       expanded: false,
     },
     {
       title: '运动',
       description: '规律的运动有助于释放压力和焦虑',
-      details: '运动可以释放内啡肽,提升你的情绪',
+      details: '运动可以释放内啡肽和多巴胺等“快乐激素”,改善情绪,减轻焦虑和抑郁,提升整体心理健康。总之,运动是一种全面提升身心健康的有效方式,能够帮助我们更好地应对生活中的压力与挑战。',
       expanded: false,
     },
     {
       title: '正念冥想',
-      description: '通过正念练习来关注当下,减少焦虑',
-      details: '正念冥想可以帮助你更好地管理情绪,提升专注力',
+      description: '通过正念冥想来关注当下,减少焦虑',
+      details: '正念冥想可以有效缓解焦虑和压力,帮助人们从烦恼和负面情绪中抽离出来,增强对当下的接受与理解。总之,正念冥想是一种有效的工具,可以帮助我们在快节奏的生活中找到内心的平静与平衡。',
       expanded: false,
     },
   ];
 
   tools = [
-    {
-      name: '焦虑管理APP',
-      description: '帮助你记录情绪,提供放松练习',
-      link: 'https://www.18183.com/down/2968763.html',
-      buttonText: '下载APP',
-    },
     {
       name: '在线冥想课程',
       description: '提供多种冥想练习,帮助你减轻焦虑',
@@ -65,11 +59,6 @@ export class TopicDetailComponent  implements OnInit {
       link: 'https://m.baidu.com/bh/m/detail/ar_4824212419687234431',
       buttonText: '阅读更多',
     },
-    {
-      title: '焦虑管理技巧',
-      link: 'https://www.bilibili.com/video/BV1Kj2KYJEYU/',
-      buttonText: '观看视频',
-    },
   ];
 
   discussions = [

+ 6 - 7
soul-app/src/app/topic-detail2/topic-detail2.component.html

@@ -20,15 +20,14 @@
       <ion-list-header>
         <ion-label>克服抑郁的方法</ion-label>
       </ion-list-header>
-      <ion-item *ngFor="let method of methods">
+      <ion-item *ngFor="let method of methods" (click)="method.expanded = !method.expanded">
         <ion-label>
           <h2>{{ method.title }}</h2>
-          <p>{{ method.description }}</p>
+          <p style="font-size: 16px;">{{ method.description }}</p>
+          <p *ngIf="method.expanded" style="text-indent:2em;font-weight: bold;font-size: 16px;">{{method.details}}</p>
         </ion-label>
-        <ion-icon name="chevron-down" slot="end" (click)="method.expanded = !method.expanded"></ion-icon>
-        <ion-item *ngIf="method.expanded">
-          <ion-label>{{ method.details }}</ion-label>
-        </ion-item>
+        <ion-icon name="chevron-down" slot="end" *ngIf="!method.expanded"></ion-icon>
+        <ion-icon name="chevron-up" slot="end" *ngIf="method.expanded"></ion-icon>
       </ion-item>
     </ion-list>
   </section>
@@ -42,7 +41,7 @@
       <ion-item *ngFor="let tool of tools">
         <ion-label>
           <h2>{{ tool.name }}</h2>
-          <p>{{ tool.description }}</p>
+          <p style="font-size: 16px;">{{ tool.description }}</p>
         </ion-label>
         <ion-button slot="end" [href]="tool.link">{{ tool.buttonText }}</ion-button>
       </ion-item>

+ 3 - 9
soul-app/src/app/topic-detail2/topic-detail2.component.ts

@@ -20,30 +20,24 @@ export class TopicDetail2Component  implements OnInit {
     {
       title: '寻求专业帮助',
       description: '咨询心理医生或心理治疗师,获得专业的支持和指导',
-      details: '专业的心理咨询可以帮助你更好地理解自己的情绪,并提供有效的应对策略',
+      details: '专业心理咨询师、心理医生或治疗师能够提供支持和指导,帮助个体更好地理解和处理自己的情绪和行为。寻求专业帮助还能够提供一个安全的空间,让人们自由表达自己的感受,获得理解和支持,从而更好地应对生活中的挑战。',
       expanded: false,
     },
     {
       title: '建立健康的生活方式',
       description: '保持规律的作息、均衡的饮食和适量的运动',
-      details: '健康的生活方式可以显著改善你的心理状态,增强抵抗抑郁的能力',
+      details: '健康的生活方式可以显著改善你的心理状态,增强抵抗抑郁的能力,提升情绪,促进整体身体心理健康,提升生活的积极性和幸福感',
       expanded: false,
     },
     {
       title: '与他人交流',
       description: '与朋友和家人分享你的感受,建立支持网络',
-      details: '交流可以减轻孤独感,增强社会支持,帮助你更好地应对抑郁',
+      details: '积极的社交互动有助于增强情感支持,提供理解和共鸣,让个体感受到被接纳和关心。此外,交流还能帮助人们获得不同的观点和应对策略,促进问题的解决和心理的疏导,改善整体情绪,增强对生活的积极态度。',
       expanded: false,
     },
   ];
 
   tools = [
-    {
-      name: '抑郁管理APP',
-      description: '帮助你记录情绪变化,提供自助练习',
-      link: 'https://bbs.51766.com/soft/712244.html',
-      buttonText: '下载APP',
-    },
     {
       name: '在线支持小组',
       description: '与其他抑郁症患者交流,分享经验',

+ 6 - 7
soul-app/src/app/topic-detail3/topic-detail3.component.html

@@ -20,15 +20,14 @@
       <ion-list-header>
         <ion-label>提升自信心的技巧</ion-label>
       </ion-list-header>
-      <ion-item *ngFor="let tip of tips">
+      <ion-item *ngFor="let tip of tips" (click)="tip.expanded = !tip.expanded">
         <ion-label>
           <h2>{{ tip.title }}</h2>
-          <p>{{ tip.description }}</p>
+          <p style="font-size: 16px;">{{ tip.description }}</p>
+          <p *ngIf="tip.expanded" style="text-indent:2em;font-weight: bold;font-size: 16px;">{{tip.details}}</p>
         </ion-label>
-        <ion-icon name="chevron-down" slot="end" (click)="tip.expanded = !tip.expanded"></ion-icon>
-        <ion-item *ngIf="tip.expanded">
-          <ion-label>{{ tip.details }}</ion-label>
-        </ion-item>
+        <ion-icon name="chevron-down" slot="end" *ngIf="!tip.expanded"></ion-icon>
+        <ion-icon name="chevron-up" slot="end" *ngIf="tip.expanded"></ion-icon>
       </ion-item>
     </ion-list>
   </section>
@@ -42,7 +41,7 @@
       <ion-item *ngFor="let tool of tools">
         <ion-label>
           <h2>{{ tool.name }}</h2>
-          <p>{{ tool.description }}</p>
+          <p style="font-size: 16px;">{{ tool.description }}</p>
         </ion-label>
         <ion-button slot="end" [href]="tool.link">{{ tool.buttonText }}</ion-button>
       </ion-item>

+ 3 - 9
soul-app/src/app/topic-detail3/topic-detail3.component.ts

@@ -21,30 +21,24 @@ export class TopicDetail3Component  implements OnInit {
     {
       title: '设定小目标',
       description: '通过设定并完成小目标来增强自信心。',
-      details: '每完成一个小目标,都会增强你的成就感。',
+      details: '通过制定具体、可实现的小目标,个体可以逐步体验到成功感和成就感,这有助于提升自信心和自我效能感。通过这种方式,设定小目标不仅有助于缓解抑郁症状,还能促进积极的生活态度和心理健康。',
       expanded: false,
     },
     {
       title: '积极自我对话',
       description: '通过积极的自我对话来改变消极思维。',
-      details: '用积极的语言鼓励自己,提升自我肯定感。',
+      details: '通过积极的自我对话个体可以增强自我肯定,减少自我怀疑,改善情绪,提升整体的心理健康水平,帮助个体在面对挑战时保持积极的心态,促进心理韧性,帮助个体更好地应对生活中的挑战与困难',
       expanded: false,
     },
     {
       title: '练习身体语言',
       description: '通过开放的身体语言来传达自信。',
-      details: '站直、微笑和保持眼神接触可以帮助你感到更自信。',
+      details: '可以传达自信和开放的态度,帮助个体在社交场合中显得更加自信,还能改善沟通能力,帮助个体更好地表达自己的情感和意图,促进积极的人际互动,对个人的心理健康和社会适应能力具有积极的影响',
       expanded: false,
     },
   ];
 
   tools = [
-    {
-      name: '自信心提升APP',
-      description: '提供每日自信心练习和积极的提醒。',
-      link: 'https://www.liqucn.com/rj/9679961013722.shtml',
-      buttonText: '下载APP',
-    },
     {
       name: '在线视频',
       description: '学习更多关于自信心提升的技巧。',

+ 34 - 0
soul-app/src/app/user-evaluate/user-evaluate.component.html

@@ -0,0 +1,34 @@
+<!-- 用户登录状态 -->
+<ion-card>
+  <ion-card-header>
+    <ion-card-title>
+      用户名:{{currentUser?.get("username")}}
+    </ion-card-title>
+    <ion-card-subtitle >请输入您的评论信息</ion-card-subtitle>
+   </ion-card-header>
+ <ion-card-content>
+
+  <ion-item>
+    <ion-input 
+      [value]="userData['content']" 
+      (ionChange)="userDataChange('content', $event)" 
+      label="评价内容" 
+      placeholder="请您输入评价内容"></ion-input>
+  </ion-item>
+  <ion-item>
+    <ion-input 
+      type="number" 
+      [value]="userData['rating']" 
+      (ionChange)="userDataChange('rating', $event)" 
+      label="星星数量" 
+      placeholder="请您输入星星数量(1-5)" 
+      min="1" 
+      max="5"></ion-input>
+  </ion-item>
+
+   <ion-button expand="block" color="danger" (click)="save()">保存</ion-button>
+   <ion-button expand="block" color="danger" (click)="cancel()">取消</ion-button>
+ 
+
+  </ion-card-content>
+</ion-card>

+ 0 - 0
soul-app/src/app/user-evaluate/user-evaluate.component.scss


+ 22 - 0
soul-app/src/app/user-evaluate/user-evaluate.component.spec.ts

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

+ 72 - 0
soul-app/src/app/user-evaluate/user-evaluate.component.ts

@@ -0,0 +1,72 @@
+import { Component, OnInit } from '@angular/core';
+import { ModalController } from '@ionic/angular/standalone';
+import { IonButton, IonCard, IonCardContent, IonCardHeader, IonCardSubtitle, IonCardTitle, 
+  IonContent, IonHeader, IonInput, IonItem, IonLabel, IonSegment, IonSegmentButton,
+   IonTitle, IonToolbar } from '@ionic/angular/standalone';
+import { CloudEvaluate, CloudUser } from 'src/lib/ncloud';
+
+@Component({
+  selector: 'app-user-evaluate',
+  templateUrl: './user-evaluate.component.html',
+  styleUrls: ['./user-evaluate.component.scss'],
+  standalone: true,
+  imports: [IonHeader, IonToolbar, IonTitle, IonContent, 
+    IonCard,IonCardContent,IonButton,IonCardHeader,IonCardTitle,IonCardSubtitle,
+    IonInput,IonItem,
+    IonSegment,IonSegmentButton,IonLabel
+  ],
+})
+export class UserEvaluateComponent  implements OnInit {
+
+  currentUser: CloudUser | undefined;
+  userData: any = {
+    content: '',
+    rating: 0,
+  };
+
+  constructor(private modalCtrl: ModalController) { 
+    this.currentUser = new CloudUser();
+  }
+
+  userDataChange(key: string, ev: any) {
+    let value = ev?.detail?.value;
+    if (value) {
+      this.userData[key] = value;
+    }
+  }
+
+  async save() {
+    // 确保 currentUser 是有效的 CloudUser 实例
+    if (!this.currentUser) {
+      console.error('当前用户未登录或未定义');
+      return; // 退出保存方法
+    }
+    const cloudEvaluate = new CloudEvaluate(this.userData, this.currentUser, this.modalCtrl);
+    const result = await cloudEvaluate.save(); // 调用 CloudEvaluate 的 save 方法
+    if (!result) {
+      console.error('评价保存失败');
+    }
+  }
+
+  cancel() {
+    this.modalCtrl.dismiss(null, "cancel");
+  }
+
+  ngOnInit() {}
+}
+  export async function openUserEvaModal(modalCtrl:ModalController):Promise<CloudUser|null>{
+    const modal = await modalCtrl.create({
+      component: UserEvaluateComponent,
+      breakpoints:[0.5,0.7],
+      initialBreakpoint:0.5
+    });
+    modal.present();
+  
+    const { data, role } = await modal.onWillDismiss();
+  
+    if (role === 'confirm') {
+      return data;
+    }
+    return null
+
+}

+ 51 - 2
soul-app/src/lib/ncloud.ts

@@ -28,8 +28,6 @@ export class CloudObject {
     }
 
     async save() {
-        console.log('Class Name:', this.className);
-        console.log('Object ID:', this.id);
         let method = "POST";
         let url = `http://dev.fmode.cn:1337/parse/classes/${this.className}`;
 
@@ -373,4 +371,55 @@ export class CloudUser extends CloudObject {
         localStorage.setItem("NCloud/dev/User",JSON.stringify(this.data))
         return this;
     }
+}
+
+// CloudEvaluate.ts
+export class CloudEvaluate extends CloudObject {
+    userData: Record<string, any>;
+    currentUser: CloudUser; // 添加当前用户的引用
+    modalCtrl: any; // 假设 modalCtrl 是通过构造函数传入的
+
+    constructor(userData: Record<string, any>, currentUser: CloudUser,modalCtrl: any) {
+        super("_ChatEvaluate"); 
+        this.userData = userData; // 保存用户评价数据
+        this.currentUser = currentUser; // 保存当前用户
+        this.modalCtrl = modalCtrl; // 保存模态控制器
+    }
+
+    /** 保存评价 */
+    override async save() {
+        // 确保 rating 是数字类型
+        if (this.userData['rating']) {
+            this.userData['rating'] = Number(this.userData['rating']);
+        }
+        console.log('保存评价被调用'); // 调试日志
+
+        // 调用后端 API 保存评价
+        const response = await fetch(`http://dev.fmode.cn:1337/parse/classes/ChatEvaluate`, {
+            headers: {
+                "x-parse-application-id": "dev",
+                "Content-Type": "application/json"
+            },
+            body: JSON.stringify({
+                content: this.userData['content'],
+                rating: this.userData['rating'],
+                avatar: this.currentUser.data?.['avatar'], // 假设用户头像存储在 data.avatar 中
+                user: { __type: "Pointer", className: "_User", objectId: this.currentUser.id } // 添加用户指针
+            }),
+            method: "POST"
+        });
+
+        const result = await response.json();
+        console.log('保存结果:', result); // 输出保存结果
+
+        if (result?.error) {
+            console.error(result?.error);
+            console.error('评价保存失败');
+            return null;
+        }
+
+        console.log('评价保存成功:', result);
+        this.modalCtrl.dismiss(result, "confirm"); // 关闭模态框并传递结果
+        return result; // 返回保存的结果
+    }
 }