18079408532 hace 1 año
padre
commit
9cb1ed0c52

+ 1 - 5
src/app/tab1/tab1.page.ts

@@ -56,11 +56,7 @@ export class Tab1Page implements OnInit {
       query.descending('createdAt');
       query.descending('createdAt');
       
       
       const results = await query.find();
       const results = await query.find();
-      this.tasks = results.map(result => {
-        const task = new Task();
-        task.fromParseObject(result);
-        return task;
-      });
+      this.tasks = results.map(result => Task.fromParseObject(result));
 
 
       // 根据状态排序:进行中 -> 逾期 -> 已完成
       // 根据状态排序:进行中 -> 逾期 -> 已完成
       this.tasks.sort((a, b) => {
       this.tasks.sort((a, b) => {

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

@@ -99,8 +99,8 @@ export class Tab2Page implements OnInit {
       this.records = records.map(record => ({
       this.records = records.map(record => ({
         id: Date.now(),
         id: Date.now(),
         type: record.category,
         type: record.category,
-        startTime: record.date.toISOString(),
-        endTime: record.date.toISOString(),
+        startTime: new Date(record.startTime).toISOString(),
+        endTime: new Date(record.endTime).toISOString(),
         duration: record.duration,
         duration: record.duration,
         parseId: record.id
         parseId: record.id
       }));
       }));
@@ -154,7 +154,7 @@ export class Tab2Page implements OnInit {
           startTime: this.timerStartTime!.toISOString(),
           startTime: this.timerStartTime!.toISOString(),
           endTime: endTime.toISOString(),
           endTime: endTime.toISOString(),
           duration: duration,
           duration: duration,
-          parseId: savedRecord.id as string
+          parseId: savedRecord.id
         };
         };
         
         
         this.records.unshift(record);
         this.records.unshift(record);

+ 17 - 18
src/app/tab3/tab3.page.ts

@@ -40,7 +40,7 @@ export class Tab3Page implements OnInit {
     { id: 'sport', name: '运动', icon: 'barbell-outline' },
     { id: 'sport', name: '运动', icon: 'barbell-outline' },
     { id: 'reading', name: '阅读', icon: 'book-outline' },
     { id: 'reading', name: '阅读', icon: 'book-outline' },
     { id: 'coding', name: '编程', icon: 'code-slash-outline' },
     { id: 'coding', name: '编程', icon: 'code-slash-outline' },
-    { id: 'meditation', name: '想', icon: 'leaf-outline' },
+    { id: 'meditation', name: '���想', icon: 'leaf-outline' },
     { id: 'music', name: '音乐', icon: 'musical-notes-outline' },
     { id: 'music', name: '音乐', icon: 'musical-notes-outline' },
     { id: 'language', name: '语言', icon: 'language-outline' },
     { id: 'language', name: '语言', icon: 'language-outline' },
     { id: 'writing', name: '写作', icon: 'pencil-outline' }
     { id: 'writing', name: '写作', icon: 'pencil-outline' }
@@ -61,7 +61,6 @@ export class Tab3Page implements OnInit {
   async loadData() {
   async loadData() {
     this.isLoading = true;
     this.isLoading = true;
     try {
     try {
-      // 并行加载数据
       const [focusRecords, tasks] = await Promise.all([
       const [focusRecords, tasks] = await Promise.all([
         this.focusDataService.getFocusRecords(),
         this.focusDataService.getFocusRecords(),
         this.focusDataService.getTasks()
         this.focusDataService.getTasks()
@@ -91,7 +90,7 @@ export class Tab3Page implements OnInit {
 
 
     // 计算最常见类别
     // 计算最常见类别
     const categoryCount = [...this.focusRecords, ...this.tasks].reduce((acc, item) => {
     const categoryCount = [...this.focusRecords, ...this.tasks].reduce((acc, item) => {
-      const category = item.category;
+      const category = item.category || '未分类';
       acc[category] = (acc[category] || 0) + 1;
       acc[category] = (acc[category] || 0) + 1;
       return acc;
       return acc;
     }, {});
     }, {});
@@ -115,8 +114,8 @@ export class Tab3Page implements OnInit {
       datasets: [{
       datasets: [{
         label: '专注时间(分钟)',
         label: '专注时间(分钟)',
         data: Object.values(groupedData),
         data: Object.values(groupedData),
-        backgroundColor: 'rgba(var(--ion-color-primary-rgb), 0.4)',
-        borderColor: 'var(--ion-color-primary)',
+        backgroundColor: 'rgba(72, 138, 255, 0.4)',
+        borderColor: 'rgba(72, 138, 255, 0.8)',
         borderWidth: 1
         borderWidth: 1
       }]
       }]
     }, 'bar');
     }, 'bar');
@@ -132,8 +131,8 @@ export class Tab3Page implements OnInit {
       datasets: [{
       datasets: [{
         data: [completed, uncompleted],
         data: [completed, uncompleted],
         backgroundColor: [
         backgroundColor: [
-          'rgba(var(--ion-color-success-rgb), 0.8)',
-          'rgba(var(--ion-color-medium-rgb), 0.4)'
+          'rgba(72, 138, 255, 0.8)',  // 浅蓝色
+          'rgba(72, 138, 255, 0.2)'   // 更浅的蓝色
         ]
         ]
       }]
       }]
     }, 'doughnut');
     }, 'doughnut');
@@ -146,23 +145,24 @@ export class Tab3Page implements OnInit {
     ];
     ];
     
     
     const categoryData = filteredData.reduce((acc, item) => {
     const categoryData = filteredData.reduce((acc, item) => {
-      const category = item.category;
+      const category = item.category || '未分类';
       acc[category] = (acc[category] || 0) + 1;
       acc[category] = (acc[category] || 0) + 1;
       return acc;
       return acc;
     }, {});
     }, {});
     
     
     this.createOrUpdateChart('category', this.categoryChart, {
     this.createOrUpdateChart('category', this.categoryChart, {
       labels: Object.keys(categoryData).map(id => 
       labels: Object.keys(categoryData).map(id => 
-        this.activityTypes.find(type => type.id === id)?.name || id
+        id === '未分类' ? '未分类' : (this.activityTypes.find(type => type.id === id)?.name || id)
       ),
       ),
       datasets: [{
       datasets: [{
         data: Object.values(categoryData),
         data: Object.values(categoryData),
         backgroundColor: [
         backgroundColor: [
-          'rgba(var(--ion-color-primary-rgb), 0.8)',
-          'rgba(var(--ion-color-secondary-rgb), 0.8)',
-          'rgba(var(--ion-color-tertiary-rgb), 0.8)',
-          'rgba(var(--ion-color-success-rgb), 0.8)',
-          'rgba(var(--ion-color-warning-rgb), 0.8)'
+          'rgba(72, 138, 255, 0.8)',   // 主蓝色
+          'rgba(72, 138, 255, 0.6)',   // 次蓝色
+          'rgba(72, 138, 255, 0.4)',   // 浅蓝色
+          'rgba(72, 138, 255, 0.2)',   // 更浅蓝色
+          'rgba(100, 149, 237, 0.8)',  // 矢车菊蓝
+          'rgba(135, 206, 235, 0.8)'   // 天蓝色
         ]
         ]
       }]
       }]
     }, 'pie');
     }, 'pie');
@@ -183,7 +183,7 @@ export class Tab3Page implements OnInit {
         startDate = new Date(now.getFullYear() - 1, now.getMonth(), now.getDate());
         startDate = new Date(now.getFullYear() - 1, now.getMonth(), now.getDate());
         break;
         break;
       default:
       default:
-        startDate = new Date(0); // 所有数据
+        startDate = new Date(0);
     }
     }
 
 
     return data.filter(item => new Date(item[dateField]) >= startDate);
     return data.filter(item => new Date(item[dateField]) >= startDate);
@@ -197,14 +197,14 @@ export class Tab3Page implements OnInit {
     }, {});
     }, {});
   }
   }
 
 
-  private createOrUpdateChart(id: string, canvas: ElementRef, data: any, type: string) {
+  private createOrUpdateChart(id: string, canvas: ElementRef, data: any, type: 'bar' | 'doughnut' | 'pie') {
     if (this.charts[id]) {
     if (this.charts[id]) {
       this.charts[id].destroy();
       this.charts[id].destroy();
     }
     }
 
 
     const ctx = canvas.nativeElement.getContext('2d');
     const ctx = canvas.nativeElement.getContext('2d');
     this.charts[id] = new Chart(ctx, {
     this.charts[id] = new Chart(ctx, {
-      type: type as keyof ChartTypeRegistry,
+      type: type,
       data: data,
       data: data,
       options: {
       options: {
         responsive: true,
         responsive: true,
@@ -247,7 +247,6 @@ export class Tab3Page implements OnInit {
 
 
   onChartTypeChange(event: any) {
   onChartTypeChange(event: any) {
     this.selectedChart = event.detail.value;
     this.selectedChart = event.detail.value;
-    // 给图表一点时间重新渲染
     setTimeout(() => this.updateCharts(), 100);
     setTimeout(() => this.updateCharts(), 100);
   }
   }
 }
 }

+ 21 - 59
src/lib/models/Task.ts

@@ -19,82 +19,44 @@ export class Task extends CloudObject {
         super('Task');
         super('Task');
     }
     }
 
 
-    fromParseObject(parseObject: Parse.Object) {
-        this.id = parseObject.id;
-        this.title = parseObject.get('title');
-        this.content = parseObject.get('content');
-        this.completed = parseObject.get('completed');
+    static async create(data: Partial<Task>): Promise<Task> {
+        const task = new Task();
+        Object.assign(task, data);
+        await task.saveTask();
+        return task;
+    }
+
+    static fromParseObject(parseObject: Parse.Object): Task {
+        const task = new Task();
+        task.setParseObject(parseObject);
+        return task;
+    }
+
+    override setParseObject(parseObject: Parse.Object<Parse.Attributes>) {
+        super.setParseObject(parseObject);
+        this.title = parseObject.get('title') || '';
+        this.content = parseObject.get('content') || '';
+        this.completed = parseObject.get('completed') || false;
         this.startTime = parseObject.get('startTime');
         this.startTime = parseObject.get('startTime');
         this.endTime = parseObject.get('endTime');
         this.endTime = parseObject.get('endTime');
         this.userId = parseObject.get('userId');
         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> {
     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;
-        }
+        await this.save();
     }
     }
 
 
     async delete(): Promise<void> {
     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;
-        }
+        await this.destroy();
     }
     }
 
 
     getStatus(): TaskStatus {
     getStatus(): TaskStatus {
         if (this.completed) {
         if (this.completed) {
             return TaskStatus.Completed;
             return TaskStatus.Completed;
         }
         }
-        
-        if (this.endTime && new Date() > new Date(this.endTime)) {
+        if (this.endTime && new Date() > this.endTime) {
             return TaskStatus.Overdue;
             return TaskStatus.Overdue;
         }
         }
-        
         return TaskStatus.InProgress;
         return TaskStatus.InProgress;
     }
     }
-
-    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;
-        }
-    }
 }
 }

+ 171 - 183
src/lib/ncloud.ts

@@ -1,122 +1,61 @@
 import * as Parse from 'parse';
 import * as Parse from 'parse';
 
 
+// 初始化 Parse
+Parse.initialize("dev", "dev");
+Parse.CoreManager.set('SERVER_URL', 'http://dev.fmode.cn:1337/parse');
+
 export class CloudObject {
 export class CloudObject {
-    protected parseObject: Parse.Object;
-    className: string;
     id: string | null = null;
     id: string | null = null;
-    createdAt: any;
-    updatedAt: any;
     data: Record<string, any> = {};
     data: Record<string, any> = {};
+    createdAt?: Date;
+    updatedAt?: Date;
 
 
-    constructor(className: string) {
-        this.parseObject = new Parse.Object(className);
-        this.className = className;
-    }
+    constructor(protected className: string) {}
 
 
-    toPointer() {
-        return { "__type": "Pointer", "className": this.className, "objectId": this.id };
+    get(key: string): any {
+        return this.data[key];
     }
     }
 
 
-    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];
-        });
+    set(key: string | Record<string, any>, value?: any) {
+        if (typeof key === 'string') {
+            this.data[key] = value;
+        } else {
+            Object.assign(this.data, key);
+        }
     }
     }
 
 
-    get(key: string) {
-        return this.data[key] || null;
+    toJSON(): Record<string, any> {
+        return { ...this.data };
     }
     }
 
 
-    async save() {
-        let method = "POST";
-        let url = `http://dev.fmode.cn:1337/parse/classes/${this.className}`;
+    setParseObject(parseObject: Parse.Object<Parse.Attributes>) {
+        this.id = parseObject.id;
+        const data = parseObject.toJSON();
+        this.data = data;
+        this.createdAt = data['createdAt'] ? new Date(data['createdAt']) : undefined;
+        this.updatedAt = data['updatedAt'] ? new Date(data['updatedAt']) : undefined;
+    }
 
 
+    async save(): Promise<this> {
+        const parseObject = new Parse.Object(this.className);
         if (this.id) {
         if (this.id) {
-            url += `/${this.id}`;
-            method = "PUT";
+            parseObject.id = this.id;
         }
         }
-
-        const body = JSON.stringify(this.data);
-        const response = await fetch(url, {
-            headers: {
-                "content-type": "application/json;charset=UTF-8",
-                "x-parse-application-id": "dev"
-            },
-            body: body,
-            method: method,
-            mode: "cors",
-            credentials: "omit"
+        Object.keys(this.data).forEach(key => {
+            parseObject.set(key, this.data[key]);
         });
         });
-
-        const result = await response?.json();
-        if (result?.error) {
-            throw new Error(result.error);
-        }
-        if (result?.objectId) {
-            this.id = result?.objectId;
-        }
+        const savedObject = await parseObject.save();
+        this.setParseObject(savedObject);
         return this;
         return this;
     }
     }
 
 
-    async destroy() {
-        if (!this.id) return;
-        const response = await fetch(`http://dev.fmode.cn:1337/parse/classes/${this.className}/${this.id}`, {
-            headers: {
-                "x-parse-application-id": "dev"
-            },
-            method: "DELETE",
-            mode: "cors",
-            credentials: "omit"
-        });
-
-        const result = await response?.json();
-        if (result?.error) {
-            throw new Error(result.error);
-        }
-        this.id = null;
+    async destroy(): Promise<boolean> {
+        if (!this.id) return false;
+        const parseObject = new Parse.Object(this.className);
+        parseObject.id = this.id;
+        await parseObject.destroy();
         return true;
         return true;
     }
     }
-
-    public setParseObject(obj: Parse.Object) {
-        this.parseObject = obj;
-    }
-}
-
-export class CloudQuery {
-    private whereOptions: Record<string, any> = {};
-    private className: string;
-
-    constructor(className: string) {
-        this.className = className;
-    }
-
-    equalTo(key: string, value: any): CloudQuery {
-        if (!this.whereOptions[key]) {
-            this.whereOptions[key] = value;
-        }
-        return this;
-    }
-
-    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: {
-                "x-parse-application-id": "dev"
-            }
-        });
-
-        const result = await response?.json();
-        return result?.results || [];
-    }
 }
 }
 
 
 export class CloudUser extends CloudObject {
 export class CloudUser extends CloudObject {
@@ -124,113 +63,162 @@ export class CloudUser extends CloudObject {
 
 
     constructor() {
     constructor() {
         super('_User');
         super('_User');
+        this.restoreFromStorage();
     }
     }
 
 
-    async logIn(username: string, password: string) {
-        const response = await fetch(`http://dev.fmode.cn:1337/parse/login`, {
-            method: 'POST',
-            headers: {
-                'Content-Type': 'application/json',
-                'X-Parse-Application-Id': 'dev'
-            },
-            body: JSON.stringify({ username, password })
-        });
-
-        const result = await response.json();
-        if (result?.error) {
-            throw new Error(result.error);
+    private restoreFromStorage() {
+        const savedUser = localStorage.getItem("NCloud/dev/User");
+        if (savedUser) {
+            try {
+                const userData = JSON.parse(savedUser);
+                this.id = userData.objectId;
+                this.sessionToken = userData.sessionToken;
+                this.data = userData;
+            } catch (error) {
+                console.error('Failed to restore user session:', error);
+                localStorage.removeItem("NCloud/dev/User");
+            }
         }
         }
-
-        this.id = result.objectId;
-        this.sessionToken = result.sessionToken;
-        this.data = result;
-        localStorage.setItem("NCloud/dev/User", JSON.stringify(result));
-        return this;
     }
     }
 
 
-    async logOut() {
-        if (!this.sessionToken) {
-            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
-            },
-            method: 'POST'
-        });
+    async logIn(username: string, password: string) {
+        try {
+            const response = await fetch(`${Parse.serverURL}/login`, {
+                method: 'POST',
+                headers: {
+                    'Content-Type': 'application/json',
+                    'X-Parse-Application-Id': 'dev',
+                    'X-Parse-Revocable-Session': '1'
+                },
+                body: JSON.stringify({ username, password })
+            });
+
+            if (!response.ok) {
+                const error = await response.json();
+                throw new Error(error.error || '登录失败');
+            }
 
 
-        const result = await response.json();
-        if (result?.error) {
-            throw new Error(result.error);
+            const result = await response.json();
+            this.id = result.objectId;
+            this.sessionToken = result.sessionToken;
+            this.data = result;
+            localStorage.setItem("NCloud/dev/User", JSON.stringify(result));
+            return this;
+        } catch (error: any) {
+            console.error('Login failed:', error);
+            throw new Error(error.message || '登录失败');
         }
         }
-
-        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> = {}) {
     async signUp(username: string, password: string, additionalData: Record<string, any> = {}) {
-        const userData = {
-            username,
-            password,
-            ...additionalData
-        };
-
-        const response = await fetch(`http://dev.fmode.cn:1337/parse/users`, {
-            headers: {
-                "x-parse-application-id": "dev",
-                "Content-Type": "application/json"
-            },
-            body: JSON.stringify(userData),
-            method: "POST"
-        });
+        try {
+            const userData = {
+                username,
+                password,
+                ...additionalData
+            };
+
+            const response = await fetch(`${Parse.serverURL}/users`, {
+                method: 'POST',
+                headers: {
+                    'Content-Type': 'application/json',
+                    'X-Parse-Application-Id': 'dev',
+                    'X-Parse-Revocable-Session': '1'
+                },
+                body: JSON.stringify(userData)
+            });
+
+            if (!response.ok) {
+                const error = await response.json();
+                throw new Error(error.error || '注册失败');
+            }
 
 
-        const result = await response?.json();
-        if (result?.error) {
-            throw new Error(result.error);
+            const result = await response.json();
+            this.id = result.objectId;
+            this.sessionToken = result.sessionToken;
+            this.data = result;
+            localStorage.setItem("NCloud/dev/User", JSON.stringify(result));
+            return this;
+        } catch (error: any) {
+            console.error('Signup failed:', error);
+            throw new Error(error.message || '注册失败');
         }
         }
+    }
 
 
-        this.id = result?.objectId;
-        this.sessionToken = result?.sessionToken;
-        this.data = result;
-        localStorage.setItem("NCloud/dev/User", JSON.stringify(result));
-        return this;
+    async logOut() {
+        try {
+            if (this.sessionToken) {
+                await fetch(`${Parse.serverURL}/logout`, {
+                    method: 'POST',
+                    headers: {
+                        'X-Parse-Application-Id': 'dev',
+                        'X-Parse-Session-Token': this.sessionToken
+                    }
+                });
+            }
+            
+            this.id = null;
+            this.sessionToken = null;
+            this.data = {};
+            localStorage.removeItem("NCloud/dev/User");
+            return true;
+        } catch (error) {
+            console.error('Logout failed:', error);
+            throw error;
+        }
     }
     }
 
 
     override async save() {
     override async save() {
         if (!this.id || !this.sessionToken) {
         if (!this.id || !this.sessionToken) {
-            throw new Error('User not logged in');
+            throw new Error('用户未登录');
         }
         }
 
 
-        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: {
-                "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"
-        });
+        try {
+            const { createdAt, updatedAt, ACL, objectId, sessionToken, password, ...data } = this.data;
+
+            const response = await fetch(`${Parse.serverURL}/users/${this.id}`, {
+                method: 'PUT',
+                headers: {
+                    'Content-Type': 'application/json',
+                    'X-Parse-Application-Id': 'dev',
+                    'X-Parse-Session-Token': this.sessionToken
+                },
+                body: JSON.stringify(data)
+            });
+
+            if (!response.ok) {
+                const error = await response.json();
+                throw new Error(error.error || '保存失败');
+            }
+
+            const result = await response.json();
+            this.data = { ...this.data, ...result };
+            localStorage.setItem("NCloud/dev/User", JSON.stringify(this.data));
+            return this;
+        } catch (error: any) {
+            console.error('Save user failed:', error);
+            throw new Error(error.message || '保存失败');
+        }
+    }
 
 
-        const result = await response?.json();
-        if (result?.error) {
-            throw new Error(result.error);
+    async current(): Promise<CloudUser | null> {
+        if (this.id && this.sessionToken) {
+            return this;
         }
         }
         
         
-        localStorage.setItem("NCloud/dev/User", JSON.stringify(this.data));
-        return this;
+        const savedUser = localStorage.getItem("NCloud/dev/User");
+        if (savedUser) {
+            try {
+                const userData = JSON.parse(savedUser);
+                this.id = userData.objectId;
+                this.sessionToken = userData.sessionToken;
+                this.data = userData;
+                return this;
+            } catch (error) {
+                console.error('Failed to restore user session:', error);
+                localStorage.removeItem("NCloud/dev/User");
+            }
+        }
+        return null;
     }
     }
 }
 }

+ 5 - 2
src/lib/services/user.service.ts

@@ -10,8 +10,11 @@ export class UserService {
 
 
   async getCurrentUser(): Promise<CloudUser | null> {
   async getCurrentUser(): Promise<CloudUser | null> {
     if (!this.currentUser) {
     if (!this.currentUser) {
-      this.currentUser = new CloudUser();
-      await this.currentUser.current();
+      const parseUser = Parse.User.current();
+      if (parseUser) {
+        this.currentUser = new CloudUser();
+        this.currentUser.setParseObject(parseUser);
+      }
     }
     }
     return this.currentUser;
     return this.currentUser;
   }
   }

+ 41 - 28
src/lib/user/modal-user-login/modal-user-login.component.html

@@ -1,36 +1,49 @@
-<!-- 用户登录状态 -->
-<ion-card>
-  <ion-card-header>
-    <ion-card-title>
-      <ion-segment [value]="type" (ionChange)="typeChange($event)">
-        <ion-segment-button value="login">
-          <ion-label>登录</ion-label>
-        </ion-segment-button>
-        <ion-segment-button value="signup">
-          <ion-label>注册</ion-label>
-        </ion-segment-button>
-      </ion-segment>
-    </ion-card-title>
-    <ion-card-subtitle>请输入账号密码</ion-card-subtitle>
-  </ion-card-header>
-  <ion-card-content>
+<ion-header>
+  <ion-toolbar>
+    <ion-title>{{ type === 'login' ? '登录' : '注册' }}</ion-title>
+    <ion-buttons slot="end">
+      <ion-button (click)="dismiss()">取消</ion-button>
+    </ion-buttons>
+  </ion-toolbar>
+</ion-header>
+
+<ion-content class="ion-padding">
+  <ion-segment [(ngModel)]="type" (ionChange)="typeChange($event)">
+    <ion-segment-button value="login">
+      <ion-label>登录</ion-label>
+    </ion-segment-button>
+    <ion-segment-button value="signup">
+      <ion-label>注册</ion-label>
+    </ion-segment-button>
+  </ion-segment>
+
+  <ion-item>
+    <ion-label position="stacked">用户名</ion-label>
+    <ion-input [(ngModel)]="username" type="text"></ion-input>
+  </ion-item>
+
+  <ion-item>
+    <ion-label position="stacked">密码</ion-label>
+    <ion-input [(ngModel)]="password" type="password"></ion-input>
+  </ion-item>
+
+  @if (type === 'signup') {
     <ion-item>
     <ion-item>
-      <ion-input [value]="username" (ionChange)="usernameChange($event)" label="账号" placeholder="请您输入账号/手机号"></ion-input>
+      <ion-label position="stacked">确认密码</ion-label>
+      <ion-input [(ngModel)]="password2" type="password"></ion-input>
     </ion-item>
     </ion-item>
+
     <ion-item>
     <ion-item>
-      <ion-input [value]="password" (ionChange)="passwordChange($event)" label="密码" type="password" value="password"></ion-input>
+      <ion-label position="stacked">邮箱(可选)</ion-label>
+      <ion-input [(ngModel)]="email" type="email"></ion-input>
     </ion-item>
     </ion-item>
+  }
 
 
-    @if(type=="signup"){
-      <ion-item>
-        <ion-input [value]="password2" (ionChange)="password2Change($event)" label="密码二次" type="password" value="password"></ion-input>
-      </ion-item>
-    }
-    @if(type=="login"){
+  <div class="ion-padding">
+    @if (type === 'login') {
       <ion-button expand="block" (click)="login()">登录</ion-button>
       <ion-button expand="block" (click)="login()">登录</ion-button>
-    }
-    @if(type=="signup"){
+    } @else {
       <ion-button expand="block" (click)="signup()">注册</ion-button>
       <ion-button expand="block" (click)="signup()">注册</ion-button>
     }
     }
-  </ion-card-content>
-</ion-card>
+  </div>
+</ion-content>

+ 22 - 0
src/lib/user/modal-user-login/modal-user-login.component.scss

@@ -0,0 +1,22 @@
+ion-segment {
+    margin-bottom: 20px;
+  }
+  
+  ion-card {
+    margin: 0;
+  }
+  
+  ion-item {
+    --padding-start: 0;
+    margin-bottom: 16px;
+  }
+  
+  ion-button[expand="block"] {
+    margin: 20px 0 0;
+  }
+  
+  .error-message {
+    color: var(--ion-color-danger);
+    font-size: 0.8em;
+    margin: 5px 0;
+  }

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

@@ -1,13 +1,11 @@
 import { Component } from '@angular/core';
 import { Component } from '@angular/core';
-import { IonContent, IonHeader, IonToolbar, IonTitle, IonButtons, IonButton, 
-         IonItem, IonLabel, IonInput, IonSegment, IonSegmentButton,
-         IonCard, IonCardHeader, IonCardTitle, IonCardSubtitle, 
-         IonCardContent } from '@ionic/angular/standalone';
+import { IonHeader, IonToolbar, IonTitle, IonContent, IonCard, IonCardContent, 
+         IonButton, IonCardHeader, IonCardTitle, IonCardSubtitle, IonInput, 
+         IonItem, IonSegment, IonSegmentButton, IonLabel, IonButtons } from '@ionic/angular/standalone';
 import { ModalController, AlertController } 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 { CloudUser } from '../../ncloud';
-import * as Parse from 'parse';
+import { CommonModule } from '@angular/common';
+import { FormsModule } from '@angular/forms';
 
 
 @Component({
 @Component({
   selector: 'app-modal-user-login',
   selector: 'app-modal-user-login',
@@ -17,110 +15,89 @@ import * as Parse from 'parse';
   imports: [
   imports: [
     CommonModule,
     CommonModule,
     FormsModule,
     FormsModule,
-    IonContent,
-    IonHeader,
-    IonToolbar,
-    IonTitle,
-    IonButtons,
-    IonButton,
-    IonItem,
-    IonLabel,
-    IonInput,
-    IonSegment,
-    IonSegmentButton,
-    IonCard,
-    IonCardHeader,
-    IonCardTitle,
-    IonCardSubtitle,
-    IonCardContent
+    IonHeader, IonToolbar, IonTitle, IonContent, IonCard, 
+    IonCardContent, IonButton, IonCardHeader, IonCardTitle, 
+    IonCardSubtitle, IonInput, IonItem, IonSegment, 
+    IonSegmentButton, IonLabel,
+    IonButtons
   ]
   ]
 })
 })
 export class ModalUserLoginComponent {
 export class ModalUserLoginComponent {
+  type: string = 'login';
   username: string = '';
   username: string = '';
   password: string = '';
   password: string = '';
   password2: string = '';
   password2: string = '';
-  type: 'login' | 'signup' = 'login';
+  email: string = '';
 
 
   constructor(
   constructor(
     private modalCtrl: ModalController,
     private modalCtrl: ModalController,
     private alertController: AlertController
     private alertController: AlertController
   ) {}
   ) {}
 
 
-  typeChange(event: any) {
-    this.type = event.detail.value;
-  }
-
-  usernameChange(event: any) {
-    this.username = event.detail.value;
-  }
-
-  passwordChange(event: any) {
-    this.password = event.detail.value;
+  async showAlert(header: string, message: string) {
+    const alert = await this.alertController.create({
+      header,
+      message,
+      buttons: ['确定']
+    });
+    await alert.present();
   }
   }
 
 
-  password2Change(event: any) {
-    this.password2 = event.detail.value;
+  typeChange(ev: any) {
+    this.type = ev.detail.value;
+    // 切换时清空表单
+    this.username = '';
+    this.password = '';
+    this.password2 = '';
+    this.email = '';
   }
   }
 
 
   async login() {
   async login() {
     if (!this.username || !this.password) {
     if (!this.username || !this.password) {
-      await this.showAlert('提示', '请输入完整的用户名和密码');
+      await this.showAlert('错误', '请输入用户名和密码');
       return;
       return;
     }
     }
 
 
     try {
     try {
-      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('错误', '登录过程中发生错误,请稍后重试');
+      const user = new CloudUser();
+      await user.logIn(this.username, this.password);
+      this.modalCtrl.dismiss({ data: user, role: 'confirm' });
+    } catch (error: any) {
+      await this.showAlert('登录失败', error.message || '请检查用户名和密码');
     }
     }
   }
   }
 
 
   async signup() {
   async signup() {
     if (!this.username || !this.password || !this.password2) {
     if (!this.username || !this.password || !this.password2) {
-      await this.showAlert('提示', '请输入完整信息');
+      await this.showAlert('错误', '请填写所有必填字段');
       return;
       return;
     }
     }
 
 
     if (this.password !== this.password2) {
     if (this.password !== this.password2) {
-      await this.showAlert('提示', '两次输入的密码不一致');
+      await this.showAlert('错误', '两次输入的密码不一致');
       return;
       return;
     }
     }
 
 
-    try {
-      const user = new Parse.User();
-      user.set("username", this.username);
-      user.set("password", this.password);
+    if (this.password.length < 6) {
+      await this.showAlert('错误', '密码长度至少6位');
+      return;
+    }
 
 
-      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('错误', '注册失败,请稍后重试');
+    try {
+      const user = new CloudUser();
+      const additionalData = this.email ? { email: this.email } : {};
+      await user.signUp(this.username, this.password, additionalData);
+      this.modalCtrl.dismiss({ data: user, role: 'confirm' });
+    } catch (error: any) {
+      await this.showAlert('注册失败', error.message || '注册失败,请稍后重试');
     }
     }
   }
   }
 
 
-  private async showAlert(header: string, message: string) {
-    const alert = await this.alertController.create({
-      header,
-      message,
-      buttons: ['确定']
-    });
-    await alert.present();
+  dismiss() {
+    this.modalCtrl.dismiss(null, 'cancel');
   }
   }
 }
 }
 
 
-// 导出打开模态框的函数
 export async function openUserLoginModal(modalController: ModalController) {
 export async function openUserLoginModal(modalController: ModalController) {
   const modal = await modalController.create({
   const modal = await modalController.create({
     component: ModalUserLoginComponent
     component: ModalUserLoginComponent