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

完善了社区功能和增加画作添加喜欢功能

何何何 1 жил өмнө
parent
commit
c461d6b38e

+ 14 - 6
paint-app/src/app/detail-page/detail-page.component.html

@@ -16,13 +16,21 @@
     <ion-card>
       <img alt="Silhouette of mountains" [src]="paintList[0].get('picture')" />
       <ion-card-header>
-        <ion-card-title>{{ getPaintDetail('name') }}</ion-card-title>
+          <ion-card-title>{{ getPaintDetail('name') }}</ion-card-title>
       </ion-card-header>
-      <ion-card-content>
-        {{ getPaintDetail('introduction') }}
-      </ion-card-content>
-    </ion-card>
-    <ion-button slot="fixed" (click)="gopage1()">ai艺聊</ion-button>
+      
+      <!-- 按钮区域 -->
+      <div class="button-container">
+          <ion-button 
+              fill="clear" 
+              (click)="isFavorite ? removeFavorite() : addFavorite()" 
+              [color]="isFavorite ? 'danger' : 'medium'"
+              class="favorite-button">
+              <ion-icon slot="icon-only" name="heart"></ion-icon>
+          </ion-button>
+      </div>
+  </ion-card>
+    <ion-button slot="fixed" (click)="gopage1(getPaintDetail('nameid'))">ai艺聊</ion-button>
 
     <h4>作者介绍</h4>
     <p>

+ 16 - 1
paint-app/src/app/detail-page/detail-page.component.scss

@@ -1,4 +1,19 @@
 ion-button[slot='fixed'] {
     top: 50%;
     right: 20px;
-  }
+  }
+  .button-container {
+    position: absolute; /* 使按钮容器绝对定位 */
+    bottom: 2px; /* 距离底部的距离,可以根据需要调整 */
+    right: 2px; /* 距离右侧的距离,可以根据需要调整 */
+}
+
+.favorite-button {
+    font-size: 24px; /* 增大按钮字体大小 */
+    width: 30px; /* 增大按钮宽度 */
+    height: 30px; /* 增大按钮高度 */
+    --padding-start: 0; /* 去掉按钮左侧的内边距 */
+    --padding-end: 0; /* 去掉按钮右侧的内边距 */
+    --padding-top: 0; /* 去掉按钮上方的内边距 */
+    --padding-bottom: 0; /* 去掉按钮下方的内边距 */
+}

+ 200 - 15
paint-app/src/app/detail-page/detail-page.component.ts

@@ -1,11 +1,14 @@
 import { Component} from '@angular/core';
 import { ActivatedRoute, Router } from '@angular/router';
-import { IonButton, IonButtons, IonCard, IonCardContent, IonCardHeader, IonCardSubtitle, IonCardTitle, IonContent, IonHeader, IonIcon, IonTitle, IonToolbar } from '@ionic/angular/standalone';
+import { IonButton, IonButtons, IonCard, IonCardContent, IonCardHeader, IonCardSubtitle, IonCardTitle, IonContent, IonFooter, IonHeader, IonIcon, IonTitle, IonToolbar, ModalController } from '@ionic/angular/standalone';
 import { CloudObject, CloudQuery } from 'src/lib/ncloud';
-import {chevronBack} from 'ionicons/icons';
-addIcons({chevronBack})
+import {chevronBack,heart,star} from 'ionicons/icons';
+addIcons({chevronBack,heart,star})
 import { addIcons } from 'ionicons';
 import { CommonModule } from '@angular/common';
+import { CloudUser } from 'src/lib/ncloud';
+import { openUserLoginModal } from 'src/lib/user/modal-user-login/modal-user-login.component';
+import { ChatPanelOptions, FmodeChat, FmodeChatMessage, openChatPanelModal } from 'fmode-ng';
 @Component({
   selector: 'app-detail-page',
   templateUrl: './detail-page.component.html',
@@ -19,16 +22,18 @@ export class DetailPageComponent{
 
 
   constructor(private router: Router,
-    private route:ActivatedRoute
-    ){}
+    private route:ActivatedRoute,
+    private modalCtrl:ModalController,
+    ){
+      this.currentfavorit = new CloudObject('plike');
+    }
 
     
   paintList:Array<CloudObject> = []
-  paintnameid: string='name5'; // 用于存储传递的参数
+  paintnameid: string=''; // 用于存储传递的参数
  
 
     ngOnInit() {
-      console.log('接收到的参数');
       // 订阅路由参数变化
       this.route.params.subscribe(params => {
           // 从路由参数中获取 'id' 参数并赋值给 paintname
@@ -39,9 +44,11 @@ export class DetailPageComponent{
           // 这里可以调用一个方法来加载与 paintname 相关的数据
           // this.loadPaintData(this.paintname); // 示例:根据 paintname 加载数据
       });
-  
-      // 调用方法加载绘画列表
-      this.loadpaintList(); // 加载绘画列表数据
+
+      this.loadpaintList().then(() => {
+        this.judgeFavorite();
+        // 这里可以调用 judgeFavorite() 等其他方法
+    });
   }
 
 
@@ -49,9 +56,10 @@ export class DetailPageComponent{
   gopage(){
     this.router.navigate(['/tabs/tab2'])
   }
-  gopage1(){
-    this.router.navigate(['/tabs/tab2'])
-  }
+
+  gopage1(objectId: string){
+    this.openPaintInquiry(objectId);
+}
 
   async loadpaintList(){
     let query = new CloudQuery("paint");
@@ -61,14 +69,191 @@ export class DetailPageComponent{
     this.paintList = await query.find()
 
     if (this.paintList && this.paintList.length > 0) {
-      console.log('有列表');
+      console.log('画作详细页面列表');
     }
     else{
-      console.log('无列表');
+      console.log('画作详细页面列表');
     }
     }
 
     getPaintDetail(property: string): string {
       return this.paintList.length > 0 ? this.paintList[0].get(property) : '';
     }
+
+    async openPaintInquiry(paintnameid: string) {
+        let query = new CloudQuery("paint");
+    
+        await query.equalTo("nameid",this.paintnameid)
+    
+        let paint:CloudObject| null =null;
+    
+        paint = await query.first()
+        
+    
+    
+        // 验证用户登录
+        let currentUser = new CloudUser(); // 创建一个新的用户对象
+        let userPrompt = ``; // 初始化用户提示信息
+        if (!currentUser?.id) { // 检查用户是否已登录
+          console.log("用户未登录,请登录后重试"); // 如果未登录,输出提示信息
+          let user = await openUserLoginModal(this.modalCtrl); // 打开登录模态框
+          if (!user?.id) { // 如果用户仍未登录
+            return; // 退出函数
+          }
+          currentUser = user; // 更新当前用户为登录的用户
+        }
+      
+        console.log('本页面的作品名:'+paint?.get('name')); // 输出绘画对象的名称
+      
+        // 构建用户信息提示
+        if (currentUser?.get("realname")) {
+          userPrompt += `当前来访的用户,姓名:${currentUser?.get("realname")}`;
+        }
+        if (currentUser?.get("gender")) {
+          userPrompt += `,性别:${currentUser?.get("gender")}`;
+        }
+        if (currentUser?.get("age")) {
+          userPrompt += `,年龄:${currentUser?.get("age")}`;
+        }
+      
+        // 将公司信息存储到本地存储中
+        localStorage.setItem("company", "E4KpGvTEto");
+      
+        // 创建新的咨询对象
+        let consult = new CloudObject("pchat");
+        let now = new Date(); // 获取当前日期
+        let dateStr = `${now.getFullYear()}-${now.getMonth() + 1}-${now.getDate()}`; // 格式化日期字符串
+        
+        // 对象权限的精确指定
+        let ACL: any = {
+          "*": { read: false, write: false } // 默认权限设置为不可读写
+        };
+        if (currentUser?.id) {
+          ACL[currentUser?.id] = { read: true, write: true }; // 为当前用户设置读写权限
+        }
+        
+        // 设置咨询对象的属性
+        consult.set({
+          title: `绘画咨询记录${dateStr}-${paint?.get("name")}`, // 设置咨询标题
+          paint: paint?.toPointer(), // 设置绘画对象的指针
+          user: currentUser.toPointer(), // 设置当前用户的指针
+          ACL: ACL // 设置权限控制列表
+        });
+      
+        // 配置聊天面板选项
+        let options: ChatPanelOptions = {
+          roleId: "2DXJkRsjXK", // 角色ID
+          onChatInit: (chat: FmodeChat) => { // 聊天初始化回调
+            // 设置角色的各种属性
+       // 设置角色的固定属性值
+    chat.role.set("name", "艺术专家"); // 设置角色名称为固定值
+    chat.role.set("title", "画作介绍员"); // 设置角色标题为固定值
+    chat.role.set("desc", "专注于艺术作品的分析与介绍"); // 设置角色描述为固定值
+    chat.role.set("tags", ["艺术", "画作", "介绍"]); // 设置角色标签为固定值
+    chat.role.set("avatar", "../../assets/icon/head1.png"); // 设置角色头像为固定值
+    
+    // 设置角色的提示信息
+    const paintName = paint?.get("name") || "这幅画"; // 获取画作名称,若未提供则使用默认值
+    const paintDescription = paint?.get("introduction") || "这是一幅美丽的艺术作品。"; // 获取画作描述,若未提供则使用默认值
+    const paintStyle = paint?.get("range") || "未知风格"; // 获取画作风格,若未提供则使用默认值
+    const paintArtist = paint?.get("artist") || "未知艺术家"; // 获取画作艺术家,若未提供则使用默认值
+    
+    chat.role.set("prompt", `
+      # 角色设定
+      您是一位艺术专家,专注于对画作进行详细介绍与分析。您将为《${paintName}》的背景信息、艺术风格(${paintStyle})及其创作意图等内容提供介绍。
+      
+      # 对话环节
+      0. 拓展的问询细节
+      例如:询问:您对${paintName}的了解程度;是否希望了解创作背景等问题。
+      - 当问询细节补充完成后进入下一个环节
+      1. 给出画作的详细介绍
+      - 根据用户的需求,提供《${paintName}》的艺术风格(${paintStyle})、创作意图及历史背景等信息。
+      2. 提供相关的艺术资源
+      - 根据用户的需求,推荐相关的艺术书籍、网站或课程。
+      - 推荐完成后在消息末尾附带[艺聊完成]
+    
+      # 开始话语
+      当您准备好了,可以以艺术专家的身份,先向来访的用户亲切地打招呼。
+      ${userPrompt}
+    `);
+          },
+          onMessage: (chat: FmodeChat, message: FmodeChatMessage) => { // 消息处理回调
+            console.log("onMessage", message); // 输出接收到的消息
+            let content: any = message?.content; // 获取消息内容
+            if (typeof content == "string") { // 如果内容是字符串
+              if (content?.indexOf("[艺聊完成]") > -1) { // 检查内容中是否包含"[方案完成]"
+                console.log("绘画咨询已完成"); // 输出咨询完成信息
+                consult.set({
+                  content: content // 设置咨询内容为消息内容
+                });
+                consult.save(); // 保存咨询对象
+              }
+            }
+          },
+          onChatSaved: (chat: FmodeChat) => { // 聊天保存回调
+            // chat?.chatSession?.id 本次会话的 chatId
+            console.log("onChatSaved", chat, chat?.chatSession, chat?.chatSession?.id); // 输出保存的聊天信息
+          }
+        };
+        
+        openChatPanelModal(this.modalCtrl, options); // 打开聊天面板模态框
+      }
+
+
+
+  isFavorite: boolean = false; // 初始状态
+  isStarred: boolean = false;   // 初始状态
+// this.isFavorite = !this.isFavorite;
+//     // 这里可以添加更多的逻辑,比如发送请求或更新状态
+  // 切换心状按钮状态
+  favoritedata: any = {};
+  currentfavorit: CloudObject | undefined; // 
+  favoritList:Array<CloudObject> = []
+  
+    async judgeFavorite() {
+    let currentUser = new CloudUser();
+    let query = new CloudQuery("plike");
+    // 检查 paintList 是否已定义且至少有一个元素
+    if (this.paintList && this.paintList.length > 0) {
+        await query.equalTo("user", currentUser.id);
+        await query.equalTo("paint", this.paintList[0].get("name")); // 确保 paintList[0] 是有效的
+        this.favoritList = await query.find();
+    } else {
+        console.error('paintList is undefined or empty');
+    }
+    if(this.favoritList && this.favoritList.length > 0){
+      this.isFavorite = !this.isFavorite;
+      console.log('判断完成')
+    }
+}
+  async addFavorite() {
+     let currentUser = new CloudUser();
+     if (currentUser?.id) {
+      this.currentfavorit?.addPointer('user', '_User', currentUser.id);
+  }
+     this.currentfavorit?.addPointer('paint','paint',this.paintList[0].get("name"));
+     await this.currentfavorit?.save();
+     console.log('添加成功')
+     this.isFavorite = !this.isFavorite;
+  }
+
+
+
+  currentfavorit1: CloudObject | undefined;  
+  favoritList1:Array<CloudObject> = []
+  async removeFavorite() {
+    let currentUser = new CloudUser();
+    let query = new CloudQuery("plike");
+    if (this.paintList && this.paintList.length > 0) {
+      await query.equalTo("user", currentUser.id);
+      await query.equalTo("paint", this.paintList[0].get("name")); // 确保 paintList[0] 是有效的
+      this.favoritList1 = await query.find();
+      this.currentfavorit1=this.favoritList1[0];
+      await this.currentfavorit1?.destroy();
+      this.isFavorite = !this.isFavorite;
+      console.log('删除成功')
+  } else {
+      console.error('paintList is undefined or empty');
+  }
+ }
 }

+ 28 - 11
paint-app/src/app/tab2/tab2.page.html

@@ -22,23 +22,40 @@
         <dl class="srhGroup clear">
             <dt>历史</dt>
             <dd class="horizontal-links">
-              <p (click)="onTextClick(this.value0)">全部</p>&nbsp;&nbsp;&nbsp;
-              <p (click)="onTextClick(this.value1)">现代艺术</p>&nbsp;&nbsp;&nbsp;
-              <p (click)="onTextClick(this.value2)">当代艺术</p>
+                <label>
+                    <input type="radio" name="history" value="全部" (click)="onHistoryChange('全部');onTextClick('全部')" checked>全部
+                </label>&nbsp;&nbsp;&nbsp;
+                <label>
+                    <input type="radio" name="history" value="现代艺术" (click)="onHistoryChange('现代艺术');onTextClick('现代艺术')">现代艺术
+                </label>&nbsp;&nbsp;&nbsp;
+                <label>
+                    <input type="radio" name="history" value="当代艺术" (click)="onHistoryChange('当代艺术');onTextClick('当代艺术')">当代艺术
+                </label>
             </dd>
         </dl>
         <dl class="srhGroup clear">
             <dt>类型</dt>
             <dd class="horizontal-links">
-              <p (click)="onTextClick1(this.value0)">全部</p>&nbsp;&nbsp;&nbsp;
-              <p (click)="onTextClick1(this.value3)">油画</p>&nbsp;&nbsp;&nbsp;
-              <p (click)="onTextClick1(this.value5)">水彩画</p>&nbsp;&nbsp;&nbsp;
-              <p (click)="onTextClick1(this.value6)">抽象画</p>&nbsp;&nbsp;&nbsp;
-              <p (click)="onTextClick1(this.value7)">素描</p>&nbsp;&nbsp;&nbsp;
-              <p (click)="onTextClick1(this.value4)">壁画</p>
+                <label>
+                    <input type="radio" name="type" value="全部" (click)="onTextClick1('全部')" [(ngModel)]="typeValue">全部
+                </label>&nbsp;&nbsp;&nbsp;
+                <label>
+                    <input type="radio" name="type" value="油画" (click)="onTextClick1('油画')" [(ngModel)]="typeValue">油画
+                </label>&nbsp;&nbsp;&nbsp;
+                <label>
+                    <input type="radio" name="type" value="水彩画" (click)="onTextClick1('水彩画')" [(ngModel)]="typeValue">水彩画
+                </label>&nbsp;&nbsp;&nbsp;
+                <label>
+                    <input type="radio" name="type" value="抽象画" (click)="onTextClick1('抽象画')" [(ngModel)]="typeValue">抽象画
+                </label>&nbsp;&nbsp;&nbsp;
+                <label>
+                    <input type="radio" name="type" value="素描" (click)="onTextClick1('素描')" [(ngModel)]="typeValue">素描
+                </label>&nbsp;&nbsp;&nbsp;
+                <label>
+                    <input type="radio" name="type" value="壁画" (click)="onTextClick1('壁画')" [(ngModel)]="typeValue">壁画
+                </label>
             </dd>
-        </dl>
-     
+        </dl>  
     </div>
 
       <!-- (click)="navigateToDetail()" -->

+ 17 - 12
paint-app/src/app/tab2/tab2.page.ts

@@ -5,6 +5,7 @@ import { IonButton, IonCard, IonCardContent, IonCardHeader, IonCardSubtitle, Ion
 import { Router } from '@angular/router';
 import { CommonModule } from '@angular/common';
 import { CloudObject, CloudQuery } from 'src/lib/ncloud';
+import { FormsModule, NgModel, ReactiveFormsModule } from '@angular/forms';
 @Component({
   selector: 'app-tab2',
   templateUrl: 'tab2.page.html',
@@ -12,7 +13,7 @@ import { CloudObject, CloudQuery } from 'src/lib/ncloud';
   standalone: true,
   imports: [IonHeader, IonToolbar, IonTitle, IonContent, ExploreContainerComponent,IonButton,
     IonCard, IonCardContent, IonCardHeader, IonCardSubtitle, IonCardTitle,IonGrid,IonCol,IonRow,IonImg
-  ,IonSegment,IonSegmentContent,IonSegmentView,IonLabel,IonSegmentButton,CommonModule]
+  ,ReactiveFormsModule,FormsModule,IonSegment,IonSegmentContent,IonSegmentView,IonLabel,IonSegmentButton,CommonModule]
 })
 export class Tab2Page{
   value1: string = '现代艺术';
@@ -27,21 +28,16 @@ export class Tab2Page{
   constructor(private router: Router){}
 
   navigateToDetail(objectId: string) {
-    console.log('进入 navigateToDetail 方法');
-    console.log('objectId:', objectId);
-
     if (objectId) {
-        console.log('准备导航到 detail-page,objectId:', objectId);
-        console.log('Navigating to:', ['/tabs/detail-page', objectId]);
         this.router.navigate(['/tabs/detail-page', encodeURIComponent(objectId)])
             .then(success => {
-                console.log('导航成功:', success);
+                console.log('前往画作详细导航成功:', success);
             })
             .catch(err => {
-                console.error('导航失败:', err);
+                console.error('前往画作详细导航失败:', err);
             });
     } else {
-        console.error('objectId is null or undefined');
+        console.error('tab2页面objectId is null or undefined');
     }
 }
   gopage(objectId: string){
@@ -49,7 +45,7 @@ export class Tab2Page{
     if (objectId) {
       this.router.navigate(['/tabs/video-page', objectId]);
     } else {
-      console.error('objectId is null or undefined');
+      console.error('tab2页面objectId is null or undefined');
     }
   }
   ngOnInit() {
@@ -74,14 +70,16 @@ export class Tab2Page{
     async onTextClick(text:string){
       let query = new CloudQuery("paint");
       this.nowvalue=text;
-      if(text!==''){
+      if(text!=='全部'){
       await query.equalTo("history",text)
     }
       this.paintList = await query.find()
     }
+
+    
     async onTextClick1(text:string){
       let query = new CloudQuery("paint");
-      if(text!==''){
+      if(text!=='全部'){
       await query.equalTo("range",text)
     }
     if(this.nowvalue!==''){
@@ -89,4 +87,11 @@ export class Tab2Page{
     }
       this.paintList = await query.find()
     }
+
+    typeValue: string = '全部'; // 默认值
+    onHistoryChange(value: string) {
+      if (value==='全部') {
+          this.typeValue = '全部'; // 自动选择类型的全部
+      }
+  }
 }

+ 36 - 19
paint-app/src/app/tab4/tab4.component.html

@@ -8,26 +8,43 @@
   
   <ion-content>
     <ion-item>
-      <ion-input (ionChange)="DataChange('content',$event)" label="评论" placeholder="请您输入评论"></ion-input>
-      <ion-button expand="block" (click)="click()">保存</ion-button>
+      <ion-input (ionChange)="DataChange('content',$event)" label="帖子" placeholder="请您输入帖子内容"></ion-input>
+      <ion-button (click)="click()">提交帖子</ion-button>
+      
     </ion-item>
-
    <div class="artwork-container">
-    <ion-card *ngFor="let comment of commentList" class="artwork-card">
-     <!-- <img [src]="artwork.image" alt="Artwork" class="artwork-image" /> -->
-     <ion-card-header>
-      <ion-card-title>{{ comment.get('username')||"未知名" }}</ion-card-title>
-      <!--<ion-card-subtitle>创作工具: {{ artwork.tools }}</ion-card-subtitle> -->
-     </ion-card-header>
-     <ion-card-content>
-      <p>{{comment.get('content')}}</p>
-      <p>{{comment.get('createdAt')}}</p>
-      <!-- <p><strong>创作过程:</strong> {{ artwork.process }}</p> --> 
-     </ion-card-content>
-     <div class="card-footer">
-      <!-- <ion-button expand="full" color="primary">点赞 <ion-icon name="thumbs-up-outline"></ion-icon></ion-button>
-      <ion-button expand="full" color="secondary">评论 <ion-icon name="chatbubble-outline"></ion-icon></ion-button> -->
-     </div>
+    <!-- 遍历帖子列表 -->
+    <ion-card *ngFor="let discuss of discussList" class="artwork-card">
+      <ion-card-header>
+        <ion-card-title>{{ discuss.get('username') || "未知名" }}</ion-card-title>
+      </ion-card-header>
+      <ion-card-content>
+        <p>{{ discuss.get('content') }}</p>
+        <p>{{ discuss.get('createdAt') }}</p>
+      </ion-card-content>
+      
+    
+        <!-- 遍历与当前帖子相关的评论 -->
+        <ng-container *ngFor="let comment of commentList">
+          <div *ngIf="comment.get('discussid').discussid === discuss.get('discussid')">
+            <ion-card class="comment-card">
+              <ion-card-header>
+                <ion-card-title>{{ comment.get('username') || "未知名" }}</ion-card-title>
+              </ion-card-header>
+              <ion-card-content>
+                <p>{{ comment.get('subtance') }}</p>
+                <p>{{ comment.get('createdAt') }}</p>
+              </ion-card-content>
+            </ion-card>
+          </div>
+        </ng-container>
+        <div class="comment-input">
+          <ion-item>
+            <ion-input (ionChange)="DataChang1('subtance',$event)" label="评论" placeholder="请您输入评论内容"></ion-input>
+            <ion-button (click)="click1(discuss)">提交</ion-button>
+          </ion-item>
+
+        </div>
     </ion-card>
-   </div>
+  </div>
   </ion-content>

+ 3 - 1
paint-app/src/app/tab4/tab4.component.scss

@@ -88,4 +88,6 @@ ion-header {
       transform: scale(1.05); /* 悬停时放大 */
       background: linear-gradient(135deg, #ff4d4d, #f7a633); /* 悬停时变色 */
      }
-    
+    
+
+     

+ 67 - 14
paint-app/src/app/tab4/tab4.component.ts

@@ -1,6 +1,6 @@
 import { Component } from '@angular/core';
 import { CommonModule } from '@angular/common'; // 确保导入 CommonModule
-import { IonHeader, IonToolbar, IonTitle, IonContent, IonCard, IonCardHeader, IonCardTitle, IonCardSubtitle, IonCardContent, IonButton, IonIcon, IonItem, IonInput } from '@ionic/angular/standalone'; // 导入 IonButton 和 IonIcon
+import { IonHeader, IonToolbar, IonTitle, IonContent, IonCard, IonCardHeader, IonCardTitle, IonCardSubtitle, IonCardContent, IonButton, IonIcon, IonItem, IonInput, IonLabel } from '@ionic/angular/standalone'; // 导入 IonButton 和 IonIcon
 import { FormsModule, ReactiveFormsModule } from '@angular/forms'; // 导入 FormsModule
 import { CloudObject ,CloudQuery} from 'src/lib/ncloud';
 import { ModalController } from '@ionic/angular/standalone';
@@ -13,13 +13,16 @@ import {  CloudUser } from 'src/lib/ncloud';
   standalone: true,
   imports: [CommonModule, IonHeader, IonToolbar, IonTitle,FormsModule,IonItem,
      IonContent, IonCard, IonCardHeader, IonCardTitle, IonCardSubtitle,ReactiveFormsModule,
-      IonCardContent, IonButton, IonIcon,IonInput] // 添加 IonButton 和 IonIcon
+      IonCardContent, IonButton, IonIcon,IonInput,IonLabel] // 添加 IonButton 和 IonIcon
 })
 export class Tab4Component{
  
-     currentcomment: CloudObject | undefined; // 用于存储输入的评论
+     currentdiscuss: CloudObject | undefined; // 用于存储输入的评论
      currentUser: CloudUser | undefined;
-     commentData: any = {};
+     discussdata: any = {};
+     currentcomment: CloudObject | undefined; // 用于存储输入的评论
+     commentdata: any = {};
+
      // 处理用户数据变化的方法
 DataChange(key: string, ev: any) {
   
@@ -29,35 +32,48 @@ DataChange(key: string, ev: any) {
   console.log(value);
   // 如果输入值存在,则将其存储到 userData 对象中
   if (value) {
-    this.commentData[key] = value;
-    this.commentData['username']=this.currentUser?.get("username");
+    this.discussdata[key] = value;
+    this.discussdata['username']=this.currentUser?.get("username");
+    this.discussdata['discussid']='discuss'+(this.discussList.length+1);
   }
 }
+
+
 // 组件构造函数
 constructor(private alertController: AlertController,
   private modalCtrl:ModalController) {
   // 初始化当前用户为一个新的 CloudUser 实例
-  this.currentcomment = new CloudObject('pdiscuss');
+  this.currentdiscuss = new CloudObject('pdiscuss');
+  this.currentcomment = new CloudObject('pcomment');
   this.currentUser = new CloudUser();
 }
 async save() {
   // 将更新后的 userData 设置到 currentUser 对象中
-  this.currentcomment?.set(this.commentData);
+  this.currentdiscuss?.set(this.discussdata);
   
   // 保存 currentUser 的数据
-  await this.currentcomment?.save();
+  await this.currentdiscuss?.save();
   
 }
 ngOnInit() {
       // 生命周期:页面加载后,运行医生列表加载函数
-      this.loadcommmentList()
+      this.loaddiscussList();
+      this.loadcommentList();
     }
   
     // 创建用于数据列表存储的属性
-    commentList:Array<CloudObject> = []
-    async loadcommmentList(){
+    discussList:Array<CloudObject> = []
+    async loaddiscussList(){
       let query = new CloudQuery("pdiscuss");
-      this.commentList = await query.find()
+      this.discussList = await query.find();
+    }
+
+    // 创建用于数据列表存储的属性
+    commentList:Array<CloudObject> = []
+    async loadcommentList(){
+      let query = new CloudQuery("pcomment");
+      query.include('discussid');
+      this.commentList = await query.find();
     }
 
     async showAlert() {
@@ -69,13 +85,50 @@ ngOnInit() {
     
       await alert.present(); // 显示提示框
     }
+
     click(){ 
       if(!this.currentUser?.id){
         console.log("用户未登录,请登录后重试"); 
          this.showAlert();
       }else{
     this.save();
-      this.loadcommmentList();
+    this.loaddiscussList();
+    this.loadcommentList();
+      }
+    }
+
+
+
+    DataChang1(key: string, ev: any) {
+  
+      // 从事件中获取输入的值
+      let value = ev?.detail?.value;
+      console.log(key);
+      console.log(value);
+      // 如果输入值存在,则将其存储到 userData 对象中
+      if (value) {
+        this.commentdata[key] = value;  
+        this.commentdata['username']=this.currentUser?.get("username");
       }
     }
+    async save1(discuss:any) {
+      // 将更新后的 userData 设置到 currentUser 对象中
+      this.currentcomment?.set(this.commentdata);
+      this.currentcomment?.addPointer('discussid','pdiscuss',discuss.id);
+      // 保存 currentUser 的数据
+      await this.currentcomment?.save();
+      
+    }
+    click1(discuss:any){ 
+      if(!this.currentUser?.id){
+        console.log("用户未登录,请登录后重试"); 
+         this.showAlert();
+      }else{
+    this.save1(discuss);
+    this.loaddiscussList();
+    this.loadcommentList();
+      }
+    }
+
+ 
 }

+ 0 - 5
paint-app/src/app/tabs/tabs.routes.ts

@@ -26,11 +26,6 @@ export const routes: Routes = [
         loadComponent: () =>
           import('../tab4/tab4.component').then((m) => m.Tab4Component),
       },
-      {
-        path: 'test',
-        loadComponent: () =>
-          import('../page-test/page-test.component').then((m) => m.PageTestComponent),
-      },
       {
         path: 'page-idea',
         loadComponent: () =>

+ 32 - 69
paint-app/src/app/test2-page/test2-page.component.html

@@ -1,69 +1,32 @@
-<ion-header>
-  <ion-toolbar>
-    <ion-buttons slot="start">
-      <ion-button (click)="gopage()">
-        <ion-icon name="settings">返回</ion-icon>
-      </ion-button>
-    </ion-buttons>
-    <ion-title>视频</ion-title>
-  </ion-toolbar>
-</ion-header>
-
-<ion-content> 
-  <div class="vido-type">
-    <video id="video" controls>
-        <source src="../../assets/6月26日(1).mp4" type="video/mp4">
-        您的浏览器不支持视频标签。
-    </video>
-    </div>
-    <!-- <div class="controls">
-        <button onclick="skip(-10)"><<<</button>
-        <button onclick="playOrPause()">暂停</button>     
-        <button onclick="skip(10)">>>></button>
-    </div> -->
-
-    <div class="art-content">
-        <!-- 评价选择 -->
-        <p class="switch-head-line">
-            <span class="mr chooseActive" eval_data='1'>评论</span>
-        </p>
-        <!-- 评价选择 -->
-        
-        <ul id="user_evaluate">
-            <li class="evaluate_li">
-                 <span class="img">
-                    <img src="images/tou2.jpg" alt="头像" />
-                </span>
-                <span class="info">
-                    <h4>爱吃馒头的宝宝</h4>
-                    <p>又是一部迪士尼的经典公主系列电影,刚开始小时候的妹妹真是萌翻了。不得不说这部电影在美国火爆了,本人在的高中,看过的人都激动得很,每天都在唱:Do you wanna build a snow man?~~</p>
-                    <p class="time">2019-04-28</p>
-                    <div class="reply_info">回复: <input type="text" id="name" name="name"></div>
-                </span>
-            </li>
-            <li class="evaluate_li">
-                <span class="img">
-                   <img src="images/tou1.jpg" alt="头像" />
-               </span>
-               <span class="info">
-                   <h4>爱你的我</h4>
-                   <p>我觉得之所以现在很多人再说不好,是因为对2的期待值过高。 不可否认,由于冰1的成功,加上6年时间的准备以及后期的有力宣传,确实抱有非常高的期待值。但是因文化差异等因素,有些部分确实会不那么让人喜欢。 [比如我个人就不太喜欢太多唱歌] 但实际上冰雪奇缘2依然是一部较优秀的作品。</p>
-                   <p class="time">2019-04-28</p>
-                   <div class="reply_info"> 回复:<input type="text" id="name" name="name"></div>
-               </span>
-           </li>
-           <li class="evaluate_li">
-            <span class="img">
-               <img src="images/tou3.jpg" alt="头像" />
-           </span>
-           <span class="info">
-               <h4>我是路人帅</h4>
-               <p>我最喜欢迪士尼音乐剧了,唱歌是用另一种方式推动剧情,角色用音乐的方式诉说或者对话,这样有童话色彩。是不是把所有唱歌的词直接改成角色正常的说话,电影就很好看了? 还有,音乐剧电影中,角色唱过的旋律后面还会再次唱,这是使电影的音乐更和谐,两段音乐呼应,会更美妙,几乎每个音乐剧都有,特别是迪士尼的经典影片,后面重复的音乐在音乐剧中叫Reprise,是音乐剧表现的普遍手法。</p>
-               <p class="time">2019-04-28</p>
-               <div class="reply_info"> 回复:<input type="text" id="name" name="name"></div>
-           </span>
-       </li>
-        </ul>
-    </div>
-</ion-content>
-
+<!-- <ion-header>
+    <ion-toolbar>
+      <ion-title>社区交流</ion-title>
+    </ion-toolbar>
+  </ion-header>
+  
+  <ion-content>
+    <ion-item>
+      <ion-label position="floating">发布新帖子</ion-label>
+      <ion-input [(ngModel)]="newPostContent"></ion-input>
+    </ion-item>
+    <ion-button expand="full" (click)="addPost()">发布</ion-button>
+  
+    <ion-list>
+      <ion-item *ngFor="let post of posts">
+        <ion-label>
+          <h2>{{ post.content }}</h2>
+          <p>评论 ({{ post.comments.length }})</p>
+        </ion-label>
+        <ion-button (click)="toggleComments(post)">查看评论</ion-button>
+        <ion-item *ngIf="post.showComments">
+          <ion-input [(ngModel)]="post.newComment" placeholder="添加评论"></ion-input>
+          <ion-button (click)="addComment(post)">提交评论</ion-button>
+        </ion-item>
+        <ion-list *ngIf="post.showComments">
+          <ion-item *ngFor="let comment of post.comments">
+            <ion-label>{{ comment }}</ion-label>
+          </ion-item>
+        </ion-list>
+      </ion-item>
+    </ion-list>
+  </ion-content> -->

+ 24 - 3
paint-app/src/app/test2-page/test2-page.component.ts

@@ -16,9 +16,30 @@ import { addIcons } from 'ionicons';
   ,IonIcon],
 })
 export class Test2PageComponent  {
-  constructor(private router: Router){}
+  newPostContent: string = '';
+  posts: { content: string; comments: string[]; showComments: boolean; newComment?: string }[] = [];
 
-  gopage(){
-    this.router.navigate(['/tabs/tab2'])
+  constructor() {}
+
+  addPost() {
+    if (this.newPostContent.trim()) {
+      this.posts.push({
+        content: this.newPostContent,
+        comments: [],
+        showComments: false,
+      });
+      this.newPostContent = '';
+    }
   }
+
+  // toggleComments(post) {
+  //   post.showComments = !post.showComments;
+  // }
+
+  // addComment(post) {
+  //   if (post.newComment && post.newComment.trim()) {
+  //     post.comments.push(post.newComment);
+  //     post.newComment = '';
+  //   }
+  // }
 }

+ 2 - 53
paint-app/src/app/video-page/video-page.component.html

@@ -20,61 +20,10 @@
     <div class="art-content">
         <!-- 评价选择 -->
         <p class="switch-head-line">
-            <span class="mr chooseActive" eval_data='1'>评论</span>
+            <span class="mr chooseActive" eval_data='1'>视频简介</span>
         </p>
         <!-- 评价选择 -->
-        
-        <ul id="user_evaluate">
-
-            <li *ngFor="let comment of commentList" class="evaluate_li">
-                 <span class="img">
-                    <img src="../../assets/icon/tou1.jpg" style="width: 50px;
-                    height:50px;
-                    border-radius: 50%;
-                    margin-right:30px;"alt="头像" />
-                </span>
-                <span class="info">
-                    <h4>{{comment.get('user')?.get('username') || '不知名的网友'}}</h4>
-                    <p>{{comment.get('subtance')}}</p>
-                    <p class="time">{{comment.get('updatedAt')}}</p>
-                    <!-- <div class="reply_info">回复: <input type="text" id="name" name="name"></div> -->
-                </span>
-            </li>
-
-
-            <!-- <div *ngFor="let comment of commentList" class="image-wrapper" (click)="navigateToDetail()">
-                <img [src]="paint.get('picture')" [alt]="paint.get('name')" />
-                <div class="description-box">
-                    <div class="text1"><p>《{{ paint.get('name') }}》——{{ paint.get('artist') }}</p></div>
-                    <div class="text2"><p>{{ paint.get('introduction') }}</p></div>
-                </div>
-            </div>
-
-
-
-            <li class="evaluate_li">
-                <span class="img">
-                   <img src="images/tou1.jpg" alt="头像" />
-               </span>
-               <span class="info">
-                   <h4>爱你的我</h4>
-                   <p>我觉得之所以现在很多人再说不好,是因为对2的期待值过高。 不可否认,由于冰1的成功,加上6年时间的准备以及后期的有力宣传,确实抱有非常高的期待值。但是因文化差异等因素,有些部分确实会不那么让人喜欢。 [比如我个人就不太喜欢太多唱歌] 但实际上冰雪奇缘2依然是一部较优秀的作品。</p>
-                   <p class="time">2019-04-28</p>
-                   <div class="reply_info"> 回复:<input type="text" id="name" name="name"></div>
-               </span>
-           </li>
-           <li class="evaluate_li">
-            <span class="img">
-               <img src="images/tou3.jpg" alt="头像" />
-           </span>
-           <span class="info">
-               <h4>我是路人帅</h4>
-               <p>我最喜欢迪士尼音乐剧了,唱歌是用另一种方式推动剧情,角色用音乐的方式诉说或者对话,这样有童话色彩。是不是把所有唱歌的词直接改成角色正常的说话,电影就很好看了? 还有,音乐剧电影中,角色唱过的旋律后面还会再次唱,这是使电影的音乐更和谐,两段音乐呼应,会更美妙,几乎每个音乐剧都有,特别是迪士尼的经典影片,后面重复的音乐在音乐剧中叫Reprise,是音乐剧表现的普遍手法。</p>
-               <p class="time">2019-04-28</p>
-               <div class="reply_info"> 回复:<input type="text" id="name" name="name"></div>
-           </span>
-       </li> -->
-        </ul>
+         <p>{{video?.get('allintroduce')}}</p>
     </div>
 </ion-content>
 

+ 6 - 13
paint-app/src/app/video-page/video-page.component.ts

@@ -26,26 +26,19 @@ export class VideoPageComponent{
     this.router.navigate(['/tabs/tab2'])
     
   }
-  commentList:Array<CloudObject> = []
+  video:CloudObject| null =null;
   videoId: string=''; // 用于存储传递的参数
   ngOnInit() {
     this.route.params.subscribe(params => {
       this.videoId = params['id'];
-      console.log('接收到的参数:', this.videoId);
       // 根据 videoId 加载视频数据
     });
-    this.loadcommentList()
+    this.loadvideolist()
   }
 
-      async loadcommentList(){
-      let query = new CloudQuery("pcomment");
-      await query.equalTo("videoname",this.videoId)
-      this.commentList = await query.find()
-      if (this.commentList && this.commentList.length > 0) {
-        console.log('有评论列表');
-      }
-      else{
-        console.log('无评论列表');
-      }
+      async loadvideolist(){
+      let query = new CloudQuery("pvideo");
+      await query.equalTo("name",this.videoId)
+      this.video = await query.first()
       }
 }

+ 531 - 85
paint-app/src/lib/ncloud.ts

@@ -1,5 +1,358 @@
+// // CloudObject.ts
+// //CloudObject 是表示数据库中单个对象的类。每个 CloudObject 实例对应数据库中的一条记录。
+// export class CloudObject {
+//     className: string; // 类名,用于标识对象的类型
+//     id: string | null = null; // 对象的唯一标识符,初始为 null
+//     createdAt: any; // 对象创建时间
+//     updatedAt: any; // 对象更新时间
+//     data: Record<string, any> = {}; // 存储对象的实际数据
+
+//     // 构造函数,初始化类名
+//     constructor(className: string) {
+//         this.className = className; // 设置对象的类名
+//     }
+
+//     // 将当前对象转换为指针形式,包含类名和对象 ID
+//     toPointer() {
+//         return { "__type": "Pointer", "className": this.className, "objectId": this.id };
+//     }
+
+//     // 设置对象的数据
+//     set(json: Record<string, any>) {
+//         Object.keys(json).forEach(key => {
+//             // 排除特定的保留字段,不允许直接设置
+//             if (["objectId", "id", "createdAt", "updatedAt", "ACL"].indexOf(key) > -1) {
+//                 return; // 如果是保留字段,则跳过
+//             }
+//             this.data[key] = json[key]; // 将数据设置到对象的 data 属性中
+//         });
+//     }
+
+//     // 获取指定键的值
+//     get(key: string) {
+//         return this.data[key] || null; // 返回对应键的值,如果不存在则返回 null
+//     }
+
+//     // 保存对象到服务器
+//     async save() {
+//         let method = "POST"; // 默认使用 POST 方法
+//         let url = `https://dev.fmode.cn/parse/classes/${this.className}`; // 基础 URL
+
+//         // 如果对象已有 ID,则为更新操作,使用 PUT 方法
+//         if (this.id) {
+//             url += `/${this.id}`; // 追加对象 ID 到 URL
+//             method = "PUT"; // 设置为 PUT 方法
+//         }
+
+//         const body = JSON.stringify(this.data); // 将数据转换为 JSON 字符串
+//         const response = await fetch(url, {
+//             headers: {
+//                 "content-type": "application/json;charset=UTF-8", // 设置请求内容类型为 JSON
+//                 "x-parse-application-id": "dev" // 设置应用 ID
+//             },
+//             body: body, // 请求体
+//             method: method, // 请求方法
+//             mode: "cors", // 跨域请求模式
+//             credentials: "omit" // 不附带凭证
+//         });
+
+//         const result = await response?.json(); // 解析响应为 JSON
+//         if (result?.error) {
+//             console.error(result?.error); // 输出错误信息
+//         }
+//         if (result?.objectId) {
+//             this.id = result?.objectId; // 如果返回了对象 ID,则更新本地 ID
+//         }
+//         return this; // 返回当前对象实例
+//     }
+
+//     // 删除对象
+//     async destroy() {
+//         if (!this.id) return; // 如果对象没有 ID,则无法删除
+//         const response = await fetch(`https://dev.fmode.cn/parse/classes/${this.className}/${this.id}`, {
+//             headers: {
+//                 "x-parse-application-id": "dev" // 设置应用 ID
+//             },
+//             body: null, // 请求体为空
+//             method: "DELETE", // 使用 DELETE 方法
+//             mode: "cors", // 跨域请求模式
+//             credentials: "omit" // 不附带凭证
+//         });
+
+//         const result = await response?.json(); // 解析响应为 JSON
+//         if (result) {
+//             this.id = null; // 删除成功后,将本地 ID 设置为 null
+//         }
+//         return true; // 返回删除成功的状态
+//     }
+// }
+
+// // CloudQuery.ts\
+// //CloudQuery 是用于查询数据库中多个对象的类。它允许你构建查询条件并获取符合条件的多个记录。
+// export class CloudQuery {
+//     className: string; // 存储类名
+//     whereOptions: Record<string, any> = {}; // 存储查询条件的对象,初始为空对象
+
+//     // 构造函数,接受一个类名作为参数
+//     constructor(className: string) {
+//         this.className = className; // 初始化类名
+//     }
+
+//     // 方法:添加大于条件
+//     greaterThan(key: string, value: any) {
+//         // 如果该键不存在,则初始化为空对象
+//         if (!this.whereOptions[key]) this.whereOptions[key] = {};
+//         // 设置大于条件
+//         this.whereOptions[key]["$gt"] = value;
+//     }
+
+//     // 方法:添加大于等于条件
+//     greaterThanAndEqualTo(key: string, value: any) {
+//         // 如果该键不存在,则初始化为空对象
+//         if (!this.whereOptions[key]) this.whereOptions[key] = {};
+//         // 设置大于等于条件
+//         this.whereOptions[key]["$gte"] = value;
+//     }
+
+//     // 方法:添加小于条件
+//     lessThan(key: string, value: any) {
+//         // 如果该键不存在,则初始化为空对象
+//         if (!this.whereOptions[key]) this.whereOptions[key] = {};
+//         // 设置小于条件
+//         this.whereOptions[key]["$lt"] = value;
+//     }
+
+//     // 方法:添加小于等于条件
+//     lessThanAndEqualTo(key: string, value: any) {
+//         // 如果该键不存在,则初始化为空对象
+//         if (!this.whereOptions[key]) this.whereOptions[key] = {};
+//         // 设置小于等于条件
+//         this.whereOptions[key]["$lte"] = value;
+//     }
+
+//     // 方法:添加等于条件
+//     equalTo(key: string, value: any) {
+//         // 直接设置等于条件
+//         this.whereOptions[key] = value;
+//     }
+
+//     async get(id: string) {
+//         const url = `https://dev.fmode.cn/parse/classes/${this.className}/${id}?`;
+
+//         const response = await fetch(url, {
+//             headers: {
+//                 "if-none-match": "W/\"1f0-ghxH2EwTk6Blz0g89ivf2adBDKY\"",
+//                 "x-parse-application-id": "dev"
+//             },
+//             body: null,
+//             method: "GET",
+//             mode: "cors",
+//             credentials: "omit"
+//         });
+
+//         const json = await response?.json();
+//         return json || {};
+//     }
+
+//     async find() {
+//         // 构建请求的基础 URL,包含类名
+//         let url = `https://dev.fmode.cn/parse/classes/${this.className}?`;
+    
+//         // 检查是否有查询条件,如果有,则将其序列化为 JSON 字符串
+//         if (Object.keys(this.whereOptions).length) {
+//             const whereStr = JSON.stringify(this.whereOptions);
+//             // 将查询条件添加到 URL 中
+//             url += `where=${whereStr}`;
+//         }
+    
+//         // 使用 fetch API 发送 GET 请求
+//         const response = await fetch(url, {
+//             headers: {
+//                 // 如果服务器返回的内容没有变化,则使用此请求头
+//                 "if-none-match": "W/\"1f0-ghxH2EwTk6Blz0g89ivf2adBDKY\"",
+//                 // 设置 Parse 应用的 ID
+//                 "x-parse-application-id": "dev"
+//             },
+//             body: null, // GET 请求不需要请求体
+//             method: "GET", // 请求方法为 GET
+//             mode: "cors", // 跨域请求模式
+//             credentials: "omit" // 不携带凭据(如 Cookies)
+//         });
+    
+//         // 解析响应为 JSON 格式
+//         const json = await response?.json();
+//         // 从结果中提取数据,默认为空数组
+//         let list = json?.results || [];
+//         // 将获取的原始数据转换为对象列表
+//         let objList = list.map((item: any) => this.dataToObj(item));
+//         // 返回转换后的对象列表,如果没有数据则返回空数组
+//         return objList || [];
+//     }
+//     async first() {
+//         let url = `https://dev.fmode.cn/parse/classes/${this.className}?`;
+
+//         if (Object.keys(this.whereOptions).length) {
+//             const whereStr = JSON.stringify(this.whereOptions);
+//             url += `where=${whereStr}`;
+//         }
+
+//         const response = await fetch(url, {
+//             headers: {
+//                 "if-none-match": "W/\"1f0-ghxH2EwTk6Blz0g89ivf2adBDKY\"",
+//                 "x-parse-application-id": "dev"
+//             },
+//             body: null,
+//             method: "GET",
+//             mode: "cors",
+//             credentials: "omit"
+//         });
+
+//         const json = await response?.json();
+//         const exists = json?.results?.[0] || null;
+//         if (exists) {
+//             let existsObject = this.dataToObj(exists)
+//             return existsObject;
+//         }
+//         return null
+//     }
+
+//     dataToObj(exists:any):CloudObject{
+//         let existsObject = new CloudObject(this.className);
+//         existsObject.set(exists);
+//         existsObject.id = exists.objectId;
+//         existsObject.createdAt = exists.createdAt;
+//         existsObject.updatedAt = exists.updatedAt;
+//         return existsObject;
+//     }
+// }
+
+// // CloudUser.ts
+// export class CloudUser extends CloudObject {
+//     constructor() {
+//         super("_User"); // 假设用户类在Parse中是"_User"
+//         // 读取用户缓存信息
+//         let userCacheStr = localStorage.getItem("NCloud/dev/User")
+//         if(userCacheStr){
+//             let userData = JSON.parse(userCacheStr)
+//             // 设置用户信息
+//             this.id = userData?.objectId;
+//             this.sessionToken = userData?.sessionToken;
+//             this.data = userData; // 保存用户数据
+//         }
+//     }
+
+//     sessionToken:string|null = ""
+//     /** 获取当前用户信息 */
+//     async current() {
+//         if (!this.sessionToken) {
+//             console.error("用户未登录");
+//             return null;
+//         }
+        
+//         const response = await fetch(`https://dev.fmode.cn/parse/users/me`, {
+//             headers: {
+//                 "x-parse-application-id": "dev",
+//                 "x-parse-session-token": this.sessionToken // 使用sessionToken进行身份验证
+//             },
+//             method: "GET"
+//         });
+
+//         const result = await response?.json();
+//         if (result?.error) {
+//             console.error(result?.error);
+//             return null;
+//         }
+//         return result;
+//     }
+
+//     /** 登录 */
+//     async login(username: string, password: string):Promise<CloudUser|null> {
+//         const response = await fetch(`https://dev.fmode.cn/parse/login`, {
+//             headers: {
+//                 "x-parse-application-id": "dev",
+//                 "Content-Type": "application/json"
+//             },
+//             body: JSON.stringify({ username, password }),
+//             method: "POST"
+//         });
+
+//         const result = await response?.json();
+//         if (result?.error) {
+//             console.error(result?.error);
+//             return null;
+//         }
+        
+//         // 设置用户信息
+//         this.id = result?.objectId;
+//         this.sessionToken = result?.sessionToken;
+//         this.data = result; // 保存用户数据
+//         // 缓存用户信息
+//         console.log(result)
+//         localStorage.setItem("NCloud/dev/User",JSON.stringify(result))
+//         return this;
+//     }
+
+//     /** 登出 */
+//     async logout() {
+//         if (!this.sessionToken) {
+//             console.error("用户未登录");
+//             return;
+//         }
+
+//         const response = await fetch(`https://dev.fmode.cn/parse/logout`, {
+//             headers: {
+//                 "x-parse-application-id": "dev",
+//                 "x-parse-session-token": this.sessionToken
+//             },
+//             method: "POST"
+//         });
+
+//         const result = await response?.json();
+//         if (result?.error) {
+//             console.error(result?.error);
+//             return false;
+//         }
+
+//         // 清除用户信息
+//         localStorage.removeItem("NCloud/dev/User")
+//         this.id = null;
+//         this.sessionToken = null;
+//         this.data = {};
+//         return true;
+//     }
+
+//     /** 注册 */
+//     async signUp(username: string, password: string, additionalData: Record<string, any> = {}) {
+//         const userData = {
+//             username,
+//             password,
+//             ...additionalData // 合并额外的用户数据
+//         };
+
+//         const response = await fetch(`https://dev.fmode.cn/parse/users`, {
+//             headers: {
+//                 "x-parse-application-id": "dev",
+//                 "Content-Type": "application/json"
+//             },
+//             body: JSON.stringify(userData),
+//             method: "POST"
+//         });
+
+//         const result = await response?.json();
+//         if (result?.error) {
+//             console.error(result?.error);
+//             return null;
+//         }
+
+//         // 设置用户信息
+//         this.id = result?.objectId;
+//         this.sessionToken = result?.sessionToken;
+//         this.data = result; // 保存用户数据
+//         return this;
+//     }
+// }
+
 // CloudObject.ts
-//CloudObject 是表示数据库中单个对象的类。每个 CloudObject 实例对应数据库中的一条记录。
 export class CloudObject {
     className: string;
     id: string | null = null;
@@ -17,7 +370,7 @@ export class CloudObject {
 
     set(json: Record<string, any>) {
         Object.keys(json).forEach(key => {
-            if (["objectId", "id", "createdAt", "updatedAt", "ACL"].indexOf(key) > -1) {
+            if (["objectId", "id", "createdAt", "updatedAt"].indexOf(key) > -1) {
                 return;
             }
             this.data[key] = json[key];
@@ -78,55 +431,52 @@ export class CloudObject {
         }
         return true;
     }
+    
+        // 新增方法:添加Pointer类型
+        addPointer(key: string, className: string, objectId: string) {
+            this.data[key] = {
+                "__type": "Pointer",
+                "className": className,
+                "objectId": objectId
+            };
+        }
 }
 
-// CloudQuery.ts\
-//CloudQuery 是用于查询数据库中多个对象的类。它允许你构建查询条件并获取符合条件的多个记录。
+// CloudQuery.ts
 export class CloudQuery {
-    className: string; // 存储类名
-    whereOptions: Record<string, any> = {}; // 存储查询条件的对象,初始为空对象
+    className: string;
+    queryParams: Record<string, any> = {};
 
-    // 构造函数,接受一个类名作为参数
     constructor(className: string) {
-        this.className = className; // 初始化类名
+        this.className = className;
     }
 
-    // 方法:添加大于条件
+    include(...fileds:string[]) {
+        this.queryParams["include"] = fileds;
+    }
     greaterThan(key: string, value: any) {
-        // 如果该键不存在,则初始化为空对象
-        if (!this.whereOptions[key]) this.whereOptions[key] = {};
-        // 设置大于条件
-        this.whereOptions[key]["$gt"] = value;
+        if (!this.queryParams["where"][key]) this.queryParams["where"][key] = {};
+        this.queryParams["where"][key]["$gt"] = value;
     }
 
-    // 方法:添加大于等于条件
     greaterThanAndEqualTo(key: string, value: any) {
-        // 如果该键不存在,则初始化为空对象
-        if (!this.whereOptions[key]) this.whereOptions[key] = {};
-        // 设置大于等于条件
-        this.whereOptions[key]["$gte"] = value;
+        if (!this.queryParams["where"][key]) this.queryParams["where"][key] = {};
+        this.queryParams["where"][key]["$gte"] = value;
     }
 
-    // 方法:添加小于条件
     lessThan(key: string, value: any) {
-        // 如果该键不存在,则初始化为空对象
-        if (!this.whereOptions[key]) this.whereOptions[key] = {};
-        // 设置小于条件
-        this.whereOptions[key]["$lt"] = value;
+        if (!this.queryParams["where"][key]) this.queryParams["where"][key] = {};
+        this.queryParams["where"][key]["$lt"] = value;
     }
 
-    // 方法:添加小于等于条件
     lessThanAndEqualTo(key: string, value: any) {
-        // 如果该键不存在,则初始化为空对象
-        if (!this.whereOptions[key]) this.whereOptions[key] = {};
-        // 设置小于等于条件
-        this.whereOptions[key]["$lte"] = value;
+        if (!this.queryParams["where"][key]) this.queryParams["where"][key] = {};
+        this.queryParams["where"][key]["$lte"] = value;
     }
 
-    // 方法:添加等于条件
     equalTo(key: string, value: any) {
-        // 直接设置等于条件
-        this.whereOptions[key] = value;
+        if (!this.queryParams["where"]) this.queryParams["where"] = {};
+        this.queryParams["where"][key] = value;
     }
 
     async get(id: string) {
@@ -144,48 +494,55 @@ export class CloudQuery {
         });
 
         const json = await response?.json();
-        return json || {};
+        if (json) {
+            let existsObject = this.dataToObj(json)
+            return existsObject;
+        }
+        return null
     }
 
-    async find() {
-        // 构建请求的基础 URL,包含类名
+    async find():Promise<Array<CloudObject>> {
         let url = `https://dev.fmode.cn/parse/classes/${this.className}?`;
-    
-        // 检查是否有查询条件,如果有,则将其序列化为 JSON 字符串
-        if (Object.keys(this.whereOptions).length) {
-            const whereStr = JSON.stringify(this.whereOptions);
-            // 将查询条件添加到 URL 中
-            url += `where=${whereStr}`;
-        }
-    
-        // 使用 fetch API 发送 GET 请求
+
+        let queryStr = ``
+        Object.keys(this.queryParams).forEach(key=>{
+            let paramStr = JSON.stringify(this.queryParams[key]);
+            if(key=="include"){
+                paramStr = this.queryParams[key]?.join(",")
+            }
+            if(queryStr) {
+                url += `${key}=${paramStr}`;
+            }else{
+                url += `&${key}=${paramStr}`;
+            }
+        })
+        // if (Object.keys(this.queryParams["where"]).length) {
+            
+        // }
+
         const response = await fetch(url, {
             headers: {
-                // 如果服务器返回的内容没有变化,则使用此请求头
                 "if-none-match": "W/\"1f0-ghxH2EwTk6Blz0g89ivf2adBDKY\"",
-                // 设置 Parse 应用的 ID
                 "x-parse-application-id": "dev"
             },
-            body: null, // GET 请求不需要请求体
-            method: "GET", // 请求方法为 GET
-            mode: "cors", // 跨域请求模式
-            credentials: "omit" // 不携带凭据(如 Cookies)
+            body: null,
+            method: "GET",
+            mode: "cors",
+            credentials: "omit"
         });
-    
-        // 解析响应为 JSON 格式
+
         const json = await response?.json();
-        // 从结果中提取数据,默认为空数组
-        let list = json?.results || [];
-        // 将获取的原始数据转换为对象列表
-        let objList = list.map((item: any) => this.dataToObj(item));
-        // 返回转换后的对象列表,如果没有数据则返回空数组
+        let list = json?.results || []
+        let objList = list.map((item:any)=>this.dataToObj(item))
         return objList || [];
     }
+
+
     async first() {
         let url = `https://dev.fmode.cn/parse/classes/${this.className}?`;
 
-        if (Object.keys(this.whereOptions).length) {
-            const whereStr = JSON.stringify(this.whereOptions);
+        if (Object.keys(this.queryParams["where"]).length) {
+            const whereStr = JSON.stringify(this.queryParams["where"]);
             url += `where=${whereStr}`;
         }
 
@@ -222,18 +579,27 @@ export class CloudQuery {
 // CloudUser.ts
 export class CloudUser extends CloudObject {
     constructor() {
-        super("_User"); // 假设用户类在Parse中是"_User"
-        // 读取用户缓存信息
-        let userCacheStr = localStorage.getItem("NCloud/dev/User")
-        if(userCacheStr){
-            let userData = JSON.parse(userCacheStr)
-            // 设置用户信息
-            this.id = userData?.objectId;
-            this.sessionToken = userData?.sessionToken;
-            this.data = userData; // 保存用户数据
+        // 调用父类构造函数,假设用户类在Parse中是"_User"
+        super("_User");
+    
+        // 从本地存储中读取用户缓存信息
+        let userCacheStr = localStorage.getItem("NCloud/dev/User");
+        
+        // 如果缓存中存在用户数据
+        if (userCacheStr) {
+            // 将缓存的字符串数据解析为JSON对象
+            let userData = JSON.parse(userCacheStr);
+            
+            // 设置当前实例的id属性为用户数据中的objectId
+            this.id = userData?.objectId; // 使用可选链操作符安全访问objectId
+            
+            // 设置当前实例的sessionToken属性为用户数据中的sessionToken
+            this.sessionToken = userData?.sessionToken; // 使用可选链操作符安全访问sessionToken
+            
+            // 保存整个用户数据对象到当前实例的data属性中
+            this.data = userData; // 将用户数据保存到data属性中,以便后续使用
         }
     }
-
     sessionToken:string|null = ""
     /** 获取当前用户信息 */
     async current() {
@@ -241,21 +607,21 @@ export class CloudUser extends CloudObject {
             console.error("用户未登录");
             return null;
         }
-        
-        const response = await fetch(`https://dev.fmode.cn/parse/users/me`, {
-            headers: {
-                "x-parse-application-id": "dev",
-                "x-parse-session-token": this.sessionToken // 使用sessionToken进行身份验证
-            },
-            method: "GET"
-        });
-
-        const result = await response?.json();
-        if (result?.error) {
-            console.error(result?.error);
-            return null;
-        }
-        return result;
+        return this;
+        // const response = await fetch(`https://dev.fmode.cn/parse/users/me`, {
+        //     headers: {
+        //         "x-parse-application-id": "dev",
+        //         "x-parse-session-token": this.sessionToken // 使用sessionToken进行身份验证
+        //     },
+        //     method: "GET"
+        // });
+
+        // const result = await response?.json();
+        // if (result?.error) {
+        //     console.error(result?.error);
+        //     return null;
+        // }
+        // return result;
     }
 
     /** 登录 */
@@ -300,18 +666,26 @@ export class CloudUser extends CloudObject {
             method: "POST"
         });
 
-        const result = await response?.json();
+        let result = await response?.json();
+
         if (result?.error) {
             console.error(result?.error);
+            if(result?.error=="Invalid session token"){
+                this.clearUserCache()
+                return true;
+            }
             return false;
         }
 
+        this.clearUserCache()
+        return true;
+    }
+    clearUserCache(){
         // 清除用户信息
         localStorage.removeItem("NCloud/dev/User")
         this.id = null;
         this.sessionToken = null;
         this.data = {};
-        return true;
     }
 
     /** 注册 */
@@ -338,9 +712,81 @@ export class CloudUser extends CloudObject {
         }
 
         // 设置用户信息
+        // 缓存用户信息
+        console.log(result)
+        localStorage.setItem("NCloud/dev/User",JSON.stringify(result))
         this.id = result?.objectId;
         this.sessionToken = result?.sessionToken;
         this.data = result; // 保存用户数据
         return this;
     }
+
+    override async save() {
+        let method = "POST";
+        let url = `https://dev.fmode.cn/parse/users`;
+    
+        // 更新用户信息
+        if (this.id) {
+            url += `/${this.id}`;
+            method = "PUT";
+        }
+    
+        let data:any = JSON.parse(JSON.stringify(this.data))
+        delete data.createdAt
+        delete data.updatedAt
+        delete data.ACL
+        delete data.objectId
+        const body = JSON.stringify(data);
+        let headersOptions:any = {
+            "content-type": "application/json;charset=UTF-8",
+            "x-parse-application-id": "dev",
+            "x-parse-session-token": this.sessionToken, // 添加sessionToken以进行身份验证
+        }
+        const response = await fetch(url, {
+            headers: headersOptions,
+            body: body,
+            method: method,
+            mode: "cors",
+            credentials: "omit"
+        });
+    
+        const result = await response?.json();
+        if (result?.error) {
+            console.error(result?.error);
+        }
+        if (result?.objectId) {
+            this.id = result?.objectId;
+        }
+        localStorage.setItem("NCloud/dev/User",JSON.stringify(this.data))
+        return this;
+    }
+}
+
+export class CloudApi{
+    async fetch(path:string,body:any,options?:{
+        method:string
+        body:any
+    }){
+
+        let reqOpts:any =  {
+            headers: {
+                "x-parse-application-id": "dev",
+                "Content-Type": "application/json"
+            },
+            method: options?.method || "POST",
+            mode: "cors",
+            credentials: "omit"
+        }
+        if(body||options?.body){
+            reqOpts.body = JSON.stringify(body || options?.body);
+            reqOpts.json = true;
+        }
+        let host = `https://dev.fmode.cn`
+        // host = `http://127.0.0.1:1337`
+        let url = `${host}/api/`+path
+        console.log(url,reqOpts)
+        const response = await fetch(url,reqOpts);
+        let json = await response.json();
+        return json
+    }
 }