功能説明

這是一個基於HarmonyOS ArkTS開發的簡易個人記賬本應用,主要功能包括:

核心功能

  1. 添加記賬記錄 - 記錄收入/支出,包含金額、類別、日期、備註
  2. 查看記賬列表 - 以卡片形式展示所有記賬記錄
  3. 編輯記錄 - 修改已保存的記賬信息
  4. 刪除記錄 - 刪除不需要的記賬記錄
  5. 收支統計 - 實時統計總收入、總支出和結餘
  6. 分類篩選 - 按類別篩選查看記錄

完整代碼

// 簡易個人記賬本
// 文件名:PersonalAccountBook.ets

import promptAction from '@ohos.promptAction';

// 記賬記錄數據模型
class AccountRecord {
  id: number = 0;
  type: string = '支出'; // 收入/支出
  amount: number = 0;
  category: string = '餐飲';
  date: string = '';
  note: string = '';
  
  constructor(id: number, type: string = '支出', amount: number = 0, 
              category: string = '餐飲', date: string = '', note: string = '') {
    this.id = id;
    this.type = type;
    this.amount = amount;
    this.category = category;
    this.date = date;
    this.note = note;
  }
}

@Entry
@Component
struct PersonalAccountBook {
  // 記賬記錄列表
  @State accountList: AccountRecord[] = [];
  
  // 收支統計
  @State totalIncome: number = 0;
  @State totalExpense: number = 0;
  @State balance: number = 0;
  
  // 編輯相關狀態
  @State currentRecord: AccountRecord = new AccountRecord(0);
  @State showEditDialog: boolean = false;
  @State isEditing: boolean = false;
  @State selectedType: string = '支出';
  
  // 類別選項
  @State expenseCategories: string[] = ['餐飲', '交通', '購物', '娛樂', '醫療', '其他'];
  @State incomeCategories: string[] = ['工資', '獎金', '投資', '兼職', '其他'];
  
  // 當前篩選類別
  @State selectedCategory: string = '全部';
  
  // 組件生命週期
  aboutToAppear() {
    this.initSampleData();
    this.calculateStatistics();
  }

  // 初始化示例數據
  initSampleData() {
    this.accountList = [
      new AccountRecord(1, '支出', 35.5, '餐飲', '2024-01-15', '午餐'),
      new AccountRecord(2, '收入', 8500, '工資', '2024-01-10', '1月份工資'),
      new AccountRecord(3, '支出', 128, '購物', '2024-01-12', '購買書籍'),
      new AccountRecord(4, '支出', 15, '交通', '2024-01-14', '地鐵費'),
      new AccountRecord(5, '收入', 500, '兼職', '2024-01-08', '兼職收入')
    ];
  }

  // 構建主界面
  build() {
    Column({ space: 0 }) {
      // 頂部標題欄
      this.buildHeader()
      
      // 收支統計卡片
      this.buildStatisticsCard()
      
      // 類別篩選
      this.buildCategoryFilter()
      
      // 記賬列表
      this.buildRecordList()
    }
    .width('100%')
    .height('100%')
    .backgroundColor('#F8F9FA')
  }

  // 頂部標題欄
  @Builder
  buildHeader() {
    Row() {
      Text('個人記賬本')
        .fontSize(22)
        .fontWeight(FontWeight.Bold)
        .fontColor('#FFFFFF')
        .layoutWeight(1)
      
      Button('記賬')
        .width(70)
        .height(35)
        .fontSize(14)
        .backgroundColor('#FFFFFF')
        .fontColor('#007DFF')
        .onClick(() => {
          this.addNewRecord();
        })
    }
    .width('100%')
    .padding({ left: 16, right: 16, top: 12, bottom: 12 })
    .backgroundColor('#007DFF')
  }

  // 收支統計卡片
  @Builder
  buildStatisticsCard() {
    Column({ space: 8 }) {
      // 總收入
      Row() {
        Text('總收入')
          .fontSize(16)
          .fontColor('#666666')
          .layoutWeight(1)
        Text('¥' + this.totalIncome.toFixed(2))
          .fontSize(20)
          .fontWeight(FontWeight.Bold)
          .fontColor('#4CAF50')
      }
      .width('100%')
      
      // 總支出
      Row() {
        Text('總支出')
          .fontSize(16)
          .fontColor('#666666')
          .layoutWeight(1)
        Text('¥' + this.totalExpense.toFixed(2))
          .fontSize(20)
          .fontWeight(FontWeight.Bold)
          .fontColor('#FF5722')
      }
      .width('100%')
      
      // 結餘
      Row() {
        Text('結餘')
          .fontSize(16)
          .fontColor('#666666')
          .layoutWeight(1)
        Text('¥' + this.balance.toFixed(2))
          .fontSize(22)
          .fontWeight(FontWeight.Bold)
          .fontColor('#007DFF')
      }
      .width('100%')
    }
    .width('90%')
    .padding(16)
    .backgroundColor('#FFFFFF')
    .borderRadius(12)
    .margin({ top: 16, bottom: 16 })
    .shadow({ radius: 4, color: '#E0E0E0', offsetX: 1, offsetY: 2 })
  }

  // 類別篩選
  @Builder
  buildCategoryFilter() {
    Scroll(.horizontal) {
      Row({ space: 8 }) {
        // "全部"選項
        Text('全部')
          .fontSize(14)
          .padding({ left: 12, right: 12, top: 6, bottom: 6 })
          .backgroundColor(this.selectedCategory === '全部' ? '#007DFF' : '#FFFFFF')
          .fontColor(this.selectedCategory === '全部' ? '#FFFFFF' : '#666666')
          .borderRadius(16)
          .onClick(() => {
            this.selectedCategory = '全部';
          })
        
        // 支出類別
        ForEach(this.expenseCategories, (category: string) => {
          Text(category)
            .fontSize(14)
            .padding({ left: 12, right: 12, top: 6, bottom: 6 })
            .backgroundColor(this.selectedCategory === category ? '#FF5722' : '#FFFFFF')
            .fontColor(this.selectedCategory === category ? '#FFFFFF' : '#666666')
            .borderRadius(16)
            .onClick(() => {
              this.selectedCategory = category;
            })
        })
        
        // 收入類別
        ForEach(this.incomeCategories, (category: string) => {
          Text(category)
            .fontSize(14)
            .padding({ left: 12, right: 12, top: 6, bottom: 6 })
            .backgroundColor(this.selectedCategory === category ? '#4CAF50' : '#FFFFFF')
            .fontColor(this.selectedCategory === category ? '#FFFFFF' : '#666666')
            .borderRadius(16)
            .onClick(() => {
              this.selectedCategory = category;
            })
        })
      }
      .padding({ left: 16, right: 16 })
    }
    .width('100%')
    .margin({ bottom: 12 })
  }

  // 記賬列表
  @Builder
  buildRecordList() {
    List({ space: 8 }) {
      ForEach(this.getFilteredRecords(), (record: AccountRecord) => {
        ListItem() {
          this.buildRecordItem(record)
        }
      })
    }
    .width('100%')
    .layoutWeight(1)
    .padding({ left: 16, right: 16 })
    
    // 編輯對話框
    if (this.showEditDialog) {
      this.buildEditDialog()
    }
  }

  // 記賬列表項
  @Builder
  buildRecordItem(record: AccountRecord) {
    Column({ space: 6 }) {
      // 第一行:類別和金額
      Row() {
        // 類別標籤
        Text(record.category)
          .fontSize(12)
          .padding({ left: 8, right: 8, top: 4, bottom: 4 })
          .backgroundColor(record.type === '收入' ? '#E8F5E9' : '#FFEBEE')
          .fontColor(record.type === '收入' ? '#4CAF50' : '#FF5722')
          .borderRadius(10)
        
        // 日期
        Text(record.date)
          .fontSize(12)
          .fontColor('#999999')
          .layoutWeight(1)
          .margin({ left: 8 })
        
        // 金額
        Text((record.type === '收入' ? '+' : '-') + '¥' + record.amount.toFixed(2))
          .fontSize(18)
          .fontWeight(FontWeight.Bold)
          .fontColor(record.type === '收入' ? '#4CAF50' : '#FF5722')
      }
      .width('100%')
      
      // 第二行:備註
      if (record.note) {
        Row() {
          Text(record.note)
            .fontSize(14)
            .fontColor('#666666')
            .maxLines(1)
            .textOverflow({ overflow: TextOverflow.Ellipsis })
        }
        .width('100%')
      }
      
      // 第三行:操作按鈕
      Row({ space: 12 }) {
        Button('編輯')
          .width(70)
          .height(30)
          .fontSize(12)
          .backgroundColor('#2196F3')
          .onClick(() => {
            this.editRecord(record);
          })
        
        Button('刪除')
          .width(70)
          .height(30)
          .fontSize(12)
          .backgroundColor('#FF5722')
          .onClick(() => {
            this.deleteRecord(record.id);
          })
      }
      .width('100%')
      .justifyContent(FlexAlign.End)
      .margin({ top: 8 })
    }
    .width('100%')
    .padding(12)
    .backgroundColor('#FFFFFF')
    .borderRadius(8)
    .shadow({ radius: 2, color: '#E0E0E0', offsetX: 1, offsetY: 1 })
  }

  // 編輯對話框
  @Builder
  buildEditDialog() {
    Column() {
      // 標題
      Text(this.isEditing ? '編輯記錄' : '添加記錄')
        .fontSize(18)
        .fontWeight(FontWeight.Bold)
        .margin({ top: 20, bottom: 16 })
      
      // 收支類型選擇
      Row({ space: 20 }) {
        Radio({ value: '支出', group: 'recordType' })
          .checked(this.currentRecord.type === '支出')
          .onChange((isChecked: boolean) => {
            if (isChecked) {
              this.currentRecord.type = '支出';
            }
          })
        Text('支出')
          .fontSize(16)
          .onClick(() => {
            this.currentRecord.type = '支出';
          })
        
        Radio({ value: '收入', group: 'recordType' })
          .checked(this.currentRecord.type === '收入')
          .onChange((isChecked: boolean) => {
            if (isChecked) {
              this.currentRecord.type = '收入';
            }
          })
        Text('收入')
          .fontSize(16)
          .onClick(() => {
            this.currentRecord.type = '收入';
          })
      }
      .margin({ bottom: 16 })
      
      // 金額輸入
      TextInput({ placeholder: '輸入金額', text: this.currentRecord.amount > 0 ? this.currentRecord.amount.toString() : '' })
        .width('90%')
        .height(45)
        .type(InputType.Number)
        .margin({ bottom: 12 })
        .onChange((value: string) => {
          this.currentRecord.amount = parseFloat(value) || 0;
        })
      
      // 類別選擇
      Row({ space: 8 }) {
        ForEach(
          this.currentRecord.type === '支出' ? this.expenseCategories : this.incomeCategories,
          (category: string) => {
            Text(category)
              .fontSize(14)
              .padding({ left: 12, right: 12, top: 6, bottom: 6 })
              .backgroundColor(this.currentRecord.category === category ? '#007DFF' : '#F0F0F0')
              .fontColor(this.currentRecord.category === category ? '#FFFFFF' : '#666666')
              .borderRadius(16)
              .onClick(() => {
                this.currentRecord.category = category;
              })
          }
        )
      }
      .width('90%')
      .margin({ bottom: 12 })
      
      // 日期輸入
      TextInput({ placeholder: '日期(如:2024-01-15)', text: this.currentRecord.date })
        .width('90%')
        .height(45)
        .margin({ bottom: 12 })
        .onChange((value: string) => {
          this.currentRecord.date = value;
        })
      
      // 備註輸入
      TextInput({ placeholder: '備註(可選)', text: this.currentRecord.note })
        .width('90%')
        .height(45)
        .margin({ bottom: 20 })
        .onChange((value: string) => {
          this.currentRecord.note = value;
        })
      
      // 操作按鈕
      Row({ space: 20 }) {
        Button('取消')
          .width(120)
          .height(40)
          .fontSize(16)
          .backgroundColor('#9E9E9E')
          .onClick(() => {
            this.showEditDialog = false;
          })
        
        Button(this.isEditing ? '保存' : '添加')
          .width(120)
          .height(40)
          .fontSize(16)
          .backgroundColor('#007DFF')
          .onClick(() => {
            this.saveRecord();
          })
      }
      .margin({ bottom: 20 })
    }
    .width('85%')
    .backgroundColor('#FFFFFF')
    .borderRadius(12)
    .shadow({ radius: 20, color: '#00000040' })
    .position({ x: '7.5%', y: '10%' })
  }

  // 添加新記錄
  addNewRecord() {
    const newId = this.accountList.length > 0 ? 
      Math.max(...this.accountList.map(item => item.id)) + 1 : 1;
    const today = new Date();
    const dateStr = `${today.getFullYear()}-${(today.getMonth() + 1).toString().padStart(2, '0')}-${today.getDate().toString().padStart(2, '0')}`;
    
    this.currentRecord = new AccountRecord(
      newId,
      '支出',
      0,
      '餐飲',
      dateStr,
      ''
    );
    this.isEditing = false;
    this.showEditDialog = true;
  }

  // 編輯記錄
  editRecord(record: AccountRecord) {
    this.currentRecord = { ...record };
    this.isEditing = true;
    this.showEditDialog = true;
  }

  // 保存記錄
  saveRecord() {
    if (this.currentRecord.amount <= 0) {
      promptAction.showToast({ message: '請輸入有效金額', duration: 2000 });
      return;
    }
    
    if (!this.currentRecord.date) {
      promptAction.showToast({ message: '請輸入日期', duration: 2000 });
      return;
    }
    
    if (this.isEditing) {
      // 更新現有記錄
      const index = this.accountList.findIndex(item => item.id === this.currentRecord.id);
      if (index >= 0) {
        this.accountList[index] = { ...this.currentRecord };
      }
      promptAction.showToast({ message: '記錄更新成功', duration: 2000 });
    } else {
      // 添加新記錄
      this.accountList.push({ ...this.currentRecord });
      promptAction.showToast({ message: '記錄添加成功', duration: 2000 });
    }
    
    this.showEditDialog = false;
    this.calculateStatistics();
  }

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

  // 計算收支統計
  calculateStatistics() {
    this.totalIncome = 0;
    this.totalExpense = 0;
    
    this.accountList.forEach(record => {
      if (record.type === '收入') {
        this.totalIncome += record.amount;
      } else {
        this.totalExpense += record.amount;
      }
    });
    
    this.balance = this.totalIncome - this.totalExpense;
  }

  // 獲取篩選後的記錄
  getFilteredRecords(): AccountRecord[] {
    if (this.selectedCategory === '全部') {
      return this.accountList;
    }
    return this.accountList.filter(record => record.category === this.selectedCategory);
  }
}

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