[文章]OpenHarmony 3.1 Beta 样例:使用分布式菜单创建点餐神器

阅读量0
1
3
(以下内容来自开发者分享,不代表 OpenHarmony 项目群工作委员会观点)

刘丽红


随着社会的进步与发展,科技手段的推陈出新,餐饮行业也在寻求新的突破与变革,手机扫描二维码点餐系统已经成为餐饮行业的未来趋势,发展空间巨大;扫码点餐,是“互联网+餐饮”潮流的产物,可以有效地为餐厅节省人力成本,提高顾客点餐用餐效率,节省顾客时间,提高餐厅翻台率。

但是,一些老年人也在面对扫码点餐时犯了难;还有些消费者不愿意使用扫码点餐,是担心个人信息泄露等安全问题。

如此,我们设计了一款分布式菜单应用,不需要个人去关注公众号或下载小程序,服务员会提供几个点单的平板,连接店铺网络,局域网内通信,这样大家点单、查看订单详情等都不受网络限制。先上效果:

润和 HiSpark Taurus AI Camera(Hi3516d)



润和大禹系列 HH-SCDAYU200 开发板


如上动图:可由一人拉起点单平板上的点单应用,大家可同时点单,点击菜品图片进入菜品详情页面,选择口味后确认,就是一次点单完成,并自动返回到菜单首页;此时可看到下方购物车数量和总额的变化,点击下方"点好了" 可进入订单详细,并通过分布式数据库让其他人也查看订单详情,从订单详情返回到点单页后,可再进行叠加点单。

下面是 Demo 的开发说明。

一、开发说明

基于 OpenAtom OpenHarmony(以下简称“OpenHarmony”) 3.1 beta 版本,并结合方舟开发框架(ArkUI)、分布式组网、分布式数据库等特性,使用 eTS 语言开发的一款分布式菜单应用;主要体现了 OpenHarmony 分布式数据库特性,根据设计师提供的 UX ,首先就要考虑分布式数据库应该要怎么设计,需要包含哪些元素;其次 demo 是没有后台服务端,结合 ArkUI 框架,需要思考多个页面间数据怎么传递。

Demo 主要包含菜单首页、菜单详情页和订单详情页,以及加入菜单分布式数据库和结算订单分布式数据库。三个页面都需要订单列表数据,因为目前 ArkUI 框架在 app.ets 定义数据,其他页面不能直接引用,所以通过 router.push 的方法,带上 param 的参数,将数据在页面间进行传递。

两个分布式数据库,一个是订单列表数据,订单列表需要根据 UX 提供的设计图,来确认数据库中的元素,本 Demo 中的订单页面数据信息其他包括菜品的信息(图片、名称、份数、辣度等)以及点单人的信息(图片、名称和点单的数量);另一个是将下单成功通知所有人。

Demo 也还有很多待完善的点,比如:点击加/减的图标进行菜单的加减、一键清空订单、以及 Demo 是否有更好的方案来达到更好的点单体验等等,期待更多的读者们来完善。

代码结构如下图:
├─entry
  1. <p style="font-family: 微软雅黑; font-size: 18px;"></p>
  2. <pre class="language-markup" style="font-family: 微软雅黑; font-size: 18px;"><code>│  └─src
  3. │      └─main
  4. │          │  config.json  // 应用配置文件
  5. │          │  
  6. │          ├─ets
  7. │          │  └─MainAbility
  8. │          │      │  app.ets  // 应用程序主入口
  9. │          │      │  
  10. │          │      ├─model
  11. │          │      │      CommonLog.ets  // 日志类
  12. │          │      │      MenuData.ets  // 初始化菜单数据类
  13. │          │      │      MenuListDistributedData.ets  // 加入菜单分布式数据库
  14. │          │      │      RemoteDeviceManager.ets  // 分布式拉起设备管理类
  15. │          │      │      SubmitData.ets   // 结算订单分布式数据库
  16. │          │      │      
  17. │          │      └─pages
  18. │          │              detailedPage.ets // 菜品详细页面
  19. │          │              index.ets // 首页
  20. │          │              menuAccount.ets // 订单详情页面
  21. │          │              
  22. │          └─resources
  23. │              ├─base
  24. │              │  ├─element
  25. │              │  │      string.json
  26. │              │  │      
  27. │              │  ├─graphic
  28. │              │  ├─layout
  29. │              │  ├─media   // 存放媒体资源
  30. │              │  │      icon.png
  31. │              │  │      icon_add.png
  32. │              │  │      icon_back.png
  33. │              │  │      icon_cart.png</code></pre>
复制代码

二、页面编写

2.1 点单首页

效果图如上,可以分为四部分:

1)顶部页标签

  1. @Component
  2. struct PageInfo {
  3.   build() {
  4.     Flex() {
  5.       Text('点单页')
  6.         .fontSize('36lpx')
  7.     }
  8.     .padding({ left: '48lpx', top: '28lpx' })
  9.     .width('100%')
  10.     .height('10%')
  11.     .backgroundColor('#FFFFFF')
  12.   }
  13. }
复制代码

2)用户信息

• 主要用到 Flex 容器 Image 和 Text 组件;
• 用户名称和头像图标,根据设备序列号不同,可展示不同的名称和图标;
• 点击右上角分享的小图标,可分布式拉起局域网内的另一台设备。

  1. @Component
  2. struct MemberInfo {
  3.   [url=home.php?mod=space&uid=3273389]@consume[/url] userImg: Resource
  4.   @Consume userName: string
  5.   
  6.   aboutToAppear() {
  7.   // 根据设备序列号不同,展示不同的名称和图标
  8.     CommonLog.info('==serial===' + deviceInfo.serial);
  9.     if (deviceInfo.serial == '150100384754463452061bba4c3d670b') {
  10.       this.userImg = $r("app.media.icon_user")
  11.       this.userName = 'Sunny'
  12.     }
  13.     else {
  14.       this.userImg = $r("app.media.icon_user_another")
  15.       this.userName = 'Jenny'
  16.     }
  17.   }

  18.   build() {
  19.     Flex({ direction: FlexDirection.Column }) {
  20.       Flex({ direction: FlexDirection.Row, alignItems: ItemAlign.Center }) {
  21.         Image(this.userImg)
  22.           .width('96lpx')
  23.           .height('96lpx')
  24.           .margin({ right: '18lpx' })
  25.         Text(this.userName)
  26.           .fontSize('36lpx')
  27.           .fontWeight(FontWeight.Bold)
  28.           .flexGrow(1)
  29.         Image($r("app.media.icon_share"))
  30.           .width('64lpx')
  31.           .height('64lpx')
  32.       }
  33.       // 打开分布式设备列表
  34.       .onClick(() => {
  35.         this.DeviceDialog.open()
  36.       })
  37.       .layoutWeight(1)
  38.       .padding({ left: '48lpx', right: '48lpx' })

  39.       Flex({ direction: FlexDirection.Row, alignItems: ItemAlign.Center }) {
  40.         Column() {
  41.           Text('124')
  42.             .fontSize('40lpx')
  43.             .margin({ bottom: '24lpx' })
  44.           Text('积分')
  45.             .fontSize('22lpx')
  46.             .opacity(0.4)
  47.         }
  48.         .flexGrow(1)

  49.         Column() {
  50.           Text('0')
  51.             .fontSize('40lpx')
  52.             .margin({ bottom: '24lpx' })
  53.           Text('优惠劵')
  54.             .fontSize('22lpx')
  55.             .opacity(0.4)
  56.         }
  57.         .flexGrow(1)

  58.         Column() {
  59.           Image($r("app.media.icon_member"))
  60.             .width('48lpx')
  61.             .height('48lpx')
  62.             .margin({ bottom: '24lpx' })
  63.           Text('会员码')
  64.             .fontSize('22lpx')
  65.             .fontColor('#000000')
  66.             .opacity(0.4)
  67.         }
  68.         .flexGrow(1)
  69.       }
  70.       .layoutWeight(1)
  71.     }
  72.     .width('93%')
  73.     .height('25%')
  74.     .borderRadius('16lpx')
  75.     .backgroundColor('#FFFFFF')
  76.     .margin({ top: '24lpx', bottom: '32lpx' })
  77.   }
  78. }
复制代码

3)列表展示

• 主要用到 Flex 容器和 Scroll 容器 Image 和 Text 组件;
• 从首页点击列表进入菜品详细页面,点菜成功后会自动返回首页,此时列表需要动态更新菜品的数量。

  1. @Component
  2. struct MenuHome {
  3.   private specialty: any[]
  4.   private winterNew: any[]
  5.   private classic: any[]
  6.   private soup: any[]
  7.   private menuItems: MenuData[]
  8.   private titleList = ['招牌菜', '冬季新品', '下饭菜', '汤品']
  9.   @State name: string = '招牌菜'

  10.   build() {
  11.     Flex({ direction: FlexDirection.Row, alignItems: ItemAlign.Start }) {
  12.       Flex({ direction: FlexDirection.Column, justifyContent: FlexAlign.SpaceAround }) {
  13.         ForEach(this.titleList, item => {
  14.           Flex({ alignItems: ItemAlign.Center, justifyContent: FlexAlign.Start }) {
  15.             Text(item)
  16.               .fontSize('24lpx')
  17.           }
  18.           .padding({ left: '24lpx' })
  19.           .backgroundColor(this.name == item ? '#1A006A3A' : '#FFFFFF')
  20.           .height('160lpx')
  21.           .onClick(() => {
  22.             this.name = item
  23.             if (this.name == '招牌菜') {
  24.               this.menuItems = initializeOnStartup(this.specialty);
  25.             }
  26.             else if (this.name == '冬季新品') {
  27.               this.menuItems = initializeOnStartup(this.winterNew);
  28.             }
  29.             else if (this.name == '下饭菜') {
  30.               this.menuItems = initializeOnStartup(this.classic);
  31.             }
  32.             else if (this.name == '汤品') {
  33.               this.menuItems = initializeOnStartup(this.soup);
  34.             }
  35.           })
  36.         }, item => item)
  37.       }
  38.       .width('20%')
  39.       .backgroundColor('#FFFFFF')

  40.       Flex({ direction: FlexDirection.Column }) {
  41.         Text(this.name)
  42.           .fontSize('32lpx')
  43.           .fontWeight(FontWeight.Bold)
  44.           .opacity(0.4)
  45.           .height('8%')
  46.         Scroll() {
  47.           Column() {
  48.             List() {
  49.               ForEach(this.menuItems, item => {
  50.                 ListItem() {
  51.                   MenuListItem({ menuItem: item })
  52.                 }
  53.               }, item => item.id.toString())
  54.             }
  55.           }
  56.         }
  57.         .height('92%')
  58.       }
  59.       .margin({ left: '10lpx' })
  60.       .width('75%')

  61.     }
  62.     .height('50%')
  63.   }
  64. }
复制代码

4)底部总额

• 主要用到 Flex 容器和 Stack 容器 Image 和 Text 组件;
• 从首页点击列表进入菜品详细页面,点菜成功后会自动返回首页,更新订单数量和总额;
• 点击底部总额框,将订单列表加入分布式数据库,@Entry 模拟监听数据库变化,拉起订单列表详情页面。

  1. @Component
  2. struct TotalInfo {
  3.   @Consume TotalMenu: any[];
  4.   private total: number = 0;
  5.   private amount: number = 0;
  6.   private remoteData: MenuListData

  7.   aboutToAppear() {
  8.     for (var index = 0; index < this.TotalMenu.length; index++) {
  9.       this.total = this.total + this.TotalMenu[index].price * this.TotalMenu[index].quantity
  10.       this.amount = this.amount + this.TotalMenu[index].quantity
  11.     }
  12.   }

  13.   build() {
  14.     Flex({ direction: FlexDirection.Row, alignItems: ItemAlign.Center }) {
  15.       Stack({ alignContent: Alignment.Center }) {
  16.         Image($r("app.media.icon_cart"))
  17.           .width('96lpx')
  18.           .height('96lpx')
  19.           .margin({ left: '22lpx' })
  20.         Text(this.amount.toString())
  21.           .backgroundColor('#F84747')
  22.           .borderRadius('30plx')
  23.           .fontSize('24plx')
  24.           .textAlign(TextAlign.Center)
  25.           .fontColor('#FFFFFF')
  26.           .width('50lpx')
  27.           .height('50lpx')
  28.           .margin({ left: '100lpx', bottom: '85lpx' })
  29.       }
  30.       .width('150lpx')
  31.       .height('150lpx')

  32.       Text('¥')
  33.         .fontSize('22lpx')
  34.         .fontColor('#006A3A')
  35.         .margin({ left: '22lpx' })
  36.       Text(this.total.toString())
  37.         .fontSize('40lpx')
  38.         .fontColor('#006A3A')
  39.         .flexGrow(1)
  40.       Text('点好了')
  41.         .height('100%')
  42.         .width('35%')
  43.         .fontColor('#FFFFFF')
  44.         .backgroundColor('#F84747')
  45.         .textAlign(TextAlign.Center)
  46.     }
  47.     // 将总的订单数据,加入分布式数据库
  48.     .onClick(() => {
  49.       this.remoteData.putData("menu_list", this.TotalMenu)
  50.     })
  51.     .width('100%')
  52.     .height('10%')
  53.     .backgroundColor('#FFFFFF')
  54.   }
  55. }
复制代码

2.2 菜品详情页

效果图如上,可以分为三部分:

1)顶部页标签

  1. @Component
  2. struct PageInfo {
  3.   build() {
  4.     Flex() {
  5.       Text('点单页')
  6.         .fontSize('36lpx')
  7.     }
  8.     .padding({ left: '48lpx', top: '28lpx' })
  9.     .width('100%')
  10.     .height('10%')
  11.     .backgroundColor('#FFFFFF')
  12.   }
  13. }
复制代码

2)菜单详情

• 主要用到 Flex 容器 Image 和 Text 组件 Button 组件;
• 辣度可以选择。

  1. @Component
  2. struct detailInfo {
  3.   private menuItem
  4.   private spicyList = ['正常辣', '加辣', '少辣']
  5.   @State spicy: string = '正常辣'
  6.   private TotalMenu: any[]
  7.   private index = 0
  8.   private userName: string

  9.   build() {
  10.     Flex({ direction: FlexDirection.Column, alignItems: ItemAlign.Center }) {
  11.       Flex({ direction: FlexDirection.Column, alignItems: ItemAlign.Start, justifyContent: FlexAlign.Start }) {
  12.         Flex({ direction: FlexDirection.Row }) {
  13.           Button()
  14.             .backgroundColor('#006A3A ')
  15.             .width('8lpx')
  16.             .height('48lpx')
  17.             .margin({ right: '12lpx' })
  18.           Text('辣度')
  19.         }
  20.         .margin({ left: '44lpx', top: '48lpx', bottom: '32lpx' })

  21.         Flex({ direction: FlexDirection.Row, justifyContent: FlexAlign.SpaceEvenly }) {
  22.           ForEach(this.spicyList, item => {

  23.             Button(item)
  24.               .fontSize('28lpx')
  25.               .height('60lpx')
  26.               .width('156lpx')
  27.               .borderRadius('12lpx')
  28.               .backgroundColor(this.spicy == item ? '#006A3A' : '#0D000000')
  29.               .fontColor(this.spicy == item ? '#FFFFFF' : '#000000')

  30.               .onClick(() => {
  31.                 this.spicy = item
  32.               })
  33.           }, item => item)
  34.         }
  35.       }
  36.       .margin({ top: '56lpx' })
  37.       .width('92%')
  38.       .height('50%')
  39.       .borderRadius('16lpx')
  40.       .backgroundColor('#FFFFFF')
  41.     }
  42.   }
  43. }
复制代码

3)点击按钮

• 点击选好了,需要判断该菜品是否已经在总订单里面,并判断是哪一个用户添加,根据判断,做出相应的增加。

  1. Button('选好了')
  2.         .fontSize('36lpx')
  3.         .width('80%')
  4.         .height('7%')
  5.         .backgroundColor('#F84747')
  6.         .onClick(() => {
  7.           for (this.index = 0; this.index < this.TotalMenu.length; this.index++) {
  8.             if (this.TotalMenu[this.index].name == this.menuItem.name && this.TotalMenu[this.index].spicy == this.spicy) {
  9.               this.TotalMenu[this.index].quantity = this.TotalMenu[this.index].quantity + 1;
  10.               if (this.userName == 'Sunny') {
  11.                 this.TotalMenu[this.index].userNumber = this.TotalMenu[this.index].userNumber + 1;
  12.               } else if (this.userName == 'Jenny') {
  13.                 this.TotalMenu[this.index].anotherUserNumber = this.TotalMenu[this.index].anotherUserNumber + 1;
  14.               }
  15.               break;
  16.             }
  17.           }
  18.           // 菜名不一样,辣度不一样,都需要重新push到列表里面
  19.           if (this.index == this.TotalMenu.length) {
  20.             this.menuItem.spicy = this.spicy;
  21.             this.menuItem.quantity = 1;
  22.             //根据不用的用户名称,
  23.             if (this.userName == 'Sunny') {
  24.               this.menuItem.userNumber = 1;
  25.             } else if (this.userName == 'Jenny') {
  26.               this.menuItem.anotherUserNumber = 1;
  27.             }
  28.             this.TotalMenu.push(this.menuItem);
  29.           }
  30.           router.push({
  31.             uri: 'pages/index',
  32.             params: { menuItem: this.menuItem, TotalMenu: this.TotalMenu }
  33.           })
  34.         })
  35.         .margin({ top: '10%' })
复制代码

2.3 订单详情页

效果如上,可以分为三部分:

1)订单列表

• 主要用到 Flex 容器 Image 和 Text 组件 Button 组件;
• 展示不同用户加入菜单数量。

  1. <pre class="language-markup" style="font-family: 微软雅黑;"><code>@Component
  2. struct TotalItem {
  3.   private totalMenu: MenuData

  4.   build() {
  5.     Flex({ direction: FlexDirection.Column }) {
  6.       Flex({ direction: FlexDirection.Row, alignContent: FlexAlign.Start, justifyContent: FlexAlign.Start }) {
  7.       if (this.totalMenu.userNumber > 0) {
  8.         Flex({ direction: FlexDirection.Row, alignItems: ItemAlign.Center }) {
  9.           Image(this.totalMenu.userImg)
  10.             .width('96lpx')
  11.             .height('96lpx')
  12.           Text(this.totalMenu.userName)
  13.             .fontSize('36lpx')
  14.             .fontWeight(FontWeight.Bold)
  15.             .margin({ left: '12lpx' })
  16.             .flexGrow(1)
  17.           Text(this.totalMenu.userNumber.toString())
  18.             .fontSize('32lpx')
  19.             .margin({ right: '11plx' })

  20.         }
  21.         .height('150lpx')
  22.       }
  23.       if (this.totalMenu.anotherUserNumber > 0) {
  24.         Flex({ direction: FlexDirection.Row, alignItems: ItemAlign.Center }) {
  25.           Image(this.totalMenu.anotherUserImg)
  26.             .width('96lpx')
  27.             .height('96lpx')
  28.           Text(this.totalMenu.anotherUserName)
  29.             .fontSize('36lpx')
  30.             .fontWeight(FontWeight.Bold)
  31.             .margin({ left: '12lpx' })
  32.             .flexGrow(1)
  33.           Text(this.totalMenu.anotherUserNumber.toString())
  34.             .fontSize('32lpx')
  35.             .margin({ right: '11plx' })

  36.         }
  37.         .height('150lpx')
  38.       }
  39.     }
  40.     .margin({ top: '12lpx' })
  41.     .borderRadius('16lpx')
  42.     .padding({ left: '3%', right: '3%', top: '2%' })
  43.     .backgroundColor('#FFFFFF')
  44.   }
  45. }</code></pre>
  46. <p></p>
复制代码

2)下单按钮

• 点击下单,将"submitOk" 加入分布式数据库,监听数据库变化后,弹出自定义对话框。

  1. @Component
  2. struct SubmitList {
  3.   private remoteData: SubmitData
  4.   private SubmitOK: any[] = [
  5.     {
  6.       submit: "submitOk"
  7.     }
  8.   ];

  9.   build() {
  10.     Flex({ alignItems: ItemAlign.Center, justifyContent: FlexAlign.Center }) {
  11.       Text('下单')
  12.         .fontSize('36lpx')
  13.         .fontColor('#FFFFFF')
  14.     }
  15.     .width('100%')
  16.     .height('10%')
  17.     .backgroundColor('#F84747')
  18.     .onClick(() => {
  19.       this.remoteData.putData("submit", this.SubmitOK)
  20.     })
  21.     .margin({ top: '5%' })
  22.   }
  23. }
复制代码

3)自定义弹框

• 通过 @CustomDialog 装饰器来创建自定义弹窗,使用方式可参考 自定义弹窗;
• 规则弹窗效果如下,弹窗组成由一个 Image 和两个 Text 竖向排列组成;
• 在 build()下使用 Flex 容器来包裹,组件代码如下:

  1. @CustomDialog
  2. struct SubmitDialog {
  3.   private controller: CustomDialogController

  4.   build() {
  5.     Flex({ direction: FlexDirection.Column, alignItems: ItemAlign.Center }) {
  6.       Flex({ justifyContent: FlexAlign.Center }) {
  7.         Image($r("app.media.icon_success"))
  8.           .width('100lpx')
  9.           .height('80lpx')
  10.       }
  11.       .flexGrow(1)

  12.       Text('下单成功')
  13.         .fontSize('36lpx')
  14.         .fontColor('#000000')
  15.         .flexGrow(1)
  16.       Text('*温馨提示:菜品具体售卖情况请以店面实际情况为准哦~')
  17.         .fontSize('22lpx')
  18.         .opacity(0.6)
  19.         .fontColor('#000000')
  20.         .padding({ left: '10lpx', right: '10lpx' })
  21.     }
  22.     .height('300lpx')
  23.     .width('100%')
  24.     .padding({ top: '50lpx', bottom: '20lpx' })

  25.   }
  26. }
复制代码

• 在 @entry 模块创建 CustomDialogController 对象并传入弹窗所需参数,设置点击允许点击遮障层退出,通过 open() 方法,显示弹窗。

  1. SubmitDialog: CustomDialogController = new CustomDialogController({
  2.     builder: SubmitDialog(),
  3.     autoCancel: true
  4.   })
  5. aboutToAppear() {
  6.   
  7.     this.remoteData.createManager(() => {
  8.       let self = this
  9.       var data;
  10.       if (JSON.stringify(self.remoteData.dataItem).length > 0) {
  11.         data = self.remoteData.dataItem;
  12.         CommonLog.info("======submit==" + data[0].submit);
  13.         if (data[0].submit == "submitOk") {
  14.           this.SubmitDialog.open()
  15.         }
  16.       }
  17.     }, "com.distributed.order", "submit")
  18.   }
复制代码

三、分布式数据管理

OpenHarmony 技术特性包括分布式数据管理、分布式任务调度等;分布式数据管理基于分布式软总线的能力,实现应用程序数据和用户数据的分布式管理。用户数据不再与单一物理设备绑定,业务逻辑与数据存储分离,跨设备的数据处理如同本地数据处理一样方便快捷,让开发者能够轻松实现全场景、多设备下的数据存储、共享和访问,为打造一致、流畅的用户体验创造了基础条件。

3.1 开发步骤

分布式数据管理要求两个或多个设备在同一网络。开发步骤:

1)导入模块

  1. import distributedData from '@ohos.data.distributedData';
复制代码

2)创建一个 KVManager 对象实例,用于管理数据库对象;注意 bundleName 需要修改为自己的包名。

  1. let kvManager;
  2. try {
  3.     const kvManagerConfig = {
  4.         bundleName : 'com.distributed.order',
  5.         userInfo : {
  6.             userId : '0',
  7.             userType : distributedData.UserType.SAME_USER_ID
  8.         }
  9.     }
  10.     distributedData.createKVManager(kvManagerConfig, function (err, manager) {
  11.         if (err) {
  12.             console.log("createKVManager err: "  + JSON.stringify(err));
  13.             return;
  14.         }
  15.         console.log("createKVManager success")
  16.         kvManager = manager
  17.     });
  18. } catch (e) {
  19.     console.log("An unexpected error occurred. Error:" + e);
  20. }
复制代码

3)通过指定 Options 和 storeId,创建并获取 KVStore 数据库,如下是参数说明;需要先通过 createKVManager 构建一个 KVManager 实例。

  1. let kvStore;
  2. let kvManager;
  3. try {
  4.     const options = {
  5.         createIfMissing : true,
  6.         encrypt : false,
  7.         backup : false,
  8.         autoSync : true,
  9.         kvStoreType : distributedData.KVStoreType.SINGLE_VERSION,
  10.         securityLevel : distributedData.SecurityLevel.S2,
  11.     };
  12.     kvManager.getKVStore('storeId', options, function (err, store) {
  13.         if (err) {
  14.             console.log("getKVStore err: "  + JSON.stringify(err));
  15.             return;
  16.         }
  17.         console.log("getKVStore success");
  18.         kvStore = store
  19.     });
  20. } catch (e) {
  21.     console.log("An unexpected error occurred. Error:" + e);
  22. }
复制代码

4)KVStore 数据库实例, KVStore.put 提供增加数据的方法,如下是参数说明。

  1. let kvStore;
  2. try {
  3.     kvStore.put(key, value, function (err,data) {
  4.         if (err != undefined) {
  5.             console.log("put err: " + JSON.stringify(err))
  6.             return;
  7.         }
  8.         console.log("put success");
  9.     });
  10. }catch (e) {
  11.     console.log("An unexpected error occurred. Error:" + e);
  12. }
复制代码

5) KVStore 数据库实例,KVStore.on 订阅指定类型的数据变更通知;一般监听远端设备变化,再进行相应操作达到分布式数据共享的效果。

  1. let kvStore;
  2. kvStore.on('dataChange', distributedData.SubscribeType.SUBSCRIBE_TYPE_LOCAL, function (data) {
  3.     console.log("dataChange callback call data: " + JSON.stringify(data));
  4. });
复制代码

6)具体开发请参考分布式数据管理:

3.2 应用示例

本项目通过 storeId (数据库唯一标识符)值不同,创建了两个数据管理类,分别是 MenuListData 类和 SubmitData 类,即 Demo 中的 MenuListDistributedData.ets SubmitData.ets 文件。

1)MenuListData 是将完整订单添加到分布式数据库,当监听到数据库变化时,获取完整订单列表,并通过 router.push 接口将数据传递到订单详情页面展示。

• 创建一个 MenuListData 类

  1. private remoteData: MenuListData = new MenuListData()
复制代码

• 定义一个订单列表集合,集合中的元素包括菜单信息和点单用户信息;点菜后就根据菜品名称和辣度的不同,对订单数据集合进行修改或增加。

  1. TotalMenu: any[] = [
  2.   {
  3.     "imgSrc": "",   // 菜品图片
  4.     "name": "",     // 菜品名称
  5.     "remarks": "",  // 菜品备注
  6.     "price": 0,     // 菜品价格
  7.     "quantity": 0,  // 菜品数量
  8.     "spicy": "",    //辣度
  9.     "userImg": ,   
  10.     "userName": "",
  11.     "userNumber": 0,
  12.     "anotherUserImg": "",
  13.     "anotherUserName": "",
  14.     "anotherUserNumber": 0,
  15.   }];
复制代码

• 将订单数据加入到分布式数据库

  1. this.remoteData.putData("menu_list", this.TotalMenu)
复制代码

• 监听数据库变化,获取数据,并将数据传递到 menuAccount 订单详情页面;

  1. this.remoteData.createManager(() => {
  2.       let self = this
  3.       var data
  4.       if (JSON.stringify(self.remoteData.dataItem).length > 0) {
  5.         data = self.remoteData.dataItem
  6.         var list = []
  7.         for (var i = 0; i < data.length; i++) {
  8.           list[i] = data[i]
  9.         }
  10.         router.push({
  11.           uri: 'pages/menuAccount',
  12.           params: { TotalMenu: list }
  13.         })
  14.       }
  15.     })
复制代码

2)SubmitData 在订单结算时点击下单,将 submitOK 集合添加到数据库,表示下单完成,监听到数据库变化,各设备弹出下单成功提示框;

• 创建一个 SubmitData 类

  1. private remoteData: SubmitData = new SubmitData();
复制代码

• 定义一个 SubmitOK 集合,这里用集合主要是为了处理数据方便

  1. private SubmitOK: any[] = [
  2.     {
  3.       submit: "submitOk"
  4.     }
  5.   ]
复制代码

• 添加 SubmitOK 集合到数据库中

  1. this.remoteData.putData("submit", this.SubmitOK)
复制代码

• 监听到数据库变化,获取数据并比较是 submitOK 后,弹出提示框,告知所有人下单成功。

  1. this.remoteData.createManager(() => {
  2.       let self = this
  3.       var data
  4.       if (JSON.stringify(self.remoteData.dataItem).length > 0) {
  5.         data = self.remoteData.dataItem
  6.         if (data[0].submit == "submitOk") {
  7.           this.SubmitDialog.open()
  8.         }
  9.       }
  10.     })
复制代码

更完整的分布式数据库的使用,请参考 Demo。

四、项目下载和导入

1)git 下载

  1. git clone https://gitee.com/openharmony-sig/knowledge_demo_temp.git
复制代码

2)项目导入

打开 DevEco Studio,点击 File->Open->下载路径/FA/Shopping/DistributedOrder

3)硬件约束

需要下载对应开发板镜像(https://gitee.com/openharmony/docs/blob/master/zh-cn/release-notes/OpenHarmony-v3.1-beta.md)进行烧录;如下图:

五、分享与共建

丰富多样的 OpenHarmony 开发样例离不开广大合作伙伴和开发者的贡献,如果你开发出了更好的 OpenHarmony 开发样例,并愿意分享给广大开发者学习,请 Fork 并 Pull Request 到如下仓库,共建 OpenHarmony 开发样例。

若您不清楚如何提交代码到仓库,请参考代码贡献教程,我们等着你的 Pull Request。(https://gitee.com/openharmony-sig/knowledge_demo_smart_home/blob/master/dev/docs/contribute/README.md)。

回帖

声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容图片侵权或者其他问题,请联系本站作侵删。 侵权投诉
链接复制成功,分享给好友