Delancey 6 månader sedan
förälder
incheckning
890e5a9fe3

+ 20 - 15
travel-app/src/app/login/login.component.html

@@ -1,5 +1,10 @@
 <ion-header [translucent]="true">
   <ion-toolbar>
+    <ion-buttons slot="start">
+      <ion-button (click)="goToTab4()" fill="clear">
+        <ion-icon name="arrow-back"></ion-icon> <!-- 使用一个箭头图标 -->
+      </ion-button>
+    </ion-buttons>
     <ion-title>注册</ion-title>
   </ion-toolbar>
 </ion-header>
@@ -7,36 +12,36 @@
   <!-- 用户登录状态 -->
   <ion-card>
     <!-- 未登录 -->
-    @if(!travelUser?.id){
+    @if(!currentUser?.id){
     <ion-card-header>
       <ion-card-title>请登录</ion-card-title>
       <ion-card-subtitle>暂无信息</ion-card-subtitle>
     </ion-card-header>
     }
     <!-- 未登录 -->
-    @if(travelUser?.id){
+    @if(currentUser?.id){
     <ion-card-header>
-      <ion-card-title
-        >{{ travelUser?.get("username") }}
-        {{ travelUser?.get("realname") }}</ion-card-title
-      >
-      <ion-card-subtitle
-        >性别:{{ travelUser?.get("gender") || "-" }} 年龄:{{
-          travelUser?.get("age") || "-"
-        }}</ion-card-subtitle
-      >
+      <div style="display: flex; align-items: center;">
+      <img [src]="currentUser?.get('avatar')" alt="头像" style="width: 50px; height: 50px; border-radius: 50%; margin-right: 10px;">
+      <div>
+        <ion-card-title>{{ currentUser?.get("username") }}
+          {{ currentUser?.get("realname") }}</ion-card-title>
+        <ion-card-subtitle style="font-size: 18px;">性别:{{ currentUser?.get("gender") || "-" }} 年龄:{{
+            currentUser?.get("age") || "-"
+          }}</ion-card-subtitle>
+      </div>
+    </div>
     </ion-card-header>
     }
     <ion-card-content>
-      @if(!travelUser?.id){
+      @if(!currentUser?.id){
       <ion-button expand="block" (click)="signup()">注册</ion-button>
       <ion-button expand="block" (click)="login()">登录</ion-button>
-      } @if(travelUser?.id){
+      } @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
->
+  </ion-card></ion-content>

+ 26 - 31
travel-app/src/app/login/login.component.ts

@@ -15,10 +15,14 @@ import {
   IonButton,
   IonIcon,
   IonInput,
-  IonCardSubtitle,
+  IonCardSubtitle,IonButtons
 } from '@ionic/angular/standalone';
 import { CommonModule } from '@angular/common';
 import { CloudUser } from 'src/lib/ncloud';
+import { ModalController } from '@ionic/angular/standalone';
+import { openUserLoginModal } from 'src/lib/user/modal-user-login/modal-user-login.component';
+import { openUserEditModal } from 'src/lib/user/modal-user-edit/modal-user-edit.component';
+import { Router } from '@angular/router';
 @Component({
   selector: 'app-login',
   templateUrl: './login.component.html',
@@ -43,11 +47,12 @@ import { CloudUser } from 'src/lib/ncloud';
     IonInput,
     CommonModule,
     IonCardSubtitle,
+    IonButtons,
   ],
 })
 export class LoginComponent implements OnInit {
   
-  travelUser: CloudUser | undefined;
+  currentUser: CloudUser | undefined;
   //定义字段
   username: string = '';
   password: string = '';
@@ -58,44 +63,34 @@ export class LoginComponent implements OnInit {
   gender: '男' | '女' | '其他' = '其他'; // 限制性别字段的值为“男”、“女”或“其他”
 
 
-  constructor() {
-    this.travelUser = new CloudUser();
+  constructor(private modalCtrl:ModalController,private router:Router) {
+    this.currentUser = new CloudUser();
   }
   async login() {
-    let user: any = new CloudUser();
-    user = await user.login(this.username, this.password);
-    if (user?.id) {
-      this.travelUser = user;
-    }else{
-      console.error('登陆失败')
+    //弹出登录窗口
+    let user = await openUserLoginModal(this.modalCtrl);
+    if(user?.id){
+      this.currentUser = user
     }
   }
 
 
   logout() {
-    this.travelUser?.logout();
+    this.currentUser?.logout();
   }
-  async signup() {
-    let user: any = new CloudUser();
-  // 假设 CloudUser 类的 signUp 方法接受用户名、密码和其他数据作为参数
-  user = await user.signUp({
-    username:this.username, 
-    password:this.password, 
-    email: this.email,
-    phone: this.phone,
-    realName: this.realName,
-    age: this.age,
-    gender: this.gender
-  });
-
-  if (user?.id) {
-    // 注册成功,可以在这里处理,例如跳转到用户主页或显示成功消息
-    this.travelUser = user;
-  } else {
-    // 注册失败,可以在这里处理错误,例如显示错误消息
-    console.error('注册失败');
+  async signup(){
+    //弹出注册窗口
+    let user = await openUserLoginModal(this.modalCtrl,"signup");
+    if(user?.id){
+      this.currentUser = user
+    }
+  }
+  // 添加返回到 Tab 4 的方法
+  goToTab4() {
+    this.router.navigate(['/tabs/tab4']); // 假设你的 tab4 路由是这个路径
   }
+  editUser(){
+    openUserEditModal(this.modalCtrl)
   }
-  editUser() {}
   ngOnInit() {}
 }

+ 2 - 2
travel-app/src/app/tabs/tabs.page.ts

@@ -1,7 +1,7 @@
 import { Component, EnvironmentInjector, inject } from '@angular/core';
 import { IonTabs, IonTabBar, IonTabButton, IonIcon, IonLabel } from '@ionic/angular/standalone';
 import { addIcons } from 'ionicons';
-import { home, chatbubbles,aperture,person} from 'ionicons/icons';
+import { home, chatbubbles,aperture,person, arrowBack} from 'ionicons/icons';
 
 @Component({
   selector: 'app-tabs',
@@ -14,6 +14,6 @@ export class TabsPage {
   public environmentInjector = inject(EnvironmentInjector);
 
   constructor() {
-    addIcons({ home, chatbubbles,aperture,person});
+    addIcons({ home, chatbubbles,aperture,person,arrowBack});
   }
 }

+ 313 - 252
travel-app/src/lib/ncloud.ts

@@ -2,329 +2,390 @@
 export class CloudObject {
   className: string;
   id: string | null = null;
-  createdAt: any;
-  updatedAt: any;
+  createdAt:any;
+  updatedAt:any;
   data: Record<string, any> = {};
 
   constructor(className: string) {
-    this.className = className;
+      this.className = className;
   }
 
   toPointer() {
-    return { __type: 'Pointer', className: this.className, objectId: this.id };
+      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];
-    });
+      Object.keys(json).forEach(key => {
+          if (["objectId", "id", "createdAt", "updatedAt"].indexOf(key) > -1) {
+              return;
+          }
+          this.data[key] = json[key];
+      });
   }
 
   get(key: string) {
-    return this.data[key] || null;
+      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';
-    }
-
-    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;
+      let method = "POST";
+      let url = `https://dev.fmode.cn/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;
   }
 
   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',
+      if (!this.id) return;
+      const response = await fetch(`https://dev.fmode.cn/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;
       }
-    );
-
-    const result = await response?.json();
-    if (result) {
-      this.id = null;
-    }
-    return true;
+      return true;
   }
 }
 
 // CloudQuery.ts
 export class CloudQuery {
   className: string;
-  whereOptions: Record<string, any> = {};
+  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) {
-    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 || {};
+      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();
+      if (json) {
+          let existsObject = this.dataToObj(json)
+          return existsObject;
+      }
+      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 || [];
+  async find():Promise<Array<CloudObject>> {
+      let url = `https://dev.fmode.cn/parse/classes/${this.className}?`;
+
+      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\"",
+              "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}`;
-    }
-
-    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;
+      let url = `https://dev.fmode.cn/parse/classes/${this.className}?`;
+
+      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": "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;
+  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;
   }
 }
 
-//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; // 保存用户数据
-    }
+      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 = '';
+  sessionToken:string|null = ""
   /** 获取当前用户信息 */
   async current() {
-    if (!this.sessionToken) {
-      console.error('用户未登录');
-      return null;
-    }
-
-    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;
+      if (!this.sessionToken) {
+          console.error("用户未登录");
+          return null;
+      }
+      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;
   }
 
   /** 登录 */
-  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;
-    }
-
-    // 设置用户信息
-    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 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(`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;
-    }
-
-    // 清除用户信息
-    localStorage.removeItem('NCloud/dev/User');
-    this.id = null;
-    this.sessionToken = null;
-    this.data = {};
-    return true;
+      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"
+      });
+
+      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 = {};
   }
 
   /** 注册 */
-  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;
+  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;
+      }
+
+      // 设置用户信息
+      // 缓存用户信息
+      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;
   }
 }

+ 35 - 3
travel-app/src/lib/user/modal-user-edit/modal-user-edit.component.html

@@ -1,3 +1,35 @@
-<p>
-  modal-user-edit works!
-</p>
+<!-- 用户登录状态 -->
+<ion-card style="max-height: 400px; overflow-y: auto;">
+  <ion-card-header>
+    <ion-card-title>
+      用户名:{{currentUser?.get("username")}}
+    </ion-card-title>
+    <ion-card-subtitle >请输入您的详细资料</ion-card-subtitle>
+   </ion-card-header>
+ <ion-card-content>
+
+    <ion-item>
+      <ion-input [value]="userData['realname']" (ionChange)="userDataChange('realname',$event)" label="姓名" placeholder="请您输入真实姓名"></ion-input>
+    </ion-item>
+    <ion-item>
+      <ion-input [value]="userData['username']" (ionChange)="userDataChange('username',$event)" label="用户名" placeholder="请您输入用户名"></ion-input>
+    </ion-item>
+    <ion-item>
+      <ion-input type="number" [value]="userData['age']" (ionChange)="userDataChange('age',$event)" label="年龄" placeholder="请您输入年龄"></ion-input>
+    </ion-item>
+    <ion-item>
+      <ion-input [value]="userData['gender']" (ionChange)="userDataChange('gender',$event)" label="性别" placeholder="请您输入男/女"></ion-input>
+    </ion-item>
+    <ion-item>
+      <ion-input [value]="userData['avatar']" (ionChange)="userDataChange('avatar',$event)" label="头像" placeholder="请您输入头像地址"></ion-input>
+    </ion-item>
+    <ion-item>
+      <ion-input [value]="userData['email']" (ionChange)="userDataChange('email',$event)" label="邮箱" placeholder="请您输入邮箱号"></ion-input>
+    </ion-item>
+
+   <ion-button expand="block" color="danger" (click)="save()">保存</ion-button>
+   <ion-button expand="block" color="danger" (click)="cancel()">取消</ion-button>
+ 
+
+  </ion-card-content>
+</ion-card>

+ 50 - 2
travel-app/src/lib/user/modal-user-edit/modal-user-edit.component.ts

@@ -1,15 +1,63 @@
-import { Component, OnInit } from '@angular/core';
+import { OnInit } from '@angular/core';
+import { Component } from '@angular/core';
+import {   IonCard, IonCardContent, IonButton, IonCardHeader, IonCardTitle, IonCardSubtitle, ModalController, IonInput, IonItem } from '@ionic/angular/standalone';
+import { CloudUser } from 'src/lib/ncloud';
 
 @Component({
   selector: 'app-modal-user-edit',
   templateUrl: './modal-user-edit.component.html',
   styleUrls: ['./modal-user-edit.component.scss'],
   standalone: true,
+  imports: [IonCard,IonCardContent,IonButton,IonCardHeader,IonCardTitle,IonCardSubtitle,
+    IonInput,IonItem,
+  ],
 })
 export class ModalUserEditComponent  implements OnInit {
 
-  constructor() { }
+  currentUser:CloudUser|undefined
+  userData:any = {}
+  userDataChange(key:string,ev:any){
+    let value = ev?.detail?.value
+    if(value){
+      this.userData[key] = value
+    }
+  }
+  constructor(private modalCtrl:ModalController) { 
+    this.currentUser = new CloudUser();
+    this.userData = this.currentUser.data;
+  }
 
   ngOnInit() {}
 
+  async save(){
+    Object.keys(this.userData).forEach(key=>{
+      if(key=="age"){
+        this.userData[key] = Number(this.userData[key])
+      }
+    })
+
+    this.currentUser?.set(this.userData)
+    await this.currentUser?.save()
+    this.modalCtrl.dismiss(this.currentUser,"confirm")
+  }
+  cancel(){
+    this.modalCtrl.dismiss(null,"cancel")
+
+  }
+}
+
+export async function openUserEditModal(modalCtrl:ModalController):Promise<CloudUser|null>{
+  const modal = await modalCtrl.create({
+    component: ModalUserEditComponent,
+    breakpoints:[0.7,1.0],
+    initialBreakpoint:0.7
+  });
+  modal.present();
+
+  const { data, role } = await modal.onWillDismiss();
+
+  if (role === 'confirm') {
+    return data;
+  }
+  return null
 }

+ 36 - 3
travel-app/src/lib/user/modal-user-login/modal-user-login.component.html

@@ -1,3 +1,36 @@
-<p>
-  modal-user-login works!
-</p>
+<!-- 用户登录状态 -->
+<ion-card>
+  <ion-card-header>
+    <ion-card-title>
+      <ion-segment [value]="type" (ionChange)="typeChange($event)">
+        <ion-segment-button value="login">
+          <ion-label>登录</ion-label>
+        </ion-segment-button>
+        <ion-segment-button value="signup">
+          <ion-label>注册</ion-label>
+        </ion-segment-button>
+      </ion-segment>
+    </ion-card-title>
+    <ion-card-subtitle>请输入账号密码</ion-card-subtitle>
+  </ion-card-header>
+  <ion-card-content>
+    <ion-item>
+      <ion-input [value]="username" (ionChange)="usernameChange($event)" label="用户名" placeholder="用户名"></ion-input>
+    </ion-item>
+    <ion-item>
+      <ion-input [value]="password" (ionChange)="passwordChange($event)" label="密码" type="password" value="password"placeholder="密码"></ion-input>
+    </ion-item>
+
+    @if(type==="signup"){
+      <ion-item>
+        <ion-input [value]="password2" (ionChange)="password2Change($event)" label="密码确认" type="password" value="password"></ion-input>
+      </ion-item>
+    }
+    @if(type==="login"){
+      <ion-button expand="block"  color="danger" (click)="login()" style="flex: 1; margin-left: 5px;">登录</ion-button>
+    }
+    @if(type==="signup"){
+      <ion-button expand="block"  color="danger" (click)="signup()" style="flex: 1; margin-right: 5px;">注册</ion-button>
+    }
+  </ion-card-content>
+</ion-card>

+ 81 - 3
travel-app/src/lib/user/modal-user-login/modal-user-login.component.ts

@@ -1,15 +1,93 @@
-import { Component, OnInit } from '@angular/core';
+import { Input, OnInit } from '@angular/core';
+import { Component } from '@angular/core';
+import {  IonCard, IonCardContent, IonButton, IonCardHeader, IonCardTitle, IonCardSubtitle, ModalController, IonInput, IonItem, IonSegment, IonSegmentButton, IonLabel } from '@ionic/angular/standalone';
+import { CloudUser } from 'src/lib/ncloud';
 
 @Component({
   selector: 'app-modal-user-login',
   templateUrl: './modal-user-login.component.html',
   styleUrls: ['./modal-user-login.component.scss'],
   standalone: true,
+  imports: [IonCard,IonCardContent,IonButton,IonCardHeader,IonCardTitle,IonCardSubtitle,
+    IonInput,IonItem,
+    IonSegment,IonSegmentButton,IonLabel
+  ],
 })
 export class ModalUserLoginComponent  implements OnInit {
-
-  constructor() { }
+  @Input()
+  type:"login"|"signup" = "login"
+  typeChange(ev:any){
+    this.type = ev?.detail?.value || ev?.value || 'login'
+  }
+  username:string = ""
+  usernameChange(ev:any){
+    console.log(ev)
+    this.username = ev?.detail?.value
+  }
+  password:string = ""
+  passwordChange(ev:any){
+    this.password = ev?.detail?.value
+  }
+  password2:string = ""
+  password2Change(ev:any){
+    this.password2 = ev?.detail?.value
+  }
+  constructor(private modalCtrl:ModalController) {
+    console.log(this.type)
+   }
 
   ngOnInit() {}
 
+  async login(){
+    if(!this.username || !this.password){
+      console.log("请输入完整")
+      return
+    }
+    let user:any = new CloudUser();
+    user = await user.login(this.username,this.password);
+    if(user?.id){
+       this.modalCtrl.dismiss(user,"confirm")
+    }else{
+      console.log("登录失败,请检查账号和密码")
+    }
+  }
+
+  async signup(){
+    if(!this.username || !this.password || !this.password2){
+      console.log("请输入完整")
+      return
+    }
+    if(this.password!=this.password2){
+      console.log("两次密码不符,请修改")
+      return
+    }
+
+    let user:any = new CloudUser();
+    user = await user.signUp(this.username,this.password);
+    if(user){
+      this.type = "login"
+      console.log("注册成功请登录")
+    }
+  }
+
+}
+
+
+export async function openUserLoginModal(modalCtrl:ModalController,type:"login"|"signup"="login"):Promise<CloudUser|null>{
+  const modal = await modalCtrl.create({
+    component: ModalUserLoginComponent,
+    componentProps:{
+      type:type
+    },
+    breakpoints:[0.5,0.7],
+    initialBreakpoint:0.5
+  });
+  modal.present();
+
+  const { data, role } = await modal.onWillDismiss();
+
+  if (role === 'confirm') {
+    return data;
+  }
+  return null
 }

+ 4 - 4
travel-server/migration/data.js

@@ -1,4 +1,4 @@
-module.exports.TravelUserList = [
+module.exports.currentUserList = [
     {
         "objectId": "user1",
         "createdAt": "2024-01-01T10:00:00.000Z",
@@ -30,7 +30,7 @@ module.exports.TravelPostList = [
         "content": "南昌的米粉真的非常好吃,推荐大家去尝试!",
         "location": {"__type": "GeoPoint", "latitude": 28.682, "longitude": 115.857},
         "privacy": "公开",
-        "user": {"__type": "Pointer", "className": "TravelUser", "objectId": "user1"},
+        "user": {"__type": "Pointer", "className": "currentUser", "objectId": "user1"},
         "tags": [
             {"__type": "Pointer", "className": "Tag", "objectId": "tag1"},
             {"__type": "Pointer", "className": "Tag", "objectId": "tag2"}
@@ -47,7 +47,7 @@ module.exports.TravelPostList = [
         "content": "推荐大家去八一起义纪念馆,了解南昌的历史。",
         "location": {"__type": "GeoPoint", "latitude": 28.678, "longitude": 115.866},
         "privacy": "公开",
-        "user": {"__type": "Pointer", "className": "TravelUser", "objectId": "user2"},
+        "user": {"__type": "Pointer", "className": "currentUser", "objectId": "user2"},
         "tags": [
             {"__type": "Pointer", "className": "Tag", "objectId": "tag3"}
         ],
@@ -62,7 +62,7 @@ module.exports.TravelPostList = [
         "content": "南昌的滕王阁风景如画,适合拍照留念。",
         "location": {"__type": "GeoPoint", "latitude": 28.685, "longitude": 115.892},
         "privacy": "私密",
-        "user": {"__type": "Pointer", "className": "TravelUser", "objectId": "user3"},
+        "user": {"__type": "Pointer", "className": "currentUser", "objectId": "user3"},
         "tags": [
             {"__type": "Pointer", "className": "Tag", "objectId": "tag4"},
             {"__type": "Pointer", "className": "Tag", "objectId": "tag5"}

+ 10 - 10
travel-server/migration/import-data.js

@@ -1,20 +1,20 @@
 const { CloudQuery, CloudObject } = require("../lib/ncloud");
-const { TravelUserList, TravelPostList } = require("./data.js");
-importTravelPostAndTravelUser()
+const { currentUserList, TravelPostList } = require("./data.js");
+importTravelPostAndcurrentUser()
 
 DataMap = {
-    TravelUser:{},
+    currentUser:{},
     TravelPost:{}
 }
 
-async function importTravelPostAndTravelUser(){
+async function importTravelPostAndcurrentUser(){
     // 导入用户数据
-    let traveluserList = TravelUserList
-    for (let index = 0; index < traveluserList.length; index++) {
-        let traveluser = traveluserList[index];
-        traveluser = await importObject("TravelUser",traveluser)
+    let currentUserList = currentUserList
+    for (let index = 0; index < currentUserList.length; index++) {
+        let currentUser = currentUserList[index];
+        currentUser = await importObject("currentUser",currentUser)
     }
-    console.log(DataMap["TravelUser"])
+    console.log(DataMap["currentUser"])
     // 导入帖子数据
     let travelpostList = TravelPostList
     for (let index = 0; index < travelpostList.length; index++) {
@@ -40,7 +40,7 @@ async function importObject(className,data){
         let srcId = field?.objectId
         if(srcId){ // 是数组字段
             if(key=="user"){
-                data[key] = DataMap?.["TravelUser"]?.[srcId]?.toPointer();
+                data[key] = DataMap?.["currentUser"]?.[srcId]?.toPointer();
             }
         }
     })