黑马健康过程记录4

一、数据模型-记录项

分析设计饮食记录数据模型,基于数据模型提供真实数据完成渲染,实现饮食数据的持久化保存。

实现的数据模型如图所示:

 数据模型代码固定,页面所需模型都在viewmodel目录下

记录项类型ItemCategory

/**
 * 记录项类型
 */
export default class ItemCategory{
  /**
   * 类型id
   */
  id: number
  /**
   * 类型名称
   */
  name: ResourceStr

  constructor(id: number, name: ResourceStr) {
    this.id = id
    this.name = name
  }
}

记录项RecordItem

/**
 * 饮食记录中的记录项,可以是食物或运动
 */
export default class RecordItem{
  /**
   * id
   */
  id: number
  /**
   * 名称
   */
  name: ResourceStr
  /**
   * 图片
   */
  image: ResourceStr
  /**
   * 分类id
   */
  categoryId: number
  /**
   * 包含的卡路里
   */
  calorie: number
  /**
   * 单位
   */
  unit: ResourceStr
  /**
   * 碳水含量,单位(克)
   */
  carbon: number
  /**
   * 蛋白质含量,单位(克)
   */
  protein: number
  /**
   * 脂肪含量,单位(克)
   */
  fat: number

  constructor(id: number, name: ResourceStr, image: ResourceStr,
              categoryId: number, unit: ResourceStr, calorie: number,
              carbon: number = 0, protein: number = 0, fat: number = 0) {
    this.id = id
    this.name = name
    this.image = image
    this.categoryId = categoryId
    this.unit = unit
    this.calorie = calorie
    this.protein = protein
    this.fat = fat
    this.carbon = carbon
  }
}

数据模型仅仅是数据格式,基于ItemCategory和RecordItem两个模型提供真实的数据和数据的查询接口,在model下创建相应的接口页面

记录项类型接口ItemCategoryModel

import ItemCategory from '../viewmodel/ItemCategory'
/**
 * 食物类型的枚举
 */
enum FoodCategoryEnum{
  /**
   * 主食
   */
  STAPLE,
  /**
   * 蔬果
   */
  FRUIT,
  /**
   * 肉蛋奶
   */
  MEAT,
  /**
   * 坚果
   */
  NUT,
  /**
   * 其它
   */
  OTHER,
}

/**
 * 食物类型数组
 */
let FoodCategories = [//食物的类型数组
  new ItemCategory(0, $r('app.string.staple')),
  new ItemCategory(1, $r('app.string.fruit')),
  new ItemCategory(2, $r('app.string.meat')),
  new ItemCategory(3, $r('app.string.nut')),
  new ItemCategory(4, $r('app.string.other_type')),
]

/**
 * 运动类型枚举
 */
enum WorkoutCategoryEnum {
  /**
   * 走路
   */
  WALKING,
  /**
   * 跑步
   */
  RUNNING,
  /**
   * 骑行
   */
  RIDING,
  /**
   * 跳操
   */
  AEROBICS,
  /**
   * 游泳
   */
  SWIMMING,
  /**
   * 打球
   */
  BALLGAME,
  /**
   * 力量训练
   */
  STRENGTH
}

/**
 * 运动类型数组
 */
let WorkoutCategories = [
  new ItemCategory(0, $r('app.string.walking_type')),
  new ItemCategory(1, $r('app.string.running')),
  new ItemCategory(2, $r('app.string.riding')),
  new ItemCategory(3, $r('app.string.aerobics')),
  new ItemCategory(4, $r('app.string.swimming')),
  new ItemCategory(5, $r('app.string.ballgame')),
  new ItemCategory(6, $r('app.string.strength')),
]

export {FoodCategories , WorkoutCategories , FoodCategoryEnum, WorkoutCategoryEnum}

记录项接口ItemModel

import RecordItem from '../viewmodel/RecordItem'
import ItemCategory from '../viewmodel/ItemCategory'
import { FoodCategories, FoodCategoryEnum, WorkoutCategories, WorkoutCategoryEnum } from './ItemCategoryModel'
import GroupInfo from '../viewmodel/GroupInfo'

const foods: RecordItem[] = [
  new RecordItem(0, '米饭',$r('app.media.rice'),FoodCategoryEnum.STAPLE, '碗',  209, 46.6, 4.7, 0.5),
  new RecordItem(1, '馒头',$r('app.media.steamed_bun'),FoodCategoryEnum.STAPLE, '个',  114, 24.0, 3.6, 0.6),
  new RecordItem(2, '面包',$r('app.media.bun'),FoodCategoryEnum.STAPLE, '个',  188, 35.2, 5.0, 3.1),
  new RecordItem(3, '全麦吐司',$r('app.media.toast'),FoodCategoryEnum.STAPLE, '片',  91, 15.5, 4.4, 1.3),
  new RecordItem(4, '紫薯',$r('app.media.purple_potato'),FoodCategoryEnum.STAPLE, '个',  163, 42.0, 1.6, 0.4),
  new RecordItem(5, '煮玉米',$r('app.media.corn'),FoodCategoryEnum.STAPLE, '根',  111, 22.6, 4.0, 1.2),
  new RecordItem(6, '黄瓜',$r('app.media.cucumber'),FoodCategoryEnum.FRUIT, '根',  29, 5.3, 1.5, 0.4),
  new RecordItem(7, '蓝莓',$r('app.media.blueberry'),FoodCategoryEnum.FRUIT, '盒',  71, 18.1, 0.9, 0.4),
  new RecordItem(8, '草莓',$r('app.media.strawberry'),FoodCategoryEnum.FRUIT, '颗',  14, 3.1, 0.4, 0.1),
  new RecordItem(9, '火龙果',$r('app.media.pitaya'),FoodCategoryEnum.FRUIT, '个',  100, 24.6, 2.2, 0.5),
  new RecordItem(10, '奇异果',$r('app.media.kiwi'),FoodCategoryEnum.FRUIT, '个',  25, 8.4, 0.5, 0.3),
  new RecordItem(11, '煮鸡蛋',$r('app.media.egg'),FoodCategoryEnum.MEAT, '个',  74, 0.1, 6.2, 5.4),
  new RecordItem(12, '煮鸡胸肉',$r('app.media.chicken_breast'),FoodCategoryEnum.MEAT, '克',  1.15, 0.011, 0.236, 0.018),
  new RecordItem(13, '煮鸡腿肉',$r('app.media.chicken_leg'),FoodCategoryEnum.MEAT, '克',  1.87, 0.0, 0.243, 0.092),
  new RecordItem(14, '牛肉',$r('app.media.beef'),FoodCategoryEnum.MEAT, '克',  1.22, 0.0, 0.23, 0.033),
  new RecordItem(15, '鱼肉',$r("app.media.fish"),FoodCategoryEnum.MEAT, '克',  1.04, 0.0, 0.206, 0.024),
  new RecordItem(16, '牛奶',$r("app.media.milk"),FoodCategoryEnum.MEAT, '毫升',  0.66, 0.05, 0.03, 0.038),
  new RecordItem(17, '酸奶',$r("app.media.yogurt"),FoodCategoryEnum.MEAT, '毫升',  0.7, 0.10, 0.032, 0.019),
  new RecordItem(18, '核桃',$r("app.media.walnut"),FoodCategoryEnum.NUT, '颗',  42, 1.2, 1.0, 3.8),
  new RecordItem(19, '花生',$r("app.media.peanut"),FoodCategoryEnum.NUT, '克',  3.13, 0.13, 0.12, 0.254),
  new RecordItem(20, '腰果',$r("app.media.cashew"),FoodCategoryEnum.NUT, '克',  5.59, 0.416, 0.173, 0.367),
  new RecordItem(21, '无糖拿铁',$r("app.media.coffee"),FoodCategoryEnum.OTHER, '毫升',  0.43, 0.044, 0.028, 0.016),
  new RecordItem(22, '豆浆',$r("app.media.soybean_milk"),FoodCategoryEnum.OTHER, '毫升',  0.31, 0.012, 0.030, 0.016),
]

const workouts: RecordItem[] = [
  new RecordItem(10000, '散步',$r('app.media.ic_walk'), WorkoutCategoryEnum.WALKING, '小时', 111),
  new RecordItem(10001, '快走',$r('app.media.ic_walk'), WorkoutCategoryEnum.WALKING, '小时',  343),
  new RecordItem(10002, '慢跑',$r('app.media.ic_running'), WorkoutCategoryEnum.RUNNING, '小时',  472),
  new RecordItem(10003, '快跑',$r('app.media.ic_running'), WorkoutCategoryEnum.RUNNING, '小时',  652),
  new RecordItem(10004, '自行车',$r('app.media.ic_ridding'), WorkoutCategoryEnum.RIDING, '小时',  497),
  new RecordItem(10005, '动感单车',$r('app.media.ic_ridding'), WorkoutCategoryEnum.RIDING, '小时',  587),
  new RecordItem(10006, '瑜伽',$r('app.media.ic_aerobics'), WorkoutCategoryEnum.AEROBICS, '小时',  172),
  new RecordItem(10007, '健身操',$r('app.media.ic_aerobics'), WorkoutCategoryEnum.AEROBICS, '小时',  429),
  new RecordItem(10008, '游泳',$r('app.media.ic_swimming'), WorkoutCategoryEnum.SWIMMING, '小时',  472),
  new RecordItem(10009, '冲浪',$r('app.media.ic_swimming'), WorkoutCategoryEnum.SWIMMING, '小时',  429),
  new RecordItem(10010, '篮球',$r('app.media.ic_basketball'), WorkoutCategoryEnum.BALLGAME, '小时',  472),
  new RecordItem(10011, '足球',$r('app.media.ic_football'), WorkoutCategoryEnum.BALLGAME, '小时',  515),
  new RecordItem(10012, '排球',$r("app.media.ic_volleyball"), WorkoutCategoryEnum.BALLGAME, '小时',  403),
  new RecordItem(10013, '羽毛球',$r("app.media.ic_badminton"), WorkoutCategoryEnum.BALLGAME, '小时',  386),
  new RecordItem(10014, '乒乓球',$r("app.media.ic_table_tennis"), WorkoutCategoryEnum.BALLGAME, '小时',  257),
  new RecordItem(10015, '哑铃飞鸟',$r("app.media.ic_dumbbell"), WorkoutCategoryEnum.STRENGTH, '小时',  343),
  new RecordItem(10016, '哑铃卧推',$r("app.media.ic_dumbbell"), WorkoutCategoryEnum.STRENGTH, '小时',  429),
  new RecordItem(10017, '仰卧起坐',$r("app.media.ic_sit_up"), WorkoutCategoryEnum.STRENGTH, '小时',  515),
]
class ItemModel {
  getById(id: number, isFood: boolean = true) {
    return isFood ? foods[id] : workouts[id - 10000]
  }
//查所有
  list(isFood: boolean = true): RecordItem[] {
    return isFood ? foods : workouts
  }
  //按组查询
  listItemGroupByCategory(isFood: boolean = true){
    //1.判断要处理的是食物还是运动
    let categories=isFood?FoodCategories:WorkoutCategories
    let items=isFood?foods:workouts
    //2.创建空的分组
    let groups=categories.map(itemCategory=>new GroupInfo(itemCategory,[]))
    //3.遍历记录项列表,将食物添加到对应的分组
    items.forEach(item=>groups[item.categoryId].items.push(item))
    //4.返回结果
    return groups
  }
}

let itemModel = new ItemModel()

export default itemModel as ItemModel
import { CommonConstants } from '../../common/constants/CommonConstants'
import ItemModel from '../../model/ItemModel'
import GroupInfo from '../../viewmodel/GroupInfo'
import ItemCategory from '../../viewmodel/ItemCategory'
import RecordItem from '../../viewmodel/RecordItem'

@Component
export default struct ItemList {
  showPanel: (item: RecordItem) => void
  @Prop isFood: boolean

  build() {
    Tabs() {
      TabContent() {
        this.TabContentBuilder(ItemModel.list(this.isFood))
      }
      .tabBar('全部')

      ForEach(
        ItemModel.listItemGroupByCategory(this.isFood),
        (group: GroupInfo<ItemCategory, RecordItem>) => {
          TabContent() {
            this.TabContentBuilder(group.items)
          }
          .tabBar(group.type.name)
        })
    }
    .width(CommonConstants.THOUSANDTH_940)
    .height('100%')
    .barMode(BarMode.Scrollable)//超出屏幕可以滚动
  }

  @Builder TabContentBuilder(items: RecordItem[]) {
    List({ space: CommonConstants.SPACE_10 }) {
      ForEach(items, (item: RecordItem) => {
        ListItem() {
          Row({ space: CommonConstants.SPACE_6 }) {
            Image(item.image).width(50)
            Column({ space: CommonConstants.SPACE_4 }) {
              Text(item.name).fontWeight(CommonConstants.FONT_WEIGHT_500)
              Text(`${item.calorie}千卡/${item.unit}`).fontSize(14).fontColor($r('app.color.light_gray'))
            }.alignItems(HorizontalAlign.Start)

            Blank()
            Image($r('app.media.ic_public_add_norm_filled'))
              .width(18)
              .fillColor($r('app.color.primary_color'))
          }
          .width('100%')
          .padding(CommonConstants.SPACE_6)
        }
        .onClick(() => this.showPanel(item))
      })
    }
    .width('100%')
    .height('100%')
  }
}
import router from '@ohos.router'
import { CommonConstants } from '../common/constants/CommonConstants'
import { RecordTypeEnum, RecordTypes } from '../model/RecordTypeModel'
import RecordService from '../service/RecordService'
import ItemCard from '../view/item/ItemCard'
import ItemList from '../view/item/ItemList'
import ItemPanelHeader from '../view/item/ItemPanelHeader'
import NumberKeyboard from '../view/item/NumberKeyboard'
import RecordItem from '../viewmodel/RecordItem'
import RecordType from '../viewmodel/RecordType'

@Extend(Button) function panelButtonStyle(){
  .width(120)
  .type(ButtonType.Normal)
  .borderRadius(6)
}

@Entry
@Component
struct ItemIndex {
  @State amount: number = 1
  @State value: string = ''
  @State showPanel: boolean = false
  @State item: RecordItem = null
  @State type: RecordType = RecordTypes[0]
  @State isFood: boolean = true

  onPanelShow(item: RecordItem) {
    this.amount = 1
    this.value = ''
    this.item = item
    this.showPanel = true
  }

  onPageShow(){
    // 1.获取跳转时的参数
    let params: any = router.getParams()
    // 2.获取点击的饮食记录类型
    this.type = params.type
    this.isFood = this.type.id !== RecordTypeEnum.WORKOUT
  }

  build() {
    Column() {
      // 1.头部导航
      this.Header()
      // 2.列表
      ItemList({ showPanel: this.onPanelShow.bind(this), isFood: this.isFood })
        .layoutWeight(1)
      // 3.底部面板
      Panel(this.showPanel) {
        // 3.1.顶部日期
        ItemPanelHeader()
        // 3.2.记录项卡片
        if(this.item){
          ItemCard({amount: this.amount, item: $item})
        }
        // 3.3.数字键盘
        NumberKeyboard({amount: $amount, value: $value})
        // 3.4.按钮
        this.PanelButton()
      }
      .mode(PanelMode.Full)
      .dragBar(false)
      .backgroundMask($r('app.color.light_gray'))
      .backgroundColor(Color.White)
    }
    .width('100%')
    .height('100%')
  }

  @Builder PanelButton(){
    Row({space: CommonConstants.SPACE_6}){
      Button('取消')
        .panelButtonStyle()
        .backgroundColor($r('app.color.light_gray'))
        .onClick(() => this.showPanel = false)
      Button('提交')
        .panelButtonStyle()
        .backgroundColor($r('app.color.primary_color'))
        .onClick(() => {
          // 1.持久化保存
          RecordService.insert(this.type.id, this.item.id, this.amount)
            .then(() => {
              // 2.关闭弹窗
              this.showPanel = false
            })
        })
    }
    .margin({top: 10})
  }

  @Builder Header() {
    Row() {
      Image($r('app.media.ic_public_back'))
        .width(24)
        .onClick(() => router.back())
      Blank()
      Text(this.type.name).fontSize(18).fontWeight(CommonConstants.FONT_WEIGHT_600)
    }
    .width(CommonConstants.THOUSANDTH_940)
    .height(32)
  }
}

二、数据模型-饮食记录

饮食记录的类型也应具有相应的模型。

实现的数据模型如图所示:

import common from '@ohos.app.ability.common';
import relationalStore from '@ohos.data.relationalStore';
import { ColumnInfo, ColumnType } from '../bean/ColumnInfo';
import Logger from './Logger';

const DB_FILENAME: string = 'HeiMaHealthy.db'

class DbUtil {
  rdbStore: relationalStore.RdbStore

  initDB(context: common.UIAbilityContext): Promise<void> {
    let config: relationalStore.StoreConfig = {
      name: DB_FILENAME,
      securityLevel: relationalStore.SecurityLevel.S1
    }
    return new Promise<void>((resolve, reject) => {
      relationalStore.getRdbStore(context, config)
        .then(rdbStore => {
          this.rdbStore = rdbStore
          Logger.debug('rdbStore 初始化完成!')
          resolve()
        })
        .catch(reason => {
          Logger.debug('rdbStore 初始化异常', JSON.stringify(reason))
          reject(reason)
        })
    })
  }

  createTable(createSQL: string): Promise<void> {//创建表
    return new Promise((resolve, reject) => {
      this.rdbStore.executeSql(createSQL)
        .then(() => {
          Logger.debug('创建表成功', createSQL)
          resolve()
        })
        .catch(err => {
          Logger.error('创建表失败,' + err.message, JSON.stringify(err))
          reject(err)
        })
    })
  }

  insert(tableName: string, obj: any, columns: ColumnInfo[]): Promise<number> {
    return new Promise((resolve, reject) => {
      // 1.构建新增数据
      let value = this.buildValueBucket(obj, columns)
      // 2.新增
      this.rdbStore.insert(tableName, value, (err, id) => {
        if (err) {
          Logger.error('新增失败!', JSON.stringify(err))//原因
          reject(err)
        } else {
          Logger.debug('新增成功!新增id:', id.toString())
          resolve(id)
        }
      })
    })
  }

  delete(predicates: relationalStore.RdbPredicates): Promise<number> {
    return new Promise((resolve, reject) => {
      this.rdbStore.delete(predicates, (err, rows) => {
        if (err) {
          Logger.error('删除失败!', JSON.stringify(err))
          reject(err)
        } else {
          Logger.debug('删除成功!删除行数:', rows.toString())
          resolve(rows)
        }
      })
    })
  }

  queryForList<T>(predicates: relationalStore.RdbPredicates, columns: ColumnInfo[]): Promise<T[]> {
    return new Promise((resolve, reject) => {
      this.rdbStore.query(predicates, columns.map(info => info.columnName), (err, result) => {
        if (err) {
          Logger.error('查询失败!', JSON.stringify(err))
          reject(err)
        } else {
          Logger.debug('查询成功!查询行数:', result.rowCount.toString())
          resolve(this.parseResultSet(result, columns))
        }
      })
    })
  }

  parseResultSet<T> (result: relationalStore.ResultSet, columns: ColumnInfo[]): T[] {//解析ResultSet
    // 1.声明最终返回的结果
    let arr = []
    // 2.判断是否有结果
    if (result.rowCount <= 0) {
      return arr
    }
    // 3.处理结果
    while (!result.isAtLastRow) {
      // 3.1.去下一行
      result.goToNextRow()
      // 3.2.解析这行数据,转为对象
      let obj = {}
      columns.forEach(info => {
        let val = null
        switch (info.type) {
          case ColumnType.LONG:
            val = result.getLong(result.getColumnIndex(info.columnName))
            break
          case ColumnType.DOUBLE:
            val = result.getDouble(result.getColumnIndex(info.columnName))
            break
          case ColumnType.STRING:
            val = result.getString(result.getColumnIndex(info.columnName))
            break
          case ColumnType.BLOB:
            val = result.getBlob(result.getColumnIndex(info.columnName))
            break
        }
        obj[info.name] = val
      })
      // 3.3.将对象填入结果数组
      arr.push(obj)
      Logger.debug('查询到数据:', JSON.stringify(obj))
    }
    return arr
  }

  buildValueBucket(obj: any, columns: ColumnInfo[]): relationalStore.ValuesBucket {
    let value = {}
    columns.forEach(info => {
      let val = obj[info.name]
      if (typeof val !== 'undefined') {
        value[info.columnName] = val
      }
    })
    return value
  }
}


let dbUtil: DbUtil = new DbUtil();

export default dbUtil as DbUtil
/**
 * 数据库存储
 */
export default class RecordPO{
  /**
   * 记录id
   */
  id?: number
  /**
   * 饮食记录类型
   */
  typeId: number
  /**
   * 记录中的食物或运动信息
   */
  itemId: number

  /**
   * 食物数量或运动时长,如果是运动信息则无
   */
  amount: number
  /**
   * 记录的日期
   */
  createTime: number
}
import RecordItem from './RecordItem'

/**
 * 饮食记录的页面数据模型
 */
export default class RecordVO {
  /**
   * 记录id
   */
  id: number
  /**
   * 饮食记录类型
   */
  typeId: number

  /**
   * 卡路里总数
   */
  calorie: number

  /**
   * 记录中的食物或运动信息
   */
  recordItem: RecordItem

  /**
   * 食物数量或运动时长,如果是运动信息则无
   */
  amount: number = 0
}
import RecordType from '../viewmodel/RecordType'

enum RecordTypeEnum {
  /**
   * 早餐
   */
  BREAKFAST,
  /**
   * 午餐
   */
  LUNCH,
  /**
   * 晚餐
   */
  DINNER,
  /**
   * 加餐
   */
  EXTRA_MEAL,
  /**
   * 运动
   */
  WORKOUT
}

/**
 * 记录类型常量
 */
const RecordTypes: RecordType[] = [
  new RecordType(0, $r("app.string.breakfast"), $r("app.media.ic_breakfast"), 423, 592),
  new RecordType(1, $r("app.string.lunch"), $r("app.media.ic_lunch"), 592, 761),
  new RecordType(2, $r("app.string.dinner"), $r("app.media.ic_dinner"), 423, 592),
  new RecordType(3, $r("app.string.extra_meal"), $r("app.media.ic_extra_m"), 0, 169),
  new RecordType(4, $r("app.string.workout"), $r("app.media.ic_workout")),
]

export {RecordTypes, RecordTypeEnum}

三、数据模型-通用DB工具

/**
 * 数据库建表语句
 */
import relationalStore from '@ohos.data.relationalStore'
import { ColumnInfo, ColumnType } from '../common/bean/ColumnInfo'
import RecordPO from '../common/bean/RecordPO'
import DbUtil from '../common/utils/DbUtil'
const CREATE_TABLE_SQL: string = `
 CREATE TABLE IF NOT EXISTS record (
   id INTEGER PRIMARY KEY AUTOINCREMENT,
   type_id INTEGER NOT NULL,
   item_id INTEGER NOT NULL,
   amount DOUBLE NOT NULL,
   create_time INTEGER NOT NULL
 )
 `
//字段信息
const COLUMNS:ColumnInfo[]=[
 {name:'id',columnName:'id',type:ColumnType.LONG},
 {name:'typeId',columnName:'type_id',type:ColumnType.LONG},
 {name:'itemId',columnName:'item_id',type:ColumnType.LONG},
 {name:'amount',columnName:'amount',type:ColumnType.DOUBLE},
 {name:'createTime',columnName:'create_time',type:ColumnType.LONG}
]

const TABLE_NAME = 'record'
const ID_COLUMN = 'id'
const DATE_COLUMN = 'create_time'

class RecordModel{
 getCreateTableSql(): string{
  return CREATE_TABLE_SQL//拿到建表语句
 }
 insert(record: RecordPO): Promise<number>{
  return DbUtil.insert(TABLE_NAME, record, COLUMNS)
 }

 deleteById(id: number): Promise<number>{
  // 1.删除条件
  let predicates = new relationalStore.RdbPredicates(TABLE_NAME)
  predicates.equalTo(ID_COLUMN, id)
  // 2.删除
  return DbUtil.delete(predicates)
 }
 listByDate(date: number): Promise<RecordPO[]>{
  // 1.查询条件
  let predicates = new relationalStore.RdbPredicates(TABLE_NAME)
  predicates.equalTo(DATE_COLUMN, date)
  // 2.查询
  return DbUtil.queryForList(predicates, COLUMNS)
 }
}
let recordModel = new RecordModel()

export default recordModel as RecordModel
/**
 * 数据库建表语句
 */
import relationalStore from '@ohos.data.relationalStore'
import { ColumnInfo, ColumnType } from '../common/bean/ColumnInfo'
import RecordPO from '../common/bean/RecordPO'
import DbUtil from '../common/utils/DbUtil'
const CREATE_TABLE_SQL: string = `
 CREATE TABLE IF NOT EXISTS record (
   id INTEGER PRIMARY KEY AUTOINCREMENT,
   type_id INTEGER NOT NULL,
   item_id INTEGER NOT NULL,
   amount DOUBLE NOT NULL,
   create_time INTEGER NOT NULL
 )
 `
//字段信息
const COLUMNS:ColumnInfo[]=[
 {name:'id',columnName:'id',type:ColumnType.LONG},
 {name:'typeId',columnName:'type_id',type:ColumnType.LONG},
 {name:'itemId',columnName:'item_id',type:ColumnType.LONG},
 {name:'amount',columnName:'amount',type:ColumnType.DOUBLE},
 {name:'createTime',columnName:'create_time',type:ColumnType.LONG}
]

const TABLE_NAME = 'record'
const ID_COLUMN = 'id'
const DATE_COLUMN = 'create_time'

class RecordModel{
 getCreateTableSql(): string{
  return CREATE_TABLE_SQL//拿到建表语句
 }
 insert(record: RecordPO): Promise<number>{
  return DbUtil.insert(TABLE_NAME, record, COLUMNS)
 }

 deleteById(id: number): Promise<number>{
  // 1.删除条件
  let predicates = new relationalStore.RdbPredicates(TABLE_NAME)
  predicates.equalTo(ID_COLUMN, id)
  // 2.删除
  return DbUtil.delete(predicates)
 }
 listByDate(date: number): Promise<RecordPO[]>{
  // 1.查询条件
  let predicates = new relationalStore.RdbPredicates(TABLE_NAME)
  predicates.equalTo(DATE_COLUMN, date)
  // 2.查询
  return DbUtil.queryForList(predicates, COLUMNS)
 }
}
let recordModel = new RecordModel()

export default recordModel as RecordModel
import UIAbility from '@ohos.app.ability.UIAbility';
import hilog from '@ohos.hilog';
import window from '@ohos.window';
import { CommonConstants } from '../common/constants/CommonConstants';
import DateUtil from '../common/utils/DateUtil';
import DbUtil from '../common/utils/DbUtil';
import PreferenceUtil from '../common/utils/PreferenceUtil'
import RecordModel from '../model/RecordModel';
export default class EntryAbility extends UIAbility {
  async onCreate(want, launchParam) {
    //1.加载用户首选项
    PreferenceUtil.loadPreference(this.context)
    //2.初始化日期
    AppStorage.SetOrCreate(CommonConstants.RECORD_DATE,DateUtil.beginTimeOfDay(new Date()))
    //3.初始化RDB工具
   await DbUtil.initDB(this.context)
    //4.创建record表
    DbUtil.createTable(RecordModel.getCreateTableSql())
    hilog.info(0x0000, 'testTag', '%{public}s', 'Ability onCreate');
  }

  onDestroy() {
    hilog.info(0x0000, 'testTag', '%{public}s', 'Ability onDestroy');
  }

  onWindowStageCreate(windowStage: window.WindowStage) {
    // Main window is created, set main page for this ability
    hilog.info(0x0000, 'testTag', '%{public}s', 'Ability onWindowStageCreate');

    windowStage.loadContent('pages/WelcomePage', (err, data) => {
      if (err.code) {
        hilog.error(0x0000, 'testTag', 'Failed to load the content. Cause: %{public}s', JSON.stringify(err) ?? '');
        return;
      }
      hilog.info(0x0000, 'testTag', 'Succeeded in loading the content. Data: %{public}s', JSON.stringify(data) ?? '');
    });
  }

  onWindowStageDestroy() {
    // Main window is destroyed, release UI related resources
    hilog.info(0x0000, 'testTag', '%{public}s', 'Ability onWindowStageDestroy');
  }

  onForeground() {
    // Ability has brought to foreground
    hilog.info(0x0000, 'testTag', '%{public}s', 'Ability onForeground');
  }

  onBackground() {
    // Ability has back to background
    hilog.info(0x0000, 'testTag', '%{public}s', 'Ability onBackground');
  }
}

效果如图所示: 

 

总结 

1.数据模型-记录项

包含了一些样式和布局的配置,如按钮样式、间距、字体大小等,以及使用@ohos.router进行页面路由跳转的逻辑。为应用程序用户提供了一个友好的界面来浏览、选择和记录他们的食品摄入和运动活动,同时提供了数据持久化的功能来存储这些记录。

2.数据模型-饮食记录

为健康饮食记录应用提供了数据库操作和数据模型的定义,使得应用能够存储、查询和管理用户的饮食和运动记录。通过 DbUtil 类,开发者可以方便地执行数据库操作,而数据模型则定义了存储和展示数据的结构。

3.数据模型-通用DB工具

展示了如何在HarmonyOS应用中使用关系型数据库进行数据持久化操作,并管理应用的生命周期。RecordModel 类作为数据访问对象模式的一部分,封装了对 record 表的所有数据库操作。EntryAbility 类作为应用的入口点,负责应用的初始化和页面加载。

  • 3
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值