核心功能

  1. 添加待辦事項 - 創建新的待辦任務,包含標題、描述、優先級、截止日期
  2. 查看任務列表 - 以卡片形式展示所有待辦事項
  3. 標記完成狀態 - 將任務標記為已完成/未完成
  4. 編輯任務 - 修改已保存的任務信息
  5. 刪除任務 - 刪除不需要的任務
  6. 任務篩選 - 按狀態篩選查看任務
  7. 任務統計 - 統計總任務數、已完成數和未完成數

技術特點

  • 使用ArkTS聲明式UI開發
  • 採用MVVM架構模式
  • 組件化設計
  • 本地數據存儲(內存中)
  • 響應式數據綁定
  • 支持任務優先級管理

完整源代碼

// 簡易待辦事項管理應用
// 文件名:TodoManager.ets

import promptAction from '@ohos.promptAction';

// 待辦事項數據模型
class TodoItem {
  id: number = 0;
  title: string = '';
  description: string = '';
  completed: boolean = false;
  priority: number = 1; // 1-低, 2-中, 3-高
  dueDate: string = '';
  createTime: string = '';
  
  constructor(id: number, title: string = '', description: string = '', 
              completed: boolean = false, priority: number = 1, 
              dueDate: string = '', createTime: string = '') {
    this.id = id;
    this.title = title;
    this.description = description;
    this.completed = completed;
    this.priority = priority;
    this.dueDate = dueDate;
    this.createTime = createTime;
  }
}

@Entry
@Component
struct TodoManager {
  // 待辦事項列表
  @State todoList: TodoItem[] = [];
  
  // 任務統計
  @State totalCount: number = 0;
  @State completedCount: number = 0;
  @State pendingCount: number = 0;
  
  // 編輯相關狀態
  @State currentItem: TodoItem = new TodoItem(0);
  @State showEditDialog: boolean = false;
  @State isEditing: boolean = false;
  
  // 篩選狀態
  @State filterStatus: string = '全部'; // 全部、未完成、已完成
  
  // 優先級選項
  @State priorities: string[] = ['低優先級', '中優先級', '高優先級'];
  
  // 組件生命週期
  aboutToAppear() {
    this.initSampleData();
    this.calculateStatistics();
  }

  // 初始化示例數據
  initSampleData() {
    const today = new Date();
    const tomorrow = new Date(today);
    tomorrow.setDate(tomorrow.getDate() + 1);
    
    this.todoList = [
      new TodoItem(1, '學習ArkTS', '完成HarmonyOS應用開發學習', false, 3, this.formatDate(tomorrow), '2024-01-15'),
      new TodoItem(2, '購物', '去超市購買生活用品', true, 1, '2024-01-14', '2024-01-13'),
      new TodoItem(3, '健身', '健身房鍛鍊1小時', false, 2, '2024-01-16', '2024-01-14'),
      new TodoItem(4, '工作會議', '項目進度彙報會議', false, 3, '2024-01-15 14:00', '2024-01-12'),
      new TodoItem(5, '閲讀書籍', '閲讀《編程之美》', true, 2, '2024-01-13', '2024-01-10')
    ];
  }

  // 構建主界面
  build() {
    Column({ space: 0 }) {
      // 頂部標題欄
      this.buildHeader()
      
      // 任務統計卡片
      this.buildStatisticsCard()
      
      // 篩選欄
      this.buildFilterBar()
      
      // 任務列表
      this.buildTodoList()
    }
    .width('100%')
    .height('100%')
    .backgroundColor('#F5F7FA')
  }

  // 頂部標題欄
  @Builder
  buildHeader() {
    Row() {
      Text('待辦事項管理')
        .fontSize(24)
        .fontWeight(FontWeight.Bold)
        .fontColor('#FFFFFF')
        .layoutWeight(1)
      
      Button('+ 新建')
        .width(80)
        .height(35)
        .fontSize(14)
        .backgroundColor('#FFFFFF')
        .fontColor('#007DFF')
        .onClick(() => {
          this.addNewItem();
        })
    }
    .width('100%')
    .padding({ left: 20, right: 20, top: 15, bottom: 15 })
    .backgroundColor('#007DFF')
  }

  // 任務統計卡片
  @Builder
  buildStatisticsCard() {
    Row() {
      // 總任務數
      Column({ space: 4 }) {
        Text(this.totalCount.toString())
          .fontSize(24)
          .fontWeight(FontWeight.Bold)
          .fontColor('#007DFF')
        Text('總任務')
          .fontSize(12)
          .fontColor('#666666')
      }
      .layoutWeight(1)
      
      // 已完成數
      Column({ space: 4 }) {
        Text(this.completedCount.toString())
          .fontSize(24)
          .fontWeight(FontWeight.Bold)
          .fontColor('#4CAF50')
        Text('已完成')
          .fontSize(12)
          .fontColor('#666666')
      }
      .layoutWeight(1)
      
      // 未完成數
      Column({ space: 4 }) {
        Text(this.pendingCount.toString())
          .fontSize(24)
          .fontWeight(FontWeight.Bold)
          .fontColor('#FF9800')
        Text('未完成')
          .fontSize(12)
          .fontColor('#666666')
      }
      .layoutWeight(1)
    }
    .width('90%')
    .padding(20)
    .backgroundColor('#FFFFFF')
    .borderRadius(12)
    .margin({ top: 20, bottom: 20 })
    .shadow({ radius: 4, color: '#E0E0E0', offsetX: 1, offsetY: 2 })
  }

  // 篩選欄
  @Builder
  buildFilterBar() {
    Row({ space: 10 }) {
      Button('全部')
        .width(80)
        .height(35)
        .fontSize(14)
        .backgroundColor(this.filterStatus === '全部' ? '#007DFF' : '#FFFFFF')
        .fontColor(this.filterStatus === '全部' ? '#FFFFFF' : '#666666')
        .onClick(() => {
          this.filterStatus = '全部';
        })
      
      Button('未完成')
        .width(80)
        .height(35)
        .fontSize(14)
        .backgroundColor(this.filterStatus === '未完成' ? '#FF9800' : '#FFFFFF')
        .fontColor(this.filterStatus === '未完成' ? '#FFFFFF' : '#666666')
        .onClick(() => {
          this.filterStatus = '未完成';
        })
      
      Button('已完成')
        .width(80)
        .height(35)
        .fontSize(14)
        .backgroundColor(this.filterStatus === '已完成' ? '#4CAF50' : '#FFFFFF')
        .fontColor(this.filterStatus === '已完成' ? '#FFFFFF' : '#666666')
        .onClick(() => {
          this.filterStatus = '已完成';
        })
    }
    .width('100%')
    .justifyContent(FlexAlign.Center)
    .margin({ bottom: 15 })
  }

  // 任務列表
  @Builder
  buildTodoList() {
    List({ space: 12 }) {
      ForEach(this.getFilteredItems(), (item: TodoItem) => {
        ListItem() {
          this.buildTodoItem(item)
        }
      })
    }
    .width('100%')
    .layoutWeight(1)
    .padding({ left: 16, right: 16 })
    
    // 編輯對話框
    if (this.showEditDialog) {
      this.buildEditDialog()
    }
  }

  // 任務項組件
  @Builder
  buildTodoItem(item: TodoItem) {
    Column({ space: 8 }) {
      // 第一行:標題和優先級
      Row() {
        // 完成狀態複選框
        Checkbox({ name: 'completed', group: 'todo' + item.id })
          .select(item.completed)
          .selectedColor('#4CAF50')
          .width(20)
          .height(20)
          .onChange((checked: boolean) => {
            this.toggleComplete(item.id, checked);
          })
        
        // 標題
        Text(item.title)
          .fontSize(18)
          .fontWeight(FontWeight.Bold)
          .fontColor(item.completed ? '#999999' : '#333333')
          .decoration({ type: item.completed ? TextDecorationType.LineThrough : TextDecorationType.None })
          .maxLines(1)
          .textOverflow({ overflow: TextOverflow.Ellipsis })
          .layoutWeight(1)
          .margin({ left: 10 })
        
        // 優先級標籤
        Text(this.priorities[item.priority - 1])
          .fontSize(12)
          .padding({ left: 6, right: 6, top: 2, bottom: 2 })
          .backgroundColor(this.getPriorityColor(item.priority, item.completed))
          .fontColor('#FFFFFF')
          .borderRadius(4)
      }
      .width('100%')
      
      // 第二行:描述
      if (item.description) {
        Row() {
          Text(item.description)
            .fontSize(14)
            .fontColor(item.completed ? '#AAAAAA' : '#666666')
            .maxLines(2)
            .textOverflow({ overflow: TextOverflow.Ellipsis })
        }
        .width('100%')
        .margin({ left: 30 })
      }
      
      // 第三行:日期信息和操作按鈕
      Row() {
        // 截止日期
        if (item.dueDate) {
          Row() {
            Image($rawfile('calendar.png'))
              .width(14)
              .height(14)
              .margin({ right: 4 })
            Text(item.dueDate)
              .fontSize(12)
              .fontColor(item.completed ? '#AAAAAA' : '#FF5722')
          }
          .layoutWeight(1)
        } else {
          Blank()
            .layoutWeight(1)
        }
        
        // 操作按鈕
        Row({ space: 8 }) {
          Button('編輯')
            .width(60)
            .height(28)
            .fontSize(12)
            .backgroundColor('#2196F3')
            .onClick(() => {
              this.editItem(item);
            })
          
          Button('刪除')
            .width(60)
            .height(28)
            .fontSize(12)
            .backgroundColor('#FF5722')
            .onClick(() => {
              this.deleteItem(item.id);
            })
        }
      }
      .width('100%')
      .margin({ left: 30, top: 8 })
    }
    .width('100%')
    .padding(16)
    .backgroundColor('#FFFFFF')
    .borderRadius(10)
    .border({ width: 1, color: item.completed ? '#E0E0E0' : this.getPriorityColor(item.priority, false) })
    .shadow({ radius: 2, color: '#E0E0E0', offsetX: 1, offsetY: 1 })
  }

  // 編輯對話框
  @Builder
  buildEditDialog() {
    Column() {
      // 標題
      Text(this.isEditing ? '編輯任務' : '新建任務')
        .fontSize(20)
        .fontWeight(FontWeight.Bold)
        .margin({ top: 20, bottom: 16 })
      
      // 任務標題
      TextInput({ placeholder: '任務標題(必填)', text: this.currentItem.title })
        .width('90%')
        .height(45)
        .fontSize(16)
        .margin({ bottom: 12 })
        .onChange((value: string) => {
          this.currentItem.title = value;
        })
      
      // 任務描述
      TextInput({ placeholder: '任務描述(可選)', text: this.currentItem.description })
        .width('90%')
        .height(60)
        .fontSize(16)
        .margin({ bottom: 12 })
        .onChange((value: string) => {
          this.currentItem.description = value;
        })
      
      // 優先級選擇
      Row() {
        Text('優先級:')
          .fontSize(16)
          .fontColor('#666666')
          .margin({ right: 10 })
        
        ForEach(this.priorities, (priority: string, index: number) => {
          Text(priority)
            .fontSize(14)
            .padding({ left: 12, right: 12, top: 6, bottom: 6 })
            .backgroundColor(this.currentItem.priority === (index + 1) ? this.getPriorityColor(index + 1, false) : '#F0F0F0')
            .fontColor(this.currentItem.priority === (index + 1) ? '#FFFFFF' : '#666666')
            .borderRadius(8)
            .margin({ right: 8 })
            .onClick(() => {
              this.currentItem.priority = index + 1;
            })
        })
      }
      .width('90%')
      .margin({ bottom: 12 })
      
      // 截止日期
      TextInput({ placeholder: '截止日期(如:2024-01-20)', text: this.currentItem.dueDate })
        .width('90%')
        .height(45)
        .fontSize(16)
        .margin({ bottom: 20 })
        .onChange((value: string) => {
          this.currentItem.dueDate = value;
        })
      
      // 操作按鈕
      Row({ space: 20 }) {
        Button('取消')
          .width(120)
          .height(42)
          .fontSize(16)
          .backgroundColor('#9E9E9E')
          .onClick(() => {
            this.showEditDialog = false;
          })
        
        Button(this.isEditing ? '保存' : '創建')
          .width(120)
          .height(42)
          .fontSize(16)
          .backgroundColor('#007DFF')
          .onClick(() => {
            this.saveItem();
          })
      }
      .margin({ bottom: 20 })
    }
    .width('85%')
    .backgroundColor('#FFFFFF')
    .borderRadius(12)
    .shadow({ radius: 20, color: '#00000040' })
    .position({ x: '7.5%', y: '10%' })
  }

  // 添加新任務
  addNewItem() {
    const newId = this.todoList.length > 0 ? 
      Math.max(...this.todoList.map(item => item.id)) + 1 : 1;
    const today = this.formatDate(new Date());
    
    this.currentItem = new TodoItem(
      newId,
      '',
      '',
      false,
      2,
      '',
      today
    );
    this.isEditing = false;
    this.showEditDialog = true;
  }

  // 編輯任務
  editItem(item: TodoItem) {
    this.currentItem = { ...item };
    this.isEditing = true;
    this.showEditDialog = true;
  }

  // 保存任務
  saveItem() {
    if (!this.currentItem.title.trim()) {
      promptAction.showToast({ message: '請輸入任務標題', duration: 2000 });
      return;
    }
    
    if (this.isEditing) {
      // 更新現有任務
      const index = this.todoList.findIndex(item => item.id === this.currentItem.id);
      if (index >= 0) {
        this.todoList[index] = { ...this.currentItem };
      }
      promptAction.showToast({ message: '任務更新成功', duration: 2000 });
    } else {
      // 添加新任務
      this.todoList.push({ ...this.currentItem });
      promptAction.showToast({ message: '任務創建成功', duration: 2000 });
    }
    
    this.showEditDialog = false;
    this.calculateStatistics();
  }

  // 切換完成狀態
  toggleComplete(id: number, completed: boolean) {
    const index = this.todoList.findIndex(item => item.id === id);
    if (index >= 0) {
      this.todoList[index].completed = completed;
      this.calculateStatistics();
    }
  }

  // 刪除任務
  deleteItem(id: number) {
    promptAction.showDialog({
      title: '確認刪除',
      message: '確定要刪除這個任務嗎?',
      buttons: [
        { text: '取消', color: '#666666' },
        { text: '刪除', color: '#FF5722' }
      ]
    }).then((result) => {
      if (result.index === 1) {
        const index = this.todoList.findIndex(item => item.id === id);
        if (index >= 0) {
          this.todoList.splice(index, 1);
          promptAction.showToast({ message: '刪除成功', duration: 2000 });
          this.calculateStatistics();
        }
      }
    });
  }

  // 計算統計信息
  calculateStatistics() {
    this.totalCount = this.todoList.length;
    this.completedCount = this.todoList.filter(item => item.completed).length;
    this.pendingCount = this.totalCount - this.completedCount;
  }

  // 獲取篩選後的任務列表
  getFilteredItems(): TodoItem[] {
    switch (this.filterStatus) {
      case '未完成':
        return this.todoList.filter(item => !item.completed);
      case '已完成':
        return this.todoList.filter(item => item.completed);
      default:
        return this.todoList;
    }
  }

  // 獲取優先級顏色
  getPriorityColor(priority: number, completed: boolean): string {
    if (completed) {
      return '#E0E0E0';
    }
    
    switch (priority) {
      case 1: // 低優先級
        return '#4CAF50';
      case 2: // 中優先級
        return '#FF9800';
      case 3: // 高優先級
        return '#FF5722';
      default:
        return '#2196F3';
    }
  }

  // 格式化日期
  formatDate(date: Date): string {
    const year = date.getFullYear();
    const month = (date.getMonth() + 1).toString().padStart(2, '0');
    const day = date.getDate().toString().padStart(2, '0');
    return `${year}-${month}-${day}`;
  }
}

想入門鴻蒙開發又怕花冤枉錢?別錯過!現在能免費系統學 -- 從 ArkTS 面向對象核心的類和對象、繼承多態,到吃透鴻蒙開發關鍵技能,還能衝刺鴻蒙基礎 +高級開發者證書,更驚喜的是考證成功還送好禮!快加入我的鴻蒙班,一起從入門到精通,班級鏈接:點擊https://developer.huawei.com/consumer/cn/training/classDetail/b7365031334e4353a9a0fd6785bb0791?type=1?ha_source=hmosclass&ha_sourceId=89000248免費進入