布丁撞奶茶 6 달 전
부모
커밋
19cf08e84e

+ 42 - 0
travel-app/src/app/login/login.component.html

@@ -0,0 +1,42 @@
+<ion-header [translucent]="true">
+  <ion-toolbar>
+    <ion-title>注册</ion-title>
+  </ion-toolbar>
+</ion-header>
+<ion-content>
+  <!-- 用户登录状态 -->
+  <ion-card>
+    <!-- 未登录 -->
+    @if(!currentUser?.id){
+    <ion-card-header>
+      <ion-card-title>请登录</ion-card-title>
+      <ion-card-subtitle>暂无信息</ion-card-subtitle>
+    </ion-card-header>
+    }
+    <!-- 未登录 -->
+    @if(currentUser?.id){
+    <ion-card-header>
+      <ion-card-title
+        >{{ currentUser?.get("username") }}
+        {{ currentUser?.get("realname") }}</ion-card-title
+      >
+      <ion-card-subtitle
+        >性别:{{ currentUser?.get("gender") || "-" }} 年龄:{{
+          currentUser?.get("age") || "-"
+        }}</ion-card-subtitle
+      >
+    </ion-card-header>
+    }
+    <ion-card-content>
+      @if(!currentUser?.id){
+      <ion-button expand="block" (click)="signup()">注册</ion-button>
+      <ion-button expand="block" (click)="login()">登录</ion-button>
+      } @if(currentUser?.id){
+      <ion-button expand="block" (click)="editUser()">编辑资料</ion-button>
+      <ion-button expand="block" (click)="logout()" color="light"
+        >登出</ion-button
+      >
+      }
+    </ion-card-content>
+  </ion-card></ion-content
+>

+ 0 - 0
travel-app/src/app/login/login.component.scss


+ 22 - 0
travel-app/src/app/login/login.component.spec.ts

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

+ 68 - 0
travel-app/src/app/login/login.component.ts

@@ -0,0 +1,68 @@
+import { Component, OnInit } from '@angular/core';
+import {
+  IonSearchbar,
+  IonToolbar,
+  IonTitle,
+  IonHeader,
+  IonContent,
+  IonCard,
+  IonCardHeader,
+  IonCardTitle,
+  IonList,
+  IonCardContent,
+  IonItem,
+  IonLabel,
+  IonButton,
+  IonIcon,
+  IonInput,
+  IonCardSubtitle,
+} from '@ionic/angular/standalone';
+import { FormsModule, ReactiveFormsModule } from '@angular/forms';
+import { IonicModule } from '@ionic/angular';
+import { CommonModule } from '@angular/common';
+import { CloudUser } from 'src/lib/ncloud';
+@Component({
+  selector: 'app-login',
+  templateUrl: './login.component.html',
+  styleUrls: ['./login.component.scss'],
+  standalone: true,
+  imports: [
+    IonList,
+    IonCard,
+    IonContent,
+    IonHeader,
+    IonSearchbar,
+    IonToolbar,
+    IonTitle,
+    IonCard,
+    IonCardHeader,
+    IonCardTitle,
+    IonCardContent,
+    IonItem,
+    IonLabel,
+    IonButton,
+    IonIcon,
+    IonInput,
+    CommonModule,
+    IonCardSubtitle,
+  ],
+})
+export class LoginComponent implements OnInit {
+  currentUser: CloudUser | undefined;
+  constructor() {
+    this.currentUser = new CloudUser();
+  }
+  async login() {
+    let user: any = new CloudUser();
+    user = await user.login('test', 'test');
+    if (user?.id) {
+      this.currentUser = user;
+    }
+  }
+  logout() {
+    this.currentUser?.logout();
+  }
+  signup() {}
+  editUser() {}
+  ngOnInit() {}
+}

+ 47 - 8
travel-app/src/app/tab1/tab1.page.scss

@@ -163,17 +163,56 @@ ion-toolbar {
 .hot-articles-container {
   padding: 16px;
 
-  h2 {
+  .section-title {
+    font-size: 20px;
+    font-weight: bold;
     margin-bottom: 16px;
+    color: #333;
   }
 
   ion-list {
-    background: none;
-  }
-
-  ion-item {
-    --background: rgba(255, 255, 255, 0.9);
-    border-radius: 8px;
-    margin-bottom: 8px;
+    ion-item {
+      --padding-start: 0;
+      --inner-padding-end: 16px;
+      border-bottom: 1px solid #e6e6e6;
+
+      &:last-child {
+        border-bottom: none;
+      }
+
+      ion-thumbnail {
+        width: 80px;
+        height: 80px;
+        margin-right: 16px;
+
+        img {
+          border-radius: 8px;
+        }
+      }
+
+      ion-label {
+        h3 {
+          font-size: 16px;
+          margin-bottom: 8px;
+        }
+
+        p {
+          color: #666;
+          font-size: 14px;
+        }
+      }
+
+      ion-button {
+        --border-radius: 50%;
+        --padding-start: 8px;
+        --padding-end: 8px;
+        --background: rgba(0, 0, 0, 0.1);
+        color: #444;
+
+        ion-icon {
+          font-size: 18px;
+        }
+      }
+    }
   }
 }

+ 48 - 50
travel-app/src/app/tab4/tab4.page.html

@@ -1,20 +1,20 @@
-
-
 <ion-content [fullscreen]="true">
-
-<!-- 头像和昵称 -->
-<div class="information">
-  <ion-item lines="none">
-    <ion-thumbnail slot="start" class="rounded-avatar">
-      <img alt="头像" src="https://cdn.dribbble.com/userupload/8724892/file/original-262c901f17794fa6f91d0e961224d6c8.jpg?resize=1024x682&vertical=center" />
-    </ion-thumbnail>
-
-    <ion-label>
-      <h2>用户昵称</h2>
-      <p>158****6846</p>
-    </ion-label>
-  </ion-item>
-</div>
+  <!-- 头像和昵称 -->
+  <div class="information">
+    <ion-item lines="none">
+      <ion-thumbnail slot="start" class="rounded-avatar" (click)="goLogin()">
+        <img
+          alt="头像"
+          src="https://cdn.dribbble.com/userupload/8724892/file/original-262c901f17794fa6f91d0e961224d6c8.jpg?resize=1024x682&vertical=center"
+        />
+      </ion-thumbnail>
+
+      <ion-label>
+        <h2>用户昵称</h2>
+        <p>158****6846</p>
+      </ion-label>
+    </ion-item>
+  </div>
 
   <div class="stats">
     <ion-grid>
@@ -28,7 +28,7 @@
           <p>我的粉丝</p>
         </ion-col>
         <ion-col>
-          <h4><strong>1.5w</strong> </h4>
+          <h4><strong>1.5w</strong></h4>
           <p>获赞与收藏</p>
         </ion-col>
       </ion-row>
@@ -44,9 +44,7 @@
             <ion-card-header>
               <ion-card-title>我的卡券</ion-card-title>
             </ion-card-header>
-            <ion-card-content>
-              兑换券/换购券
-            </ion-card-content>
+            <ion-card-content> 兑换券/换购券 </ion-card-content>
           </ion-card>
         </ion-col>
         <ion-col>
@@ -55,9 +53,7 @@
             <ion-card-header>
               <ion-card-title>我的收藏</ion-card-title>
             </ion-card-header>
-            <ion-card-content>
-              票点攻略/笔记故事
-            </ion-card-content>
+            <ion-card-content> 票点攻略/笔记故事 </ion-card-content>
           </ion-card>
         </ion-col>
       </ion-row>
@@ -79,8 +75,6 @@
           <p>全部订单</p>
         </ion-col>
 
-
-
         <ion-col size="3" text-center>
           <ion-icon name="calendar" size="large"></ion-icon>
           <p>门票预约</p>
@@ -105,50 +99,54 @@
   </ion-item>
 
   <ion-card>
-  <ion-grid>
-    <ion-row>
-      <ion-col size="3" size-md="4" size-lg="2" class="icon-text-container" routerLink="https://jwc.jxnu.edu.cn/Portal/Index.aspx">
+    <ion-grid>
+      <ion-row>
+        <ion-col
+          size="3"
+          size-md="4"
+          size-lg="2"
+          class="icon-text-container"
+          routerLink="https://jwc.jxnu.edu.cn/Portal/Index.aspx"
+        >
           <ion-icon name="settings" size="large"></ion-icon>
           <p>账号设置</p>
-      </ion-col>
+        </ion-col>
 
-      <ion-col size="3" size-md="4" size-lg="2">
+        <ion-col size="3" size-md="4" size-lg="2">
           <ion-icon name="create" size="large"></ion-icon>
           <p>我的创作</p>
-      </ion-col>
+        </ion-col>
 
-      <ion-col size="3" size-md="4" size-lg="2">
+        <ion-col size="3" size-md="4" size-lg="2">
           <ion-icon name="gift" size="large"></ion-icon>
           <p>活动参与</p>
-      </ion-col>
+        </ion-col>
 
-      <ion-col size="3" size-md="4" size-lg="2">
+        <ion-col size="3" size-md="4" size-lg="2">
           <ion-icon name="walk" size="large"></ion-icon>
           <p>我的行程</p>
-      </ion-col>
+        </ion-col>
 
-      <ion-col size="3" size-md="4" size-lg="2">
-          <ion-icon name="notifications" size="large"start></ion-icon>
+        <ion-col size="3" size-md="4" size-lg="2">
+          <ion-icon name="notifications" size="large" start></ion-icon>
           <p>我的创作</p>
-      </ion-col>
+        </ion-col>
 
-      <ion-col size="3" size-md="4" size-lg="2">
+        <ion-col size="3" size-md="4" size-lg="2">
           <ion-icon name="document" size="large"></ion-icon>
           <p>问题建议</p>
-      </ion-col>
+        </ion-col>
 
-      <ion-col size="3" size-md="4" size-lg="2">
+        <ion-col size="3" size-md="4" size-lg="2">
           <ion-icon name="call" size="large"></ion-icon>
           <p>投诉反馈</p>
-      </ion-col>
+        </ion-col>
 
-      <ion-col size="3" size-md="4" size-lg="2">
+        <ion-col size="3" size-md="4" size-lg="2">
           <ion-icon name="share-social" size="large"></ion-icon>
-          <p>分享好友</p>  
-      </ion-col>
-
-    </ion-row>
-  </ion-grid>
-</ion-card>
-
+          <p>分享好友</p>
+        </ion-col>
+      </ion-row>
+    </ion-grid>
+  </ion-card>
 </ion-content>

+ 77 - 18
travel-app/src/app/tab4/tab4.page.ts

@@ -1,32 +1,91 @@
 import { Component } from '@angular/core';
-import { IonHeader, IonToolbar, IonTitle, IonContent, IonList, IonItem, IonLabel, IonAvatar, NavController, IonCard, IonCardContent, IonCardHeader, IonCardSubtitle, IonCardTitle, IonIcon, IonNote, IonThumbnail, IonGrid, IonRow, IonCol, IonButton } from '@ionic/angular/standalone';
+import {
+  IonHeader,
+  IonToolbar,
+  IonTitle,
+  IonContent,
+  IonList,
+  IonItem,
+  IonLabel,
+  IonAvatar,
+  NavController,
+  IonCard,
+  IonCardContent,
+  IonCardHeader,
+  IonCardSubtitle,
+  IonCardTitle,
+  IonIcon,
+  IonNote,
+  IonThumbnail,
+  IonGrid,
+  IonRow,
+  IonCol,
+  IonButton,
+} from '@ionic/angular/standalone';
 import { ExploreContainerComponent } from '../explore-container/explore-container.component';
 import { addIcons } from 'ionicons';
-import { documentText,calendar,chatboxEllipses,informationCircle,settings,create,
-  gift,walk,notifications,document,call,shareSocial
+import {
+  documentText,
+  calendar,
+  chatboxEllipses,
+  informationCircle,
+  settings,
+  create,
+  gift,
+  walk,
+  notifications,
+  document,
+  call,
+  shareSocial,
 } from 'ionicons/icons';
-
+import { Router } from '@angular/router';
 @Component({
   selector: 'app-tab4',
   templateUrl: 'tab4.page.html',
   styleUrls: ['tab4.page.scss'],
   standalone: true,
-  imports: [IonHeader,IonContent,IonToolbar, IonTitle, ExploreContainerComponent,IonCard,
-    IonCardContent,IonCardHeader,IonCardSubtitle,IonCardTitle,
-    IonIcon,IonNote,IonThumbnail,IonGrid,IonRow,IonCol,IonButton,
-    IonList, IonItem, IonLabel, IonAvatar],
+  imports: [
+    IonHeader,
+    IonContent,
+    IonToolbar,
+    IonTitle,
+    ExploreContainerComponent,
+    IonCard,
+    IonCardContent,
+    IonCardHeader,
+    IonCardSubtitle,
+    IonCardTitle,
+    IonIcon,
+    IonNote,
+    IonThumbnail,
+    IonGrid,
+    IonRow,
+    IonCol,
+    IonButton,
+    IonList,
+    IonItem,
+    IonLabel,
+    IonAvatar,
+  ],
 })
-
-
-
 export class Tab4Page {
-
-  constructor() {
-    addIcons({ documentText,calendar,chatboxEllipses,informationCircle,settings,create,
-      gift,walk,notifications,document,call,shareSocial
+  constructor(private router: Router) {
+    addIcons({
+      documentText,
+      calendar,
+      chatboxEllipses,
+      informationCircle,
+      settings,
+      create,
+      gift,
+      walk,
+      notifications,
+      document,
+      call,
+      shareSocial,
     });
   }
-
-
-
+  goLogin() {
+    this.router.navigate(['/tabs/login']);
+  }
 }

+ 11 - 2
travel-app/src/app/tabs/tabs.routes.ts

@@ -29,12 +29,21 @@ export const routes: Routes = [
       {
         path: 'Container',
         loadComponent: () =>
-          import('../explore-container/explore-container.component').then((m) => m.ExploreContainerComponent),
+          import('../explore-container/explore-container.component').then(
+            (m) => m.ExploreContainerComponent
+          ),
       },
       {
         path: 'recommend',
         loadComponent: () =>
-          import('../page-recommend/page-recommend.component').then((m) => m.PageRecommendComponent),
+          import('../page-recommend/page-recommend.component').then(
+            (m) => m.PageRecommendComponent
+          ),
+      },
+      {
+        path: 'login',
+        loadComponent: () =>
+          import('../login/login.component').then((m) => m.LoginComponent),
       },
       {
         path: '',

+ 296 - 160
travel-app/src/lib/ncloud.ts

@@ -1,194 +1,330 @@
 // CloudObject.ts
 export class CloudObject {
-    className: string;
-    id: string | null = null;
-    createdAt:any;
-    updatedAt:any;
-    data: Record<string, any> = {};
-
-    constructor(className: string) {
-        this.className = className;
-    }
+  className: string;
+  id: string | null = null;
+  createdAt: any;
+  updatedAt: any;
+  data: Record<string, any> = {};
 
-    toPointer() {
-        return { "__type": "Pointer", "className": this.className, "objectId": this.id };
-    }
+  constructor(className: string) {
+    this.className = className;
+  }
 
-    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];
-        });
-    }
+  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;
+  }
 
-    get(key: string) {
-        return this.data[key] || null;
+  async save() {
+    let method = 'POST';
+    let url = `http://dev.fmode.cn:1337/parse/classes/${this.className}`;
+
+    // 更新
+    if (this.id) {
+      url += `/${this.id}`;
+      method = 'PUT';
     }
 
-    async save() {
-        let method = "POST";
-        let url = `http://dev.fmode.cn:1337/parse/classes/${this.className}`;
-
-        // 更新
-        if (this.id) {
-            url += `/${this.id}`;
-            method = "PUT";
-        }
-
-        const body = JSON.stringify(this.data);
-        const response = await fetch(url, {
-            headers: {
-                "content-type": "application/json;charset=UTF-8",
-                "x-parse-application-id": "dev"
-            },
-            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;
-        }
-        return this;
+    const body = JSON.stringify(this.data);
+    const response = await fetch(url, {
+      headers: {
+        'content-type': 'application/json;charset=UTF-8',
+        'x-parse-application-id': 'dev',
+      },
+      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;
+    }
+    return this;
+  }
+
+  async destroy() {
+    if (!this.id) return;
+    const response = await fetch(
+      `http://dev.fmode.cn:1337/parse/classes/${this.className}/${this.id}`,
+      {
+        headers: {
+          'x-parse-application-id': 'dev',
+        },
+        body: null,
+        method: 'DELETE',
+        mode: 'cors',
+        credentials: 'omit',
+      }
+    );
 
-    async destroy() {
-        if (!this.id) return;
-        const response = await fetch(`http://dev.fmode.cn:1337/parse/classes/${this.className}/${this.id}`, {
-            headers: {
-                "x-parse-application-id": "dev"
-            },
-            body: null,
-            method: "DELETE",
-            mode: "cors",
-            credentials: "omit"
-        });
-
-        const result = await response?.json();
-        if (result) {
-            this.id = null;
-        }
-        return true;
+    const result = await response?.json();
+    if (result) {
+      this.id = null;
     }
+    return true;
+  }
 }
 
 // CloudQuery.ts
 export class CloudQuery {
-    className: string;
-    whereOptions: Record<string, any> = {};
+  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 = `http://dev.fmode.cn:1337/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',
+    });
 
-    constructor(className: string) {
-        this.className = className;
+    const json = await response?.json();
+    return json || {};
+  }
+
+  async find() {
+    let url = `http://dev.fmode.cn:1337/parse/classes/${this.className}?`;
+
+    if (Object.keys(this.whereOptions).length) {
+      const whereStr = JSON.stringify(this.whereOptions);
+      url += `where=${whereStr}`;
     }
 
-    greaterThan(key: string, value: any) {
-        if (!this.whereOptions[key]) this.whereOptions[key] = {};
-        this.whereOptions[key]["$gt"] = value;
+    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();
+    let list = json?.results || [];
+    let objList = list.map((item: any) => this.dataToObj(item));
+    return objList || [];
+  }
+
+  async first() {
+    let url = `http://dev.fmode.cn:1337/parse/classes/${this.className}?`;
+
+    if (Object.keys(this.whereOptions).length) {
+      const whereStr = JSON.stringify(this.whereOptions);
+      url += `where=${whereStr}`;
     }
 
-    greaterThanAndEqualTo(key: string, value: any) {
-        if (!this.whereOptions[key]) this.whereOptions[key] = {};
-        this.whereOptions[key]["$gte"] = value;
+    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;
+  }
+}
 
-    lessThan(key: string, value: any) {
-        if (!this.whereOptions[key]) this.whereOptions[key] = {};
-        this.whereOptions[key]["$lt"] = value;
+//CloudQuery.ts
+// 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; // 保存用户数据
     }
+  }
 
-    lessThanAndEqualTo(key: string, value: any) {
-        if (!this.whereOptions[key]) this.whereOptions[key] = {};
-        this.whereOptions[key]["$lte"] = value;
+  sessionToken: string | null = '';
+  /** 获取当前用户信息 */
+  async current() {
+    if (!this.sessionToken) {
+      console.error('用户未登录');
+      return null;
     }
 
-    equalTo(key: string, value: any) {
-        this.whereOptions[key] = value;
+    const response = await fetch(`http://dev.fmode.cn:1337/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 get(id: string) {
-        const url = `http://dev.fmode.cn:1337/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 login(username: string, password: string): Promise<CloudUser | null> {
+    const response = await fetch(`http://dev.fmode.cn:1337/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;
     }
 
-    async find() {
-        let url = `http://dev.fmode.cn:1337/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();
-        let list = json?.results || []
-        let objList = list.map((item:any)=>this.dataToObj(item))
-        return objList || [];
+    // 设置用户信息
+    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;
     }
 
-    async first() {
-        let url = `http://dev.fmode.cn:1337/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
+    const response = await fetch(`http://dev.fmode.cn:1337/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;
     }
 
-    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;
+    // 清除用户信息
+    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(`http://dev.fmode.cn:1337/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;
+  }
+}