18079408532 1 년 전
부모
커밋
d9e9dfaa53

+ 3 - 3
package-lock.json

@@ -10,12 +10,12 @@
       "dependencies": {
         "@angular/animations": "^18.0.0",
         "@angular/cdk": "^17.0.0",
-        "@angular/common": "^18.0.0",
+        "@angular/common": "^18.2.13",
         "@angular/compiler": "^18.0.0",
-        "@angular/core": "^18.0.0",
+        "@angular/core": "^18.2.13",
         "@angular/forms": "^18.2.13",
         "@angular/material": "^17.0.0",
-        "@angular/platform-browser": "^18.0.0",
+        "@angular/platform-browser": "^18.2.13",
         "@angular/platform-browser-dynamic": "^18.0.0",
         "@angular/router": "^18.0.0",
         "@capacitor/app": "6.0.2",

+ 3 - 3
package.json

@@ -15,12 +15,12 @@
   "dependencies": {
     "@angular/animations": "^18.0.0",
     "@angular/cdk": "^17.0.0",
-    "@angular/common": "^18.0.0",
+    "@angular/common": "^18.2.13",
     "@angular/compiler": "^18.0.0",
-    "@angular/core": "^18.0.0",
+    "@angular/core": "^18.2.13",
     "@angular/forms": "^18.2.13",
     "@angular/material": "^17.0.0",
-    "@angular/platform-browser": "^18.0.0",
+    "@angular/platform-browser": "^18.2.13",
     "@angular/platform-browser-dynamic": "^18.0.0",
     "@angular/router": "^18.0.0",
     "@capacitor/app": "6.0.2",

+ 12 - 2
src/app/app.component.ts

@@ -13,7 +13,17 @@ import * as Parse from 'parse';
 export class AppComponent {
   constructor() {
     addIcons({ trash, add });
-    Parse.initialize('YOUR_APP_ID', 'YOUR_JS_KEY', undefined);
+    Parse.initialize('dev');
     (Parse as any).serverURL = 'http://dev.fmode.cn:1337/parse';
+    
+    // 恢复用户会话
+    const storedUser = localStorage.getItem('NCloud/dev/User');
+    if (storedUser) {
+      const userData = JSON.parse(storedUser);
+      Parse.User.become(userData.sessionToken).catch(error => {
+        console.error('Session token 已过期:', error);
+        localStorage.removeItem('NCloud/dev/User');
+      });
+    }
   }
-}
+}

+ 84 - 15
src/app/components/task-modal/task-modal.component.ts

@@ -1,16 +1,21 @@
 import { Component } from '@angular/core';
 import { CommonModule } from '@angular/common';
-import { IonicModule, ModalController } from '@ionic/angular';
 import { FormsModule } from '@angular/forms';
+import { IonHeader, IonToolbar, IonTitle, IonButtons, IonButton, IonContent, 
+         IonItem, IonLabel, IonInput, IonTextarea, IonDatetimeButton, 
+         IonModal, IonDatetime } from '@ionic/angular/standalone';
+import { ModalController, AlertController } from '@ionic/angular/standalone';
+import { Task } from '../../../lib/models/Task';
 
 @Component({
   selector: 'app-task-modal',
   template: `
     <ion-header>
       <ion-toolbar>
-        <ion-title>新建任务</ion-title>
+        <ion-title>{{ task.id ? '编辑任务' : '新建任务' }}</ion-title>
         <ion-buttons slot="end">
           <ion-button (click)="dismiss()">取消</ion-button>
+          <ion-button (click)="confirm()" [strong]="true">确定</ion-button>
         </ion-buttons>
       </ion-toolbar>
     </ion-header>
@@ -18,7 +23,12 @@ import { FormsModule } from '@angular/forms';
     <ion-content class="ion-padding">
       <ion-item>
         <ion-label position="stacked">标题</ion-label>
-        <ion-input [(ngModel)]="task.title"></ion-input>
+        <ion-input [(ngModel)]="task.title" placeholder="请输入任务标题"></ion-input>
+      </ion-item>
+
+      <ion-item>
+        <ion-label position="stacked">内容</ion-label>
+        <ion-textarea [(ngModel)]="task.content" placeholder="请输入任务内容" rows="3"></ion-textarea>
       </ion-item>
 
       <ion-item>
@@ -26,32 +36,91 @@ import { FormsModule } from '@angular/forms';
         <ion-datetime-button datetime="startTime"></ion-datetime-button>
         <ion-modal [keepContentsMounted]="true">
           <ng-template>
-            <ion-datetime id="startTime" [(ngModel)]="task.startTime"></ion-datetime>
+            <ion-datetime 
+              id="startTime"
+              presentation="date-time"
+              [preferWheel]="true"
+              [(ngModel)]="task.startTime"
+              locale="zh-CN">
+            </ion-datetime>
           </ng-template>
         </ion-modal>
       </ion-item>
 
-      <ion-button expand="block" (click)="confirm()" class="ion-margin-top">
-        创建任务
-      </ion-button>
+      <ion-item>
+        <ion-label position="stacked">结束时间</ion-label>
+        <ion-datetime-button datetime="endTime"></ion-datetime-button>
+        <ion-modal [keepContentsMounted]="true">
+          <ng-template>
+            <ion-datetime 
+              id="endTime"
+              presentation="date-time"
+              [preferWheel]="true"
+              [(ngModel)]="task.endTime"
+              locale="zh-CN">
+            </ion-datetime>
+          </ng-template>
+        </ion-modal>
+      </ion-item>
     </ion-content>
   `,
   standalone: true,
-  imports: [IonicModule, CommonModule, FormsModule]
+  imports: [
+    CommonModule,
+    FormsModule,
+    IonHeader,
+    IonToolbar,
+    IonTitle,
+    IonButtons,
+    IonButton,
+    IonContent,
+    IonItem,
+    IonLabel,
+    IonInput,
+    IonTextarea,
+    IonDatetimeButton,
+    IonModal,
+    IonDatetime
+  ]
 })
 export class TaskModalComponent {
-  task = {
-    title: '',
-    startTime: new Date().toISOString()
-  };
+  task: Task;
 
-  constructor(private modalCtrl: ModalController) {}
+  constructor(
+    private modalCtrl: ModalController,
+    private alertController: AlertController
+  ) {
+    this.task = new Task();
+  }
 
   dismiss() {
     this.modalCtrl.dismiss(null, 'cancel');
   }
 
-  confirm() {
+  async confirm() {
+    if (!this.task.title) {
+      await this.showAlert('提示', '请输入任务标题');
+      return;
+    }
+
+    if (this.task.startTime && this.task.endTime) {
+      const startTime = new Date(this.task.startTime);
+      const endTime = new Date(this.task.endTime);
+      if (endTime < startTime) {
+        await this.showAlert('提示', '结束时间不能早于开始时间');
+        return;
+      }
+    }
+
     this.modalCtrl.dismiss(this.task, 'confirm');
   }
-} 
+
+  private async showAlert(header: string, message: string) {
+    const alert = await this.alertController.create({
+      header,
+      message,
+      buttons: ['确定']
+    });
+    await alert.present();
+  }
+}

+ 41 - 169
src/app/countdown/countdown.page.ts

@@ -1,198 +1,70 @@
-import { Component, OnInit, OnDestroy } from '@angular/core';
+import { Component, OnInit } from '@angular/core';
 import { CommonModule } from '@angular/common';
 import { FormsModule } from '@angular/forms';
-import { IonicModule, NavController, AlertController } from '@ionic/angular';
-import { ActivatedRoute } from '@angular/router';
+import { IonHeader, IonToolbar, IonTitle, IonContent, IonButtons, IonButton,
+         IonIcon, IonProgressBar } from '@ionic/angular/standalone';
+import { AlertController } from '@ionic/angular/standalone';
 import { addIcons } from 'ionicons';
-import { 
-  schoolOutline, 
-  briefcaseOutline, 
-  moonOutline,
-  barbellOutline,
-  bookOutline,
-  codeSlashOutline,
-  leafOutline,
-  musicalNotesOutline,
-  languageOutline,
-  pencilOutline,
-  pauseOutline,
-  playOutline,
-  stopOutline,
-  exitOutline,
-  arrowBackOutline
-} from 'ionicons/icons';
-import { FocusRecordService } from '../services/ncloud';
+import { arrowBackOutline, pauseOutline, playOutline, stopOutline } from 'ionicons/icons';
 
 @Component({
   selector: 'app-countdown',
   templateUrl: './countdown.page.html',
   styleUrls: ['./countdown.page.scss'],
   standalone: true,
-  imports: [IonicModule, CommonModule, FormsModule]
+  imports: [
+    CommonModule,
+    FormsModule,
+    IonHeader,
+    IonToolbar,
+    IonTitle,
+    IonContent,
+    IonButtons,
+    IonButton,
+    IonIcon,
+    IonProgressBar
+  ]
 })
-export class CountdownPage implements OnInit, OnDestroy {
-  remainingTime: string = '';
-  activityType: string = '';
+export class CountdownPage implements OnInit {
   activityName: string = '';
-  duration: number = 0;
-  timer: any;
-  isRunning: boolean = false;
-  progress: number = 1;
+  activityType: string = '工作';
+  progress: number = 0;
+  remainingTime: string = '';
   remainingSeconds: number = 0;
-  alertAudio: HTMLAudioElement;
+  isRunning: boolean = false;
+  duration: number = 25;
+  timer: any;
 
-  constructor(
-    private route: ActivatedRoute, 
-    private navCtrl: NavController,
-    private alertController: AlertController
-  ) {
-    addIcons({
-      'school-outline': schoolOutline,
-      'briefcase-outline': briefcaseOutline,
-      'moon-outline': moonOutline,
-      'barbell-outline': barbellOutline,
-      'book-outline': bookOutline,
-      'code-slash-outline': codeSlashOutline,
-      'leaf-outline': leafOutline,
-      'musical-notes-outline': musicalNotesOutline,
-      'language-outline': languageOutline,
-      'pencil-outline': pencilOutline,
-      'pause-outline': pauseOutline,
-      'play-outline': playOutline,
-      'stop-outline': stopOutline,
-      'exit-outline': exitOutline,
-      'arrow-back-outline': arrowBackOutline
+  constructor(private alertController: AlertController) {
+    addIcons({ 
+      arrowBackOutline, 
+      pauseOutline, 
+      playOutline, 
+      stopOutline 
     });
-
-    this.alertAudio = new Audio('assets/alert.mp3');
   }
 
   ngOnInit() {
-    console.log('CountdownPage initialized');
-    this.route.queryParams.subscribe(params => {
-      console.log('Received params:', params);
-      this.activityType = params['type'];
-      this.activityName = params['name'];
-      this.duration = parseInt(params['duration']);
-      this.remainingSeconds = this.duration * 60;
-      this.remainingTime = this.formatTime(this.remainingSeconds);
-      this.progress = 1;
-    });
-  }
-
-  ngOnDestroy() {
-    this.stopTimer();
-  }
-
-  startTimer() {
-    if (this.timer) {
-      clearInterval(this.timer);
-    }
-
-    const startTime = this.duration * 60;
-    this.isRunning = true;
-    
-    this.timer = setInterval(() => {
-      if (this.remainingSeconds > 0) {
-        this.remainingSeconds--;
-        this.progress = this.remainingSeconds / startTime;
-        this.remainingTime = this.formatTime(this.remainingSeconds);
-      } else {
-        this.stopTimer();
-        this.playAlertSound();
-        this.showCompletionAlert();
-      }
-    }, 1000);
-  }
-
-  stopTimer() {
-    if (this.timer) {
-      clearInterval(this.timer);
-      this.timer = null;
-    }
-    this.isRunning = false;
+    this.remainingSeconds = this.duration * 60;
+    this.updateRemainingTime();
   }
 
-  formatTime(seconds: number): string {
-    const hours = Math.floor(seconds / 3600);
-    const minutes = Math.floor((seconds % 3600) / 60);
-    const secs = seconds % 60;
-    return `${this.padNumber(hours)}:${this.padNumber(minutes)}:${this.padNumber(secs)}`;
+  private updateRemainingTime() {
+    const minutes = Math.floor(this.remainingSeconds / 60);
+    const seconds = this.remainingSeconds % 60;
+    this.remainingTime = `${minutes.toString().padStart(2, '0')}:${seconds.toString().padStart(2, '0')}`;
+    this.progress = 1 - (this.remainingSeconds / (this.duration * 60));
   }
 
-  padNumber(num: number): string {
-    return num.toString().padStart(2, '0');
+  exit() {
+    // 实现退出方法
   }
 
   togglePause() {
-    if (this.isRunning) {
-      this.stopTimer();
-    } else {
-      this.startTimer();
-    }
+    // 实现暂停方法
   }
 
   reset() {
-    this.stopTimer();
-    this.remainingSeconds = this.duration * 60;
-    this.remainingTime = this.formatTime(this.remainingSeconds);
-    this.progress = 1;
-  }
-
-  async exit() {
-    if (this.isRunning) {
-      const alert = await this.alertController.create({
-        header: '确认退出',
-        message: '计时正在进行中,确定要退出吗?',
-        buttons: [
-          {
-            text: '取消',
-            role: 'cancel'
-          },
-          {
-            text: '确定',
-            handler: () => {
-              this.stopTimer();
-              this.navCtrl.back();
-            }
-          }
-        ]
-      });
-      await alert.present();
-    } else {
-      this.navCtrl.back();
-    }
-  }
-
-  async showCompletionAlert() {
-    const alert = await this.alertController.create({
-      header: '专注完成!',
-      message: `恭喜你完成了 ${this.duration} 分钟的${this.activityName}`,
-      buttons: ['确定']
-    });
-    await alert.present();
-  }
-
-  private playAlertSound() {
-    this.alertAudio.play().catch(error => {
-      console.error('Error playing alert sound:', error);
-    });
-  }
-
-  async completeTimer() {
-    try {
-      await FocusRecordService.createRecord({
-        duration: this.duration,
-        category: this.activityType,
-        startTime: new Date(Date.now() - this.duration * 60 * 1000),
-        endTime: new Date(),
-        completed: true
-      });
-      
-      await this.showCompletionAlert();
-      this.playAlertSound();
-    } catch (error) {
-      console.error('保存专注记录失败:', error);
-    }
+    // 实现重置方法
   }
 }

+ 88 - 34
src/app/models/Task.ts

@@ -1,4 +1,4 @@
-import { CloudObject, CloudQuery } from '../../lib/ncloud';
+import { CloudObject } from '../../lib/ncloud';
 import * as Parse from 'parse';
 
 export class Task extends CloudObject {
@@ -16,6 +16,53 @@ export class Task extends CloudObject {
     this.parseObject = new Parse.Object('Task');
   }
 
+  // 创建新任务
+  static async create(data: any): Promise<Task> {
+    try {
+      const currentUser = Parse.User.current();
+      if (!currentUser) {
+        throw new Error('No user logged in');
+      }
+
+      const task = new Task();
+      
+      // 设置ACL
+      const acl = new Parse.ACL();
+      acl.setPublicReadAccess(false);
+      acl.setPublicWriteAccess(false);
+      acl.setReadAccess(currentUser.id, true);
+      acl.setWriteAccess(currentUser.id, true);
+      task.parseObject.setACL(acl);
+
+      // 设置任务数据
+      task.parseObject.set('title', data.title);
+      task.parseObject.set('content', data.content || '');
+      task.parseObject.set('startTime', data.startTime || new Date().toISOString());
+      task.parseObject.set('endTime', data.endTime || new Date().toISOString());
+      task.parseObject.set('completed', data.completed || false);
+      task.parseObject.set('userId', currentUser.id);
+      task.parseObject.set('user', currentUser);
+
+      // 保存到数据库
+      await task.parseObject.save();
+      
+      // 设置本地数据
+      task.id = task.parseObject.id;
+      task.title = data.title;
+      task.content = data.content || '';
+      task.startTime = data.startTime || new Date().toISOString();
+      task.endTime = data.endTime || new Date().toISOString();
+      task.completed = data.completed || false;
+      task.userId = currentUser.id;
+
+      return task;
+    } catch (error) {
+      console.error('Failed to create task:', error);
+      throw error;
+    }
+  }
+
+  // 获取用户的所有任务
   static async getUserTasks(userId: string): Promise<Task[]> {
     try {
       if (!userId) {
@@ -24,12 +71,20 @@ export class Task extends CloudObject {
       
       const query = new Parse.Query('Task');
       query.equalTo('userId', userId);
+      query.descending('createdAt');
       
       const results = await query.find();
       return results.map(result => {
         const task = new Task();
         task.parseObject = result;
-        Object.assign(task, result.toJSON());
+        task.id = result.id;
+        const data = result.toJSON();
+        task.title = data['title'];
+        task.content = data['content'];
+        task.startTime = data['startTime'];
+        task.endTime = data['endTime'];
+        task.completed = data['completed'];
+        task.userId = data['userId'];
         return task;
       });
     } catch (error) {
@@ -38,53 +93,52 @@ export class Task extends CloudObject {
     }
   }
 
-  static async create(data: Partial<Task>): Promise<Task> {
+  // 保存任务更新
+  async saveTask(): Promise<void> {
     try {
-      const task = new Task();
-      
-      // 处理日期
-      if (typeof data.startTime === 'string') {
-        data.startTime = new Date(data.startTime).toISOString();
-      }
-      if (typeof data.endTime === 'string') {
-        data.endTime = new Date(data.endTime).toISOString();
+      if (!this.id) {
+        throw new Error('Task ID is required for update');
       }
 
-      // 设置数据到 parseObject
-      Object.keys(data).forEach(key => {
-        task.parseObject.set(key, (data as any)[key]);
-      });
-
-      // 保存到数据库
-      await task.parseObject.save();
-      
-      // 设置本地数据
-      Object.assign(task, data);
-      task.id = task.parseObject.id;
+      // 更新所有属性到 parseObject
+      this.parseObject.set('title', this.title);
+      this.parseObject.set('content', this.content);
+      this.parseObject.set('startTime', this.startTime);
+      this.parseObject.set('endTime', this.endTime);
+      this.parseObject.set('completed', this.completed);
       
-      console.log('Task created:', task);  // 添加日志
-      return task;
+      await this.parseObject.save();
     } catch (error) {
-      console.error('Failed to create task:', error);
+      console.error('Failed to save task:', error);
       throw error;
     }
   }
 
+  // 删除任务
   async delete(): Promise<void> {
     try {
+      if (!this.id) {
+        throw new Error('Task ID is required for deletion');
+      }
       await this.parseObject.destroy();
     } catch (error) {
-      console.error('Delete failed:', error);
+      console.error('Failed to delete task:', error);
       throw error;
     }
   }
 
-  async saveTask(): Promise<void> {
-    try {
-      await this.parseObject.save();
-    } catch (error) {
-      console.error('保存任务失败:', error);
-      throw error;
-    }
+  // 从 Parse.Object 创建 Task 实例
+  static fromParseObject(parseObject: Parse.Object): Task {
+    const task = new Task();
+    task.parseObject = parseObject;
+    task.id = parseObject.id;
+    const data = parseObject.toJSON();
+    task.title = data['title'];
+    task.content = data['content'];
+    task.startTime = data['startTime'];
+    task.endTime = data['endTime'];
+    task.completed = data['completed'];
+    task.userId = data['userId'];
+    return task;
   }
-} 
+}

+ 28 - 12
src/app/services/auth.service.ts

@@ -1,30 +1,46 @@
 import { Injectable } from '@angular/core';
 import * as Parse from 'parse';
-import { CloudUser } from '../../lib/ncloud';
+import { BehaviorSubject } from 'rxjs';
 
 @Injectable({
   providedIn: 'root'
 })
 export class AuthService {
-  currentUser: CloudUser | null = null;
+  private currentUserSubject = new BehaviorSubject<Parse.User | null>(null);
+  currentUser$ = this.currentUserSubject.asObservable();
 
   constructor() {
-    this.checkAuthState();
+    this.checkCurrentUser();
   }
 
-  async checkAuthState() {
-    const parseUser = Parse.User.current();
-    if (parseUser) {
-      this.currentUser = parseUser as unknown as CloudUser;
-    }
-    return this.currentUser;
+  private checkCurrentUser() {
+    const currentUser = Parse.User.current() as Parse.User | null;
+    this.currentUserSubject.next(currentUser);
   }
 
-  setCurrentUser(user: CloudUser | null) {
-    this.currentUser = user;
+  async login(username: string, password: string): Promise<Parse.User> {
+    const user = await Parse.User.logIn(username, password);
+    this.currentUserSubject.next(user);
+    return user;
+  }
+
+  async register(username: string, password: string, email: string): Promise<Parse.User> {
+    const user = new Parse.User();
+    user.set('username', username);
+    user.set('password', password);
+    user.set('email', email);
+    
+    await user.signUp();
+    this.currentUserSubject.next(user);
+    return user;
+  }
+
+  async logout() {
+    await Parse.User.logOut();
+    this.currentUserSubject.next(null);
   }
 
   isLoggedIn(): boolean {
     return Parse.User.current() !== null;
   }
-} 
+}

+ 32 - 0
src/app/services/config.service.ts

@@ -0,0 +1,32 @@
+import { Injectable } from '@angular/core';
+import * as Parse from 'parse';
+
+@Injectable({
+  providedIn: 'root'
+})
+export class ConfigService {
+  private static initialized = false;
+
+  constructor() {
+    this.initializeParse();
+  }
+
+  private initializeParse() {
+    if (!ConfigService.initialized) {
+      Parse.initialize('dev');
+      (Parse as any).serverURL = 'http://dev.fmode.cn:1337/parse';
+      
+      // 简化的错误处理
+      Parse.CoreManager.set('REQUEST_ATTEMPT_LIMIT', 1);
+      
+      ConfigService.initialized = true;
+    }
+  }
+
+  public getApiConfig() {
+    return {
+      serverUrl: Parse.serverURL,
+      appId: 'dev'
+    };
+  }
+} 

+ 60 - 6
src/app/services/focus-data.service.ts

@@ -1,16 +1,70 @@
 import { Injectable } from '@angular/core';
+import * as Parse from 'parse';
 
 @Injectable({
   providedIn: 'root'
 })
 export class FocusDataService {
-  private focusRecords: { date: string, duration: number }[] = [];
+  async addFocusRecord(data: {
+    duration: number;
+    category: string;
+    startTime: Date;
+    endTime: Date;
+  }) {
+    try {
+      const FocusRecord = Parse.Object.extend('FocusRecord');
+      const record = new FocusRecord();
+      
+      record.set('duration', data.duration);
+      record.set('category', data.category);
+      record.set('startTime', data.startTime);
+      record.set('endTime', data.endTime);
+      record.set('completed', true);
+      record.set('userId', Parse.User.current()?.id);
 
-  addFocusRecord(date: string, duration: number) {
-    this.focusRecords.push({ date, duration });
+      await record.save();
+      return record;
+    } catch (error) {
+      console.error('保存专注记录失败:', error);
+      throw error;
+    }
   }
 
-  getFocusRecords() {
-    return this.focusRecords;
+  async getFocusRecords() {
+    try {
+      const query = new Parse.Query('FocusRecord');
+      query.equalTo('userId', Parse.User.current()?.id);
+      query.descending('createdAt');
+      query.limit(30); // 获取最近30天的记录
+      
+      const results = await query.find();
+      return results.map(record => ({
+        date: record.get('startTime'),
+        duration: record.get('duration'),
+        category: record.get('category')
+      }));
+    } catch (error) {
+      console.error('获取专注记录失败:', error);
+      return [];
+    }
   }
-} 
+
+  async getWeeklyStats() {
+    try {
+      const query = new Parse.Query('FocusRecord');
+      query.equalTo('userId', Parse.User.current()?.id);
+      query.greaterThan('startTime', new Date(Date.now() - 7 * 24 * 60 * 60 * 1000));
+      query.ascending('startTime');
+      
+      const results = await query.find();
+      return results.map(record => ({
+        date: record.get('startTime'),
+        duration: record.get('duration'),
+        category: record.get('category')
+      }));
+    } catch (error) {
+      console.error('获取周统计失败:', error);
+      return [];
+    }
+  }
+}

+ 56 - 100
src/app/services/ncloud.ts

@@ -1,52 +1,5 @@
 import * as Parse from 'parse';
-
-export class CloudObject {
-  protected parseObject: Parse.Object;
-
-  constructor() {
-    this.parseObject = new Parse.Object(this.constructor.name);
-  }
-
-  async save(): Promise<void> {
-    try {
-      await this.parseObject.save(this);
-    } catch (error) {
-      console.error('Save failed:', error);
-      throw error;
-    }
-  }
-
-  setParseObject(parseObject: Parse.Object): void {
-    this.parseObject = parseObject;
-  }
-}
-
-export class CloudQuery {
-  private query: Parse.Query;
-
-  constructor(className: string) {
-    this.query = new Parse.Query(className);
-  }
-
-  equalTo(key: string, value: any): CloudQuery {
-    this.query.equalTo(key, value);
-    return this;
-  }
-
-  async find(): Promise<CloudObject[]> {
-    try {
-      const results = await this.query.find();
-      return results.map((result: Parse.Object) => {
-        const obj = new CloudObject();
-        obj.setParseObject(result);
-        return obj;
-      });
-    } catch (error) {
-      console.error('Query failed:', error);
-      throw error;
-    }
-  }
-}
+import { CloudObject, CloudQuery } from '../../lib/ncloud';
 
 export class Task extends CloudObject {
   objectId?: string;
@@ -56,12 +9,13 @@ export class Task extends CloudObject {
   completed: boolean = false;
   startTime?: Date;
   endTime?: Date;
-  createdAt?: Date;
-  updatedAt?: Date;
+  override createdAt: Date;
+  override updatedAt: Date;
 
   constructor() {
-    super();
-    this.parseObject = new Parse.Object('Task');
+    super('Task');
+    this.createdAt = new Date();
+    this.updatedAt = new Date();
   }
 
   static fromParseObject(parseObject: Parse.Object): Task {
@@ -79,7 +33,7 @@ export class Task extends CloudObject {
     return task;
   }
 
-  override async save(): Promise<void> {
+  override async save(): Promise<this> {
     const currentUser = Parse.User.current();
     if (!currentUser) {
       throw new Error('User not logged in');
@@ -92,17 +46,18 @@ export class Task extends CloudObject {
     this.parseObject.set('startTime', this.startTime);
     this.parseObject.set('endTime', this.endTime);
 
-    // 设置 ACL
     const acl = new Parse.ACL(currentUser);
     acl.setPublicReadAccess(false);
     acl.setPublicWriteAccess(false);
     this.parseObject.setACL(acl);
 
     await super.save();
+    return this;
   }
 
-  async destroy(): Promise<void> {
+  override async destroy(): Promise<true | undefined> {
     await this.parseObject.destroy();
+    return true;
   }
 }
 
@@ -114,12 +69,13 @@ export class FocusRecord extends CloudObject {
   startTime?: Date;
   endTime?: Date;
   completed: boolean = false;
-  createdAt?: Date;
-  updatedAt?: Date;
+  override createdAt: Date;
+  override updatedAt: Date;
 
   constructor() {
-    super();
-    this.parseObject = new Parse.Object('FocusRecord');
+    super('FocusRecord');
+    this.createdAt = new Date();
+    this.updatedAt = new Date();
   }
 
   static fromParseObject(parseObject: Parse.Object): FocusRecord {
@@ -137,7 +93,7 @@ export class FocusRecord extends CloudObject {
     return record;
   }
 
-  override async save(): Promise<void> {
+  override async save(): Promise<this> {
     const currentUser = Parse.User.current();
     if (!currentUser) {
       throw new Error('User not logged in');
@@ -150,50 +106,13 @@ export class FocusRecord extends CloudObject {
     this.parseObject.set('endTime', this.endTime);
     this.parseObject.set('completed', this.completed);
 
-    // 设置 ACL
     const acl = new Parse.ACL(currentUser);
     acl.setPublicReadAccess(false);
     acl.setPublicWriteAccess(false);
     this.parseObject.setACL(acl);
 
     await super.save();
-  }
-}
-
-export class FocusRecordService {
-  static async createRecord(data: {
-    duration: number;
-    category: string;
-    startTime: Date;
-    endTime: Date;
-    completed: boolean;
-  }): Promise<FocusRecord> {
-    try {
-      const record = new FocusRecord();
-      Object.assign(record, data);
-      await record.save();
-      return record;
-    } catch (error) {
-      console.error('创建专注记录失败:', error);
-      throw error;
-    }
-  }
-
-  static async getRecords(): Promise<FocusRecord[]> {
-    try {
-      const query = new CloudQuery('FocusRecord');
-      query.equalTo('userId', Parse.User.current()?.id);
-      const results = await query.find();
-      return results.map(result => {
-        if (result instanceof Parse.Object) {
-          return FocusRecord.fromParseObject(result);
-        }
-        return result as FocusRecord;
-      });
-    } catch (error) {
-      console.error('获取专注记录失败:', error);
-      throw error;
-    }
+    return this;
   }
 }
 
@@ -203,7 +122,7 @@ export class TaskService {
       const query = new CloudQuery('Task');
       query.equalTo('user', Parse.User.current());
       const results = await query.find();
-      return results.map(result => {
+      return results.map((result: Parse.Object | Task) => {
         if (result instanceof Parse.Object) {
           return Task.fromParseObject(result);
         }
@@ -254,4 +173,41 @@ export class TaskService {
       throw error;
     }
   }
-} 
+}
+
+export class FocusRecordService {
+  static async createRecord(data: {
+    duration: number;
+    category: string;
+    startTime: Date;
+    endTime: Date;
+    completed: boolean;
+  }): Promise<FocusRecord> {
+    try {
+      const record = new FocusRecord();
+      Object.assign(record, data);
+      await record.save();
+      return record;
+    } catch (error) {
+      console.error('创建专注记录失败:', error);
+      throw error;
+    }
+  }
+
+  static async getRecords(): Promise<FocusRecord[]> {
+    try {
+      const query = new CloudQuery('FocusRecord');
+      query.equalTo('userId', Parse.User.current()?.id);
+      const results = await query.find();
+      return results.map((result: Parse.Object | FocusRecord) => {
+        if (result instanceof Parse.Object) {
+          return FocusRecord.fromParseObject(result);
+        }
+        return result as FocusRecord;
+      });
+    } catch (error) {
+      console.error('获取专注记录失败:', error);
+      throw error;
+    }
+  }
+}

+ 38 - 67
src/app/tab1/tab1.page.html

@@ -1,77 +1,48 @@
-<ion-header [translucent]="true">
+<ion-header>
   <ion-toolbar>
-    <ion-title>
-      任务列表
-    </ion-title>
+    <ion-title>任务列表</ion-title>
     <ion-buttons slot="end">
-      <ion-button (click)="setOpen(true)">
-        <ion-icon name="add"></ion-icon>
+      <ion-button (click)="addTask()">
+        <ion-icon slot="icon-only" name="add-outline"></ion-icon>
       </ion-button>
     </ion-buttons>
   </ion-toolbar>
 </ion-header>
 
-<ion-content [fullscreen]="true">
-  <ion-list>
-    <ion-item *ngFor="let task of tasks">
-      <ion-checkbox slot="start" 
-                    [(ngModel)]="task.completed"
-                    (ionChange)="toggleComplete(task)">
-      </ion-checkbox>
-      <ion-label>
-        <h2>{{task.title}}</h2>
-        <p>{{task.content}}</p>
-        <p *ngIf="task.startTime">开始时间: {{task.startTime | date}}</p>
-        <p *ngIf="task.endTime">结束时间: {{task.endTime | date}}</p>
-      </ion-label>
-    </ion-item>
-  </ion-list>
+<ion-content>
+  <ion-refresher slot="fixed" (ionRefresh)="loadTasks($event)">
+    <ion-refresher-content></ion-refresher-content>
+  </ion-refresher>
 
-  <ion-modal [isOpen]="isModalOpen">
-    <ng-template>
-      <ion-header>
-        <ion-toolbar>
-          <ion-title>新建任务</ion-title>
-          <ion-buttons slot="end">
-            <ion-button (click)="setOpen(false)">关闭</ion-button>
-          </ion-buttons>
-        </ion-toolbar>
-      </ion-header>
-      <ion-content class="ion-padding">
-        <ion-item>
-          <ion-label position="stacked">标题</ion-label>
-          <ion-input [(ngModel)]="newTask.title" placeholder="输入任务标题"></ion-input>
-        </ion-item>
-        
-        <ion-item>
-          <ion-label position="stacked">描述</ion-label>
-          <ion-textarea [(ngModel)]="newTask.content" placeholder="输入任务描述"></ion-textarea>
-        </ion-item>
-        
-        <ion-item>
-          <ion-label position="stacked">开始时间</ion-label>
-          <ion-datetime-button datetime="startTime"></ion-datetime-button>
-          <ion-modal [keepContentsMounted]="true">
-            <ng-template>
-              <ion-datetime id="startTime" [(ngModel)]="newTask.startTime"></ion-datetime>
-            </ng-template>
-          </ion-modal>
-        </ion-item>
+  <ion-progress-bar type="indeterminate" *ngIf="loading"></ion-progress-bar>
 
-        <ion-item>
-          <ion-label position="stacked">结束时间</ion-label>
-          <ion-datetime-button datetime="endTime"></ion-datetime-button>
-          <ion-modal [keepContentsMounted]="true">
-            <ng-template>
-              <ion-datetime id="endTime" [(ngModel)]="newTask.endTime"></ion-datetime>
-            </ng-template>
-          </ion-modal>
-        </ion-item>
+  <ion-list>
+    <ion-item-sliding *ngFor="let task of tasks">
+      <ion-item [ngClass]="getTaskStatusClass(task)">
+        <ion-checkbox slot="start" 
+                     [(ngModel)]="task.completed" 
+                     (ionChange)="toggleComplete(task)">
+        </ion-checkbox>
+        <ion-label>
+          <div class="task-header">
+            <h2>{{ task.title }}</h2>
+            <ion-badge [color]="getTaskStatusColor(task)">
+              {{ getTaskStatusText(task) }}
+            </ion-badge>
+          </div>
+          <p>{{ task.content }}</p>
+          <p *ngIf="task.startTime || task.endTime">
+            <ion-icon name="calendar-outline"></ion-icon>
+            {{ task.startTime | date:'short' }} - {{ task.endTime | date:'short' }}
+          </p>
+        </ion-label>
+      </ion-item>
 
-        <ion-button expand="block" (click)="addTask()" class="ion-margin-top">
-          创建任务
-        </ion-button>
-      </ion-content>
-    </ng-template>
-  </ion-modal>
-</ion-content>
+      <ion-item-options side="end">
+        <ion-item-option color="danger" (click)="deleteTask(task)">
+          <ion-icon slot="icon-only" name="trash-outline"></ion-icon>
+        </ion-item-option>
+      </ion-item-options>
+    </ion-item-sliding>
+  </ion-list>
+</ion-content>

+ 36 - 32
src/app/tab1/tab1.page.scss

@@ -1,41 +1,45 @@
-:host {
-  --background: #e0f7e9; /* 浅绿色背景 */
+.task-completed {
+  --background: rgba(var(--ion-color-success-rgb), 0.15);
+  --color: var(--ion-color-success-shade);
+  
+  ion-checkbox {
+      --border-color: var(--ion-color-success);
+      --background-checked: var(--ion-color-success);
+  }
 }
 
-ion-content {
-  --background: var(--background);
-  background-color: var(--background); /* 确保背景颜色应用 */
+.task-overdue {
+  --background: rgba(var(--ion-color-danger-rgb), 0.15);
+  --color: var(--ion-color-danger-shade);
+  
+  ion-checkbox {
+      --border-color: var(--ion-color-danger);
+      --background-checked: var(--ion-color-danger);
+  }
 }
 
-.task-item {
-  border-radius: 8px;
-  margin: 8px;
-  box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
-  --background: var(--task-color, #e0f7e9); /* 默认浅绿色背景 */
-  background-color: var(--background); /* 确保背景颜色应用 */
+.task-in-progress {
+  --background: rgba(var(--ion-color-primary-rgb), 0.15);
+  --color: var(--ion-color-primary-shade);
+  
+  ion-checkbox {
+      --border-color: var(--ion-color-primary);
+      --background-checked: var(--ion-color-primary);
+  }
 }
 
-.task-label h2 {
-  font-weight: bold;
-  margin: 0;
-  color: var(--ion-color-dark);
-}
-
-.task-label p {
-  margin: 0;
-  color: var(--ion-color-medium);
-}
-
-.strikethrough {
-  text-decoration: line-through;
-  color: var(--ion-color-medium);
+.task-header {
+  display: flex;
+  justify-content: space-between;
+  align-items: center;
+  margin-bottom: 4px;
+  
+  h2 {
+      margin: 0;
+  }
 }
 
 ion-badge {
-  font-size: 0.8em;
-}
-
-ion-toolbar {
-  --background: var(--ion-color-light);
-  --color: var(--ion-color-dark);
-}
+  font-size: 12px;
+  padding: 4px 8px;
+}

+ 161 - 62
src/app/tab1/tab1.page.ts

@@ -1,10 +1,15 @@
 import { Component, OnInit } from '@angular/core';
-import { IonicModule, AlertController } from '@ionic/angular';
 import { CommonModule } from '@angular/common';
 import { FormsModule } from '@angular/forms';
+import { IonHeader, IonToolbar, IonTitle, IonContent, IonButtons, IonButton, 
+         IonIcon, IonList, IonItemSliding, IonItem, IonCheckbox, IonLabel, 
+         IonItemOptions, IonItemOption, IonProgressBar, IonRefresher, 
+         IonRefresherContent, IonBadge } from '@ionic/angular/standalone';
+import { AlertController, ModalController } from '@ionic/angular/standalone';
 import { addIcons } from 'ionicons';
-import { addOutline } from 'ionicons/icons';
-import { Task } from '../models/Task';
+import { addOutline, calendarOutline, trashOutline } from 'ionicons/icons';
+import { Task, TaskStatus } from '../../lib/models/Task';
+import { TaskModalComponent } from '../components/task-modal/task-modal.component';
 import * as Parse from 'parse';
 
 @Component({
@@ -12,98 +17,192 @@ import * as Parse from 'parse';
   templateUrl: 'tab1.page.html',
   styleUrls: ['tab1.page.scss'],
   standalone: true,
-  imports: [IonicModule, CommonModule, FormsModule]
+  imports: [
+    CommonModule, 
+    FormsModule, 
+    TaskModalComponent,
+    IonHeader, IonToolbar, IonTitle, IonContent, IonButtons, IonButton,
+    IonIcon, IonList, IonItemSliding, IonItem, IonCheckbox, IonLabel,
+    IonItemOptions, IonItemOption, IonProgressBar, IonRefresher,
+    IonRefresherContent, IonBadge
+  ]
 })
 export class Tab1Page implements OnInit {
   tasks: Task[] = [];
-  isModalOpen = false;
-  newTask: Task = new Task();
+  loading = false;
 
   constructor(
-    private alertController: AlertController
+    private alertController: AlertController,
+    private modalCtrl: ModalController
   ) {
-    addIcons({ addOutline });
+    addIcons({ addOutline, calendarOutline, trashOutline });
   }
 
   ngOnInit() {
-    this.checkLoginAndLoadTasks();
+    this.loadTasks();
   }
 
   ionViewWillEnter() {
-    this.checkLoginAndLoadTasks();
+    this.loadTasks();
   }
 
-  private async checkLoginAndLoadTasks() {
-    const currentUser = Parse.User.current();
-    console.log('Current User:', currentUser);
-    if (currentUser) {
-      await this.loadTasks();
-    }
-  }
-
-  private async loadTasks() {
+  async loadTasks(event?: any) {
     try {
-      this.tasks = await Task.getUserTasks(Parse.User.current()?.id || '');
+      this.loading = true;
+      const query = new Parse.Query('Task');
+      if (Parse.User.current()) {
+        query.equalTo('userId', Parse.User.current()?.id);
+      }
+      query.descending('createdAt');
+      
+      const results = await query.find();
+      this.tasks = results.map(result => {
+        const task = new Task();
+        task.fromParseObject(result);
+        return task;
+      });
+
+      // 根据状态排序:进行中 -> 逾期 -> 已完成
+      this.tasks.sort((a, b) => {
+        const statusOrder = {
+          [TaskStatus.InProgress]: 0,
+          [TaskStatus.Overdue]: 1,
+          [TaskStatus.Completed]: 2
+        };
+        return statusOrder[a.getStatus()] - statusOrder[b.getStatus()];
+      });
+
     } catch (error) {
       console.error('加载任务失败:', error);
+      await this.showErrorAlert('加载任务失败');
+    } finally {
+      this.loading = false;
+      if (event) {
+        event.target.complete();
+      }
     }
   }
 
   async addTask() {
-    const currentUser = Parse.User.current();
-    if (!currentUser) {
-      const alert = await this.alertController.create({
-        header: '提示',
-        message: '请先登录后再创建任务',
-        buttons: ['确定']
+    try {
+      const modal = await this.modalCtrl.create({
+        component: TaskModalComponent,
+        componentProps: {
+          task: new Task()
+        }
       });
-      await alert.present();
-      return;
-    }
+      await modal.present();
 
-    try {
-      if (!this.newTask.title) {
-        throw new Error('标题不能为空');
+      const { data: task, role } = await modal.onDidDismiss();
+      if (role === 'confirm' && task) {
+        const newTask = await Task.create({
+          title: task.title,
+          content: task.content,
+          startTime: task.startTime ? new Date(task.startTime) : undefined,
+          endTime: task.endTime ? new Date(task.endTime) : undefined,
+          completed: false,
+          userId: Parse.User.current()?.id
+        });
+        
+        this.tasks.unshift(newTask);
+        // 重新排序
+        await this.loadTasks();
       }
-
-      const newTaskData = {
-        title: this.newTask.title,
-        content: this.newTask.content || '',
-        completed: false,
-        startTime: new Date().toISOString(),
-        endTime: new Date().toISOString(),
-        userId: currentUser.id
-      };
-
-      const task = await Task.create(newTaskData);
-      console.log('Task created:', task);
-      this.tasks.push(task);
-      this.setOpen(false);
-      this.newTask = new Task();
     } catch (error) {
       console.error('创建任务失败:', error);
-      const errorAlert = await this.alertController.create({
-        header: '错误',
-        message: error instanceof Error ? error.message : '创建任务失败,请重试',
-        buttons: ['确定']
-      });
-      await errorAlert.present();
-    }
-  }
-
-  setOpen(isOpen: boolean) {
-    this.isModalOpen = isOpen;
-    if (!isOpen) {
-      this.newTask = new Task();
+      await this.showErrorAlert('创建任务失败');
     }
   }
 
   async toggleComplete(task: Task) {
-    task.completed = !task.completed;
     try {
+      task.completed = !task.completed;
       await task.saveTask();
+      
+      // 重新加载以保持正确的排序
+      await this.loadTasks();
     } catch (error) {
       console.error('更新任务失败:', error);
+      task.completed = !task.completed;
+      await this.showErrorAlert('更新任务状态失败');
+    }
+  }
+
+  async deleteTask(task: Task) {
+    const alert = await this.alertController.create({
+      header: '确认删除',
+      message: '确定要删除这个任务吗?',
+      buttons: [
+        {
+          text: '取消',
+          role: 'cancel'
+        },
+        {
+          text: '删除',
+          role: 'destructive',
+          handler: async () => {
+            try {
+              await task.delete();
+              this.tasks = this.tasks.filter(t => t.id !== task.id);
+            } catch (error) {
+              console.error('删除任务失败:', error);
+              await this.showErrorAlert('删除任务失败');
+            }
+          }
+        }
+      ]
+    });
+    await alert.present();
+  }
+
+  getTaskStatusClass(task: Task): string {
+    const status = task.getStatus();
+    switch (status) {
+      case TaskStatus.Completed:
+        return 'task-completed';
+      case TaskStatus.Overdue:
+        return 'task-overdue';
+      case TaskStatus.InProgress:
+        return 'task-in-progress';
+      default:
+        return '';
     }
   }
-}
+
+  getTaskStatusText(task: Task): string {
+    const status = task.getStatus();
+    switch (status) {
+      case TaskStatus.Completed:
+        return '已完成';
+      case TaskStatus.Overdue:
+        return '已逾期';
+      case TaskStatus.InProgress:
+        return '进行中';
+      default:
+        return '';
+    }
+  }
+
+  getTaskStatusColor(task: Task): string {
+    const status = task.getStatus();
+    switch (status) {
+      case TaskStatus.Completed:
+        return 'success';
+      case TaskStatus.Overdue:
+        return 'danger';
+      case TaskStatus.InProgress:
+        return 'primary';
+      default:
+        return 'medium';
+    }
+  }
+
+  private async showErrorAlert(message: string) {
+    const alert = await this.alertController.create({
+      header: '错误',
+      message,
+      buttons: ['确定']
+    });
+    await alert.present();
+  }
+}

+ 3 - 3
src/app/tab3/tab3.page.ts

@@ -20,9 +20,9 @@ export class Tab3Page implements OnInit {
 
   constructor(private focusDataService: FocusDataService) {}
 
-  ngOnInit() {
-    this.focusRecords = this.focusDataService.getFocusRecords();
-    console.log('Focus Records in Tab3:', this.focusRecords); // 检查数据是否正确获取
+  async ngOnInit() {
+    this.focusRecords = await this.focusDataService.getFocusRecords();
+    console.log('Focus Records in Tab3:', this.focusRecords);
     this.loadChartData();
   }
 

+ 44 - 34
src/app/tab4/tab4.page.ts

@@ -1,5 +1,7 @@
 import { Component } from '@angular/core';
-import { IonHeader, IonToolbar, IonTitle, IonContent, IonCard, IonCardContent, IonButton, IonCardHeader, IonCardTitle, IonCardSubtitle, ModalController, AlertController } from '@ionic/angular/standalone';
+import { IonHeader, IonToolbar, IonTitle, IonContent, IonCard, IonCardContent, 
+         IonButton, IonCardHeader, IonCardTitle, IonCardSubtitle } from '@ionic/angular/standalone';
+import { ModalController, AlertController } from '@ionic/angular/standalone';
 
 import { Router } from '@angular/router';
 import { openUserLoginModal } from '../../lib/user/modal-user-login/modal-user-login.component';
@@ -39,43 +41,43 @@ export class Tab4Page {
     this.currentUser = new CloudUser();
   }
 
-  async login(){
-    try {
-      let user = await openUserLoginModal(this.modalCtrl);
-      if(user?.id){
-        this.currentUser = user;
-        this.auth.setCurrentUser(user);
-      } else {
-        // 登录失败时显示提示
-        const alert = await this.alertController.create({
-          header: '登录失败',
-          message: '用户名或密码错误,请重试',
-          buttons: ['确定']
-        });
-        await alert.present();
+  async openLoginModal() {
+    const { data } = await openUserLoginModal(this.modalCtrl);
+    if (data?.role === 'confirm') {
+      const cloudUser = data.data as CloudUser;
+      if (cloudUser?.id) {
+        this.currentUser = cloudUser;
+        await this.auth.login(cloudUser.get('username'), cloudUser.get('password'));
       }
-    } catch (error) {
-      // 处理其他错误
-      const alert = await this.alertController.create({
-        header: '登录错误',
-        message: '登录过程中发生错误,请稍后重试',
-        buttons: ['确定']
-      });
-      await alert.present();
     }
   }
 
-  async signup(){
-    // 弹出注册窗口
-    let user = await openUserLoginModal(this.modalCtrl,"signup");
-    if(user?.id){
-      this.currentUser = user
+  async openSignupModal() {
+    const { data } = await openUserLoginModal(this.modalCtrl);
+    if (data?.role === 'confirm') {
+      const cloudUser = data.data as CloudUser;
+      if (cloudUser?.id) {
+        this.currentUser = cloudUser;
+        await this.auth.register(
+          cloudUser.get('username'), 
+          cloudUser.get('password'), 
+          cloudUser.get('email') || ''
+        );
+      }
+    }
+  }
+
+  async handleUserAction() {
+    const { data } = await openUserLoginModal(this.modalCtrl);
+    if (!data?.data) {
+      return;
     }
+    this.currentUser = data.data as CloudUser;
   }
 
   logout(){
-    this.currentUser?.logout();
-    this.auth.setCurrentUser(null);
+    this.currentUser?.logOut();
+    this.auth.logout();
   }
 
   editUser(){
@@ -88,12 +90,20 @@ export class Tab4Page {
     let userPrompt = ``
     if(!currentUser?.id){
       console.log("用户未登录,请登录后重试");
-      let user = await openUserLoginModal(this.modalCtrl);
-      if(!user?.id){
-        return
+      const { data } = await openUserLoginModal(this.modalCtrl);
+      if (!data?.data) {
+        return;
       }
-      currentUser = user;
+      currentUser = data.data as CloudUser;
     }
     this.editTags=ev;
   }
+
+  login() {
+    this.openLoginModal();
+  }
+
+  signup() {
+    this.openSignupModal();
+  }
 }

+ 11 - 1
src/index.html

@@ -12,12 +12,22 @@
   <meta name="format-detection" content="telephone=no" />
   <meta name="msapplication-tap-highlight" content="no" />
 
+  <!-- 添加 CSP -->
+  <meta http-equiv="Content-Security-Policy" 
+        content="default-src 'self' data: https://ssl.gstatic.com 'unsafe-eval' 'unsafe-inline' https://cdn.jsdelivr.net http://dev.fmode.cn:1337;
+                 style-src 'self' 'unsafe-inline' https://cdn.jsdelivr.net;
+                 font-src 'self' data: https://cdn.jsdelivr.net;
+                 img-src 'self' data: https: blob:;
+                 connect-src 'self' http://dev.fmode.cn:1337 ws://localhost:* wss://localhost:*;">
+
   <link rel="icon" type="image/png" href="assets/icon/favicon.png" />
 
   <!-- add to homescreen for ios -->
   <meta name="apple-mobile-web-app-capable" content="yes" />
   <meta name="apple-mobile-web-app-status-bar-style" content="black" />
 
+  <!-- 修改 ionicons 的引入方式 -->
+  <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@ionic/core/css/ionic.bundle.css" />
   <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/ionicons@5.5.2/dist/css/ionicons.min.css">
 </head>
 
@@ -25,4 +35,4 @@
   <app-root></app-root>
 </body>
 
-</html>
+</html>

+ 21 - 0
src/lib/interfaces/base.interface.ts

@@ -0,0 +1,21 @@
+export interface IBaseModel {
+    id?: string;
+    createdAt?: Date;
+    updatedAt?: Date;
+  }
+  
+  export interface IUser extends IBaseModel {
+    username: string;
+    realname?: string;
+    age?: number;
+    gender?: string;
+    avatar?: string;
+  }
+  
+  export interface ITask extends IBaseModel {
+    title: string;
+    startTime: Date;
+    endTime: Date;
+    completed: boolean;
+    userId: string;
+  }

+ 89 - 23
src/lib/models/Task.ts

@@ -1,34 +1,100 @@
-import { CloudObject, CloudQuery } from '../ncloud';
+import { CloudObject } from '../ncloud';
+import * as Parse from 'parse';
+
+export enum TaskStatus {
+    InProgress = 'inProgress',
+    Completed = 'completed',
+    Overdue = 'overdue'
+}
 
 export class Task extends CloudObject {
+    title: string = '';
+    content: string = '';
+    completed: boolean = false;
+    startTime?: Date;
+    endTime?: Date;
+    userId?: string;
+
     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;
+    fromParseObject(parseObject: Parse.Object) {
+        this.id = parseObject.id;
+        this.title = parseObject.get('title');
+        this.content = parseObject.get('content');
+        this.completed = parseObject.get('completed');
+        this.startTime = parseObject.get('startTime');
+        this.endTime = parseObject.get('endTime');
+        this.userId = parseObject.get('userId');
+    }
+
+    toParseObject(): any {
+        return {
+            title: this.title,
+            content: this.content,
+            completed: this.completed,
+            startTime: this.startTime,
+            endTime: this.endTime,
+            userId: this.userId
+        };
+    }
+
+    async saveTask(): Promise<void> {
+        try {
+            const data = this.toParseObject();
+            const parseObject = new Parse.Object('Task');
+            
+            if (this.id) {
+                parseObject.id = this.id;
+            }
+            
+            Object.keys(data).forEach(key => {
+                parseObject.set(key, data[key]);
+            });
+
+            await parseObject.save();
+            this.id = parseObject.id;
+        } catch (error) {
+            console.error('保存任务失败:', error);
+            throw error;
+        }
+    }
+
+    async delete(): Promise<void> {
+        try {
+            if (!this.id) return;
+            
+            const parseObject = new Parse.Object('Task');
+            parseObject.id = this.id;
+            await parseObject.destroy();
+        } catch (error) {
+            console.error('删除任务失败:', error);
+            throw error;
+        }
     }
 
-    // 获取用户的所有任务
-    static async getUserTasks(userId: string) {
-        const query = new CloudQuery('Task');
-        query.equalTo('userId', userId);
-        return await query.find();
+    getStatus(): TaskStatus {
+        if (this.completed) {
+            return TaskStatus.Completed;
+        }
+        
+        if (this.endTime && new Date() > new Date(this.endTime)) {
+            return TaskStatus.Overdue;
+        }
+        
+        return TaskStatus.InProgress;
     }
 
-    // 更新任务状态
-    async updateStatus(completed: boolean) {
-        this.set({ completed });
-        return await this.save();
+    static async create(data: Partial<Task>): Promise<Task> {
+        try {
+            const task = new Task();
+            Object.assign(task, data);
+            await task.saveTask();
+            return task;
+        } catch (error) {
+            console.error('Create task failed:', error);
+            throw error;
+        }
     }
-} 
+}

+ 70 - 209
src/lib/ncloud.ts

@@ -1,12 +1,11 @@
 import * as Parse from 'parse';
 
-// CloudObject.ts
 export class CloudObject {
     protected parseObject: Parse.Object;
     className: string;
     id: string | null = null;
-    createdAt:any;
-    updatedAt:any;
+    createdAt: any;
+    updatedAt: any;
     data: Record<string, any> = {};
 
     constructor(className: string) {
@@ -21,6 +20,7 @@ export class CloudObject {
     set(json: Record<string, any>) {
         Object.keys(json).forEach(key => {
             if (["objectId", "id", "createdAt", "updatedAt", "ACL"].indexOf(key) > -1) {
+                if (key === "objectId") this.id = json[key];
                 return;
             }
             this.data[key] = json[key];
@@ -35,7 +35,6 @@ export class CloudObject {
         let method = "POST";
         let url = `http://dev.fmode.cn:1337/parse/classes/${this.className}`;
 
-        // 更新
         if (this.id) {
             url += `/${this.id}`;
             method = "PUT";
@@ -55,7 +54,7 @@ export class CloudObject {
 
         const result = await response?.json();
         if (result?.error) {
-            console.error(result?.error);
+            throw new Error(result.error);
         }
         if (result?.objectId) {
             this.id = result?.objectId;
@@ -69,243 +68,116 @@ export class CloudObject {
             headers: {
                 "x-parse-application-id": "dev"
             },
-            body: null,
             method: "DELETE",
             mode: "cors",
             credentials: "omit"
         });
 
         const result = await response?.json();
-        if (result) {
-            this.id = null;
+        if (result?.error) {
+            throw new Error(result.error);
         }
+        this.id = null;
         return true;
     }
 
-    protected setParseObject(obj: Parse.Object) {
+    public setParseObject(obj: Parse.Object) {
         this.parseObject = obj;
     }
 }
 
-// CloudQuery.ts
 export class CloudQuery {
-    private query: Parse.Query;
-    className: string;
-    queryParams: Record<string, any> = {};
+    private whereOptions: Record<string, any> = {};
+    private className: string;
 
     constructor(className: string) {
         this.className = className;
-        this.query = new Parse.Query(className);
-    }
-    // 作用是将查询参数转换为对象
-    include(...fileds:string[]) {
-        this.queryParams["include"] = fileds;
-    }
-    greaterThan(key: string, value: any) {
-        if (!this.queryParams["where"][key]) this.queryParams["where"][key] = {};
-        this.queryParams["where"][key]["$gt"] = value;
-    }
-
-    greaterThanAndEqualTo(key: string, value: any) {
-        if (!this.queryParams["where"][key]) this.queryParams["where"][key] = {};
-        this.queryParams["where"][key]["$gte"] = value;
-    }
-
-    lessThan(key: string, value: any) {
-        if (!this.queryParams["where"][key]) this.queryParams["where"][key] = {};
-        this.queryParams["where"][key]["$lt"] = value;
-    }
-
-    lessThanAndEqualTo(key: string, value: any) {
-        if (!this.queryParams["where"][key]) this.queryParams["where"][key] = {};
-        this.queryParams["where"][key]["$lte"] = value;
-    }
-
-    equalTo(key: string, value: any) {
-        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 exists = json?.results?.[0] || null;
-        if (exists) {
-            let existsObject = this.dataToObj(exists)
-            return existsObject;
-        }
-        return null
-
     }
 
-    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;
+    equalTo(key: string, value: any): CloudQuery {
+        if (!this.whereOptions[key]) {
+            this.whereOptions[key] = value;
         }
+        return this;
     }
 
-    async first() {
-        let url = `http://dev.fmode.cn:1337/parse/classes/${this.className}?`;
-
-        if (Object.keys(this.queryParams["where"]).length) {
-            const whereStr = JSON.stringify(this.queryParams["where"]);
-            url += `where=${whereStr}`;
+    async find() {
+        let url = `http://dev.fmode.cn:1337/parse/classes/${this.className}`;
+        
+        if (Object.keys(this.whereOptions).length > 0) {
+            url += `?where=${JSON.stringify(this.whereOptions)}`;
         }
 
         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 list = json?.results || []
-        let objList = list.map((item:any)=>this.dataToObj(item))
-        return objList || [];
-    }
-
-    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;
+        const result = await response?.json();
+        return result?.results || [];
     }
 }
 
-// CloudUser.ts
 export class CloudUser extends CloudObject {
-    constructor() {
-        super("_User"); // 假设用户类在Parse中是"_User"
-        // 读取用户缓存信息
-        let userCacheStr = localStorage.getItem("NCloud/dev/User")
-        if(userCacheStr){
-            let userData = JSON.parse(userCacheStr)
-            // 设置用户信息
-            this.id = userData?.objectId;
-            this.sessionToken = userData?.sessionToken;
-            this.data = userData; // 保存用户数据
-        }
-    }
+    sessionToken: string | null = null;
 
-    sessionToken:string|null = ""
-    /** 获取当前用户信息 */
-    async current() {
-        if (!this.sessionToken) {
-            console.error("用户未登录");
-            return null;
-        }
-        return this;
-        // 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;
+    constructor() {
+        super('_User');
     }
 
-    /** 登录 */
-    async login(username: string, password: string):Promise<CloudUser|null> {
+    async logIn(username: string, password: string) {
         const response = await fetch(`http://dev.fmode.cn:1337/parse/login`, {
+            method: 'POST',
             headers: {
-                "x-parse-application-id": "dev",
-                "Content-Type": "application/json"
+                'Content-Type': 'application/json',
+                'X-Parse-Application-Id': 'dev'
             },
-            body: JSON.stringify({ username, password }),
-            method: "POST"
+            body: JSON.stringify({ username, password })
         });
 
-        const result = await response?.json();
+        const result = await response.json();
         if (result?.error) {
-            console.error(result?.error);
-            return null;
+            throw new Error(result.error);
         }
-        
-        // 设置用户信息
-        this.id = result?.objectId;
-        this.sessionToken = result?.sessionToken;
-        this.data = result; // 保存用户数据
-        // 缓存用户信息
-        console.log(result)
-        localStorage.setItem("NCloud/dev/User",JSON.stringify(result))
+
+        this.id = result.objectId;
+        this.sessionToken = result.sessionToken;
+        this.data = result;
+        localStorage.setItem("NCloud/dev/User", JSON.stringify(result));
         return this;
     }
 
-    /** 登出 */
-    async logout() {
+    async logOut() {
         if (!this.sessionToken) {
-            console.error("用户未登录");
-            return;
+            throw new Error('User not logged in');
         }
 
         const response = await fetch(`http://dev.fmode.cn:1337/parse/logout`, {
             headers: {
-                "x-parse-application-id": "dev",
-                "x-parse-session-token": this.sessionToken
+                'X-Parse-Application-Id': 'dev',
+                'X-Parse-Session-Token': this.sessionToken
             },
-            method: "POST"
+            method: 'POST'
         });
 
-        const result = await response?.json();
+        const result = await response.json();
         if (result?.error) {
-            console.error(result?.error);
-            return false;
+            throw new Error(result.error);
         }
 
-        // 清除用户信息
-        localStorage.removeItem("NCloud/dev/User")
         this.id = null;
         this.sessionToken = null;
         this.data = {};
+        localStorage.removeItem("NCloud/dev/User");
         return true;
     }
 
-    /** 注册 */
     async signUp(username: string, password: string, additionalData: Record<string, any> = {}) {
         const userData = {
             username,
             password,
-            ...additionalData // 合并额外的用户��据
+            ...additionalData
         };
 
         const response = await fetch(`http://dev.fmode.cn:1337/parse/users`, {
@@ -319,57 +191,46 @@ export class CloudUser extends CloudObject {
 
         const result = await response?.json();
         if (result?.error) {
-            console.error(result?.error);
-            return null;
+            throw new Error(result.error);
         }
 
-        // 设置用户信息
-        // 缓存用户信息
-        console.log(result)
-        localStorage.setItem("NCloud/dev/User",JSON.stringify(result))
         this.id = result?.objectId;
         this.sessionToken = result?.sessionToken;
-        this.data = result; // 保存用户数据
+        this.data = result;
+        localStorage.setItem("NCloud/dev/User", JSON.stringify(result));
         return this;
     }
 
     override async save() {
-        let method = "POST";
-        let url = `http://dev.fmode.cn: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": "dev",
-            "x-parse-session-token": this.sessionToken, // 添加sessionToken以进行身份验证
+        if (!this.id || !this.sessionToken) {
+            throw new Error('User not logged in');
         }
+
+        let url = `http://dev.fmode.cn:1337/parse/users/${this.id}`;
+        let data: any = JSON.parse(JSON.stringify(this.data));
+        delete data.createdAt;
+        delete data.updatedAt;
+        delete data.ACL;
+        delete data.objectId;
+        
         const response = await fetch(url, {
-            headers: headersOptions,
-            body: body,
-            method: method,
+            headers: {
+                "content-type": "application/json;charset=UTF-8",
+                "x-parse-application-id": "dev",
+                "x-parse-session-token": this.sessionToken
+            },
+            body: JSON.stringify(data),
+            method: "PUT",
             mode: "cors",
             credentials: "omit"
         });
-    
+
         const result = await response?.json();
         if (result?.error) {
-            console.error(result?.error);
+            throw new Error(result.error);
         }
-        if (result?.objectId) {
-            this.id = result?.objectId;
-        }
-        localStorage.setItem("NCloud/dev/User",JSON.stringify(this.data))
+        
+        localStorage.setItem("NCloud/dev/User", JSON.stringify(this.data));
         return this;
     }
 }

+ 26 - 0
src/lib/services/task.service.ts

@@ -0,0 +1,26 @@
+import { Injectable } from '@angular/core';
+import { Task } from '../models/Task';
+import { ITask } from '../interfaces/base.interface';
+
+@Injectable({
+  providedIn: 'root'
+})
+export class TaskService {
+  async createTask(taskData: Partial<ITask>): Promise<Task | null> {
+    try {
+      return await Task.create(taskData as any);
+    } catch (error) {
+      console.error('Create task failed:', error);
+      return null;
+    }
+  }
+
+  async getUserTasks(userId: string): Promise<Task[]> {
+    try {
+      return await Task.getUserTasks(userId);
+    } catch (error) {
+      console.error('Get user tasks failed:', error);
+      return [];
+    }
+  }
+}

+ 32 - 0
src/lib/services/user.service.ts

@@ -0,0 +1,32 @@
+import { Injectable } from '@angular/core';
+import { CloudUser } from '../ncloud';
+import { IUser } from '../interfaces/base.interface';
+
+@Injectable({
+  providedIn: 'root'
+})
+export class UserService {
+  private currentUser: CloudUser | null = null;
+
+  async getCurrentUser(): Promise<CloudUser | null> {
+    if (!this.currentUser) {
+      this.currentUser = new CloudUser();
+      await this.currentUser.current();
+    }
+    return this.currentUser;
+  }
+
+  async updateUserProfile(userData: Partial<IUser>): Promise<boolean> {
+    try {
+      const user = await this.getCurrentUser();
+      if (!user) return false;
+      
+      user.set(userData);
+      await user.save();
+      return true;
+    } catch (error) {
+      console.error('Update user profile failed:', error);
+      return false;
+    }
+  }
+}

+ 30 - 21
src/lib/user/modal-user-edit/modal-user-edit.component.ts

@@ -1,7 +1,11 @@
-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 { Component, OnInit } from '@angular/core';
+import { IonHeader, IonToolbar, IonTitle, IonContent, IonCard, IonCardContent, 
+         IonButton, IonCardHeader, IonCardTitle, IonCardSubtitle, IonInput, 
+         IonItem, IonSegment, IonSegmentButton, IonLabel } from '@ionic/angular/standalone';
+import { ModalController } from '@ionic/angular/standalone';
 import { CloudUser } from '../../ncloud';
+import { CommonModule } from '@angular/common';
+import { FormsModule } from '@angular/forms';
 
 @Component({
   selector: 'app-modal-user-edit',
@@ -9,11 +13,24 @@ import { CloudUser } from '../../ncloud';
   styleUrls: ['./modal-user-edit.component.scss'],
   standalone: true,
   imports: [
-    IonHeader, IonToolbar, IonTitle, IonContent, 
-    IonCard,IonCardContent,IonButton,IonCardHeader,IonCardTitle,IonCardSubtitle,
-    IonInput,IonItem,
-    IonSegment,IonSegmentButton,IonLabel
-  ],
+    CommonModule,
+    FormsModule,
+    IonHeader,
+    IonToolbar,
+    IonTitle,
+    IonContent,
+    IonCard,
+    IonCardContent,
+    IonButton,
+    IonCardHeader,
+    IonCardTitle,
+    IonCardSubtitle,
+    IonInput,
+    IonItem,
+    IonSegment,
+    IonSegmentButton,
+    IonLabel
+  ]
 })
 export class ModalUserEditComponent  implements OnInit {
 
@@ -49,18 +66,10 @@ export class ModalUserEditComponent  implements OnInit {
   }
 }
 
-export async function openUserEditModal(modalCtrl:ModalController):Promise<CloudUser|null>{
-  const modal = await modalCtrl.create({
-    component: ModalUserEditComponent,
-    breakpoints:[0.7,1.0],
-    initialBreakpoint:0.7
+export async function openUserEditModal(modalController: ModalController) {
+  const modal = await modalController.create({
+    component: ModalUserEditComponent
   });
-  modal.present();
-
-  const { data, role } = await modal.onWillDismiss();
-
-  if (role === 'confirm') {
-    return data;
-  }
-  return null
+  await modal.present();
+  return modal.onDidDismiss();
 }

+ 84 - 80
src/lib/user/modal-user-login/modal-user-login.component.ts

@@ -1,7 +1,13 @@
-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, AlertController } from '@ionic/angular/standalone';
+import { IonContent, IonHeader, IonToolbar, IonTitle, IonButtons, IonButton, 
+         IonItem, IonLabel, IonInput, IonSegment, IonSegmentButton,
+         IonCard, IonCardHeader, IonCardTitle, IonCardSubtitle, 
+         IonCardContent } from '@ionic/angular/standalone';
+import { ModalController, AlertController } from '@ionic/angular/standalone';
+import { FormsModule } from '@angular/forms';
+import { CommonModule } from '@angular/common';
 import { CloudUser } from '../../ncloud';
+import * as Parse from 'parse';
 
 @Component({
   selector: 'app-modal-user-login',
@@ -9,50 +15,51 @@ import { CloudUser } from '../../ncloud';
   styleUrls: ['./modal-user-login.component.scss'],
   standalone: true,
   imports: [
-    IonHeader, IonToolbar, IonTitle, IonContent, 
-    IonCard, IonCardContent, IonButton, IonCardHeader, IonCardTitle, IonCardSubtitle,
-    IonInput, IonItem, IonSegment, IonSegmentButton, IonLabel
-  ],
+    CommonModule,
+    FormsModule,
+    IonContent,
+    IonHeader,
+    IonToolbar,
+    IonTitle,
+    IonButtons,
+    IonButton,
+    IonItem,
+    IonLabel,
+    IonInput,
+    IonSegment,
+    IonSegmentButton,
+    IonCard,
+    IonCardHeader,
+    IonCardTitle,
+    IonCardSubtitle,
+    IonCardContent
+  ]
 })
-export class ModalUserLoginComponent implements OnInit {
-  @Input()
-  type: "login"|"signup" = "login"
-  
-  typeChange(ev: any) {
-    this.type = ev?.detail?.value || ev?.value || 'login'
-  }
-  
-  username: string = ""
-  usernameChange(ev: any) {
-    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
-  }
-  
+export class ModalUserLoginComponent {
+  username: string = '';
+  password: string = '';
+  password2: string = '';
+  type: 'login' | 'signup' = 'login';
+
   constructor(
     private modalCtrl: ModalController,
-    private alertCtrl: AlertController
-  ) {
-    console.log(this.type)
+    private alertController: AlertController
+  ) {}
+
+  typeChange(event: any) {
+    this.type = event.detail.value;
   }
 
-  ngOnInit() {}
+  usernameChange(event: any) {
+    this.username = event.detail.value;
+  }
 
-  async showAlert(header: string, message: string) {
-    const alert = await this.alertCtrl.create({
-      header,
-      message,
-      buttons: ['确定']
-    });
-    await alert.present();
+  passwordChange(event: any) {
+    this.password = event.detail.value;
+  }
+
+  password2Change(event: any) {
+    this.password2 = event.detail.value;
   }
 
   async login() {
@@ -61,66 +68,63 @@ export class ModalUserLoginComponent implements OnInit {
       return;
     }
 
-    let user: any = new CloudUser();
     try {
-      user = await user.login(this.username, this.password);
-      if (user?.id) {
-        this.modalCtrl.dismiss(user, "confirm");
-        console.log("登录成功");
+      const user = await Parse.User.logIn(this.username, this.password);
+      if (user) {
+        await Parse.User.become(user.getSessionToken());
+        const cloudUser = new CloudUser();
+        cloudUser.setParseObject(user);
+        this.modalCtrl.dismiss(cloudUser, "confirm");
       } else {
         await this.showAlert('登录失败', '用户名或密码错误');
       }
     } catch (error) {
+      console.error("Login error:", error);
       await this.showAlert('错误', '登录过程中发生错误,请稍后重试');
     }
   }
 
   async signup() {
     if (!this.username || !this.password || !this.password2) {
-      await this.showAlert('提示', '请填写完整的注册信息');
+      await this.showAlert('提示', '请输入完整信息');
       return;
     }
-    
-    if (this.password != this.password2) {
-      await this.showAlert('提示', '两次输入的密码不一致,请重新输入');
+
+    if (this.password !== this.password2) {
+      await this.showAlert('提示', '两次输入的密码不一致');
       return;
     }
 
     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);
+      const user = new Parse.User();
+      user.set("username", this.username);
+      user.set("password", this.password);
+
+      await user.signUp();
+      const cloudUser = new CloudUser();
+      cloudUser.setParseObject(user);
+      this.modalCtrl.dismiss(cloudUser, "confirm");
+    } catch (error) {
+      console.error("Signup error:", error);
+      await this.showAlert('错误', '注册失败,请稍后重试');
     }
   }
+
+  private async showAlert(header: string, message: string) {
+    const alert = await this.alertController.create({
+      header,
+      message,
+      buttons: ['确定']
+    });
+    await alert.present();
+  }
 }
 
-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
+// 导出打开模态框的函数
+export async function openUserLoginModal(modalController: ModalController) {
+  const modal = await modalController.create({
+    component: ModalUserLoginComponent
   });
-  modal.present();
-
-  const { data, role } = await modal.onWillDismiss();
-
-  if (role === 'confirm') {
-    return data;
-  }
-  return null;
+  await modal.present();
+  return modal.onDidDismiss();
 }

+ 0 - 86
src/models/Task.ts

@@ -1,86 +0,0 @@
-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();
-  }
-}