s202226701053 6 ماه پیش
والد
کامیت
b302524768

+ 12 - 20
E-Cover-app/src/app/tab2/tab2.page.html

@@ -32,32 +32,15 @@
                                     </ion-button>
                               </div>
 
-                              <div style="clear: both;margin: 5px 0;">
+                              <div style="clear: both;margin: 5px 0;" *ngFor="let tag of tags">
                                     <ion-img style="float: left;width:15px;margin: 5px;"
                                           src="https://s1.imagehub.cc/images/2024/12/24/a369c70551f442aeec3718575b7eeffe.png" />
                                     <div style="float: left;">
-                                          <p class="text">快乐圣诞派对</p>
-                                          <p class="intro">31.8k热度</p>
+                                          <p class="text">{{ tag?.get('name') }}</p>
+                                          <p class="intro">{{ formatNumber(tag?.get('click')) }} 热度</p>
                                     </div>
                               </div>
 
-                              <div style="clear: both;margin: 15px 0;">
-                                    <ion-img style="float: left;width:15px;margin: 5px;"
-                                          src="https://s1.imagehub.cc/images/2024/12/24/a369c70551f442aeec3718575b7eeffe.png" />
-                                    <div style="float: left;">
-                                          <p class="text">快乐圣诞派对</p>
-                                          <p class="intro">31.8k热度</p>
-                                    </div>
-                              </div>
-
-                              <div style="clear: both;margin: 5px 0;">
-                                    <ion-img style="float: left;width:15px;margin: 5px;"
-                                          src="https://s1.imagehub.cc/images/2024/12/24/a369c70551f442aeec3718575b7eeffe.png" />
-                                    <div style="float: left;">
-                                          <p class="text">快乐圣诞派对</p>
-                                          <p class="intro">31.8k热度</p>
-                                    </div>
-                              </div>
                         </ion-card>
                         <ion-card id="rolling-2">
                               <div class="rolling-top">
@@ -71,6 +54,15 @@
                         </ion-card>
                         <ion-card id="rolling-3">你卡上,到那时打开拉萨的那棵树的那是肯定</ion-card>
                   </div>
+                  <!-- <ion-button (click)="shuaxin()">刷新</ion-button>
+                  <div *ngFor="let post of posts; else noPosts">
+                        发帖用户:{{ post?.get('UserID')?.name }}<br />
+                        发帖标题:{{ post?.get('UserID')?.avatar }}<br />
+                        发帖内容:{{ post?.get('content') }}<br />
+                        发帖图片:{{ post?.get('image') }}<br />
+                        发帖标签:{{ post?.get('tag') }}<br />
+                  </div> -->
+                  <app-post-list></app-post-list>
             </ion-segment-content>
       </ion-segment-view>
 

+ 2 - 1
E-Cover-app/src/app/tab2/tab2.page.scss

@@ -42,7 +42,7 @@ ion-header {
 }
 
 ion-content {
-  --background: #f8f8f8;
+  --background: white;
   color: black;
 
   ion-segment-view {
@@ -54,6 +54,7 @@ ion-content {
         scrollbar-width: none;
         width: 100%;
         white-space: nowrap;
+        background-color: white;
 
         ion-card {
           border-radius: 15px;

+ 61 - 5
E-Cover-app/src/app/tab2/tab2.page.ts

@@ -4,21 +4,77 @@ import { ExploreContainerComponent } from '../explore-container/explore-containe
 import { Router } from '@angular/router';
 import { addIcons } from 'ionicons';
 import { addOutline, chevronForwardCircle } from 'ionicons/icons';
-addIcons({ addOutline,chevronForwardCircle})
+import { CloudObject, CloudQuery } from 'src/lib/ncloud';
+import { CommonModule } from '@angular/common';
+import { PostListComponent } from 'src/lib/component/post-list/post-list.component';
+addIcons({ addOutline, chevronForwardCircle })
 
 @Component({
   selector: 'app-tab2',
   templateUrl: 'tab2.page.html',
   styleUrls: ['tab2.page.scss'],
   standalone: true,
-  imports: [IonHeader, IonToolbar, IonTitle, IonContent, ExploreContainerComponent,IonButton,
-    IonSegment,IonSegmentButton,IonSegmentContent,IonSegmentView,IonIcon,IonText,IonLabel,
-    IonCard,IonImg
+  imports: [IonHeader, IonToolbar, IonTitle, IonContent, ExploreContainerComponent, IonButton,
+    IonSegment, IonSegmentButton, IonSegmentContent, IonSegmentView, IonIcon, IonText, IonLabel,
+    IonCard, IonImg, CommonModule,PostListComponent
   ]
 })
 export class Tab2Page {
-  constructor(private router:Router) {}
+  constructor(private router: Router) { }
+  ionViewWillEnter() {
+    this.getTop3Tag();
+  }
+  /**
+   * @读取top3话题
+   */
+  tags: Array<CloudObject> = [];
+  async getTop3Tag() {
+    let query = new CloudQuery("tag");
+    try {
+      //query.orderByDescending("click");
+      //query.setLimit(3);
+      let tags = await query.find();
+      this.tags = tags;
+      // tags.sort((a, b) => b.get('click') - a.get('click'));
+      // this.tags = this.tags.slice(0, 3);
+      console.log("查询top3话题结果如下:")
+      console.log(this.tags);
+    } catch (error) {
+      console.error("查询失败:", error);
+      this.tags = []; // 确保即使查询失败,posts 也被初始化为一个空数组
+    }
+  }
+  // 格式化数字的方法
+  formatNumber(num: number): string {
+    if (num >= 10000) {
+      return (num / 10000).toFixed(1) + 'w';
+    } else if (num >= 1000) {
+      return (num / 1000).toFixed(1) + 'k';
+    } else {
+      return num + '';
+    }
+  }
   goSendPost() {
     this.router.navigate(['/sendPost']);
   }
+  posts: Array<CloudObject> = [];
+  async shuaxin() {
+    let query = new CloudQuery("post");
+    query.include("UserID");
+    let obj = new CloudObject("_User");
+    obj.id = "e3wWcCfNwm";
+    query.equalTo("UserID", obj.toPointer())
+    console.log(query.queryParams)
+    console.log(query);
+    try {
+      let posts = await query.find();
+      this.posts = posts;
+      console.log(this.posts);
+    } catch (error) {
+      console.error("查询失败:", error);
+      this.posts = []; // 确保即使查询失败,posts 也被初始化为一个空数组
+    }
+
+    this.getTop3Tag();
+  }
 }

+ 2 - 0
E-Cover-app/src/app/tab3/tab3.page.scss

@@ -4,6 +4,7 @@
 
 ion-content {
     --background: black;
+    scrollbar-width: none;
 
     ion-card {
         width: 100%;
@@ -140,6 +141,7 @@ ion-content {
     height: fit-content;
     column-count: 2;
     column-gap: 20px; // 设置列之间的间距
+    scrollbar-width: none;
 
     ion-card {
         // width: 46%;

+ 4 - 2
E-Cover-app/src/app/tab3/tab3.page.ts

@@ -16,7 +16,7 @@ addIcons({ personAddOutline, cardOutline, flameOutline, chevronForwardOutline })
   imports: [IonicModule,CommonModule],
 })
 export class Tab3Page {
-  currentUser: CloudUser | undefined
+  currentUser: CloudUser | undefined;
   constructor(private modalCtrl: ModalController, private router: Router) {}
   // 格式化数字的方法
   formatNumber(num: number): string {
@@ -40,7 +40,9 @@ export class Tab3Page {
     }
     else {
       console.log("用户已登录,更新用户缓存信息")
-      await user.updateCache();
+      console.log("当前用户信息(未更新缓存前):");
+      console.log(user);
+      //await user.updateCache();
       console.log("当前用户信息:");
       console.log(user);
     }

+ 1 - 1
E-Cover-app/src/app/user-info/user-info.component.ts

@@ -20,7 +20,7 @@ export class UserInfoComponent implements OnInit {
     this.currentUser = new CloudUser();
   }
   async ionViewWillEnter() {
-    await this.currentUser?.updateCache();
+    //await this.currentUser?.updateCache();
   }
   ngOnInit() { }
 

+ 2 - 2
E-Cover-app/src/lib/component/custom-header/custom-header.component.scss

@@ -25,8 +25,8 @@ ion-header {
 
     font-family: 'header-font';
     top: 24px;
-    left:0;
-    width: 100vw;
+    left:10vw;
+    width: 80vw;
     text-align: center;
     margin:0 0;
 }

+ 43 - 0
E-Cover-app/src/lib/component/post-list/post-list.component.html

@@ -0,0 +1,43 @@
+<div class="post" *ngFor="let post of posts">
+  <div class="post-header">
+    <div class="avatar">
+      <img
+        [src]="post.get('UserID')?.avatar || 'https://tse1-mm.cn.bing.net/th/id/OIP-C.X-VG5gTN2ak8rGRij3oCogAAAA?rs=1&pid=ImgDetMain'"
+        alt="User Avatar" class="avatar-image">
+    </div>
+    <div class="user-info">
+      <span class="username">{{ post.get('user')?.username || "该用户还没有名字" }}</span>
+      <ion-icon name="ellipsis-horizontal" class="more-icon"></ion-icon>
+    </div>
+  </div>
+  <h2 class="post-title">{{ post?.get('title') }}</h2>
+  <!--标签-->
+  <div class="tag-container">
+    <div class="tag" *ngFor="let tag of post.get('tag')">
+      <ion-icon name="bookmark-outline" class="tagpicture"></ion-icon>{{ tag }}
+    </div>
+  </div>
+
+  <p class="post-content-text">{{ post?.get('content') }}</p>
+  <div class="image-gallery">
+    <img *ngFor="let image of post.get('image')" [src]="image" alt="Post Image" class="post-image">
+  </div>
+
+  <!-- 按钮区域 -->
+  <div class="button-container">
+    <ion-button fill="clear" class="action-button">
+      <ion-icon name="share-social-outline" class=""></ion-icon>
+      <span>分享</span>
+    </ion-button>
+    <ion-button fill="clear" class="action-button">
+      <ion-icon name="chatbubble-outline"></ion-icon>
+      <span>评论</span>
+    </ion-button>
+    <ion-button fill="clear" class="action-button" (click)="toggleLike()">
+      <ion-icon name="heart-outline" [name]="isLiked ? 'heart' : 'heart-outline'"
+        [style.color]="isLiked ? 'red' : 'black'"></ion-icon>
+      <span>点赞</span>
+    </ion-button>
+  </div>
+
+</div>

+ 0 - 0
E-Cover-app/src/lib/component/post-list/post-list.component.scss


+ 22 - 0
E-Cover-app/src/lib/component/post-list/post-list.component.spec.ts

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

+ 38 - 0
E-Cover-app/src/lib/component/post-list/post-list.component.ts

@@ -0,0 +1,38 @@
+import { CommonModule } from '@angular/common';
+import { Component, OnInit } from '@angular/core';
+import { IonButton, IonContent, IonIcon } from '@ionic/angular/standalone';
+import { addIcons } from 'ionicons';
+import { bookmarkOutline, chatbubbleOutline, ellipsisHorizontal, heart, heartOutline, shareSocialOutline, } from 'ionicons/icons';
+import { CloudObject, CloudQuery, CloudUser } from 'src/lib/ncloud';
+addIcons({ ellipsisHorizontal, bookmarkOutline, shareSocialOutline, chatbubbleOutline, heartOutline, heart })
+
+@Component({
+  selector: 'app-post-list',
+  templateUrl: './post-list.component.html',
+  styleUrls: ['./post-list.component.scss'],
+  standalone: true,
+  imports: [IonContent, IonIcon, IonButton, CommonModule]
+})
+export class PostListComponent implements OnInit {
+  constructor() { }
+
+  posts: CloudObject[] = []; // 存储帖子
+  resultUser: any;
+  async ngOnInit() {
+    const query = new CloudQuery('post'); // 创建查询对象
+    console.log(query);
+    query.include('UserID'); // 包含 user 属性
+    this.posts = await query.find(); // 使用 find 方法获取所有帖子
+    console.log("测试帖子头像:")
+    console.log(this.posts);
+  }
+
+
+  // 用于跟踪点赞状态
+  isLiked: boolean = false;
+
+  // 切换点赞状态
+  toggleLike() {
+    this.isLiked = !this.isLiked; // 切换状态
+  }
+}

+ 149 - 162
E-Cover-app/src/lib/ncloud.ts

@@ -2,9 +2,8 @@
 export class CloudObject {
     className: string;
     id: string | null = null;
-    createdAt: any;
-    updatedAt: any;
-    sessionToken: string | null = ""
+    createdAt:any;
+    updatedAt:any;
     data: Record<string, any> = {};
 
     constructor(className: string) {
@@ -17,7 +16,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];
@@ -37,13 +36,11 @@ export class CloudObject {
             url += `/${this.id}`;
             method = "PUT";
         }
-        console.log("准备发送"+method+"请求:"+url+",body为:");
+
         const body = JSON.stringify(this.data);
-        console.log(body);
         const response = await fetch(url, {
             headers: {
                 "content-type": "application/json;charset=UTF-8",
-                "x-parse-session-token": this.sessionToken||"",
                 "x-parse-application-id": "hcx"
             },
             body: body,
@@ -51,7 +48,7 @@ export class CloudObject {
             mode: "cors",
             credentials: "omit"
         });
-        console.log(response);
+
         const result = await response?.json();
         if (result?.error) {
             console.error(result?.error);
@@ -85,38 +82,38 @@ export class CloudObject {
 // CloudQuery.ts
 export class CloudQuery {
     className: string;
-    sessionToken: string | null = "";
-    whereOptions: Record<string, any> = {};
+    queryParams: Record<string, any> = {};
 
     constructor(className: string) {
         this.className = className;
     }
 
     include(...fileds:string[]) {
-        this.whereOptions["include"] = fileds;
+        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) {
@@ -134,16 +131,31 @@ export class CloudQuery {
         });
 
         const json = await response?.json();
-        return json || {};
+        if (json) {
+            let existsObject = this.dataToObj(json)
+            return existsObject;
+        }
+        return null
     }
 
-    async find() {
+    async find():Promise<Array<CloudObject>> {
         let url = `http://1.94.237.145:1337/parse/classes/${this.className}?`;
 
-        if (Object.keys(this.whereOptions).length) {
-            const whereStr = JSON.stringify(this.whereOptions);
-            url += `where=${whereStr}`;
-        }
+        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: {
@@ -158,32 +170,23 @@ export class CloudQuery {
 
         const json = await response?.json();
         let list = json?.results || []
-        let objList = list.map((item: any) => this.dataToObj(item))
+        let objList = list.map((item:any)=>this.dataToObj(item))
         return objList || [];
     }
-    /**
-     * @返回第一个查找到的结果
-     * @返回结果参考:CloudObject {
-     * id: 'e3wWcCfNwm', 
-     * data: {…}, 
-     * className: '_User', 
-     * sessionToken:"r:c0f4fe9cb8eb83d7f0295ff57e948419"
-     * createdAt: '2024-12-17T02:41:34.768Z', 
-     * updatedAt: '2024-12-23T00:33:15.961Z'}
-     */
+
+
     async first() {
         let url = `http://1.94.237.145:1337/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}`;
         }
 
         const response = await fetch(url, {
             headers: {
                 "if-none-match": "W/\"1f0-ghxH2EwTk6Blz0g89ivf2adBDKY\"",
-                "x-parse-application-id": "hcx",
-                "x-parse-session-token":this.sessionToken||"",
+                "x-parse-application-id": "hcx"
             },
             body: null,
             method: "GET",
@@ -200,7 +203,7 @@ export class CloudQuery {
         return null
     }
 
-    dataToObj(exists: any): CloudObject {
+    dataToObj(exists:any):CloudObject{
         let existsObject = new CloudObject(this.className);
         existsObject.set(exists);
         existsObject.id = exists.objectId;
@@ -215,10 +218,17 @@ export class CloudUser extends CloudObject {
     constructor() {
         super("_User"); // 假设用户类在Parse中是"_User"
         // 读取用户缓存信息
-        this.readCache();
+        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 = ""
+    sessionToken:string|null = ""
     /** 获取当前用户信息 */
     async current() {
         if (!this.sessionToken) {
@@ -226,29 +236,24 @@ export class CloudUser extends CloudObject {
             return null;
         }
         return this;
-    }
-
-    /**更新用户缓存 */
-    async updateCache() {
-        if (!this.sessionToken) {
-            console.error("正在执行更新用户缓存:用户未登录");
-            return;
-        }
-        let query = new CloudQuery("_User");
-        query.equalTo("objectId", this.id)
-        console.log("设置条件:objectId==" + this.id)
-        let user: any = await query.first()
-        console.log("查询到条件用户信息:")
-        console.log(user)
-        //需要把sessionToken也保存起来
-        user.sessionToken = this.sessionToken
-        localStorage.setItem("NCloud/hcx/User", JSON.stringify(user))
-        console.log("已将该信息更新至用户缓存!请检查");
-        this.readCache();
+        // const response = await fetch(`http://1.94.237.145:1337/parse/users/me`, {
+        //     headers: {
+        //         "x-parse-application-id": "hcx",
+        //         "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 loginByUsername(username: string, password: string): Promise<CloudUser | null> {
+    async loginByUsername(username: string, password: string):Promise<CloudUser|null> {
         const response = await fetch(`http://1.94.237.145:1337/parse/login`, {
             headers: {
                 "x-parse-application-id": "hcx",
@@ -263,81 +268,17 @@ export class CloudUser extends CloudObject {
             console.error(result?.error);
             return null;
         }
-
-        // 设置用户信息
-        this.id = result?.objectId;
-        this.sessionToken = result?.sessionToken;
-        this.updatedAt = result?.updatedAt;
-        this.className = '_User';
-        this.createdAt = result?.createdAt;
-        let excludedKeys = ["objectId", "sessionToken", "createdAt", "updatedAt"];
-        for (let key of excludedKeys) {
-            delete result[key];
-        }
-        this.data = result; // 保存用户数据
-        // 缓存用户信息
-        console.log("登录成功后即将缓存的信息如下:");
-        console.log(this)
-        localStorage.setItem("NCloud/hcx/User", JSON.stringify(this))
-        return this;
-    }
-
-    async loginByPhone(phone: string, verCode: string, trueVerCode: string): Promise<CloudUser | null> {
-        if (trueVerCode !== verCode) {
-            console.error('验证码错误');
-            return null;
-        }
-        let query = new CloudQuery("_User");
-        query.equalTo("phone", phone);
-        let user: any = await query.first();
-        //查询手机号对应的用户信息
-        let username: string='';
-        let password: string='secretpassword';
-        if (!user?.id) {
-            console.error('该手机号未注册');
-            //用户名即为手机号
-            username = phone.slice(0, 3) + '****' + phone.slice(-4);
-            console.log('该手机号未注册,即将自动创建该用户:'+username+',密码为:'+password);
-        }
-        //如果用户存在,则直接登录
-        console.log('该手机号已注册,即将直接登录该用户')
-        username = user.get('username');
-        console.log('用户名:'+username+',密码为:'+password);
-        const response = await fetch(`http://1.94.237.145:1337/parse/login`, {
-            headers: {
-                "x-parse-application-id": "hcx",
-                "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.updatedAt = result?.updatedAt;
-        this.className = '_User';
-        this.createdAt = result?.createdAt;
-        let excludedKeys = ["objectId", "sessionToken", "createdAt", "updatedAt"];
-        for (let key of excludedKeys) {
-            delete result[key];
-        }
         this.data = result; // 保存用户数据
-
         // 缓存用户信息
-        console.log("登录成功后即将缓存的信息如下:");
-        console.log(this);
-        localStorage.setItem("NCloud/hcx/User", JSON.stringify(this));
+        console.log(result)
+        localStorage.setItem("NCloud/dev/User",JSON.stringify(result))
         return this;
     }
 
-
     /** 登出 */
     async logout() {
         if (!this.sessionToken) {
@@ -353,18 +294,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/hcx/User")
+        localStorage.removeItem("NCloud/dev/User")
         this.id = null;
         this.sessionToken = null;
         this.data = {};
-        return true;
     }
 
     /** 注册 */
@@ -393,41 +342,79 @@ export class CloudUser extends CloudObject {
         // 设置用户信息
         // 缓存用户信息
         console.log(result)
-        localStorage.setItem("NCloud/hcx/User", JSON.stringify(result))
+        localStorage.setItem("NCloud/dev/User",JSON.stringify(result))
         this.id = result?.objectId;
         this.sessionToken = result?.sessionToken;
         this.data = result; // 保存用户数据
         return this;
     }
 
-    /**
-     * @读取缓存
-     * @读取示例:json{
-     *  id: "5b29481e037c6a007f7d0320",
-     *  className: "_User",
-     *  createdAt: "2018-06-27T09:54:38.815Z",
-     *  updatedAt: "2018-06-27T09:54:38.815Z",
-     *  sessionToken: "<KEY>",
-     *  data: {...}
-     * }
-     */
-    readCache(){
-        console.log("正在执行readCache方法:读取用户缓存信息");
-        let userCacheStr = localStorage.getItem("NCloud/hcx/User")
-        console.log("读取到的用户缓存信息:");
-        console.log(userCacheStr);
-        if (userCacheStr) {
-            let userData = JSON.parse(userCacheStr)
-            // 设置用户信息
-            this.id = userData?.id;
-            this.className = "_User";
-            this.updatedAt = userData?.updatedAt;
-            this.createdAt = userData?.createdAt;
-            this.sessionToken = userData?.sessionToken;
-            this.data = userData.data // 保存用户数据
-            console.log("用户缓存信息读取完毕:");
-            console.log(this);
+    override async save() {
+        let method = "POST";
+        let url = `http://1.94.237.145:1337/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": "hcx",
+            "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": "hcx",
+                "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 = `http://1.94.237.145:1337`
+        // 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
+    }
 }

+ 664 - 0
E-Cover-app/src/lib/ncloud1.ts

@@ -0,0 +1,664 @@
+// CloudObject.ts
+export class CloudObject {
+    className: string;
+    id: string | null = null;
+    createdAt: any;
+    updatedAt: any;
+    sessionToken: string | null = ""
+    data: Record<string, any> = {};
+
+    constructor(className: string) {
+        this.className = className;
+    }
+
+    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];
+        });
+    }
+
+    get(key: string) {
+        return this.data[key] || null;
+    }
+
+    async save() {
+        let method = "POST";
+        let url = `http://1.94.237.145:1337/parse/classes/${this.className}`;
+
+        // 更新
+        if (this.id) {
+            url += `/${this.id}`;
+            method = "PUT";
+        }
+        console.log("准备发送" + method + "请求:" + url + ",body为:");
+        const body = JSON.stringify(this.data);
+        console.log(body);
+        const response = await fetch(url, {
+            headers: {
+                "content-type": "application/json;charset=UTF-8",
+                "x-parse-session-token": this.sessionToken || "",
+                "x-parse-application-id": "hcx"
+            },
+            body: body,
+            method: method,
+            mode: "cors",
+            credentials: "omit"
+        });
+        console.log(response);
+        const result = await response?.json();
+        if (result?.error) {
+            console.error(result?.error);
+        }
+        if (result?.objectId) {
+            this.id = result?.objectId;
+        }
+        return this;
+    }
+
+    async destroy() {
+        if (!this.id) return;
+        const response = await fetch(`http://1.94.237.145:1337/parse/classes/${this.className}/${this.id}`, {
+            headers: {
+                "x-parse-application-id": "hcx"
+            },
+            body: null,
+            method: "DELETE",
+            mode: "cors",
+            credentials: "omit"
+        });
+
+        const result = await response?.json();
+        if (result) {
+            this.id = null;
+        }
+        return true;
+    }
+}
+
+// CloudQuery.ts
+// export class CloudQuery {
+//     className: string;
+//     sessionToken: string | null = "";
+//     whereOptions: Record<string, any> = {};
+
+//     constructor(className: string) {
+//         this.className = className;
+//     }
+
+//     include(...fileds: string[]) {
+//         this.whereOptions["include"] = fileds;
+//     }
+//     greaterThan(key: string, value: any) {
+//         if (!this.whereOptions["where"][key]) this.whereOptions["where"][key] = {};
+//         this.whereOptions["where"][key]["$gt"] = value;
+//     }
+
+//     greaterThanAndEqualTo(key: string, value: any) {
+//         if (!this.whereOptions["where"][key]) this.whereOptions["where"][key] = {};
+//         this.whereOptions["where"][key]["$gte"] = value;
+//     }
+
+//     lessThan(key: string, value: any) {
+//         if (!this.whereOptions["where"][key]) this.whereOptions["where"][key] = {};
+//         this.whereOptions["where"][key]["$lt"] = value;
+//     }
+
+//     lessThanAndEqualTo(key: string, value: any) {
+//         if (!this.whereOptions["where"][key]) this.whereOptions["where"][key] = {};
+//         this.whereOptions["where"][key]["$lte"] = value;
+//     }
+
+//     equalTo(key: string, value: any) {
+//         if (!this.whereOptions["where"]) this.whereOptions["where"] = {};
+//         this.whereOptions["where"][key] = value;
+//     }
+
+//     async get(id: string) {
+//         const url = `http://1.94.237.145:1337/parse/classes/${this.className}/${id}?`;
+
+//         const response = await fetch(url, {
+//             headers: {
+//                 "if-none-match": "W/\"1f0-ghxH2EwTk6Blz0g89ivf2adBDKY\"",
+//                 "x-parse-application-id": "hcx"
+//             },
+//             body: null,
+//             method: "GET",
+//             mode: "cors",
+//             credentials: "omit"
+//         });
+
+//         const json = await response?.json();
+//         if (json) {
+//             let existsObject = this.dataToObj(json);
+//             return existsObject;
+//         }
+//         return null;
+//     }
+//     /**
+//      * @select查询
+//      */
+//     async main() {
+//         let response = await fetch(`http://1.94.237.145:1337/api/psql/select`, {
+//             headers: {
+//                 "Content-Type": "application/json",
+//             },
+//             body: JSON.stringify({ "sql": "SELECT * FROM \"_User\" limit 5", "params": [] }),
+//             method: "POST",
+//             mode: "cors",
+//             credentials: "omit"
+//         });
+
+//         let result = await response?.json();
+//         console.log(result)
+//     }
+
+//     async find(): Promise<Array<CloudObject>> {
+//         let url = `http://1.94.237.145:1337/parse/classes/${this.className}?`;
+
+//         let queryStr = ``
+//         // if (Object.keys(this.whereOptions).length) {
+//         //     const whereStr = JSON.stringify(this.whereOptions);
+//         //     url += `where=${whereStr}`;
+//         // }
+//         Object.keys(this.whereOptions).forEach(key => {
+//             let paramStr = JSON.stringify(this.whereOptions[key]);
+//             if (key == "include") {
+//                 paramStr = this.whereOptions[key]?.join(",")
+//             }
+//             if (queryStr) {
+//                 url += `${key}=${paramStr}`;
+//             } else {
+//                 url += `&${key}=${paramStr}`;
+//             }
+//         })
+
+//         const response = await fetch(url, {
+//             headers: {
+//                 "if-none-match": "W/\"1f0-ghxH2EwTk6Blz0g89ivf2adBDKY\"",
+//                 "x-parse-application-id": "hcx"
+//             },
+//             body: null,
+//             method: "GET",
+//             mode: "cors",
+//             credentials: "omit"
+//         });
+
+//         const json = await response?.json();
+//         let list = json?.results || []
+//         let objList = list.map((item: any) => this.dataToObj(item))
+//         return objList || [];
+//     }
+//     /**
+//      * @返回第一个查找到的结果
+//      * @返回结果参考:CloudObject {
+//      * id: 'e3wWcCfNwm', 
+//      * data: {…}, 
+//      * className: '_User', 
+//      * sessionToken:"r:c0f4fe9cb8eb83d7f0295ff57e948419"
+//      * createdAt: '2024-12-17T02:41:34.768Z', 
+//      * updatedAt: '2024-12-23T00:33:15.961Z'}
+//      */
+//     async first() {
+//         let url = `http://1.94.237.145:1337/parse/classes/${this.className}?`;
+
+//         if (Object.keys(this.whereOptions["where"]).length) {
+//             const whereStr = JSON.stringify(this.whereOptions["where"]);
+//             console.log("first查询条件" + whereStr)
+//             url += `where=${whereStr}`;
+//             console.log("first方法请求URL:" + url)
+//         }
+
+//         const response = await fetch(url, {
+//             headers: {
+//                 "if-none-match": "W/\"1f0-ghxH2EwTk6Blz0g89ivf2adBDKY\"",
+//                 "x-parse-application-id": "hcx",
+//                 "x-parse-session-token": this.sessionToken || "",
+//             },
+//             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;
+//     }
+// }
+
+export class CloudQuery {
+    className: string;
+    sessionToken: string | null = null;
+    whereOptions: Record<string, any> = {};
+    orderOptions: string[] = []; // 用于存储排序字段和方向的数组
+    limit: number | null = null; // 限制返回对象的数量
+
+    constructor(className: string) {
+        this.className = className;
+    }
+
+    include(...fields: string[]) {
+        this.whereOptions["include"] = fields;
+    }
+
+    greaterThan(key: string, value: any) {
+        if (!this.whereOptions["where"]) this.whereOptions["where"] = {};
+        this.whereOptions["where"][key] = { "$gt": value };
+    }
+
+    greaterThanAndEqualTo(key: string, value: any) {
+        if (!this.whereOptions["where"]) this.whereOptions["where"] = {};
+        this.whereOptions["where"][key] = { "$gte": value };
+    }
+
+    lessThan(key: string, value: any) {
+        if (!this.whereOptions["where"]) this.whereOptions["where"] = {};
+        this.whereOptions["where"][key] = { "$lt": value };
+    }
+
+    lessThanAndEqualTo(key: string, value: any) {
+        if (!this.whereOptions["where"]) this.whereOptions["where"] = {};
+        this.whereOptions["where"][key] = { "$lte": value };
+    }
+
+    equalTo(key: string, value: any) {
+        if (!this.whereOptions["where"]) this.whereOptions["where"] = {};
+        this.whereOptions["where"][key] = value;
+    }
+
+    orderByAscending(key: string) {
+        this.orderOptions.push(key); // 升序排序
+    }
+
+    orderByDescending(key: string) {
+        this.orderOptions.push(`-${key}`); // 降序排序
+    }
+
+    setLimit(limit: number) {
+        this.limit = limit;
+    }
+
+    async get(id: string): Promise<CloudObject | null> {
+        const url = `http://1.94.237.145:1337/parse/classes/${this.className}/${id}`;
+
+        const response = await fetch(url, {
+            headers: {
+                "X-Parse-Application-Id": "hcx",
+                "X-Parse-Session-Token": this.sessionToken || ""
+            },
+            method: "GET",
+            mode: "cors",
+            credentials: "omit"
+        });
+
+        const json = await response.json();
+        if (json) {
+            return this.dataToObj(json);
+        }
+        return null;
+    }
+    /**
+     * @select查询
+     */
+    async main() {
+        let response = await fetch(`http://1.94.237.145:1337/api/psql/select`, {
+            headers: {
+                "Content-Type": "application/json",
+            },
+            body: JSON.stringify({ "sql": "SELECT * FROM \"_User\" limit 5", "params": [] }),
+            method: "POST",
+            mode: "cors",
+            credentials: "omit"
+        });
+
+        let result = await response?.json();
+        console.log(result)
+    }
+
+    async find(): Promise<Array<CloudObject>> {
+        const url = new URL(`http://1.94.237.145:1337/parse/classes/${this.className}`);
+        const params = new URLSearchParams();
+
+        // 添加 where 参数
+        if (this.whereOptions["where"]) {
+            params.append('where', JSON.stringify(this.whereOptions["where"]));
+        }
+
+        // 添加 include 参数
+        if (this.whereOptions["include"]) {
+            params.append('include', this.whereOptions["include"].join(','));
+        }
+
+        // 添加 order 参数
+        if (this.orderOptions.length > 0) {
+            params.append('order', this.orderOptions.join(','));
+        }
+
+        // 添加 limit 参数
+        if (this.limit !== null) {
+            params.append('limit', this.limit.toString());
+        }
+
+        // 设置 URL 的搜索参数
+        url.search = params.toString();
+
+        const response = await fetch(url.href, {
+            headers: {
+                "X-Parse-Application-Id": "hcx",
+                "X-Parse-Session-Token": this.sessionToken || ""
+            },
+            method: "GET",
+            mode: "cors",
+            credentials: "omit"
+        });
+
+        const json = await response.json();
+        const results = json.results || [];
+        return results.map((item: any) => this.dataToObj(item));
+    }
+    /**
+     * @返回第一个查找到的结果
+     * @返回结果参考:CloudObject {
+     * id: 'e3wWcCfNwm', 
+     * data: {…}, 
+     * className: '_User', 
+     * sessionToken:"r:c0f4fe9cb8eb83d7f0295ff57e948419"
+     * createdAt: '2024-12-17T02:41:34.768Z', 
+     * updatedAt: '2024-12-23T00:33:15.961Z'}
+     */
+    async first() {
+        let url = `http://1.94.237.145:1337/parse/classes/${this.className}?`;
+
+        if (Object.keys(this.whereOptions["where"]).length) {
+            const whereStr = JSON.stringify(this.whereOptions["where"]);
+            console.log("first查询条件" + whereStr)
+            url += `where=${whereStr}`;
+            console.log("first方法请求URL:" + url)
+        }
+
+        const response = await fetch(url, {
+            headers: {
+                "if-none-match": "W/\"1f0-ghxH2EwTk6Blz0g89ivf2adBDKY\"",
+                "x-parse-application-id": "hcx",
+                "x-parse-session-token": this.sessionToken || "",
+            },
+            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(data: any): CloudObject {
+        let obj = new CloudObject(this.className);
+        obj.set(data);
+        obj.id = data.objectId;
+        obj.createdAt = data.createdAt;
+        obj.updatedAt = data.updatedAt;
+        return obj;
+    }
+}
+
+// CloudUser.ts
+export class CloudUser extends CloudObject {
+    constructor() {
+        super("_User"); // 假设用户类在Parse中是"_User"
+        // 读取用户缓存信息
+        this.readCache();
+    }
+
+    //sessionToken: string | null = ""
+    /** 获取当前用户信息 */
+    current() {
+        if (!this.sessionToken) {
+            console.error("用户未登录");
+            return null;
+        }
+        return this;
+    }
+
+    /**更新用户缓存 */
+    async updateCache() {
+        if (!this.sessionToken) {
+            console.error("正在执行更新用户缓存:用户未登录");
+            return;
+        }
+        let query = new CloudQuery("_User");
+        query.equalTo("objectId", this.id)
+        console.log("设置条件:objectId==" + this.id)
+        let user: any = await query.find()
+        console.log("查询到条件用户信息:")
+        console.log(user)
+        //需要把sessionToken也保存起来
+        user.sessionToken = this.sessionToken
+        localStorage.setItem("NCloud/hcx/User", JSON.stringify(user))
+        console.log("已将该信息更新至用户缓存!请检查");
+        this.readCache();
+        return user;
+    }
+
+    /** 登录 */
+    async loginByUsername(username: string, password: string): Promise<CloudUser | null> {
+        const response = await fetch(`http://1.94.237.145:1337/parse/login`, {
+            headers: {
+                "x-parse-application-id": "hcx",
+                "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.updatedAt = result?.updatedAt;
+        this.className = '_User';
+        this.createdAt = result?.createdAt;
+        let excludedKeys = ["objectId", "sessionToken", "createdAt", "updatedAt"];
+        for (let key of excludedKeys) {
+            delete result[key];
+        }
+        this.data = result; // 保存用户数据
+        // 缓存用户信息
+        console.log("登录成功后即将缓存的信息如下:");
+        console.log(this)
+        localStorage.setItem("NCloud/hcx/User", JSON.stringify(this))
+        return this;
+    }
+
+    async loginByPhone(phone: string, verCode: string, trueVerCode: string): Promise<CloudUser | null> {
+        if (trueVerCode !== verCode) {
+            console.error('验证码错误');
+            return null;
+        }
+        let query = new CloudQuery("_User");
+        query.equalTo("phone", phone);
+        let user: any = await query.first();
+        //查询手机号对应的用户信息
+        let username: string = '';
+        let password: string = 'secretpassword';
+        if (!user?.id) {
+            console.error('该手机号未注册');
+            //用户名即为手机号
+            username = phone.slice(0, 3) + '****' + phone.slice(-4);
+            console.log('该手机号未注册,即将自动创建该用户:' + username + ',密码为:' + password);
+        }
+        //如果用户存在,则直接登录
+        console.log('该手机号已注册,即将直接登录该用户')
+        username = user.get('username');
+        console.log('用户名:' + username + ',密码为:' + password);
+        const response = await fetch(`http://1.94.237.145:1337/parse/login`, {
+            headers: {
+                "x-parse-application-id": "hcx",
+                "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.updatedAt = result?.updatedAt;
+        this.className = '_User';
+        this.createdAt = result?.createdAt;
+        let excludedKeys = ["objectId", "sessionToken", "createdAt", "updatedAt"];
+        for (let key of excludedKeys) {
+            delete result[key];
+        }
+        this.data = result; // 保存用户数据
+
+        // 缓存用户信息
+        console.log("登录成功后即将缓存的信息如下:");
+        console.log(this);
+        localStorage.setItem("NCloud/hcx/User", JSON.stringify(this));
+        return this;
+    }
+
+
+    /** 登出 */
+    async logout() {
+        if (!this.sessionToken) {
+            console.error("用户未登录");
+            return;
+        }
+
+        const response = await fetch(`http://1.94.237.145:1337/parse/logout`, {
+            headers: {
+                "x-parse-application-id": "hcx",
+                "x-parse-session-token": this.sessionToken
+            },
+            method: "POST"
+        });
+
+        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/hcx/User")
+        this.id = null;
+        this.sessionToken = null;
+        this.data = {};
+    }
+
+    /** 注册 */
+    async signUp(username: string, password: string, additionalData: Record<string, any> = {}) {
+        const userData = {
+            username,
+            password,
+            ...additionalData // 合并额外的用户数据
+        };
+
+        const response = await fetch(`http://1.94.237.145:1337/parse/users`, {
+            headers: {
+                "x-parse-application-id": "hcx",
+                "Content-Type": "application/json"
+            },
+            body: JSON.stringify(userData),
+            method: "POST"
+        });
+
+        const result = await response?.json();
+        if (result?.error) {
+            console.error(result?.error);
+            return null;
+        }
+
+        // 设置用户信息
+        // 缓存用户信息
+        console.log(result)
+        localStorage.setItem("NCloud/hcx/User", JSON.stringify(result))
+        this.id = result?.objectId;
+        this.sessionToken = result?.sessionToken;
+        this.data = result; // 保存用户数据
+        return this;
+    }
+
+    /**
+     * @读取缓存
+     * @读取示例:json{
+     *  id: "5b29481e037c6a007f7d0320",
+     *  className: "_User",
+     *  createdAt: "2018-06-27T09:54:38.815Z",
+     *  updatedAt: "2018-06-27T09:54:38.815Z",
+     *  sessionToken: "<KEY>",
+     *  data: {...}
+     * }
+     */
+    readCache() {
+        console.log("正在执行readCache方法:读取用户缓存信息");
+        let userCacheStr = localStorage.getItem("NCloud/hcx/User")
+        console.log("读取到的用户缓存信息:");
+        console.log(userCacheStr);
+        if (userCacheStr) {
+            let userData = JSON.parse(userCacheStr)
+            console.log(userData)
+            // 设置用户信息
+            console.log(userData?.id)
+            this.id = userData?.id;
+            this.className = "_User";
+            console.log(userData?.updatedAt)
+            this.updatedAt = userData?.updatedAt;
+            console.log(userData?.createdAt)
+            this.createdAt = userData?.createdAt;
+            console.log(userData?.sessionToken)
+            this.sessionToken = userData?.sessionToken;
+            this.data = userData.data // 保存用户数据
+            console.log("用户缓存信息读取完毕:");
+            console.log(this);
+        }
+        return this;
+    }
+}