Harmony OS个人项目——简单记账APP(4)

一、对统计页面进行修改

将收入和支出分为了两类展示,这两类中有相同的类别,为了避免混淆,方便后续保存和数据同步等操作。具体修改如下:

import router from '@ohos.router'
import classInfo from '../viewmodel/classInfo'
import budgetPanel from '../views/budgetPanel'

@Entry
@Component
struct statistics {
  //支出选项
  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'))
  ]
  //展示支出统计
  @State showPayoutPanel: boolean = true
  //收入文本颜色
  @State incomeColor: string = '#ff000000'
  //支出文本颜色
  @State payoutColor: string = '#ffff0000'

  build() {
    Column(){
      //标题栏,包括返回按钮和标题
      Row(){
        Image($r('app.media.back'))
          .width(50)
          .borderRadius(50)
          .onClick(() => {
            router.pushUrl(
              {
                url: 'pages/Index'
              },
              router.RouterMode.Single,
              err => {
                if(err){
                  console.log('返回主页失败')
                }
              }
            )
          })
        Text('类别收支统计')
          .fontSize(30)
          .margin({left: 10})
      }
      .width('100%')
      .margin({bottom: 20})

      //收入支出切换设置
      Row(){
        Text('支出')
          .fontSize(25)
          .fontColor(this.payoutColor)
          .onClick(() => {
            this.payoutColor = '#ffff0000'
            this.incomeColor = '#ff000000'
            this.showPayoutPanel = true
          })
        Text(' | ')
          .fontSize(25)
        Text('收入')
          .fontSize(25)
          .fontColor(this.incomeColor)
          .onClick(() => {
            this.payoutColor = '#ff000000'
            this.incomeColor = '#ffff0000'
            this.showPayoutPanel = false
          })
      }
      .width('100%')
      .justifyContent(FlexAlign.End)
      .padding({right: 20})
      .margin({bottom: 20})

      Row(){
        //显示支出面板
        if(this.showPayoutPanel){
          List(){
            ForEach(
              this.payout,
              (item: classInfo) => {
                ListItem(){
                  Row(){
                    Row(){
                      Image(item.img)
                        .width(50)
                        .borderRadius(20)
                      Text(item.name)
                        .fontSize(20)
                        .margin({left: 5})
                    }
                    .margin({left: 10})
                    //支出类别金额为负
                    Text('-¥' + item.money.toFixed(2))
                      .fontSize(20)
                      .fontColor(Color.Red)
                  }
                  .width('90%')
                  .justifyContent(FlexAlign.SpaceBetween)
                  .margin({top: 15})
                }
              }
            )
          }
          //显示收入面板
        } else {
          List(){
            ForEach(
              this.income,
              (item: classInfo) => {
                ListItem(){
                  Row(){
                    Row(){
                      Image(item.img)
                        .width(50)
                        .borderRadius(20)
                      Text(item.name)
                        .fontSize(20)
                        .margin({left: 5})
                    }
                    .margin({left: 10})
                    //收入类别金额为正
                    Text('¥' + item.money.toFixed(2))
                      .fontSize(20)
                      .fontColor(Color.Red)
                  }
                  .width('90%')
                  .justifyContent(FlexAlign.SpaceBetween)
                  .margin({top: 15})
                }
              }
            )
          }
        }
      }
      .width('90%')
      .layoutWeight(1)
      .backgroundColor(Color.White)
      .borderRadius(10)
      .shadow({radius: 20, color: Color.Black, offsetX: 0, offsetY: 0})
      .alignItems(VerticalAlign.Top)
    }
    .width('100%')
    .height('100%')
    .backgroundColor('#ffbfe8fd')
  }
}

二、添加数据库实现持久化保存

将每次支出收入的明细都存储到数据库中的明细表中,以便退出应用后可以保存,下次打开时仍然存在,于是单独编写了一个数据库操作类,以及对明细页面和添加页面实现了数据库的交互。具体代码如下:

数据库操作类:

import relationalStore from '@ohos.data.relationalStore'   //导入关系型数据库模板
import detailedInfo from '../viewmodel/detailedInfo'

class DetailedModel{

  //定义关系型数据库存储对象
  private rdbStore: relationalStore.RdbStore
  //表名
  private tableName: string = 'DETAILED'

  //初始化
  initTaskDB(context){
    const config = {
      name: 'MyApplication.db',   //数据库名
      securityLevel: relationalStore.SecurityLevel.S1   //安全级别为S1
    }

    //创建表的SQL语句
    const sql = `CREATE TABLE IF NOT EXISTS DETAILED (
                NAME TEXT PRIMARY KEY,
                IMG TEXT,
                AMOUNT DOUBLE,
                DATE TEXT
               )`

    //获取数据库存储对象并执行初始化
    relationalStore.getRdbStore(context,config,(err,rdbStore) => {
      if(err){
        console.log('textTag','获取rdbStore失败!')  //获取失败信息
        return
      }

      rdbStore.executeSql(sql)   //执行sql语句创建表
      console.log('textTag','创建detailed成功!')   //创建成功提示信息
      //将数据库存储对象赋值给私有变量
      this.rdbStore = rdbStore
    })
  }

  //查询
  async getTaskList(){
    //创建查询谓词对象
    let predicates = new relationalStore.RdbPredicates(this.tableName)
    //执行查询操作
    let result = await this.rdbStore.query(predicates,['NAME','IMG','AMOUNT','DATE'])
    //存储查询结果的数组
    let detailed: detailedInfo[] = []
    //循环终止条件,遍历到结果集最后一行
    while(!result.isAtLastRow){
      //移动到结果集的下一行
      result.goToNextRow()
      let name = result.getString(result.getColumnIndex('NAME'))   //获取name值
      let img = result.getString(result.getColumnIndex('IMG'))     //获取img值
      let amount = result.getDouble(result.getColumnIndex('AMOUNT'))  //获取amount值
      let date = result.getString(result.getColumnIndex('DATE'))    //获取date值
      //将查询结果存入数组
      detailed.push({name,img,amount,date}) 
    }
    console.log('taskTag','查询到数据:',JSON.stringify(detailed))
    return detailed  //返回查询结果数组
  }

  //添加
  addTask(name: string, img: string, amount: number, date: string): Promise<number>{
    //执行插入操作并返回插入的行数
    return this.rdbStore.insert(this.tableName,{name,img,amount,date})
  }

  //更新——待实现(目前未用到)

  //删除——待实现(目前未用到)

}
//创建DetailedModel类的实例
let detailedModel = new DetailedModel();
//导出DetailedModel类的实例作为默认导出
export default detailedModel as DetailedModel

添加页面的数据库操作语句:

 明细展示页面添加的数据库操作语句:

 其中数据库的初始化操作均在entryability目录下的EntryAbility.ets文件中实现。

这里在写的时候发现了一些小问题。

我们在存储类别图片时使用的是ResourceStr类型,但是数据库基本类型中没有这种类型,所以在存储到数据库中时只能通过string类型,SQL语句中为TEXT,在存储时没有问题,但是当从数据库导出时,在页面上不会展示效果。所以这里为图片路径进行了更改。将类别图片放到了ResourceStr目录下的rawfile文件夹中,通过image($rawfile{'image.png'})的形式进行调用,最终实现预期效果。

效果实现:

添加明细持久化实现

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值