|
@@ -1,15 +1,31 @@
|
|
|
import { Component, OnInit } from '@angular/core';
|
|
import { Component, OnInit } from '@angular/core';
|
|
|
import { CommonModule } from '@angular/common';
|
|
import { CommonModule } from '@angular/common';
|
|
|
import { FormsModule } from '@angular/forms';
|
|
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 {
|
|
|
|
|
+ IonHeader,
|
|
|
|
|
+ IonToolbar,
|
|
|
|
|
+ IonTitle,
|
|
|
|
|
+ IonContent,
|
|
|
|
|
+ IonButtons,
|
|
|
|
|
+ IonButton,
|
|
|
|
|
+ IonIcon,
|
|
|
|
|
+ IonList,
|
|
|
|
|
+ IonItemSliding,
|
|
|
|
|
+ IonItem,
|
|
|
|
|
+ IonCheckbox,
|
|
|
|
|
+ IonLabel,
|
|
|
|
|
+ IonItemOptions,
|
|
|
|
|
+ IonItemOption,
|
|
|
|
|
+ IonProgressBar,
|
|
|
|
|
+ IonRefresher,
|
|
|
|
|
+ IonRefresherContent,
|
|
|
|
|
+ IonBadge,
|
|
|
|
|
+ IonText,
|
|
|
|
|
+ AlertController
|
|
|
|
|
+} from '@ionic/angular/standalone';
|
|
|
import { addIcons } from 'ionicons';
|
|
import { addIcons } from 'ionicons';
|
|
|
-import { addOutline, calendarOutline, trashOutline } from 'ionicons/icons';
|
|
|
|
|
-import { Task, TaskStatus } from '../../lib/models/Task';
|
|
|
|
|
-import { TaskModalComponent } from '../components/task-modal/task-modal.component';
|
|
|
|
|
|
|
+import { addOutline, calendarOutline, trashOutline, createOutline } from 'ionicons/icons';
|
|
|
|
|
+import { Task, TaskStatus } from '../models/Task';
|
|
|
import * as Parse from 'parse';
|
|
import * as Parse from 'parse';
|
|
|
|
|
|
|
|
@Component({
|
|
@Component({
|
|
@@ -19,12 +35,26 @@ import * as Parse from 'parse';
|
|
|
standalone: true,
|
|
standalone: true,
|
|
|
imports: [
|
|
imports: [
|
|
|
CommonModule,
|
|
CommonModule,
|
|
|
- FormsModule,
|
|
|
|
|
- TaskModalComponent,
|
|
|
|
|
- IonHeader, IonToolbar, IonTitle, IonContent, IonButtons, IonButton,
|
|
|
|
|
- IonIcon, IonList, IonItemSliding, IonItem, IonCheckbox, IonLabel,
|
|
|
|
|
- IonItemOptions, IonItemOption, IonProgressBar, IonRefresher,
|
|
|
|
|
- IonRefresherContent, IonBadge
|
|
|
|
|
|
|
+ FormsModule,
|
|
|
|
|
+ IonHeader,
|
|
|
|
|
+ IonToolbar,
|
|
|
|
|
+ IonTitle,
|
|
|
|
|
+ IonContent,
|
|
|
|
|
+ IonButtons,
|
|
|
|
|
+ IonButton,
|
|
|
|
|
+ IonIcon,
|
|
|
|
|
+ IonList,
|
|
|
|
|
+ IonItemSliding,
|
|
|
|
|
+ IonItem,
|
|
|
|
|
+ IonCheckbox,
|
|
|
|
|
+ IonLabel,
|
|
|
|
|
+ IonItemOptions,
|
|
|
|
|
+ IonItemOption,
|
|
|
|
|
+ IonProgressBar,
|
|
|
|
|
+ IonRefresher,
|
|
|
|
|
+ IonRefresherContent,
|
|
|
|
|
+ IonBadge,
|
|
|
|
|
+ IonText
|
|
|
]
|
|
]
|
|
|
})
|
|
})
|
|
|
export class Tab1Page implements OnInit {
|
|
export class Tab1Page implements OnInit {
|
|
@@ -32,10 +62,9 @@ export class Tab1Page implements OnInit {
|
|
|
loading = false;
|
|
loading = false;
|
|
|
|
|
|
|
|
constructor(
|
|
constructor(
|
|
|
- private alertController: AlertController,
|
|
|
|
|
- private modalCtrl: ModalController
|
|
|
|
|
|
|
+ private alertController: AlertController
|
|
|
) {
|
|
) {
|
|
|
- addIcons({ addOutline, calendarOutline, trashOutline });
|
|
|
|
|
|
|
+ addIcons({ addOutline, calendarOutline, createOutline, trashOutline });
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
ngOnInit() {
|
|
ngOnInit() {
|
|
@@ -49,16 +78,15 @@ export class Tab1Page implements OnInit {
|
|
|
async loadTasks(event?: any) {
|
|
async loadTasks(event?: any) {
|
|
|
try {
|
|
try {
|
|
|
this.loading = true;
|
|
this.loading = true;
|
|
|
- const query = new Parse.Query('Task');
|
|
|
|
|
- if (Parse.User.current()) {
|
|
|
|
|
- query.equalTo('userId', Parse.User.current()?.id);
|
|
|
|
|
|
|
+ const currentUser = Parse.User.current();
|
|
|
|
|
+ if (!currentUser) {
|
|
|
|
|
+ this.tasks = [];
|
|
|
|
|
+ return;
|
|
|
}
|
|
}
|
|
|
- query.descending('createdAt');
|
|
|
|
|
-
|
|
|
|
|
- const results = await query.find();
|
|
|
|
|
- this.tasks = results.map(result => Task.fromParseObject(result));
|
|
|
|
|
|
|
|
|
|
- // 根据状态排序:进行中 -> 逾期 -> 已完成
|
|
|
|
|
|
|
+ this.tasks = await Task.getUserTasks(currentUser.id);
|
|
|
|
|
+
|
|
|
|
|
+ // 根据状态排序
|
|
|
this.tasks.sort((a, b) => {
|
|
this.tasks.sort((a, b) => {
|
|
|
const statusOrder = {
|
|
const statusOrder = {
|
|
|
[TaskStatus.InProgress]: 0,
|
|
[TaskStatus.InProgress]: 0,
|
|
@@ -80,46 +108,76 @@ export class Tab1Page implements OnInit {
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
async addTask() {
|
|
async addTask() {
|
|
|
- try {
|
|
|
|
|
- const modal = await this.modalCtrl.create({
|
|
|
|
|
- component: TaskModalComponent,
|
|
|
|
|
- componentProps: {
|
|
|
|
|
- task: new Task()
|
|
|
|
|
|
|
+ const alert = await this.alertController.create({
|
|
|
|
|
+ header: '新建任务',
|
|
|
|
|
+ inputs: [
|
|
|
|
|
+ {
|
|
|
|
|
+ name: 'title',
|
|
|
|
|
+ type: 'text',
|
|
|
|
|
+ placeholder: '任务标题'
|
|
|
|
|
+ },
|
|
|
|
|
+ {
|
|
|
|
|
+ name: 'content',
|
|
|
|
|
+ type: 'textarea',
|
|
|
|
|
+ placeholder: '任务描述'
|
|
|
|
|
+ },
|
|
|
|
|
+ {
|
|
|
|
|
+ name: 'startTime',
|
|
|
|
|
+ type: 'datetime-local',
|
|
|
|
|
+ label: '开始时间',
|
|
|
|
|
+ value: new Date().toISOString().slice(0, 16)
|
|
|
|
|
+ },
|
|
|
|
|
+ {
|
|
|
|
|
+ name: 'endTime',
|
|
|
|
|
+ type: 'datetime-local',
|
|
|
|
|
+ label: '截止时间',
|
|
|
|
|
+ value: new Date().toISOString().slice(0, 16)
|
|
|
}
|
|
}
|
|
|
- });
|
|
|
|
|
- await modal.present();
|
|
|
|
|
-
|
|
|
|
|
- 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();
|
|
|
|
|
- }
|
|
|
|
|
- } catch (error) {
|
|
|
|
|
- console.error('创建任务失败:', error);
|
|
|
|
|
- await this.showErrorAlert('创建任务失败');
|
|
|
|
|
- }
|
|
|
|
|
|
|
+ ],
|
|
|
|
|
+ buttons: [
|
|
|
|
|
+ {
|
|
|
|
|
+ text: '取消',
|
|
|
|
|
+ role: 'cancel'
|
|
|
|
|
+ },
|
|
|
|
|
+ {
|
|
|
|
|
+ text: '确定',
|
|
|
|
|
+ handler: async (data) => {
|
|
|
|
|
+ if (!data.title?.trim()) {
|
|
|
|
|
+ return false;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ try {
|
|
|
|
|
+ await Task.create({
|
|
|
|
|
+ title: data.title.trim(),
|
|
|
|
|
+ content: data.content?.trim() || '',
|
|
|
|
|
+ startTime: new Date(data.startTime),
|
|
|
|
|
+ endTime: new Date(data.endTime),
|
|
|
|
|
+ completed: false
|
|
|
|
|
+ });
|
|
|
|
|
+
|
|
|
|
|
+ await this.loadTasks();
|
|
|
|
|
+ return true;
|
|
|
|
|
+ } catch (error) {
|
|
|
|
|
+ console.error('创建任务失败:', error);
|
|
|
|
|
+ await this.showErrorAlert('创建任务失败');
|
|
|
|
|
+ return false;
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ ]
|
|
|
|
|
+ });
|
|
|
|
|
+
|
|
|
|
|
+ await alert.present();
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
async toggleComplete(task: Task) {
|
|
async toggleComplete(task: Task) {
|
|
|
try {
|
|
try {
|
|
|
task.completed = !task.completed;
|
|
task.completed = !task.completed;
|
|
|
await task.saveTask();
|
|
await task.saveTask();
|
|
|
-
|
|
|
|
|
- // 重新加载以保持正确的排序
|
|
|
|
|
- await this.loadTasks();
|
|
|
|
|
|
|
+ await this.loadTasks(); // 重新加载以保持正确的排序
|
|
|
} catch (error) {
|
|
} catch (error) {
|
|
|
console.error('更新任务失败:', error);
|
|
console.error('更新任务失败:', error);
|
|
|
- task.completed = !task.completed;
|
|
|
|
|
|
|
+ task.completed = !task.completed; // 恢复状态
|
|
|
await this.showErrorAlert('更新任务状态失败');
|
|
await this.showErrorAlert('更新任务状态失败');
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
@@ -138,8 +196,8 @@ export class Tab1Page implements OnInit {
|
|
|
role: 'destructive',
|
|
role: 'destructive',
|
|
|
handler: async () => {
|
|
handler: async () => {
|
|
|
try {
|
|
try {
|
|
|
- await task.delete();
|
|
|
|
|
- this.tasks = this.tasks.filter(t => t.id !== task.id);
|
|
|
|
|
|
|
+ await task.destroy();
|
|
|
|
|
+ await this.loadTasks();
|
|
|
} catch (error) {
|
|
} catch (error) {
|
|
|
console.error('删除任务失败:', error);
|
|
console.error('删除任务失败:', error);
|
|
|
await this.showErrorAlert('删除任务失败');
|
|
await this.showErrorAlert('删除任务失败');
|
|
@@ -151,6 +209,54 @@ export class Tab1Page implements OnInit {
|
|
|
await alert.present();
|
|
await alert.present();
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
+ async editTask(task: Task) {
|
|
|
|
|
+ const alert = await this.alertController.create({
|
|
|
|
|
+ header: '编辑任务',
|
|
|
|
|
+ inputs: [
|
|
|
|
|
+ {
|
|
|
|
|
+ name: 'title',
|
|
|
|
|
+ type: 'text',
|
|
|
|
|
+ value: task.title,
|
|
|
|
|
+ placeholder: '任务标题'
|
|
|
|
|
+ },
|
|
|
|
|
+ {
|
|
|
|
|
+ name: 'content',
|
|
|
|
|
+ type: 'textarea',
|
|
|
|
|
+ value: task.content,
|
|
|
|
|
+ placeholder: '任务描述'
|
|
|
|
|
+ }
|
|
|
|
|
+ ],
|
|
|
|
|
+ buttons: [
|
|
|
|
|
+ {
|
|
|
|
|
+ text: '取消',
|
|
|
|
|
+ role: 'cancel'
|
|
|
|
|
+ },
|
|
|
|
|
+ {
|
|
|
|
|
+ text: '确定',
|
|
|
|
|
+ handler: async (data) => {
|
|
|
|
|
+ if (!data.title?.trim()) {
|
|
|
|
|
+ return false;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ try {
|
|
|
|
|
+ task.title = data.title.trim();
|
|
|
|
|
+ task.content = data.content?.trim() || '';
|
|
|
|
|
+ await task.saveTask();
|
|
|
|
|
+ await this.loadTasks();
|
|
|
|
|
+ return true;
|
|
|
|
|
+ } catch (error) {
|
|
|
|
|
+ console.error('编辑任务失败:', error);
|
|
|
|
|
+ await this.showErrorAlert('编辑任务失败');
|
|
|
|
|
+ return false;
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ ]
|
|
|
|
|
+ });
|
|
|
|
|
+
|
|
|
|
|
+ await alert.present();
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
getTaskStatusClass(task: Task): string {
|
|
getTaskStatusClass(task: Task): string {
|
|
|
const status = task.getStatus();
|
|
const status = task.getStatus();
|
|
|
switch (status) {
|
|
switch (status) {
|
|
@@ -165,31 +271,31 @@ export class Tab1Page implements OnInit {
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- getTaskStatusText(task: Task): string {
|
|
|
|
|
|
|
+ getTaskStatusColor(task: Task): string {
|
|
|
const status = task.getStatus();
|
|
const status = task.getStatus();
|
|
|
switch (status) {
|
|
switch (status) {
|
|
|
case TaskStatus.Completed:
|
|
case TaskStatus.Completed:
|
|
|
- return '已完成';
|
|
|
|
|
|
|
+ return 'success';
|
|
|
case TaskStatus.Overdue:
|
|
case TaskStatus.Overdue:
|
|
|
- return '已逾期';
|
|
|
|
|
|
|
+ return 'danger';
|
|
|
case TaskStatus.InProgress:
|
|
case TaskStatus.InProgress:
|
|
|
- return '进行中';
|
|
|
|
|
|
|
+ return 'primary';
|
|
|
default:
|
|
default:
|
|
|
- return '';
|
|
|
|
|
|
|
+ return 'medium';
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- getTaskStatusColor(task: Task): string {
|
|
|
|
|
|
|
+ getTaskStatusText(task: Task): string {
|
|
|
const status = task.getStatus();
|
|
const status = task.getStatus();
|
|
|
switch (status) {
|
|
switch (status) {
|
|
|
case TaskStatus.Completed:
|
|
case TaskStatus.Completed:
|
|
|
- return 'success';
|
|
|
|
|
|
|
+ return '已完成';
|
|
|
case TaskStatus.Overdue:
|
|
case TaskStatus.Overdue:
|
|
|
- return 'danger';
|
|
|
|
|
|
|
+ return '已逾期';
|
|
|
case TaskStatus.InProgress:
|
|
case TaskStatus.InProgress:
|
|
|
- return 'primary';
|
|
|
|
|
|
|
+ return '进行中';
|
|
|
default:
|
|
default:
|
|
|
- return 'medium';
|
|
|
|
|
|
|
+ return '';
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
|
|
|