18079408532 vor 1 Jahr
Ursprung
Commit
3dae4cd41f

+ 97 - 2
package-lock.json

@@ -26,6 +26,7 @@
         "@ionic/angular": "^8.0.0",
         "chart.js": "^4.4.7",
         "ionicons": "^7.2.1",
+        "parse": "^5.3.0",
         "rxjs": "~7.8.0",
         "tslib": "^2.3.0",
         "zone.js": "~0.14.2"
@@ -43,6 +44,7 @@
         "@capacitor/cli": "6.2.0",
         "@ionic/angular-toolkit": "^11.0.1",
         "@types/jasmine": "~5.1.0",
+        "@types/parse": "^3.0.9",
         "@typescript-eslint/eslint-plugin": "^6.0.0",
         "@typescript-eslint/parser": "^6.0.0",
         "eslint": "^8.57.0",
@@ -2608,6 +2610,19 @@
         "node": ">=6.9.0"
       }
     },
+    "node_modules/@babel/runtime-corejs3": {
+      "version": "7.24.7",
+      "resolved": "https://registry.npmmirror.com/@babel/runtime-corejs3/-/runtime-corejs3-7.24.7.tgz",
+      "integrity": "sha512-eytSX6JLBY6PVAeQa2bFlDx/7Mmln/gaEpsit5a3WEvjGfiIytEsgAwuIXCPM0xvw0v0cJn3ilq0/TvXrW0kgA==",
+      "license": "MIT",
+      "dependencies": {
+        "core-js-pure": "^3.30.2",
+        "regenerator-runtime": "^0.14.0"
+      },
+      "engines": {
+        "node": ">=6.9.0"
+      }
+    },
     "node_modules/@babel/template": {
       "version": "7.25.9",
       "resolved": "https://registry.npmmirror.com/@babel/template/-/template-7.25.9.tgz",
@@ -6621,6 +6636,16 @@
         "@types/node": "*"
       }
     },
+    "node_modules/@types/parse": {
+      "version": "3.0.9",
+      "resolved": "https://registry.npmmirror.com/@types/parse/-/parse-3.0.9.tgz",
+      "integrity": "sha512-DGTHygc7krgmNAK8h42giwmAofCd9uv2++RD+zw6OmWI7AEnlTYZwEuWsx22SA2CSMQrZW8P2INHLpQbnQFUng==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "@types/node": "*"
+      }
+    },
     "node_modules/@types/qs": {
       "version": "6.9.17",
       "resolved": "https://registry.npmmirror.com/@types/qs/-/qs-6.9.17.tgz",
@@ -8961,6 +8986,17 @@
         "url": "https://opencollective.com/core-js"
       }
     },
+    "node_modules/core-js-pure": {
+      "version": "3.39.0",
+      "resolved": "https://registry.npmmirror.com/core-js-pure/-/core-js-pure-3.39.0.tgz",
+      "integrity": "sha512-7fEcWwKI4rJinnK+wLTezeg2smbFFdSBP6E2kQZNbnzM2s1rpKQ6aaRteZSSg7FLU3P0HGGVo/gbpfanU36urg==",
+      "hasInstallScript": true,
+      "license": "MIT",
+      "funding": {
+        "type": "opencollective",
+        "url": "https://opencollective.com/core-js"
+      }
+    },
     "node_modules/core-util-is": {
       "version": "1.0.3",
       "resolved": "https://registry.npmmirror.com/core-util-is/-/core-util-is-1.0.3.tgz",
@@ -9041,6 +9077,13 @@
         "node": ">= 8"
       }
     },
+    "node_modules/crypto-js": {
+      "version": "4.2.0",
+      "resolved": "https://registry.npmmirror.com/crypto-js/-/crypto-js-4.2.0.tgz",
+      "integrity": "sha512-KALDyEYgpY+Rlob/iriUtjV6d5Eq+Y191A5g4UqLAi8CyGP9N1+FdVbkc1SxKc2r4YAYqG8JzO2KGL+AizD70Q==",
+      "license": "MIT",
+      "optional": true
+    },
     "node_modules/css-loader": {
       "version": "7.1.2",
       "resolved": "https://registry.npmmirror.com/css-loader/-/css-loader-7.1.2.tgz",
@@ -11649,6 +11692,12 @@
         "postcss": "^8.1.0"
       }
     },
+    "node_modules/idb-keyval": {
+      "version": "6.2.1",
+      "resolved": "https://registry.npmmirror.com/idb-keyval/-/idb-keyval-6.2.1.tgz",
+      "integrity": "sha512-8Sb3veuYCyrZL+VBt9LJfZjLUPWVvqn8tG28VqYNFCo43KHcKuq+b4EiXGeuaLAQWL2YmyDgMp2aSpH9JHsEQg==",
+      "license": "Apache-2.0"
+    },
     "node_modules/ieee754": {
       "version": "1.2.1",
       "resolved": "https://registry.npmmirror.com/ieee754/-/ieee754-1.2.1.tgz",
@@ -14927,6 +14976,26 @@
         "node": ">=6"
       }
     },
+    "node_modules/parse": {
+      "version": "5.3.0",
+      "resolved": "https://registry.npmmirror.com/parse/-/parse-5.3.0.tgz",
+      "integrity": "sha512-mWBnE6hHJhdvlx5KPQcYgCGRdgqKhPw+5fSC0j7vOfse3Lkh3xtDwOfmDpvv2LXZVBj72G/mgVKMRmbAICRzkQ==",
+      "license": "Apache-2.0",
+      "dependencies": {
+        "@babel/runtime-corejs3": "7.24.7",
+        "idb-keyval": "6.2.1",
+        "react-native-crypto-js": "1.0.0",
+        "uuid": "10.0.0",
+        "ws": "8.17.1",
+        "xmlhttprequest": "1.8.0"
+      },
+      "engines": {
+        "node": "18 || 19 || 20 || 22"
+      },
+      "optionalDependencies": {
+        "crypto-js": "4.2.0"
+      }
+    },
     "node_modules/parse-imports": {
       "version": "2.2.1",
       "resolved": "https://registry.npmmirror.com/parse-imports/-/parse-imports-2.2.1.tgz",
@@ -14977,6 +15046,19 @@
         "node": ">= 0.10"
       }
     },
+    "node_modules/parse/node_modules/uuid": {
+      "version": "10.0.0",
+      "resolved": "https://registry.npmmirror.com/uuid/-/uuid-10.0.0.tgz",
+      "integrity": "sha512-8XkAphELsDnEGrDxUOHB3RGvXz6TeuYSGEZBOjtTtPm2lwhGBjLgOzLHB63IUWfBpNucQjND6d3AOudO+H3RWQ==",
+      "funding": [
+        "https://github.com/sponsors/broofa",
+        "https://github.com/sponsors/ctavan"
+      ],
+      "license": "MIT",
+      "bin": {
+        "uuid": "dist/bin/uuid"
+      }
+    },
     "node_modules/parse5": {
       "version": "7.2.1",
       "resolved": "https://registry.npmmirror.com/parse5/-/parse5-7.2.1.tgz",
@@ -15629,6 +15711,12 @@
         "node": ">= 0.8"
       }
     },
+    "node_modules/react-native-crypto-js": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmmirror.com/react-native-crypto-js/-/react-native-crypto-js-1.0.0.tgz",
+      "integrity": "sha512-FNbLuG/HAdapQoybeZSoes1PWdOj0w242gb+e1R0hicf3Gyj/Mf8M9NaED2AnXVOX01b2FXomwUiw1xP1K+8sA==",
+      "license": "MIT"
+    },
     "node_modules/readable-stream": {
       "version": "3.6.2",
       "resolved": "https://registry.npmmirror.com/readable-stream/-/readable-stream-3.6.2.tgz",
@@ -15724,7 +15812,6 @@
       "version": "0.14.1",
       "resolved": "https://registry.npmmirror.com/regenerator-runtime/-/regenerator-runtime-0.14.1.tgz",
       "integrity": "sha512-dYnhHh0nJoMfnkZs6GmmhFknAGRrLznOu5nc9ML+EJxGvrx6H7teuevqVqCuPcPK//3eDrrjQhehXVx9cnkGdw==",
-      "dev": true,
       "license": "MIT"
     },
     "node_modules/regenerator-transform": {
@@ -19205,7 +19292,6 @@
       "version": "8.17.1",
       "resolved": "https://registry.npmmirror.com/ws/-/ws-8.17.1.tgz",
       "integrity": "sha512-6XQFvXTkbfUOZOKKILFG1PDK2NDQs4azKQl26T0YS5CxqWLgXajbPZ+h4gZekJyRqFU8pvnbAbbs/3TgRPy+GQ==",
-      "dev": true,
       "license": "MIT",
       "engines": {
         "node": ">=10.0.0"
@@ -19257,6 +19343,15 @@
         "node": ">=8.0"
       }
     },
+    "node_modules/xmlhttprequest": {
+      "version": "1.8.0",
+      "resolved": "https://registry.npmmirror.com/xmlhttprequest/-/xmlhttprequest-1.8.0.tgz",
+      "integrity": "sha512-58Im/U0mlVBLM38NdZjHyhuMtCqa61469k2YP/AaPbvCoV9aQGUpbJBj1QRm2ytRiVQBD/fsw7L2bJGDVQswBA==",
+      "license": "MIT",
+      "engines": {
+        "node": ">=0.4.0"
+      }
+    },
     "node_modules/y18n": {
       "version": "5.0.8",
       "resolved": "https://registry.npmmirror.com/y18n/-/y18n-5.0.8.tgz",

+ 2 - 0
package.json

@@ -31,6 +31,7 @@
     "@ionic/angular": "^8.0.0",
     "chart.js": "^4.4.7",
     "ionicons": "^7.2.1",
+    "parse": "^5.3.0",
     "rxjs": "~7.8.0",
     "tslib": "^2.3.0",
     "zone.js": "~0.14.2"
@@ -48,6 +49,7 @@
     "@capacitor/cli": "6.2.0",
     "@ionic/angular-toolkit": "^11.0.1",
     "@types/jasmine": "~5.1.0",
+    "@types/parse": "^3.0.9",
     "@typescript-eslint/eslint-plugin": "^6.0.0",
     "@typescript-eslint/parser": "^6.0.0",
     "eslint": "^8.57.0",

BIN
src/assets/images/lifepartner.jpg


+ 34 - 0
src/lib/models/Task.ts

@@ -0,0 +1,34 @@
+import { CloudObject, CloudQuery } from '../ncloud';
+
+export class Task extends CloudObject {
+    constructor() {
+        super('Task');
+    }
+
+    // 创建新任务
+    static async create(data: {
+        title: string;
+        startTime: Date;
+        endTime: Date;
+        completed: boolean;
+        userId: string;
+    }) {
+        const task = new Task();
+        task.set(data);
+        await task.save();
+        return task;
+    }
+
+    // 获取用户的所有任务
+    static async getUserTasks(userId: string) {
+        const query = new CloudQuery('Task');
+        query.equalTo('userId', userId);
+        return await query.find();
+    }
+
+    // 更新任务状态
+    async updateStatus(completed: boolean) {
+        this.set({ completed });
+        return await this.save();
+    }
+} 

+ 23 - 37
src/lib/ncloud.ts

@@ -1,5 +1,8 @@
+import * as Parse from 'parse';
+
 // CloudObject.ts
 export class CloudObject {
+    protected parseObject: Parse.Object;
     className: string;
     id: string | null = null;
     createdAt:any;
@@ -7,6 +10,7 @@ export class CloudObject {
     data: Record<string, any> = {};
 
     constructor(className: string) {
+        this.parseObject = new Parse.Object(className);
         this.className = className;
     }
 
@@ -77,15 +81,21 @@ export class CloudObject {
         }
         return true;
     }
+
+    protected setParseObject(obj: Parse.Object) {
+        this.parseObject = obj;
+    }
 }
 
 // CloudQuery.ts
 export class CloudQuery {
+    private query: Parse.Query;
     className: string;
     queryParams: Record<string, any> = {};
 
     constructor(className: string) {
         this.className = className;
+        this.query = new Parse.Query(className);
     }
     // 作用是将查询参数转换为对象
     include(...fileds:string[]) {
@@ -140,44 +150,20 @@ export class CloudQuery {
 
     }
 
-    async find() {
-        let url = `http://dev.fmode.cn:1337/parse/classes/${this.className}?`;
-
-        let queryStr = ``
-        Object.keys(this.queryParams).forEach(key=>{
-            let paramStr = JSON.stringify(this.queryParams[key]); // 作用是将对象转换为JSON字符串
-            if(key=="include"){
-                paramStr = this.queryParams[key]?.join(",")
-            }
-            if(key=="where"){
-                paramStr = JSON.stringify(this.queryParams[key]);
-
-            }
-            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": "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<CloudObject[]> {
+        try {
+            const results = await this.query.find();
+            return results.map((result: Parse.Object) => {
+                const obj = new CloudObject(this.className);
+                (obj as any).parseObject = result;  // 使用类型断言
+                return obj;
+            });
+        } catch (error) {
+            console.error('Query failed:', error);
+            throw error;
+        }
     }
 
-
     async first() {
         let url = `http://dev.fmode.cn:1337/parse/classes/${this.className}?`;
 
@@ -319,7 +305,7 @@ export class CloudUser extends CloudObject {
         const userData = {
             username,
             password,
-            ...additionalData // 合并额外的用户
+            ...additionalData // 合并额外的用户��
         };
 
         const response = await fetch(`http://dev.fmode.cn:1337/parse/users`, {

+ 77 - 47
src/lib/user/modal-user-login/modal-user-login.component.ts

@@ -1,6 +1,6 @@
 import { Input, OnInit } from '@angular/core';
 import { Component } from '@angular/core';
-import { IonHeader, IonToolbar, IonTitle, IonContent, IonCard, IonCardContent, IonButton, IonCardHeader, IonCardTitle, IonCardSubtitle, ModalController, IonInput, IonItem, IonSegment, IonSegmentButton, IonLabel } from '@ionic/angular/standalone';
+import { IonHeader, IonToolbar, IonTitle, IonContent, IonCard, IonCardContent, IonButton, IonCardHeader, IonCardTitle, IonCardSubtitle, ModalController, IonInput, IonItem, IonSegment, IonSegmentButton, IonLabel, AlertController } from '@ionic/angular/standalone';
 import { CloudUser } from '../../ncloud';
 
 @Component({
@@ -10,80 +10,110 @@ import { CloudUser } from '../../ncloud';
   standalone: true,
   imports: [
     IonHeader, IonToolbar, IonTitle, IonContent, 
-    IonCard,IonCardContent,IonButton,IonCardHeader,IonCardTitle,IonCardSubtitle,
-    IonInput,IonItem,
-    IonSegment,IonSegmentButton,IonLabel
+    IonCard, IonCardContent, IonButton, IonCardHeader, IonCardTitle, IonCardSubtitle,
+    IonInput, IonItem, IonSegment, IonSegmentButton, IonLabel
   ],
 })
-export class ModalUserLoginComponent  implements OnInit {
+export class ModalUserLoginComponent implements OnInit {
   @Input()
-  type:"login"|"signup" = "login"
-  typeChange(ev:any){
+  type: "login"|"signup" = "login"
+  
+  typeChange(ev: any) {
     this.type = ev?.detail?.value || ev?.value || 'login'
   }
-  username:string = ""
-  usernameChange(ev:any){
-    console.log(ev)
+  
+  username: string = ""
+  usernameChange(ev: any) {
     this.username = ev?.detail?.value
   }
-  password:string = ""
-  passwordChange(ev:any){
+  
+  password: string = ""
+  passwordChange(ev: any) {
     this.password = ev?.detail?.value
   }
-  password2:string = ""
-  password2Change(ev:any){
+  
+  password2: string = ""
+  password2Change(ev: any) {
     this.password2 = ev?.detail?.value
   }
-  constructor(private modalCtrl:ModalController) {
+  
+  constructor(
+    private modalCtrl: ModalController,
+    private alertCtrl: AlertController
+  ) {
     console.log(this.type)
-   }
+  }
 
   ngOnInit() {}
 
-  async login(){
-    if(!this.username || !this.password){
-      console.log("请输入完整")
-      return
+  async showAlert(header: string, message: string) {
+    const alert = await this.alertCtrl.create({
+      header,
+      message,
+      buttons: ['确定']
+    });
+    await alert.present();
+  }
+
+  async login() {
+    if (!this.username || !this.password) {
+      await this.showAlert('提示', '请输入完整的用户名和密码');
+      return;
     }
-    let user:any = new CloudUser();
-    user = await user.login(this.username,this.password);
-    if(user?.id){
-       this.modalCtrl.dismiss(user,"confirm") // 
-       console.log("登录成功")
-    }else{
-      console.log("登录失败")
+
+    let user: any = new CloudUser();
+    try {
+      user = await user.login(this.username, this.password);
+      if (user?.id) {
+        this.modalCtrl.dismiss(user, "confirm");
+        console.log("登录成功");
+      } else {
+        await this.showAlert('登录失败', '用户名或密码错误');
+      }
+    } catch (error) {
+      await this.showAlert('错误', '登录过程中发生错误,请稍后重试');
     }
   }
 
-  async signup(){
-    if(!this.username || !this.password || !this.password2){
-      console.log("请输入完整")
-      return
+  async signup() {
+    if (!this.username || !this.password || !this.password2) {
+      await this.showAlert('提示', '请填写完整的注册信息');
+      return;
     }
-    if(this.password!=this.password2){
-      console.log("两次密码不符,请修改")
-      return
+    
+    if (this.password != this.password2) {
+      await this.showAlert('提示', '两次输入的密码不一致,请重新输入');
+      return;
     }
 
-    let user:any = new CloudUser();
-    user = await user.signUp(this.username,this.password);
-    if(user){
-      this.type = "login"
-      console.log("注册成功请登录")
+    try {
+      let user: any = new CloudUser();
+      user = await user.signUp(this.username, this.password);
+      if (user) {
+        await this.showAlert('成功', '注册成功,请登录');
+        this.type = "login";
+        console.log("注册成功请登录");
+      } else {
+        await this.showAlert('注册失败', '注册失败,请稍后重试');
+      }
+    } catch (error: any) {
+      let message = '注册过程中发生错误,请稍后重试';
+      if (error.code === 202) {
+        message = '用户名已存在,请更换用户名';
+      }
+      await this.showAlert('错误', message);
     }
   }
-
 }
 
-
-export async function openUserLoginModal(modalCtrl:ModalController,type:"login"|"signup"="login"):Promise<CloudUser|null>{
+export async function openUserLoginModal(modalCtrl: ModalController, type: "login"|"signup" = "login"): Promise<CloudUser|null> {
   const modal = await modalCtrl.create({
     component: ModalUserLoginComponent,
-    componentProps:{
-      type:type
+    componentProps: {
+      type: type
     },
-    breakpoints:[0.5,0.7],
-    initialBreakpoint:0.5
+    breakpoints: [0.5, 0.7],
+    initialBreakpoint: 0.5
   });
   modal.present();
 
@@ -92,5 +122,5 @@ export async function openUserLoginModal(modalCtrl:ModalController,type:"login"|
   if (role === 'confirm') {
     return data;
   }
-  return null
+  return null;
 }

+ 14 - 9
src/main.ts

@@ -1,14 +1,19 @@
+import { enableProdMode } from '@angular/core';
 import { bootstrapApplication } from '@angular/platform-browser';
-import { RouteReuseStrategy, provideRouter, withPreloading, PreloadAllModules } from '@angular/router';
-import { IonicRouteStrategy, provideIonicAngular } from '@ionic/angular/standalone';
-
-import { routes } from './app/app.routes';
 import { AppComponent } from './app/app.component';
+import { provideRouter } from '@angular/router';
+import { routes } from './app/app.routes';
+import { provideIonicAngular } from '@ionic/angular/standalone';
+import * as Parse from 'parse';
+
+// 初始化 Parse
+Parse.initialize('YOUR_APP_ID', 'YOUR_JS_KEY');
+(Parse as any).serverURL = 'http://dev.fmode.cn:1337/parse';
 
+// 启动应用
 bootstrapApplication(AppComponent, {
   providers: [
-    { provide: RouteReuseStrategy, useClass: IonicRouteStrategy },
-    provideIonicAngular(),
-    provideRouter(routes, withPreloading(PreloadAllModules)),
-  ],
-});
+    provideRouter(routes),
+    provideIonicAngular({})
+  ]
+}).catch(err => console.error(err));

+ 86 - 0
src/models/Task.ts

@@ -0,0 +1,86 @@
+import Parse from 'parse';
+
+export class Task {
+  id?: string;
+  title: string = '';
+  content: string = '';
+  startTime?: Date;
+  endTime?: Date;
+  completed: boolean = false;
+  userId?: string;
+
+  constructor(data?: any) {
+    if (data) {
+      this.id = data.id || data.objectId;
+      this.title = data.title || '';
+      this.content = data.content || '';
+      this.startTime = data.startTime ? new Date(data.startTime) : undefined;
+      this.endTime = data.endTime ? new Date(data.endTime) : undefined;
+      this.completed = data.completed || false;
+      this.userId = data.userId;
+    }
+  }
+
+  static async create(data: any) {
+    const currentUser = Parse.User.current();
+    console.log('Current user:', currentUser);
+    console.log('Session token:', currentUser?.getSessionToken());
+
+    if (!currentUser) {
+      throw new Error('No user logged in');
+    }
+
+    const task = new Parse.Object('Task');
+    const acl = new Parse.ACL();
+    
+    // 设置该任务的访问控制
+    acl.setPublicReadAccess(false);
+    acl.setPublicWriteAccess(false);
+    acl.setReadAccess(currentUser.id, true);
+    acl.setWriteAccess(currentUser.id, true);
+    
+    task.setACL(acl);
+    
+    // 设置任务数据
+    Object.keys(data).forEach(key => {
+      task.set(key, data[key]);
+    });
+
+    // 设置用户关联
+    task.set('user', currentUser);
+
+    try {
+      const savedTask = await task.save();
+      console.log('Task saved successfully:', savedTask);
+      return savedTask;
+    } catch (error) {
+      console.error('Failed to create task:', error);
+      throw error;
+    }
+  }
+
+  static async getUserTasks(userId: string) {
+    const query = new Parse.Query('Task');
+    query.equalTo('userId', userId);
+    query.descending('createdAt');
+    
+    try {
+      const results = await query.find();
+      return results.map(task => new Task({
+        id: task.id,
+        ...task.toJSON()
+      }));
+    } catch (error) {
+      console.error('Error fetching tasks:', error);
+      throw error;
+    }
+  }
+
+  async save() {
+    if (!this.id) return;
+    const task = new Parse.Object('Task');
+    task.id = this.id;
+    task.set('completed', this.completed);
+    await task.save();
+  }
+} 

+ 2 - 1
tsconfig.json

@@ -22,7 +22,8 @@
     "target": "es2022",
     "module": "es2020",
     "lib": ["es2018", "dom"],
-    "useDefineForClassFields": false
+    "useDefineForClassFields": false,
+    "allowSyntheticDefaultImports": true
   },
   "angularCompilerOptions": {
     "enableI18nLegacyMessageIdFormat": false,