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

一、制作账单页面

该页面用来展示每天支出和收入总计,以列表的形式展现。其中,需要保存这个月的收支情况,所以需要实现数据持久化,为了方便编写,设计了一个类,包含日期,一天支出,一天收入三个属性元素。将对该类的数据持久化操作也单独放到一个文件中进行导入。

1、账单页面实现代码

其中调用了数据库操作类,将数据库中的数据存到数组中进行展示。

js 复制代码
import router from '@ohos.router'
import dailyModel from '../model/DailyModel';
import dailyInfo from '../viewmodel/dailyInfo';
 
@Entry
@Component
struct Bill {
  //获取当前时间
  time: Date = new Date()
  //当月天数
  day: number = this.time.getDate()
  //当前日期
  date: string = this.time.getFullYear()+'/'+this.time.getMonth()+'/'
  //每日收支
  @State dailyStatic: dailyInfo[] = []
 
  //生命周期函数,在build执行之前执行函数中的内容
  aboutToAppear(){
    //获取当月每日的收入支出情况数组数据
    dailyModel.getTaskList()
      .then(dailyStatic => {
        this.dailyStatic = dailyStatic
        console.log('taskLog','每日收支记录加载成功')
      })
  }
 
  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: 30})
 
     Row(){
       Column(){
         //提示文本信息
         Row(){
           Text('日期')
             .fontSize(25)
           Text('支出')
             .fontSize(25)
           Text('收入')
             .fontSize(25)
         }
         .width('100%')
         .margin({top: 10, bottom: 10})
         .justifyContent(FlexAlign.SpaceAround)
         //分割线
         Row(){
           Divider()
             .color(Color.Black)
             .strokeWidth(3)
         }
         .width('100%')
         //每日收支列表
         Row(){
           List(){
             ForEach(
               this.dailyStatic,
               (item: dailyInfo, index) => {
                 ListItem(){
                   Row(){
                     Column(){
                       Text(item.date.substring(5))
                         .fontSize(20)
                     }
                     .width('30%')
                     Column(){
                       //如果当日没有支出则显示'-'
                       if(item.payout == 0){
                         Text('-')
                           .fontSize(20)
                       } else {
                         Text('-¥'+item.payout.toFixed(2))
                           .fontSize(20)
                       }
                     }
                     .width('30%')
                     Column(){
                       //如果当日没有收入则显示'-'
                       if(item.income == 0){
                         Text('-')
                           .fontSize(20)
                       } else {
                         Text('¥'+item.income.toFixed(2))
                           .fontSize(20)
                       }
                     }
                     .width('30%')
                   }
                   .width('100%')
                   .margin({bottom: 10})
                   .justifyContent(FlexAlign.SpaceAround)
                 }
               }
             )
           }
         }
         .width('100%')
         .height(600)
         .margin({top: 10})
         .alignItems(VerticalAlign.Top)
 
       }
       .width('100%')
       .backgroundColor(Color.White)
       .borderRadius(10)
       .shadow({radius: 20, color: Color.Black, offsetX: 0, offsetY: 0})
     }
     .width('90%')
   }
    .width('100%')
    .height('100%')
    .backgroundColor('#ffbfe8fd')
  }
}
 

2、每日情况类的创建代码

包括三个属性,日期,该日期下的总支出和总收入。

js 复制代码
export default class dailyInfo{
  //日期
  date: string
  //当日总支出
  payout: number
  //当日总收入
  income: number
 
  constructor(date: string, payout: number, income: number) {
    this.date = date
    this.payout = payout
    this.income = income
  }
}

3、数据库操作类的代码

该类主要是进行数据库操作的,其中初始化数据库操作在EntryAbility页面中执行。

js 复制代码
import relationalStore from '@ohos.data.relationalStore' //导入关系型数据库模板
import dailyInfo from '../viewmodel/dailyInfo'
 
class DailyModel{
 
  //当前日期
  time: Date = new Date()
  date: string = this.time.getFullYear()+'/'+this.time.getMonth()+'/'
  day: number = this.time.getDate()
  //数据库实例
  private rdbStore: relationalStore.RdbStore
  //表名
  private tableName: string = 'DAILY'
 
  //初始化
  initTaskDB(context){
    const config = {
      name: 'MyApplication.db',  //数据库名称
      securityLevel: relationalStore.SecurityLevel.S1  //安全级别
    }
    //创建表的sql语句
    const sql = `CREATE TABLE IF NOT EXISTS DAILY (
                DATE TEXT PRIMARY KEY,
                PAYOUT DOUBLE,
                INCOME DOUBLE
               )`
    //执行rdb
    relationalStore.getRdbStore(context,config,(err,rdbStore) => {
      if(err){
        console.log('taskLog','获取rdbStore失败!')
        return
      }
      //执行sql语句创建表
      rdbStore.executeSql(sql)
      console.log('taskLog','创建daily成功!')
      //赋值
      this.rdbStore = rdbStore
    })
  }
 
  //查询列表
  async getTaskList(){
    //创建查询条件
    let predicates = new relationalStore.RdbPredicates(this.tableName)
    //执行查询,获取结果集
    let result = await this.rdbStore.query(predicates,['DATE','PAYOUT','INCOME'])
    //临时存放数组
    let dailyStatic: dailyInfo[] = []
    //记录上一条执行的结果日期
    let last = 1
    //遍历结果集
    while(!result.isAtLastRow){
      result.goToNextRow()  //移动到下一行
      let date = result.getString(result.getColumnIndex('DATE'))   //获取日期
      let payout = result.getDouble(result.getColumnIndex('PAYOUT'))   //获取支出
      let income = result.getDouble(result.getColumnIndex('INCOME'))   //获取收入
      //当前结果日期的日部分
      let next = parseInt(date.substring(this.date.length))
 
      for(let i = last; i < next; i++){
        const date = this.date+i.toString();  //构造日期字符串
        const payout = 0;  //默认支出为0
        const income = 0;   //默认收入为0
        dailyStatic.push({date,payout,income})   //添加到临时数组
      }
      //将当前数据添加到临时数组
      dailyStatic.push({date, payout, income})
      //更新上一个处理的日期
      last = next+1;
    }
 
    for(let i = last; i <= this.day; i++){
      const date = this.date+i.toString();  //构造日期字符串
      const payout = 0;  //默认支出为0
      const income = 0;  //默认收入为0
      dailyStatic.push({date, payout, income})
    }
 
    console.log('taskLog','查询到数据:',JSON.stringify(dailyStatic))
    return dailyStatic  //返回查询结果
  }
 
  //查询该数据是否存在
  async getTask(date: string): Promise<boolean>{
    //创建查询条件
    let predicates = new relationalStore.RdbPredicates(this.tableName)
    //执行查询
    let result = await this.rdbStore.query(predicates,['DATE','PAYOUT','INCOME'])
    //遍历结果集
    while(!result.isAtLastRow){
      result.goToNextRow()  //移动到下一行
      let value = result.getString(result.getColumnIndex('DATE'))  //获取日期
      //如果当前日期存在一条数据
      if(value == date){
        console.log('taskLog','查询到数据')
        return true  //返回true
      }
    }
    console.log('taskLog','未查询到数据')
    return false
  }
 
  //添加
  addTask(date: string, payout: number, income: number): Promise<number>{
    return this.rdbStore.insert(this.tableName,{date, payout, income})
  }
 
  //更新支出
  async updateTaskStatus(date: string, amount: number, value: number){
    //创建查询条件
    let predicates = new relationalStore.RdbPredicates(this.tableName)
    //添加日期条件
    predicates.equalTo('DATE',date)
    //执行查询
    let result = await this.rdbStore.query(predicates,['DATE','PAYOUT','INCOME'])
    //移动到结果集第一行
    result.goToNextRow()
    //如果当前value值为1,则执行更改支出金额,否则更改收入金额
    if(value){
      //新的支出金额
      let payout =amount + result.getDouble(result.getColumnIndex('PAYOUT'))
      let data = {'payout': payout}
      //执行更新操作
      return this.rdbStore.update(data,predicates)
    } else {
      //新的收入金额
      let income =amount + result.getDouble(result.getColumnIndex('INCOME'))
      let data = {'income': income}
      //执行更新操作
      return this.rdbStore.update(data,predicates)
    }
 
  }
 
  //删除------未实现(目前未用到)
 
}
//创建数据模型实例
let dailyModel = new DailyModel();
//导出模型实例
export default dailyModel as DailyModel

4、执行数据库数据更新操作

在addAmount页面中,当当天打开app时没有当天的数据,就执行插入操作,如果有,根据添加的明细进行更改收入,支出数据。

在aboutToAppear函数中进行判断是否为第一次打开操作。

在handleAddTask函数中进行更新操作,如果当前进行的时支出操作,代码如下,收入操作类似。

二、对我的页面进行数据持久化操作

1、我的页面数据类的实现

一共包含四个属性元素,预算,总支出,总收入和结余。

js 复制代码
export default class mineInfo{
  //预算
  budget: number
  //总支出
  month_payout: number
  //总收入
  month_income: number
  //结余
  balance: number
}

2、数据库操作类的代码

该类主要是对数据库进行操作,其初始化再EntryAbility中调用

js 复制代码
import relationalStore from '@ohos.data.relationalStore'
import mineInfo from '../viewmodel/mineInfo'
class MineModel {
  //数据库实例
  private rdbStore: relationalStore.RdbStore
  //表名
  private tableName: string = 'MINE'
  //初始化
  initTaskDB(context) {
    const config = {
      name: 'MyApplication.db', //数据库名称
      securityLevel: relationalStore.SecurityLevel.S1 //安全级别
    }
    //创建表的sql语句
    const sql = `CREATE TABLE IF NOT EXISTS MINE (
                ID INTEGER,
                BUDGET DOUBLE,
                MONTH_PAYOUT DOUBLE,
                MONTH_INCOME DOUBLE,
                BALANCE DOUBLE
               )`
    //执行rdb
    relationalStore.getRdbStore(context, config, (err, rdbStore) => {
      if (err) {
        console.log('taskLog', '获取rdbStore失败!')
        return
      }
      //执行sql语句创建表
      rdbStore.executeSql(sql)
      console.log('taskLog', '创建mine成功!')
      //赋值
      this.rdbStore = rdbStore
    })
  }
 
  //查询数据
  async getTask() {
    //创建查询条件
    let predicates = new relationalStore.RdbPredicates(this.tableName)
    //执行查询
    let result = await this.rdbStore.query(predicates, ['ID','BUDGET', 'MONTH_PAYOUT', 'MONTH_INCOME','BALANCE'])
    //临时数据存放
    let mine: mineInfo = {budget: 0, month_payout: 0, month_income: 0, balance: 0}
    let i = 0
    while (!result.isAtLastRow) {
      //移动到结果集第一行
      result.goToNextRow()
      let budget = result.getDouble(result.getColumnIndex('BUDGET'))
      let month_payout = result.getDouble(result.getColumnIndex('MONTH_PAYOUT'))
      let month_income = result.getDouble(result.getColumnIndex('MONTH_INCOME'))
      //更新数据对象
      mine.budget = budget
      mine.month_payout = month_payout
      mine.month_income = month_income
      mine.balance = budget - month_payout + month_income
      i++;
    }
    //如果没有查询到数据,添加一条默认数据
    if(i === 0){
      this.addTask(1,0,0,0,0)
    }
 
    return mine
  }
 
  //添加
  addTask(id: number, budget: number, month_payout: number, month_income: number, balance: number): Promise<number>{
    return this.rdbStore.insert(this.tableName,{id, budget, month_payout, month_income, balance})
  }
 
  //更新数据
  async updateTaskStatus(value: number, flag: number){
    //创建查询条件
    let predicates = new relationalStore.RdbPredicates(this.tableName)
    predicates.equalTo('ID', 1)
    //执行查询
    let result = await this.rdbStore.query(predicates,['ID','BUDGET','MONTH_PAYOUT','MONTH_INCOME'])
    //移动到结果集第一行
    result.goToNextRow()
    //如果当前flag值为1,则执行更改预算,为2更改总支出,为3更改总收入,每一种情况都需要更新结余
    if(flag === 1){
      let month_payout = result.getDouble(result.getColumnIndex('MONTH_PAYOUT'))
      let month_income = result.getDouble(result.getColumnIndex('MONTH_INCOME'))
      let balance = value - month_payout + month_income
      //新的预算金额
      let data = {'budget': value, 'balance': balance}
      //执行更新操作
      return this.rdbStore.update(data,predicates)
    } else if(flag === 2) {
      let budget = result.getDouble(result.getColumnIndex('BUDGET'))
      let month_income = result.getDouble(result.getColumnIndex('MONTH_INCOME'))
      let balance = budget - value + month_income
      //新的支出金额
      let month_payout = value + result.getDouble(result.getColumnIndex('MONTH_PAYOUT'))
      let data = {'month_payout': month_payout, 'balance': balance}
      //执行更新操作
      return this.rdbStore.update(data,predicates)
    } else {
      let budget = result.getDouble(result.getColumnIndex('BUDGET'))
      let month_payout = result.getDouble(result.getColumnIndex('MONTH_PAYOUT'))
      let balance = budget - month_payout + value
      //新的收入金额
      let month_income = value + result.getDouble(result.getColumnIndex('MONTH_INCOME'))
      let data = {'month_income': month_income, 'balance': balance}
      //执行更新操作
      return this.rdbStore.update(data,predicates)
    }
  }
}
//创建数据模型实例
let mineModel = new MineModel();
//导出模型实例
export default mineModel as MineModel;

3、执行操作的代码

其中预算值的更新修改在mine页面中,在页面刚加载时就进行数据的查询和插入,获得初始数据,通过获取弹出框中的值来修改预算值。

在addAmount页面中,每添加一条明细都需要对总支出或者总收入进行修改,通过弹出框中获取的值,通过回调函数对总支出和总收入进行修改,同时修改预算值。

主要代码如下:

项目完成!

相关推荐
打小就很皮...2 小时前
简单实现Ajax基础应用
前端·javascript·ajax
wanhengidc3 小时前
服务器租用:高防CDN和加速CDN的区别
运维·服务器·前端
哆啦刘小洋3 小时前
HTML Day04
前端·html
再学一点就睡4 小时前
JSON Schema:禁锢的枷锁还是突破的阶梯?
前端·json
从零开始学习人工智能5 小时前
FastMCP:构建 MCP 服务器和客户端的高效 Python 框架
服务器·前端·网络
烛阴5 小时前
自动化测试、前后端mock数据量产利器:Chance.js深度教程
前端·javascript·后端
好好学习O(∩_∩)O5 小时前
QT6引入QMediaPlaylist类
前端·c++·ffmpeg·前端框架
敲代码的小吉米5 小时前
前端HTML contenteditable 属性使用指南
前端·html
testleaf6 小时前
React知识点梳理
前端·react.js·typescript
站在风口的猪11086 小时前
《前端面试题:HTML5、CSS3、ES6新特性》
前端·css3·html5