【保举+1】HarmonyOS官方模板良好案例 (第4期:餐饮行业 · 美食菜谱)

[复制链接]
发表于 2025-8-28 14:12:43 | 显示全部楼层 |阅读模式

马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。

您需要 登录 才可以下载或查看,没有账号?立即注册

×
💡 鸿蒙生态为开发者提供海量的HarmonyOS模板/组件,助力开发效率原地起飞 💡
★ 一键直达生态市场组件&模板市场 , 快速应用DevEco Studio插件市场集成组件&模板 ★
好用的菜谱APP能够帮助饮食管理事半功倍!

小编本期为大家介绍餐饮行业案例

👉 覆盖20+行业,本帖以汇总形式持续更新中,点击收藏!一键三连!常看常新!
【第4期】餐饮行业 · 美食菜谱

一、概述

1. 行业洞察

1)行业痛点:


  • 传统餐饮私域流量缺失,依赖第三方平台导流,佣金本钱高且较难沉淀用户。
  • 网络菜谱步骤描述模糊,用料配比不准确,乐成率低。
  • 个性化不敷:缺乏根据用户口味偏好、饮食限制(素食/低糖/无麸质)的智能保举。
  • 购物未便:菜谱食材无法一键购买,特别调料难以配齐。
  • 数据代价未挖掘:用户烹饪行为数据未形成精准画像。
  • 互动体验差:用户作品分享渠道单一,缺乏专业厨师点评指导。
2)行业常用三方SDK

分类
三方库名称
功能
支持情况
SDK链接
媒体
阿里云视频播放器SDK
音视频
已支持
支付宝SDK
微信支付SDK
银联SDK
腾讯QQ SDK
新浪微博SDK
极光PUSH SDK
友盟移动统计SDK
腾讯微信SDK
高德地图SDK
个推
Bugly
ShareSDK
听云SDK
登录认证
中国移动一键登录SDK/易盾一键登录SDK/创蓝闪验/极光安全认证/阿里云号码认证SDK/中国电信一键登录SDK
登录
已支持
分享
友盟/ShareSDK/微信分享/QQ分享/新浪微博SDK/MobTech ShareSDK
统计/推送/分享
已支持
支付
支付宝支付/微信支付/银联支付
支付
已支持
数据分析
友盟移动统计SD/神策数据SDK
数据收集、处理、分析、运用
已支持
性能监控
腾讯Bugly SDK/听云SDK/岳鹰全景监控SDK
异常上报和运营统计
已支持
地图
高德地图SDK
地图
已支持
推送
个推/华为推送/极光PUSH/阿里推送SDK
消息推送
已支持
媒体
阿里云视频播放器SDK
音视频
已支持
说明:“以上三方库及链接仅为示例,三方库由三方开发者独立提供,以其官方内容为准”
2. 案例概览(下载模板)

基于以上行业分析,本期将介绍鸿蒙生态市场餐饮行业模板——美食菜谱应用模板,为行业提供常用功能的开发案例,涵盖分类搜刮、作品分享、菜谱用料、热量计算、饮食计划等多个实用功能。

  • Stage开发模型 + 声明式UI开发范式。
  • 分层架构设计 + 组件化拆分,支持开发者在开发时既可以选择完整使用模板,也可以根据需求单独选用此中的业务组件。
  • 集成华为账号、支付等服务,只需做少量设置和定制即可快速实现华为账号的登录、菜谱上传等功能。

本模板紧张页面及核心功能如下所示:


二、应用架构设计

1. 分层模块化设计


  • 产物定制层:专注于满足差别设备或使用场景的个性化需求,作为应用的入口,是用户直接互动的界面。

    • 本实践暂时只支持直板机,为单HAP包形式,包罗路由根节点、底部导航栏等。

  • 基础特性层:用于存放相对独立的功能UI和业务逻辑实现。

    • 本实践的基础特性层将应用底部导航栏的每个选项拆分成一个独立的业务功能模块,包罗首页、分类、热量计算和我的。
    • 每个功能模块都具备高内聚、低耦合、可定制的特点,支持产物的灵活摆设。

  • 公共能力层:存放公共能力,包罗公共UI组件、数据管理、外部交互和工具库等共享功能。

    • 本实践的公共能力层分为公共基础能力和可分可合组件,均打包为HAR包被上层业务组件引用。
    • 公共基础能力包罗日志、文件处理等工具类,公共范例界说,网络库,以及弹窗、加载等公共组件。
    • 可分可合组件将包罗行业特点、可完全自闭环的能力抽出独立的组件模块,支持开发者在开发中单独集成使用,详见业务组件设计章节。


2. 业务组件设计

为支持开发者单独获取特定场景的页面和功能,例如开发者已搭建了一个本身的美食菜谱元服务工程,只想单独取用本模板中的菜篮子或热量计算功能,本模板将功能完全自闭环的部门能力抽离出独立的行业组件模块,不依赖公共基础能力包,开发者可以单独集成,开箱即用,降低使用难度。

三、行业场景技能方案

1. 账号管理

1)场景说明

支持华为账号一键登录及其他方式(账号密码登录、微信登录)。
用户登录后展示昵称和头像,点击用户信息栏可进入用户主页,检察并编辑个人信息。

2)技能方案


  • 华为账号一键登录

  • 微信登录

    • 根据鸿蒙接入指南接入微信SDK,可通过跳转微信并获取微信用户授权进行登录。

  • 头像修改

    • 通过Scenario Fusion Kit提供的选择头像Button快速拉起头像选择页面,供用户完成华为账号头像或其他头像的选择与展示。

3)代码参考


  • 部门核心代码拜见个人信息实现章节。
2. 分类搜刮

1)场景说明


  • 支持按菜谱分类展示和搜刮菜谱,点击菜谱可以检察菜谱详细信息。

2)技能方案
使用List和Grid组件实现分类列表的展示、一连滚动以及搜刮结果展示。
3)代码参考

  • 部门核心代码拜见分类搜刮实现章节。
3. 饮食计划

1)场景说明

支持制定饮食计划的食材,也可以自界说食材并填写热量。

2)技能方案


  • 列表展示
  • 使用List和ListItemGroup实现列表的一连滚动,并快速滚动到指定分类。
  • 自界说添加食物
  • 使用bindSheet方法对当前页面绑定半模态弹框,实现自界说食物的添加。
4. 热量计算

1)场景说明

支持检察当日饮食热量摄入情况,大概检察一周热量摄入统计。

2)技能方案


  • 使用Progress绘制环形数据统计,使用LinearGradient实现环形颜色的渐变结果。
  • 使用三方库@ohos/mpchart绘制柱状图,展示一周热量摄入信息。
3)代码参考


  • 部门核心代码拜见热量计算实现章节。
四、模板代码

1. 工程结构(下载模板)

详细代码结构如下所示:
  1. Recipes
  2.   ├─commons/commonlib/src/main
  3.   │  ├─ets
  4.   │  │  ├─components
  5.   │  │  │      BaseHeader.ets                 // 一级页面标题组件
  6.   │  │  │      BuildTitleBar.ets              // 二级页面标题组件
  7.   │  │  │      HeaderMenuBuilder.ets          // 标题菜单内容组件
  8.   │  │  │      MenuItemBuilder.ets            // 下拉菜单选项
  9.   │  │  ├─constants
  10.   │  │  │      CommonContants.ets             // 公共常量
  11.   │  │  │      CommonEnums.ets                // 公共枚举值
  12.   │  │  ├─types
  13.   │  │  │      Types.ets                      // 公共抽象类
  14.   │  │  └─utils
  15.   │  │         AccountUtil.ets                // 账号工具类
  16.   │  │         DialogUtil.ets                 // 弹窗工具类
  17.   │  │         FormatUtil.ets                 // 格式化工具类
  18.   │  │         Logger.ets                     // 日志工具类
  19.   │  │         PermissionUtil.ets             // 权限获取工具类
  20.   │  │         PreferenceUtil.ets             // 数据持久化工具类
  21.   │  │         RouterModule.ets               // 路由工具类
  22.   │  │         WindowUtil.ets                 // 窗口管理工具类
  23.   │  └─resources
  24.   ├─commons/network/src/main
  25.   │  ├─ets
  26.   │  │  ├─apis
  27.   │  │  │      APIList.ets                    // 网络请求API
  28.   │  │  │      HttpRequest.ets                // 网络请求
  29.   │  │  ├─mocks
  30.   │  │  │  └─MockData
  31.   │  │  │         Calories.ets                // 热量mock数据
  32.   │  │  │         Mine.ets                    // 我的mock数据
  33.   │  │  │         Notice.ets                  // 通知mock数据
  34.   │  │  │         RecipeList.ets              // 菜谱mock数据
  35.   │  │  │      AxiosMock.ets                  // mock请求
  36.   │  │  │      RequestMock.ets                // mock API
  37.   │  │  └─types
  38.   │  │         Calories.ets                   // 热量抽象类
  39.   │  │         Member.ets                     // 会员抽象类
  40.   │  │         Notice.ets                     // 通知抽象类
  41.   │  │         Recipe.ets                     // 菜谱抽象类
  42.   │  └─resources
  43.   │─components/aggregated_ads/src/main   
  44.   │  ├─ets
  45.   │  │  ├─common
  46.   │  │  │      Constant.ets                   // 常量类
  47.   │  │  ├─components
  48.   │  │  │      AdServicePage.ets              // 广告服务组件
  49.   │  │  │      HwAdService.ets                // 华为广告
  50.   │  │  ├─util
  51.   │  │  │      UIUtil.ets                     // UI工具类
  52.   │  │  └─viewmodel
  53.   │  │         AggreagetedAdVM.ets            // 广告页面数据模型
  54.   │  └─resources
  55.   │─components/aggregated_login/src/main   
  56.   │  ├─ets
  57.   │  │  ├─common
  58.   │  │  │      Constant.ets                   // 常量类
  59.   │  │  │      Logger.ets                     // 日志类
  60.   │  │  ├─components
  61.   │  │  │      AgreementDialog.ets            // 协议弹窗组件
  62.   │  │  │      LoginService.ets               // 登录组件
  63.   │  │  ├─model
  64.   │  │  │      Index.ets                      // 数据类型
  65.   │  │  │      WXApiWrap.ets                  // 微信登录数据类型
  66.   │  │  └─viewmodel
  67.   │  │         AggregatedLoginVM.ets          // 登录组件数据模型
  68.   │  └─resources
  69.   │─components/aggregated_payment/src/main   
  70.   │  ├─ets
  71.   │  │  ├─common
  72.   │  │  │      Constant.ets                   // 常量类
  73.   │  │  ├─components
  74.   │  │  │      AggregatedPaymentPicker.ets    // 支付组件
  75.   │  │  ├─model
  76.   │  │  │      Index.ets                      // 数据类型
  77.   │  │  │      WXApiWrap.ets                  // 微信支付数据类型
  78.   │  │  └─viewmodel
  79.   │  │         AggregatedPaymentVM.ets        // 支付组件数据模型
  80.   │  └─resources
  81.   │─components/base_ui/src/main   
  82.   │  ├─ets
  83.   │  │  ├─components
  84.   │  │  │      BaseTabs.ets                   // Tabs组件
  85.   │  │  └──types
  86.   │  │         Index.ets                      // 数据类型
  87.   │  └─resources
  88.   │─components/calorie_calculation/src/main   
  89.   │  ├─ets
  90.   │  │  ├─components
  91.   │  │  │      BarChart.ets                   // 协议弹窗组件
  92.   │  │  │      CalorieCalculation.ets         // 热量计算组件
  93.   │  │  │      CaloriesSummary.ets            // 热量汇总组件
  94.   │  │  │      FoodDiary.ets                  // 饮食计划组件
  95.   │  │  ├─types
  96.   │  │  │      Index.ets                      // 数据类型
  97.   │  │  └─viewModels
  98.   │  │         CaloriesSummaryVM.ets          // 热量计算数据模型
  99.   │  └─resources
  100.   │─components/featured_recipes/src/main   
  101.   │  ├─ets
  102.   │  │  ├─components
  103.   │  │  │      FeaturedRecipes.ets            // 菜谱瀑布流组件
  104.   │  │  │      RecommendedCard.ets            // 菜谱卡片
  105.   │  │  │─types
  106.   │  │  │      Index.ets                      // 数据类型
  107.   │  │  └─utils
  108.   │  │         LazyDataSource.ets             // 懒加载对象
  109.   │  │         Logger.ets                     // 日志工具
  110.   │  │         ObservedArray.ets              // 数组监听工具
  111.   │  └─resources
  112.   │─components/home_search/src/main   
  113.   │  ├─ets
  114.   │  │  ├─components
  115.   │  │  │      HomeSearch.ets                 // 搜索组件
  116.   │  │  │      SearchKeys.ets                 // 热搜词组件
  117.   │  │  │      SearchResult.ets               // 搜索结果组件
  118.   │  │  └─types
  119.   │  │         Index.ets                      // 数据类型
  120.   │  └─resources
  121.   │─components/link_category/src/main   
  122.   │  ├─ets
  123.   │  │  ├─components
  124.   │  │  │      LinkCategory.ets               // 分类列表组件
  125.   │  │  └─types
  126.   │  │         Index.ets                      // 数据类型
  127.   │  └─resources
  128.   │─components/personal_homepage/src/main   
  129.   │  ├─ets
  130.   │  │  ├─components
  131.   │  │  │      BloggerInfomation.ets          // 个人介绍组件
  132.   │  │  │      PersonalHomepage.ets           // 个人中心组件
  133.   │  │  └─types
  134.   │  │         Index.ets                      // 数据类型
  135.   │  └─resources
  136.   │─components/shopping_basket/src/main   
  137.   │  ├─ets
  138.   │  │  ├─components
  139.   │  │  │      IngredientList.ets             // 用料列表
  140.   │  │  │      PurchaseIngredients.ets        // 用料组件
  141.   │  │  │      ShoppingBasket.ets             // 菜篮子组件
  142.   │  │  └─types
  143.   │  │         Index.ets                      // 数据类型
  144.   │  └─resources
  145.   │─components/upload_recipe/src/main   
  146.   │  ├─ets
  147.   │  │  ├─components
  148.   │  │  │      UploadRecipe.ets               // 上传菜谱组件
  149.   │  │  ├─types
  150.   │  │  │      Index.ets                      // 数据类型
  151.   │  │  └─viewmodel
  152.   │  │         UploadRecipeVM.ets             // 上传菜谱数据模型
  153.   │  └─resources
  154.   │─features/calories/src/main   
  155.   │  ├─ets
  156.   │  │  ├─pages
  157.   │  │  │      CaloriesPage.ets               // 热量页面
  158.   │  │  │      DietPlanPage.ets               // 饮食计划食物列表页面
  159.   │  │  │      SearchFoodPage.ets             // 食物搜索页面
  160.   │  │  ├─types
  161.   │  │  │      Index.ets                      // 数据对象
  162.   │  │  └─viewModels
  163.   │  │         CaloriesPageVM.ets             // 热量页面数据模型
  164.   │  │         DietPlanPageVM.ets             // 食物列表页面数据模型
  165.   │  │         SearchFoodPageVM.ets           // 食物搜索页面数据模型
  166.   │  └─resources
  167.   │─features/classification/src/main   
  168.   │  ├─ets
  169.   │  │  ├─constants
  170.   │  │  │      Enums.ets                      // 枚举数据
  171.   │  │  ├─pages
  172.   │  │  │      ClassificationPage.ets         // 分类页面
  173.   │  │  │      DishesPage.ets                 // 菜谱详情页面
  174.   │  │  │      ShoppingBasketPage.ets         // 菜篮子页面
  175.   │  │  ├─types
  176.   │  │  │      Index.ets                      // 菜谱数据对象
  177.   │  │  └─viewModels
  178.   │  │         ClassificationVM.ets           // 分类页面数据模型
  179.   │  │         DishesVM.ets                   // 菜谱详情页面数据模型
  180.   │  └─resources
  181.   │─features/home/src/main   
  182.   │  ├─ets
  183.   │  │  ├─pages
  184.   │  │  │      BloggerProfilePage.ets         // 博主信息页面
  185.   │  │  │      FollowersPage.ets              // 博主关注页面
  186.   │  │  │      HomePage.ets                   // 首页页面
  187.   │  │  │      SearchPage.ets                 // 搜索页面
  188.   │  │  ├─types
  189.   │  │  │      Index.ets                      // 首页数据对象
  190.   │  │  └─viewModels
  191.   │  │         BloggerProfilePageVM.ets       // 博主信息页面数据模型
  192.   │  │         FollowersPageVM.ets            // 博主关注页面数据模型
  193.   │  │         HomePageVM.ets                 // 首页页面数据模型
  194.   │  │         SearchPageVM.ets               // 搜索页面数据模型
  195.   │─features/mine/src/main   
  196.   │  ├─ets
  197.   │  │  ├─components
  198.   │  │  │      ConfirmDialogComponent.ets     // 确认弹窗组件
  199.   │  │  │      Recipes.ets                    // 菜谱卡片组件
  200.   │  │  ├─mapper
  201.   │  │  │      Index.ets                      // 数据映射
  202.   │  │  ├─model
  203.   │  │  │      Index.ets                      // 数据类型
  204.   │  │  ├─pages
  205.   │  │  │      BrowsingHistory.ets            // 浏览历史页面
  206.   │  │  │      MemberCenterPage.ets           // 会员中心页面
  207.   │  │  │      MinePage.ets                   // 我的页面
  208.   │  │  │      MyCollection.ets               // 我的收藏页面
  209.   │  │  │      NoticeCenterPage.ets           // 通知中心页面
  210.   │  │  │      NoticeDetailPage.ets           // 通知详情页面
  211.   │  │  │      PersonalInfo.ets               // 个人信息页面
  212.   │  │  │      PrivacyPolicyDetailPage.ets    // 用户协议页面
  213.   │  │  │      QuickLoginPage.ets             // 一键登录页面
  214.   │  │  │      SettingsPage.ets               // 设置页面
  215.   │  │  │      SideBarPage.ets                // 服务菜单页面
  216.   │  │  │      TermsOfServicePage.ets         // 隐私政策页面
  217.   │  │  │      UploadRecipe.ets               // 上传菜谱页面
  218.   │  │  ├─types
  219.   │  │  │      Index.ets                      // 抽象类
  220.   │  │  ├─util
  221.   │  │  │      MockApi.ets                    // 支付mock数据
  222.   │  │  │      OrderInfoUtil.ets              // 支付mock参数工具
  223.   │  │  │      SignUtils.ets                  // 支付mock签名工具
  224.   │  │  └─viewModels
  225.   │  │         BrowsingHistoryVM.ets          // 浏览历史页面数据模型
  226.   │  │         MemberCenterPageVM.ets         // 会员中心页面数据模型
  227.   │  │         MinePageVM.ets                 // 我的页面数据模型
  228.   │  │         MyCollectionVM.ets             // 我的收藏页面数据模型
  229.   │  │         MyRecipeVM.ets                 // 我的菜谱页面数据模型
  230.   │  │         NoticeCenterPageVM.ets         // 通知中心页面数据模型
  231.   │  │         SettingsPageVM.ets             // 设置页面数据模型
  232.   │  │         UploadRecipeVM.ets             // 上传菜谱页面数据模型
  233.   │  └─resources
  234.   └─products/entry/src/main   
  235.      ├─ets
  236.      │  ├─entryability
  237.      │  │      EntryAbility.ets               // 应用程序入口
  238.      │  ├─entryformability
  239.      │  │      EntryFormAbility.ets           // 卡片程序入口
  240.      │  ├─pages
  241.      │  │      Index.ets                      // 入口页面
  242.      │  │      LaunchAdPage.ets               // 广告页面
  243.      │  │      LaunchPage.ets                 // 开屏页面
  244.      │  │      MainEntry.ets                  // 主页面
  245.      │  │      PrivacyPolicyPage.ets          // 隐私协议页面
  246.      │  ├─types
  247.      │  │      Types.ets                      // 抽象类
  248.      │  ├─viewModels
  249.      │  │      MainEntryVM.ets                // 入口页面数据
  250.      │  └─widget/pages
  251.      │         WidgetCard.ets                 // 卡片页面
  252.      └─resources
复制代码
2. 关键代码解读

本篇代码非应用的全量代码,只包罗应用的部门能力的关键代码。
若需获取全量代码,请检察模板集成章节。
1)个人信息

  • 华为账号一键登录
  1. ​javascript
  2. // components/aggregated_login/src/main/ets/components/LoginService.ets
  3. // 登录组件
  4. LoginWithHuaweiIDButton({
  5.     params: {
  6.         style: loginComponentManager.Style.BUTTON_CUSTOM,
  7.         loginType: loginComponentManager.LoginType.QUICK_LOGIN,
  8.         supportDarkMode: true,
  9.         customButtonParams: {
  10.             fontColor: loginComponentManager.FontColor.WHITE,
  11.             backgroundColor: this.loginBtnBgColor,
  12.         },
  13.     },
  14.     controller: this.controller,
  15. });
  16. ...
  17. // 登录方法控制器
  18. controller: loginComponentManager.LoginWithHuaweiIDButtonController =
  19.     new loginComponentManager.LoginWithHuaweiIDButtonController()
  20. // 需要用户同意协议才能完成华为账号登录,请先设置协议状态为NOT_ACCEPTED,当用户同意协议后设置协议状态为ACCEPTED,才可以完成华为账号登录
  21.     .setAgreementStatus(loginComponentManager.AgreementStatus.NOT_ACCEPTED)
  22.     .onClickLoginWithHuaweiIDButton((error: BusinessError, response: loginComponentManager.HuaweiIDCredential) => {
  23.     // 处理用户点击一键登录按钮逻辑,灰度传入undefined模拟流程,应用申请权限后,传入error
  24.     this.handleLoginWithHuaweiIDButton(undefined, response);
  25. });
  26. ...
  27. // 处理点击一键登录后的方法
  28. handleLoginWithHuaweiIDButton(error: BusinessError | undefined,
  29.                               response: loginComponentManager.HuaweiIDCredential) {
  30.     this.enableStatus = false;
  31.     // if部分内容配置好可用的调试证书和client_id后再放开
  32.     if (error) {
  33.         Logger.error(this.domainId, this.logTag,
  34.                      `Failed to click LoginWithHuaweiIDButton. Code is ${error.code}, message is ${error.message}`);
  35.         this.error = error;
  36.         if (error.code === LoginErrorCode.ERROR_CODE_NETWORK_ERROR) {
  37.             AlertDialog.show(
  38.                 {
  39.                     message: 'No Internet connection. Check your network settings. ',
  40.                     offset: { dx: 0, dy: -12 },
  41.                     alignment: DialogAlignment.Bottom,
  42.                     autoCancel: false,
  43.                     confirm: {
  44.                         value: 'OK',
  45.                         action: () => {
  46.                         },
  47.                     },
  48.                 },
  49.             );
  50.         } else if (error.code === LoginErrorCode.ERROR_CODE_AGREEMENT_STATUS_NOT_ACCEPTED) {
  51.             // 未同意协议,弹出协议弹框,推荐使用该回调方式
  52.             this.agreementDialog.open();
  53.             this.customerDiaLogOpen = true;
  54.         } else if (error.code === LoginErrorCode.ERROR_CODE_LOGIN_OUT) {
  55.             // 华为账号未登录提示
  56.             this.showToast($r('app.string.not_login_in'));
  57.         } else if (error.code === LoginErrorCode.ERROR_CODE_NOT_SUPPORTED) {
  58.             // 账号不支持该scopes或permissions提示
  59.             this.showToast($r('app.string.scope_not_supported'));
  60.         } else if (error.code === LoginErrorCode.ERROR_CODE_NOT_REQUIRED_SCOPE_OR_PERMISSION) {
  61.             // 应用没有申请scope权限
  62.             this.showToast($r('app.string.app_not_required_scopes_or_permissions'));
  63.         } else {
  64.             // 其他提示系统或服务异常
  65.             this.showToast($r('app.string.service_error'));
  66.         }
  67.         this.enableStatus = true;
  68.         return;
  69.     }
  70.     try {
  71.         if (this.isSelected) {
  72.             // 配置好可用的调试证书和client_id后需要处理response
  73.             Logger.info(this.domainId, this.logTag, 'Succeed in clicking LoginWithHuaweiIDButton.');
  74.             if (this.response.idToken !== undefined) {
  75.                 this.response = response;
  76.                 // 模拟登录成功后回调
  77.                 this.loginFinishedCb(true, this.unionID)
  78.             }
  79.             // 模拟登录成功后回调
  80.             this.loginFinishedCb(false)
  81.         } else {
  82.             this.agreementDialog.open();
  83.             this.customerDiaLogOpen = true;
  84.         }
  85.     } catch (e) {
  86.         Logger.info(this.domainId, this.logTag,
  87.                     `Failed to LoginWithHuaweiIDButton, errCode: ${e.code}, errMessage: ${e.message}`);
  88.         AlertDialog.show(
  89.             {
  90.                 message: $r('app.string.service_error'),
  91.                 offset: { dx: 0, dy: -12 },
  92.                 alignment: DialogAlignment.Bottom,
  93.                 autoCancel: false,
  94.                 confirm: {
  95.                     value: 'OK',
  96.                     action: () => {
  97.                     },
  98.                 },
  99.             },
  100.         );
  101.     } finally {
  102.         this.enableStatus = true;
  103.     }
  104. }
复制代码
2)分类搜刮


  • 分类列表
  1. ​javascript
  2. // components/link_category/src/main/ets/components/LinkCategory.ets
  3. // 列表页
  4. Row() {
  5.     List({ space: 8, scroller: this.titleItemScroller }) {
  6.         ForEach(this.recipeCategoryList, (item: RecipeCategory, index: number) => {
  7.             ListItem() {
  8.                 this.leftListBuilder(item.name, index)
  9.             }
  10.         }, (item: RecipeCategory, index: number) => item.name + index)
  11.     }
  12.     .width(92)
  13.     .height('100%')
  14.     .backgroundColor('#F1F3F5')
  15.     .listDirection(Axis.Vertical) // 排列方向
  16.     .scrollBar(BarState.Off)
  17.     .contentStartOffset(12)
  18.     .contentEndOffset(12)
  19.     List({ space: 12, scroller: this.scroller }) {
  20.         ForEach(this.recipeCategoryList, (item: RecipeCategory) => {
  21.             ListItemGroup({
  22.                 header: this.listTitleBuilder(item.name),
  23.                 space: 12,
  24.             }) {
  25.                 ListItem() {
  26.                     Grid() {
  27.                         ForEach(item.recipeList, (listItem: RecipeBriefInfo) => {
  28.                             GridItem() {
  29.                                 Column() {
  30.                                     Image($r(`app.media.${listItem.thumbnail}`)).width(76).height(76).borderRadius(8)
  31.                                     Text(listItem.title)
  32.                                         .fontSize(14)
  33.                                         .fontWeight(FontWeight.Medium)
  34.                                         .fontColor($r('sys.color.font_primary'))
  35.                                         .textAlign(TextAlign.Center)
  36.                                         .constraintSize({ maxWidth: 76 })
  37.                                         .maxLines(2)
  38.                                         .margin({ top: 4 })
  39.                                         .textOverflow({ overflow: TextOverflow.Ellipsis })
  40.                                 }
  41.                             }.onClick(() => {
  42.                                 this.onRecipeClick(listItem)
  43.                             })
  44.                         }, (listItem: RecipeBriefInfo) => `${item.id}${listItem.id}`)
  45.                     }
  46.                     .rowsGap(8)
  47.                     .columnsGap(8)
  48.                     .columnsTemplate('1fr 1fr 1fr')
  49.                 }
  50.             }
  51.         }, (item: RecipeCategory) => item.id.toString())
  52.     }
  53.     .layoutWeight(1)
  54.     .height('100%')
  55.     .margin({ left: 8, right: 16 })
  56.     .scrollBar(BarState.Off)
  57.     .sticky(StickyStyle.None)
  58.     .contentStartOffset(12)
  59.     .contentEndOffset(12)
  60.     .onScrollIndex((start: number) => this.currentIndexChangeAction(start, false))
  61. }.layoutWeight(1)
  62. ...
  63. // 下标索引处理
  64. currentIndexChangeAction(index: number, isClassify: boolean): void {
  65.     if (this.currentIndex !== index) {
  66.         this.changeCurrentIndex(index);
  67.         if (isClassify) {
  68.             this.scroller.scrollToIndex(index);
  69.         } else {
  70.             this.titleItemScroller.scrollToIndex(index);
  71.         }
  72.     }
  73. }
复制代码
3)热量计算

  • 环形图
  1. javascript
  2. // commons/lib_common/src/main/ets/utils/LoginUtils.ets
  3. // 环形组件
  4. Progress({ value: this.todayCalories, total: 2000, type: ProgressType.Ring })
  5.             .width(176).style({ strokeWidth: 20 })
  6.             .color(this.vm.gradientColor)
  7. ...
  8. // components/calorie_calculation/src/main/ets/viewModels/CaloriesSummaryVM.ets
  9. // 渐变色设置
  10. gradientColor: LinearGradient =
  11.     new LinearGradient([{ color: '#C6F093', offset: 0.25 }, { color: '#83CE26', offset: 0.5 },
  12.                         { color: '#88DB23', offset: 0.85 }, { color: '#88DB24', offset: 1.0 }])
复制代码

  • 柱状图
  1. javascript
  2. // components/calorie_calculation/src/main/ets/components/BarChart.ets
  3. // 柱状图参数设置
  4. this.name = this.xData[this.xData.length - 1]
  5. this.rate = this.seriesData[this.seriesData.length - 1]
  6. // Step1:必须:初始化图表配置构建类
  7. this.model = new BarChartModel();
  8. // Step2:配置图表指定样式,各部件间没有先后之分
  9. // 为图表添加数据选择的监听器
  10. this.model.setOnChartValueSelectedListener(this.valueSelectedListener);
  11. // 获取图表描述部件,设置图表描述部件不可用,即图表不进行绘制描述部件
  12. let description: Description | null = this.model.getDescription()
  13. if (description) {
  14.     description.setEnabled(false);
  15. }
  16. // 获取图表图例部件,设置图表图例部件不可用
  17. let legend: Legend | null = this.model.getLegend();
  18. if (legend) {
  19.     legend.setEnabled(false);
  20. }
  21. // 设置图表数据最大的绘制数,如果超过该数值,则不进行绘制图表的数值标签
  22. this.model.setMaxVisibleValueCount(7);
  23. // 为左Y轴设置LimitLine,可设置限制线的宽度,线段样式,限制标签的位置,标签字体大小等
  24. this.limitLine1 = new LimitLine(120, 'Upper Limit');
  25. this.limitLine1.setLineWidth(4);
  26. //设置虚线样式
  27. this.limitLine1.enableDashedLine(10, 10, 0);
  28. //设置标签位置
  29. this.limitLine1.setLabelPosition(LimitLabelPosition.RIGHT_TOP);
  30. this.limitLine1.setTextSize(10);
  31. this.limitLine2 = new LimitLine(50, 'Lower Limit');
  32. this.limitLine2.setLineWidth(4);
  33. this.limitLine2.enableDashedLine(10, 10, 0);
  34. this.limitLine2.setLineColor(Color.Yellow);
  35. this.limitLine2.setLabelPosition(LimitLabelPosition.RIGHT_BOTTOM);
  36. this.limitLine2.setTextSize(10);
  37. // 设置图表左Y轴信息
  38. this.leftAxis = this.model.getAxisLeft();
  39. if (this.leftAxis) {
  40.     //设置绘制标签个数
  41.     this.leftAxis.setLabelCount(7, false);
  42.     //设置标签位置
  43.     this.leftAxis.setPosition(YAxisLabelPosition.OUTSIDE_CHART)
  44.     //设置距离顶部距离
  45.     this.leftAxis.setSpaceTop(15);
  46.     //设置最小值
  47.     this.leftAxis.setAxisMinimum(0);
  48.     //设置最大值
  49.     this.leftAxis.setAxisMaximum(2000);
  50.     this.leftAxis.setGridDashedLine({ dash: [2, 2, 0], offset: 0 })
  51.     this.leftAxis.setTextColor('#E6000000')
  52.     this.leftAxis.setTextSize(12)
  53. }
  54. // 设置图表右Y轴信息
  55. this.rightAxis = this.model.getAxisRight();
  56. if (this.rightAxis) {
  57.     this.rightAxis.setEnabled(false);
  58. }
  59. class YAxisValueFormatter implements IAxisValueFormatter {
  60.     getFormattedValue(value: number, axis: AxisBase): string {
  61.         //将原本存在的对应的value转换成需要的字符串
  62.         return value.toString();
  63.     }
  64. }
  65. this.leftAxis?.setValueFormatter(new YAxisValueFormatter())
  66. // 设置X轴信息
  67. this.xAxis = this.model.getXAxis();
  68. if (this.xAxis) {
  69.     this.xAxis.setPosition(XAxisPosition.BOTTOM);
  70.     this.xAxis.setDrawGridLines(false);
  71.     this.xAxis.setGranularity(1);
  72.     this.xAxis.setLabelCount(this.xData.length);
  73.     this.xAxis.setTextColor('#E6000000')
  74.     this.xAxis.setTextSize(12)
  75. }
  76. class XAxisValueFormatter implements IAxisValueFormatter {
  77.     data: string[] = []
  78.     constructor(data: string[]) {
  79.         this.data = data
  80.     }
  81.     getFormattedValue(value: number, axis: AxisBase): string {
  82.         //将原本存在的对应的value转换成需要的字符串
  83.         let day = new Date().getDay() - 1
  84.         if (day === value) {
  85.             return '今日'
  86.         }
  87.         return xMap[value];
  88.     }
  89. }
  90. this.xAxis?.setValueFormatter(new XAxisValueFormatter(this.xData))
  91. // 生成图表数据
  92. let barData: BarData = this.getBarData();
  93. // 将数据与图表配置类绑定
  94. this.model.setData(barData);
  95. // 设置图表最大的X轴显示范围,如不设置,则默认显示全部数据
  96. this.model.setVisibleXRangeMaximum(20);
  97. ...
  98. // 柱状图组件
  99. BarChart({ model: this.model }).width('100%').height(190)
复制代码
3. 模板集成

本模板提供了两种代码集成方式,供开发者自由选用。
1)整体集成(下载模板)

开发者可以选择直接基于模板工程开发本身的应用工程。

  • 模板代码获取:

  • 打开模板工程,根据README说明中的快速入门章节,将本身的应用信息设置在模板工程内,即可运行并检察模板结果。


  • 对接开发者本身的服务器接口,转换数据结构,展示真实的云侧数据。
将commons/lib_common/src/main/ets/httprequest/HttpRequestApi.ets文件中的mock接口更换为真实的服务器接口。

在commons/lib_common/src/main/ets/httprequest/HttpRequest.ets文件中将云侧开发者自界说的数据结构转换为端侧数据结构。

根据本身的业务内容修改模板,进行定制化开发。
2)按需集成

若开发者已搭建好本身的应用工程,但暂未实现此中的部门场景能力,可以选择取用此中的业务组件,集成在本身的工程中。

  • 组件代码获取:

  • 下载组件源码,根据README中的说明,将组件包设置在本身的工程中。


  • 根据API参考和示例代码,将组件集成在本身的对应场景中。
以上是第四期“餐饮行业-美食菜谱”行业良好案例的内容,更多行业敬请等待~
欢迎下载使用行业模板“点击下载”,若您有体验和开发问题,大概迫不及待想相识XX行业的良好案例,欢迎在评论区留言,小编会快马加鞭为您解答~


👉 本系列持续更新,欢迎点击帖子末尾左下角“
”收藏本帖!
期数
帖子
链接
第1期
HarmonyOS官方模板良好案例 | 便捷生活行业 · 购物中心
点击检察
第2期
HarmonyOS官方模板良好案例 | 消息行业 · 综合消息
点击检察
第3期
HarmonyOS官方模板良好案例 | 教诲行业 · 教诲备考
点击检察
第4期
HarmonyOS官方模板良好案例 | 餐饮行业 · 美食菜谱
点击检察
第5期
HarmonyOS官方模板良好案例 | 工具行业 · 日历应用
点击检察
第6期
小编加急整理中,敬请等待
 
👉 HarmonyOS组件模板干系保举


  • 【活动ing】HarmonyOS组件/模板集成创新活动,报名时间截止2025年8月30日,点击检察
  • 鸿蒙应用开发者激励计划2025,点击检察
回复

使用道具 举报

登录后关闭弹窗

登录参与点评抽奖  加入IT实名职场社区
去登录
快速回复 返回顶部 返回列表