HarmonyOS5个人小项目——简单记账(2)

56 阅读3分钟

明细类的接口: image.png

收支操作页面布局

import classInfo from '../viewmodel/classInfo'
import amountPanel from '../views/amountPanel'
 
@Entry
@Component
struct addAccounts {
  //图片
  image: ResourceStr
  //名称
  name: string
  //选中类别下标
  index: number = -1
  //显示支出列表
  @State showPayoutList: boolean = true
  //支出颜色
  @State payoutColor: string = '#ffff0000'
  //收入颜色
  @State incomeColor: string = '#ff000000'
  //支出选项
  payout: classInfo[] = [
      new classInfo('餐饮',$r('app.media.img1')),
      new classInfo('购物',$r('app.media.img2')),
      new classInfo('日用',$r('app.media.img3')),
      new classInfo('交通',$r('app.media.img4')),
      new classInfo('零食',$r('app.media.img5')),
      new classInfo('运动',$r('app.media.img6')),
      new classInfo('娱乐',$r('app.media.img7')),
      new classInfo('通讯',$r('app.media.img8')),
      new classInfo('服饰',$r('app.media.img9')),
      new classInfo('美容',$r('app.media.img10')),
      new classInfo('住房',$r('app.media.img11')),
      new classInfo('家庭',$r('app.media.img12')),
      new classInfo('社交',$r('app.media.img13')),
      new classInfo('医疗',$r('app.media.img14')),
      new classInfo('学习',$r('app.media.img15')),
      new classInfo('宠物',$r('app.media.img16')),
      new classInfo('礼品',$r('app.media.img17')),
      new classInfo('办公',$r('app.media.img18')),
      new classInfo('维修',$r('app.media.img19')),
      new classInfo('捐赠',$r('app.media.img20')),
      new classInfo('红包',$r('app.media.img21')),
      new classInfo('还款',$r('app.media.img22')),
      new classInfo('借出',$r('app.media.img23')),
      new classInfo('其它',$r('app.media.img24'))
  ]
  //收入选项
  income: classInfo[] = [
      new classInfo('工资',$r('app.media.img25')),
      new classInfo('红包',$r('app.media.img21')),
      new classInfo('礼金',$r('app.media.img26')),
      new classInfo('分红',$r('app.media.img27')),
      new classInfo('理财',$r('app.media.img28')),
      new classInfo('借入',$r('app.media.img29')),
      new classInfo('收款',$r('app.media.img30')),
      new classInfo('其它',$r('app.media.img24'))
  ]
 
  //弹出框操作
  dialogController: CustomDialogController = new CustomDialogController({
    builder: amountPanel({onTaskConfirm: this.handleAddTask.bind(this)})
  })
 
  //对弹出框输入内容和类别进行操作
  handleAddTask(amount: number){
    if(this.showPayoutList){
      this.payout[this.index].money -= amount
      console.log('1')
    } else {
      this.income[this.index].money += amount
      console.log('2')
    }
    // this.dialogController.close()
  }
 
  build() {
    Column() {
      Row(){
        //标题栏:由返回按钮以及支出/收入操作组成
        Column(){
          Image($r('app.media.back'))
            .width(50)
            .borderRadius(50)
        }
        .width(50)
        .margin({right: 70})
        //用于显示支出列表的文字提示
        Text('支出')
          .fontSize(30)
          .fontColor(this.payoutColor)
          //点击事件,点击修改变量值
          .onClick(() => {
            this.payoutColor = '#ffff0000'
            this.incomeColor = '#ff000000'
            this.showPayoutList = true
          })
        Text(' | ')
          .fontSize(30)
        //用与显示收入列表的文本提示
        Text('收入')
          .fontSize(30)
          .fontColor(this.incomeColor)
          //点击事件,修改样式
          .onClick(() => {
            this.incomeColor = '#ffff0000'
            this.payoutColor = '#ff000000'
            this.showPayoutList = false
          })
      }
      .width('100%')
      .margin({bottom: 10})
      //账目类别列表
      Row(){
        //点击了支出文本,当前显示支出列表
        if(this.showPayoutList){
          //网格布局
          Grid(){
            ForEach(
              this.payout,
              (item: classInfo,index) => {
                GridItem(){
                  Column(){
                    //每个类别设计为单选按钮,点击会弹出弹出框输入金额
                    Radio({value: item.name, group: 'radioGroup'})
                      .checked(false)
                      .width(70)
                      .backgroundImage(item.img)
                      .backgroundImageSize({width:70,height:70})
                      .borderRadius(40)
                        //弹出弹出框,获取当前选中的类别
                      .onClick(() => {
                        this.index = index
                        this.image = item.img
                        this.name = item.name
                        this.dialogController.open()
                      })
                    Text(item.name)
                      .fontSize(20)
                  }
                  .width(80)
                  .margin({left: 7, top: 10})
                }
              }
            )
          }
          //四列
          .columnsTemplate('1fr 1fr 1fr 1fr')
          //点击了收入文本,展示收入列表
        } else {
          //网格布局
          Grid(){
            ForEach(
              this.income,
              (item: classInfo,index) => {
                GridItem(){
                  Column(){
                    //每个类别设计为单选按钮,点击会弹出弹出框输入金额
                    Radio({value: item.name, group: 'radioGroup'})
                      .checked(false)
                      .width(70)
                      .backgroundImage(item.img)
                      .backgroundImageSize({width:70,height:70})
                      .borderRadius(40)
                        //弹出弹出框,获取当前选中的类别
                      .onClick(() => {
                        this.index = index
                        this.image = item.img
                        this.name = item.name
                        this.dialogController.open()
                      })
                    Text(item.name)
                      .fontSize(20)
                  }
                  .width(80)
                  .margin({left: 7, top: 10})
                }
              }
            )
          }
          //四列
          .columnsTemplate('1fr 1fr 1fr 1fr')
        }
      }
      .width('100%')
    }
    .width('100%')
    .height('100%')
    .backgroundColor('#ffbfe8fd')
  }
}

弹出框页面布局:

//自定义弹出框样式设计:用于获取交易金额
@CustomDialog
export default struct amountPanel{
  //金额
  @State amount: number = 0
  //管理对话框状态
  controller: CustomDialogController
  //回调函数,用于完成任务时传递金额参数
  onTaskConfirm: (amount: number) => void
 
  build(){
    Column(){
      Row(){
        //金额输入框
        TextInput({placeholder: '点击输入金额...'})
          .backgroundColor(Color.White)
          //添加事件,当输入内容变化时触发
          .onChange(value => {
            this.amount = parseInt(value) //更新金额值
          })
      }
      .width('90%')
      .margin(25)
      Row(){
        Button('完成')
          .backgroundColor('#ff1280f6')
          //点击事件,调用确认任务的回调函数,传递当前amount值
          .onClick(() => {
            this.onTaskConfirm(this.amount)
          })
        Button('取消')
          .backgroundColor('#ff1280f6')
          //点击事件,关闭对话框
          .onClick(() => {
            this.controller.close()
          })
      }
      .width('100%')
      .justifyContent(FlexAlign.SpaceEvenly)
    }
    .width('100%')
    .height(150)
    .backgroundColor('#ff67d0f8')
    .borderRadius(30)
    .shadow({radius: 20, color: Color.Black,offsetX: 0,offsetY: 0})
  }
}

统计页面布局

该页面用于展示各类别的收支情况,通过List遍历。

具体代码如下:

import classInfo from '../viewmodel/classInfo'
import budgetPanel from '../views/budgetPanel'
 
@Entry
@Component
struct statistics {
  //类别总计金额
  total: classInfo[] = [
    new classInfo('餐饮',$r('app.media.img1')),
    new classInfo('购物',$r('app.media.img2')),
    new classInfo('日用',$r('app.media.img3')),
    new classInfo('交通',$r('app.media.img4')),
    new classInfo('零食',$r('app.media.img5')),
    new classInfo('运动',$r('app.media.img6')),
    new classInfo('娱乐',$r('app.media.img7')),
    new classInfo('通讯',$r('app.media.img8')),
    new classInfo('服饰',$r('app.media.img9')),
    new classInfo('美容',$r('app.media.img10')),
    new classInfo('住房',$r('app.media.img11')),
    new classInfo('家庭',$r('app.media.img12')),
    new classInfo('社交',$r('app.media.img13')),
    new classInfo('医疗',$r('app.media.img14')),
    new classInfo('学习',$r('app.media.img15')),
    new classInfo('宠物',$r('app.media.img16')),
    new classInfo('礼品',$r('app.media.img17')),
    new classInfo('办公',$r('app.media.img18')),
    new classInfo('维修',$r('app.media.img19')),
    new classInfo('捐赠',$r('app.media.img20')),
    new classInfo('红包',$r('app.media.img21')),
    new classInfo('还款',$r('app.media.img22')),
    new classInfo('借出',$r('app.media.img23')),
    new classInfo('其它',$r('app.media.img24')),
    new classInfo('工资',$r('app.media.img25')),
    new classInfo('礼金',$r('app.media.img26')),
    new classInfo('分红',$r('app.media.img27')),
    new classInfo('理财',$r('app.media.img28')),
    new classInfo('借入',$r('app.media.img29')),
    new classInfo('收款',$r('app.media.img30'))
  ]
 
  build() {
    Column(){
      //标题栏,包括返回按钮和标题
      Row(){
        Image($r('app.media.back'))
          .width(50)
          .borderRadius(50)
        Text('类别收支统计')
          .fontSize(30)
          .margin({left: 10})
      }
      .width('100%')
      .margin({bottom: 40})
      //显示类别信息列表
      Row(){
        List(){
          ForEach(
            this.total,
            (item: classInfo) => {
              ListItem(){
                Row(){
                  Row(){
                    Image(item.img)
                      .width(50)
                      .borderRadius(20)
                    Text(item.name)
                      .fontSize(20)
                      .margin({left: 5})
                  }
                  .margin({left: 10})
                  //支出类别金额为负
                  if(item.money < 0){
                    Text('-¥' + item.money.toFixed(2))
                      .fontSize(20)
                      .fontColor(Color.Red)
                    //收入类别金额为正
                  } else {
                    Text('¥' + item.money.toFixed(2))
                      .fontSize(20)
                      .fontColor(Color.Red)
                  }
                }
                .width('90%')
                .justifyContent(FlexAlign.SpaceBetween)
                .margin({top: 15})
              }
            }
          )
        }
      }
      .width('90%')
      .height(650)
      .backgroundColor(Color.White)
      .borderRadius(10)
      .shadow({radius: 20, color: Color.Black, offsetX: 0, offsetY: 0})
    }
    .width('100%')
    .height('100%')
    .backgroundColor('#ffbfe8fd')
  }
}

我的页面布局

用于录入预算金额,以及支出总金额,收入总金额,剩余金额。

具体代码如下:

import budgetPanel from '../views/budgetPanel'
 
@Entry
@Component
struct Mine {
  //预算
  @State budget: number = 0
  //总支出
  @State month_payout: number = 0
  //总收入
  @State month_income: number = 0
  //余额
  @State balance: number = 0
 
  //预算弹出框
  dialogController: CustomDialogController = new CustomDialogController({
    builder: budgetPanel({onTaskConfirm: this.handleAddTask.bind(this)})
  })
 
  //更新预算值
  handleAddTask(budget: number){
    this.budget = budget
    this.dialogController.close()
  }
 
  build() {
    Column(){
      //标题栏,包括返回按钮和标题
      Row(){
        Image($r('app.media.back'))
          .width(50)
          .borderRadius(50)
        Text('信息管理')
          .fontSize(30)
          .margin({left: 10})
      }
      .width('100%')
      .margin({bottom: 30})
        //预算显示设计
      Row() {
        Text('月预算:')
          .fontSize(30)
          .fontWeight(FontWeight.Bold)
        Text('¥' + this.budget.toFixed(2))
          .fontSize(30)
          .fontColor(Color.Red)
        Image($r('app.media.budget'))
          .width(30)
          .margin({ left: 5 })
            //点击弹出弹出框,输入预算进行后续操作
          .onClick(() => {
            this.dialogController.open()
          })
      }
      .width('90%')
      .height(100)
      .backgroundColor(Color.White)
      .borderRadius(10)
      .border({width: {top: 2, bottom: 2, left: 2, right: 2} })
      .margin({bottom: 20})
      //本月收支情况的概述
      Row(){
        Column(){
          //剩余金额
          Row(){
            Text('本月结余')
              .fontSize(20)
              .fontWeight(FontWeight.Bold)
          }
          .width('100%')
          .padding({left: 10, right: 10})
          .margin({bottom: 15})
          Row(){
            if(this.balance < 0){
              Text('-¥' + this.month_payout.toFixed(2))
                .fontSize(30)
                .fontColor(Color.Red)
            } else {
              Text('¥' + this.month_payout.toFixed(2))
                .fontSize(30)
                .fontColor(Color.Red)
            }
          }
          .width('100%')
          .padding({left: 20})
          .margin({bottom: 15})
          //总支出
          Row(){
            Text('本月支出:')
              .fontSize(20)
            Text('-¥' + this.month_payout.toFixed(2))
              .fontSize(20)
              .fontColor(Color.Red)
          }
          .width('100%')
          .justifyContent(FlexAlign.SpaceBetween)
          .padding({left: 10, right: 10})
          .margin({bottom: 20})
          //总收入
          Row(){
            Text('本月收入:')
              .fontSize(20)
            Text('¥' + this.month_payout.toFixed(2))
              .fontSize(20)
              .fontColor(Color.Red)
          }
          .width('100%')
          .justifyContent(FlexAlign.SpaceBetween)
          .padding({left: 10, right: 10})
        }
      }
      .width('90%')
      .height(200)
      .backgroundColor(Color.White)
      .borderRadius(10)
      .border({width: {top: 2, bottom: 2, left: 2, right: 2} })
    }
    .width('100%')
    .height('100%')
    .backgroundImage($r("app.media.mine_background"))
    .backgroundImageSize({width: '100%', height: '100%'})
  }
}

页面路由跳转的实现

页面路由:指在应用程序中实现不同页面之间的跳转和数据传递。

具体代码如下:

import router from '@ohos.router'
 
@Entry
@Component
struct Index {
 
  build() {
    Column() {
      Row(){
        //明细图标:用于跳转到明细详情页
        Column(){
          Image($r('app.media.detailed'))
            .width(50)
          Text('明细')
            .fontSize(15)
        }
        .width(70)
        //点击事件
        .onClick(() => {
          //页面路由,挑战到明细页面
          router.pushUrl(
            {
              url: 'pages/detailed'
            },
            router.RouterMode.Single,
            err => {
              if(err){
                console.log('加载明细页面失败')
              }
            }
          )
        })
        //账单图标:用于跳转到账单页
        Column(){
          Image($r('app.media.bill'))
            .width(45)
          Text('账单')
            .fontSize(15)
        }
        .width(70)
        //点击事件
        .onClick(() => {
          //页面路由,跳转到账单页面
          router.pushUrl(
            {
              url: 'pages/bill'
            },
            router.RouterMode.Single,
            err => {
              if(err){
                console.log('加载账单页面失败')
              }
            }
          )
        })
        //添加图标:用于添加一笔账目信息
        Column(){
          Button('+')
            .fontSize(60)
            .backgroundColor(Color.Pink)
            .borderColor(Color.Black)
            //点击事件
            .onClick(() => {
              //页面路由,跳转到添加账目页面
              router.pushUrl(
                {
                  url: 'pages/addAccounts'
                },
                router.RouterMode.Single,
                err => {
                  if(err){
                    console.log('加载添加账目页面失败')
                  }
                }
              )
            })
        }
        .width(90)
        //存钱图标:用于跳转到存钱页面
        Column(){
          Image($r('app.media.statistics'))
            .width(40)
            .margin({bottom: 7})
          Text('统计')
            .fontSize(15)
        }
        .width(70)
        //点击事件
        .onClick(() => {
          //页面路由,跳转到统计页面
          router.pushUrl(
            {
              url: 'pages/statistics'
            },
            router.RouterMode.Single,
            err => {
              if(err){
                console.log('加载统计页面失败')
              }
            }
          )
        })
        //我的图标:用于跳转到账号管理页面
        Column(){
          Image($r('app.media.mine'))
            .width(40)
          Text('我的')
            .fontSize(15)
        }
        .width(70)
        //点击事件
        .onClick(() => {
          //页面路由,跳转到我的页面
          router.pushUrl(
            {
              url: 'pages/mine',
            },
            router.RouterMode.Single,
            err => {
              if(err)
                console.log('加载我的页面失败')
            }
          )
        })
      }
      .width('100%')
      .height(100)
      .position({x: 0,y: 690})
    }
    .width('100%')
    .height('100%')
    .backgroundImage($r('app.media.background'))
    .backgroundImageSize({width: 370, height: 750})
  }
}