Эх сурвалжийг харах

feat :data.js and update :tab2 page

cainiao-hue 4 сар өмнө
parent
commit
e41659d3da

+ 9 - 9
docs-prod/schema.md

@@ -3,11 +3,11 @@
 ' 聊天项目类图英文版
 @startuml
 class User { 
-    + userID: String //用户唯一标识符
-    + username: String //用户名
+    + objectId: String //用户唯一标识符
+    + name: String //用户名
     + password: String //用户密码
     + email: String //用户邮箱
-    + avatar: String //用户头像URL
+    + avatar: String //用户头像
     + bio: String //用户个人简介
     + startChat(): void 
     + chooseChatPartner(): String
@@ -16,27 +16,27 @@ class User {
 
 ' Store information about chat partners
 class ChatPartner {
-    + partnerID: String //陪聊师唯一标识符
+    + objectId: String //陪聊师唯一标识符
     + name: String //陪聊师姓名
     + expertise: String //陪聊师专业领域(普通陪聊师可为空)
-    + avatar: String //陪聊师头像URL
+    + avatar: String //陪聊师头像
     + bio: String //陪聊师个人简介
     + provideChat(): String 
 }
 
 ' Record chat history between users and chat partners
 class ChatRecord {
-    + recordID: String //聊天记录唯一标识符
+    + objectId: String //聊天记录唯一标识符
     + timestamp: Date //聊天时间戳
     - chatContent: List //聊天内容列表
-    + user: User //关联的用户对象
-    + chatBot: ChatBot //关联的聊天机器人对象
+    + user: Pointer<User> //关联的用户对象
+    + chatpartner: Pointer<ChatPartner> //关联的聊天机器人对象
     + getChatHistory(): List
 }
 
 ' Record generated reports
 class Report {
-    + reportID: String //报告唯一标识符
+    + objectId: String //报告唯一标识符
     - analysisResult: String //分析结果
     + generateReport(): String //生成报告的方法
 }

+ 4 - 4
soul-app/package-lock.json

@@ -22,7 +22,7 @@
         "@capacitor/keyboard": "6.0.3",
         "@capacitor/status-bar": "6.0.2",
         "@ionic/angular": "^8.0.0",
-        "fmode-ng": "^0.0.62",
+        "fmode-ng": "^0.0.63",
         "ionicons": "^7.2.1",
         "rxjs": "~7.8.0",
         "tslib": "^2.3.0",
@@ -10378,9 +10378,9 @@
       "license": "ISC"
     },
     "node_modules/fmode-ng": {
-      "version": "0.0.62",
-      "resolved": "https://registry.npmmirror.com/fmode-ng/-/fmode-ng-0.0.62.tgz",
-      "integrity": "sha512-F0RzEu47NgKpaHp/vBEzjsU4efJ1lKLAbbdPE5hltj1W1cDaeht/i6UlEidid4FAEdAg7c9rrQrLgOh/zUfCsg==",
+      "version": "0.0.63",
+      "resolved": "https://registry.npmmirror.com/fmode-ng/-/fmode-ng-0.0.63.tgz",
+      "integrity": "sha512-gTiDZO2CchcTYAmlaweapasqV/8PdhG2vizJNn5dYZyXjgtrjyW+KeW5k2EVyIDvM1+bMGjjhGmr76Fc0TElxw==",
       "license": "COPYRIGHT © 未来飞马 未来全栈 www.fmode.cn All RIGHTS RESERVED",
       "dependencies": {
         "tslib": "^2.3.0"

+ 1 - 1
soul-app/package.json

@@ -27,7 +27,7 @@
     "@capacitor/keyboard": "6.0.3",
     "@capacitor/status-bar": "6.0.2",
     "@ionic/angular": "^8.0.0",
-    "fmode-ng": "^0.0.62",
+    "fmode-ng": "^0.0.63",
     "ionicons": "^7.2.1",
     "rxjs": "~7.8.0",
     "tslib": "^2.3.0",

+ 4 - 4
soul-app/src/app/tab2/tab2.page.html

@@ -23,13 +23,13 @@
         <ion-list>
           <ion-item *ngFor="let consultant of consultants">
             <ion-avatar slot="start">
-              <img [src]="consultant.avatar" alt="{{ consultant.name }}"/>
+              <img [src]="consultant.avatar" alt="{{ consultant.title }}"/>
             </ion-avatar>
             <ion-label>
-              <h2>{{ consultant.name }}</h2>
-              <p>{{ consultant.fields.join(', ') }}</p>
+              <h2>{{ consultant.title }}</h2>
+              <p>{{ consultant.tags.join(', ') }}</p>
             </ion-label>
-            <ion-button slot="end" (click)="clickToConsult()">开始陪聊</ion-button>
+            <ion-button slot="end" (click)="clickToConsult(consultant)">开始陪聊</ion-button>
           </ion-item>
         </ion-list>
       </ion-card-content>

+ 42 - 13
soul-app/src/app/tab2/tab2.page.ts

@@ -5,6 +5,8 @@ import { IonButton, IonCard, IonCardContent, IonCardHeader, IonCardTitle, IonIte
    IonList,IonSelect, IonSelectOption } from '@ionic/angular/standalone';
 import { CommonModule } from '@angular/common';
 import { Router } from '@angular/router';
+import { ChatPanelOptions, FmodeChat, openChatPanelModal } from 'fmode-ng';
+import { ModalController } from '@ionic/angular/standalone';
 
 @Component({
   selector: 'app-tab2',
@@ -22,33 +24,60 @@ import { Router } from '@angular/router';
 })
 export class Tab2Page {
 
-  constructor(private router: Router) {
+  private modalCtrl: ModalController;
+  constructor(private router: Router,modalCtrl: ModalController) {
+    this.modalCtrl = modalCtrl;
     // 其他构造函数代码
   }
   consultants = [
     {
-      name: '智能心理陪聊师',
+      name: '张衡',
+      desc:"是温柔学长,国家中级心理咨询师",
+      title: '中级心理咨询师',
       avatar: '/assets/img/2.png',
-      fields: ['专业领域:焦虑']
+      tags: ['专业领域:焦虑']
     },
     {
-      name: '智能心理陪聊师',
+      name: '王雅',
+      desc:"是热心学姐,国家中级心理咨询师",
+      title: '中级心理咨询师',
       avatar: '/assets/img/4.png',
-      fields: ['专业领域:抑郁']
+      tags: ['专业领域:抑郁']
     },
     {
-      name: '智能心理陪聊师',
+      name: '孙晴',
+      desc:"是活泼学妹,国家初级心理咨询师",
+      title: '初级心理咨询师',
       avatar: '/assets/img/5.png',
-      fields: ['专业领域:压力']
+      tags: ['专业领域:压力']
     }
   ];
-  
-  clickToConsult() {
-    // 开始咨询
-    //this.router.navigate(['tabs/page-consult'])
-    this.router.navigateByUrl("/chat/session/role/2DXJkRsjXK")
+  clickToConsult(consultant:any) {
+    // 弹窗形式聊天:开始咨询
+    let options:ChatPanelOptions = {
+      roleId:"2DXJkRsjXK",
+      onChatInit: (chat: FmodeChat) => {
+        console.log("onChatInit");
+        console.log("预设角色", chat.role);
+        chat.role.set("name", consultant.name);
+        chat.role.set("title", consultant.title);
+        chat.role.set("desc",consultant.desc);
+        chat.role.set("tags", consultant.tags);
+        chat.role.set("avatar", consultant.avatar)
+        chat.role.set("prompt", `
+        # 角色设定
+        您是${consultant.name},一位${consultant.title},${consultant.desc},需要为学生提供陪伴和支持等积极情绪。
+`);
+      },
+      onChatSaved:(chat:FmodeChat)=>{
+        // chat?.chatSession?.id 本次会话的 chatId
+        console.log("onChatSaved",chat,chat?.chatSession,chat?.chatSession?.id)
+      },
+    }
+    openChatPanelModal(this.modalCtrl,options)
+    // 页面形式聊天:开始咨询
+    // this.router.navigateByUrl("/chat/session/role/2DXJkRsjXK")
   }
-
   //selectedIssue:string='';
   matchedCounselor: { name: string; specialty: string } | null = null;
 

+ 1 - 1
soul-app/src/main.ts

@@ -17,7 +17,7 @@ Parse.serverURL = "https://server.fmode.cn/parse";
 localStorage.setItem("NOVA_APIG_SERVER", 'aHR0cHMlM0ElMkYlMkZzZXJ2ZXIuZm1vZGUuY24lMkZhcGklMkZhcGlnJTJG')
 
 // 注意:替换Token 根据Token设置Parse服务帐套权限
-Parse.User.become('r:bf1dc433a0b48ca0937e559134e3e316')
+Parse.User.become('r:86287c6e67fc4e6ea9c197cdd4f00c10')
 
 //'r:bf1dc433a0b48ca0937e559134e3e316'
 bootstrapApplication(AppComponent, {

+ 46 - 3
soul-server/lib/ncloud.js

@@ -5,12 +5,15 @@ class CloudObject{
     constructor(className){
         this.className = className
     }
+    toPointer(){
+      return {"__type":"Pointer","className":this.className,"objectId":this.id} 
+    }
     set(json){
         Object.keys(json).forEach(key=>{
         if(["objectId","id","createdAt","updatedAt","ACL"].indexOf(key)>-1){
-            return
+          return
         }
-            this.data[key] = json[key]
+          this.data[key] = json[key]
         })
     }
     get(key){
@@ -86,6 +89,21 @@ class CloudQuery{
     equalTo(key,value){
         this.whereOptions[key] = value
     }
+    greaterThan(key,value){
+      if(!this.whereOptions[key]) this.whereOptions[key] = {}
+      this.whereOptions[key]["$gt"] = value
+    }
+    greaterThanAndEqualTo(key,value){
+        if(!this.whereOptions[key]) this.whereOptions[key] = {}
+        this.whereOptions[key]["$gte"] = value
+    }
+    lessThan(key,value){
+        if(!this.whereOptions[key]) this.whereOptions[key] = {}
+        this.whereOptions[key]["$lt"] = value
+    }
+    lessThanAndEqualTo(key,value){
+        if(!this.whereOptions[key]) this.whereOptions[key] = {}
+    }
     async get(id){ // 通过id查询
         let url = "http://dev.fmode.cn:1337/parse/classes/"+this.className+"/"+id+"?"
         let response = await fetch(url, {
@@ -120,7 +138,32 @@ class CloudQuery{
           let json = await response?.json();
           return json?.results || []
     }
-    first(){ // 只查询第一项
+    async first(){ // 只查询第一项
+        let url = "http://dev.fmode.cn:1337/parse/classes/"+this.className+"?"
+        if(Object.keys(this.whereOptions)?.length){
+            let whereStr = JSON.stringify(this.whereOptions)
+            url += `where=${whereStr}`
+        }
+        let response = await fetch(url, {
+            "headers": {
+              "if-none-match": "W/\"22c-NGsQZp5SnqjXTAX+NXjLAv6LaLA\"",
+              "x-parse-application-id": "dev"
+            },
+            "body": null,
+            "method": "GET",
+            "mode": "cors",
+            "credentials": "omit"
+          });
+          let json = await response?.json();
+          let exists = json?.results?.[0] || null
+          if(exists){
+            let existsObject = new CloudObject(this.className)
+            existsObject.set(exists)
+            existsObject.id = exists.objectId
+            existsObject.createdAt = exists.createdAt
+            existsObject.updateAt = exists.updateAt
+            return existsObject
+          }
     }
 }
 module.exports.CloudObject = CloudObject

+ 62 - 0
soul-server/migration/data.js

@@ -0,0 +1,62 @@
+module.exports.ChatPartnerList = [
+    {
+      "objectId": "part001",
+      "name": "李明",
+      "expertise": "心理咨询",
+      "avatar": "https://example.com/avatars/therapist_001.jpg",
+      "bio": "李明是一名拥有十年经验的心理咨询师,专注于焦虑和抑郁的治疗。"
+    },
+    {
+      "objectId": "part002",
+      "name": "张华",
+      "expertise": "儿童心理",
+      "avatar": "https://example.com/avatars/therapist_002.jpg",
+      "bio": "张华专注于儿童心理健康,致力于帮助孩子们克服成长中的挑战。"
+    },
+    {
+      "objectId": "part003",
+      "name": "王芳",
+      "expertise": "",
+      "avatar": "https://example.com/avatars/therapist_003.jpg",
+      "bio": "王芳是一名普通陪聊师,擅长倾听和陪伴。"
+    }
+]
+
+module.exports.ChatRecordList = [
+    {
+      "objectId": "chat001",
+      "timestamp": "2024-12-17T14:00:00Z",
+      "chatContent": [
+        "用户:你好,我最近感到很焦虑。",
+        "陪聊师:你好,李明在这里。可以告诉我是什么让你感到焦虑吗?",
+        "用户:我总是担心工作上的事情。",
+        "陪聊师:工作压力确实会影响我们的情绪。你觉得具体是哪些方面让你感到压力呢?"
+      ],
+      //"user": { "objectId": "user001" },
+      "chatpartner": { "objectId": "part001" }
+    },
+    {
+      "objectId": "chat002",
+      "timestamp": "2024-12-17T14:10:00Z",
+      "chatContent": [
+        "用户:我有个孩子,他最近有些不开心。",
+        "陪聊师:你好,张华在这里。你能告诉我一些关于他不开心的事情吗?",
+        "用户:他在学校里交不到朋友。",
+        "陪聊师:社交问题对孩子来说是很常见的。我们可以一起探讨一些解决方法。"
+      ],
+      //"user": { "objectId": "user002" },
+      "chatpartner": { "objectId": "part002" }
+    },
+    {
+      "objectId": "chat003",
+      "timestamp": "2024-12-17T14:20:00Z",
+      "chatContent": [
+        "用户:我感觉有点孤独。",
+        "陪聊师:你好,王芳在这里。孤独的感觉是很正常的,你想聊聊吗?",
+        "用户:我不知道该怎么开始。",
+        "陪聊师:没关系,我们可以慢慢来。你最近有什么有趣的事情吗?"
+      ],
+      //"user": { "objectId": "user003" },
+      "chatpartner": { "objectId": "part003" }
+    }
+]

+ 72 - 20
soul-server/migration/import-data.js

@@ -1,27 +1,79 @@
 const { CloudQuery, CloudObject } = require("../lib/ncloud");
-//testCRUD()
-testQuery()
-//ChatPartner表的查询
-async function testQuery(){
-    let query = new CloudQuery("ChatPartner")
-    //query.greaterThanAndEqualTo("age",40)查询条件
-    //query.lessThan("age",41)查询条件
-    let list = await query.find();
-    console.log(list)
+const { ChatPartnerList, ChatRecordList } = require("./data");
+
+DataMap = {
+    ChatPartner:{},
+    ChatRecord:{}
 }
 
-async function testCRUD(){
-    // ChatPartner表基本的增删查改测试
-    let query = new CloudQuery("ChatPartner")
-    let chatpartnerList = await query.find();
-    console.log("chatpartnerList count",chatpartnerList?.length)
+// 查询
+//async function testQuery(){
+    //let query = new CloudQuery("ChatPartner")
+    //query.greaterThanAndEqualTo("",)查询条件
+    //query.lessThan("",)查询条件
+    //let list = await query.find();
+    //console.log(list)
+//}
+//testCRUD()// 测试ChatPartner表的查询
+
+// 增删改查
+//async function testCRUD(){
+    //let query = new CloudQuery("ChatPartner")
+    //let chatpartnerList = await query.find();
+    //console.log("chatpartnerList count",chatpartnerList?.length)
 
-    let newChatPartner = new CloudObject("ChatPartner")
-    newChatPartner.set({"name":"123"})
+    //let newChatPartner = new CloudObject("ChatPartner")
+    //newChatPartner.set({"name":"123"})
     
-    newChatPartner = await newChatPartner.save(newChatPartner)
-    console.log("newChatPartner",newChatPartner)
+    //newChatPartner = await newChatPartner.save(newChatPartner)
+    //console.log("newChatPartner",newChatPartner)
+
+    //await newChatPartner.destory()
+    //console.log("newChatPartner 已删除",newChatPartner)
+//}
+//testQuery()// ChatPartner表基本的增删查改测试
 
-    await newChatPartner.destory()
-    console.log("newChatPartner 已删除",newChatPartner)
+async function inportDapartAndChatPartner(){
+    // 导入陪聊师数据
+    let chatpartnerList = ChatPartnerList
+    for(let index = 0;index < chatpartnerList.length;index++){
+        let chatpartner = chatpartnerList[index];
+        chatpartner = await importObject("ChatPartner",chatpartner)
+    }
+    // 导入聊天记录数据
+    let chatrecordList = ChatRecordList
+    for(let index = 0;index < chatrecordList.length;index++){
+        let chatrecord = chatrecordList[index];
+        chatrecord = await importObject("ChatRecord",chatrecord)
+    }
+    console.log(DataMap)
 }
+inportDapartAndChatPartner()
+
+async function importObject(className,data){
+
+    // 查看 srcId 数据源列表中的objectId并非数据库生成的唯一ID,因此需要有一个srcId字段进行记录,并查重
+    let query = new CloudQuery(className)
+    let srcId = data.objectId
+    query.equalTo("srcId",srcId)
+    let importObj = await query.first()
+    // 导入 新对象需要添加
+    // 导入前批量处理Pointer类型数据,进行重定向
+    Object.keys(data)?.forEach(key=>{
+        let field = data[key]
+        let srcId = field?.objectId
+        if(srcId){ // 数组字段
+            if(key=="chatpartner"){
+                data[key] = DataMap["ChatPartner"]?.[srcId]?.toPointer();
+            }
+        }
+    })
+    // 新对象需要添加
+    if(!importObj?.id){
+        importObj = new CloudObject(className)
+        data.srcId = srcId;
+        importObj.set(data);
+        importObj = await importObj.save();
+    }
+    DataMap[className][srcId] = importObj
+}