基于HarmonyOS的情侣美食管理应用开发实战

基于HarmonyOS的情侣美食管理应用开发实战
基于HarmonyOS的情侣美食管理应用开发实战一- 项目设计与角色管理-1 系列文章目录一项目设计与角色管理本文二菜谱管理与订单系统三美食相册与设置功能四数据库优化与问题解决…一、项目背景与需求分析1.1 项目灵感在情侣日常生活中经常面临这样的场景主厨不知道今天该做什么菜食客想吃什么但不知道如何表达做过的美食没有记录下次想做时找不到想要记录一起品尝美食的美好时光基于这些痛点我开发了一款情侣美食管理应用帮助情侣更好地规划、记录和分享美食时光。1.2 核心功能功能模块主厨角色食客角色角色管理选择成为主厨管理菜谱选择成为食客浏览点餐菜谱管理添加、编辑、删除菜谱浏览菜谱、查看详情订单管理接单、完成订单点餐、查看订单状态美食相册上传美食照片浏览、点赞美食照片设置页面修改个人信息、清除数据修改个人信息、清除数据1.3 技术选型开发框架HarmonyOS ArkUI声明式UI开发语言ArkTSTypeScript扩展数据存储关系型数据库RDB状态管理State、Prop、Link装饰器UI设计HarmonyOS设计规范二、项目架构设计2.1 目录结构entry/src/main/ets/ ├── common/ # 公共工具类 │ ├── CommonConstant.ets # 常量定义 │ ├── LogUtil.ets # 日志工具 │ ├── RdbUtil.ets # 数据库工具 │ └── PreferencesUtil.ets # 偏好设置工具 ├── model/ # 数据模型 │ ├── Recipe.ets # 菜谱模型 │ ├── Order.ets # 订单模型 │ ├── GalleryImage.ets # 相册图片模型 │ └── CoupleConfig.ets # 情侣配置模型 ├── pages/ # 页面 │ ├── SplashPage.ets # 启动页 │ ├── RoleSelectPage.ets # 角色选择页 │ ├── ChefHomePage.ets # 主厨首页 │ ├── DinerHomePage.ets # 食客首页 │ ├── RecipeManagePage.ets # 菜谱管理页 │ ├── OrderManagePage.ets # 订单管理页 │ ├── GalleryPage.ets # 美食相册页 │ └── SettingsPage.ets # 设置页 └── entryability/ └── EntryAbility.ets # 应用入口2.2 数据库设计2.2.1 情侣配置表couple_configCREATETABLEIFNOTEXISTScouple_config(idINTEGERPRIMARYKEYAUTOINCREMENT,space_nameTEXTNOTNULL,-- 空间名称chef_nameTEXTNOTNULL,-- 主厨昵称diner_nameTEXTNOTNULL,-- 食客昵称create_timeINTEGERNOTNULL-- 创建时间)2.2.2 菜谱表recipeCREATETABLEIFNOTEXISTSrecipe(idINTEGERPRIMARYKEYAUTOINCREMENT,nameTEXTNOTNULL,-- 菜谱名称typeINTEGERNOTNULL,-- 菜谱类型0-荤菜 1-素菜 2-汤品 3-主食 4-甜点imageTEXT,-- 菜谱图片ingredientsTEXT,-- 食材清单stepsTEXT,-- 制作步骤create_timeINTEGERNOTNULL-- 创建时间)2.2.3 订单表order_recordCREATETABLEIFNOTEXISTSorder_record(idINTEGERPRIMARYKEYAUTOINCREMENT,recipe_idINTEGERNOTNULL,-- 菜谱IDrecipe_nameTEXTNOTNULL,-- 菜谱名称recipe_imageTEXT,-- 菜谱图片statusINTEGERDEFAULT0,-- 订单状态0-待接单 1-制作中 2-已完成remarkTEXT,-- 备注信息order_timeINTEGERNOTNULL,-- 下单时间accept_timeINTEGER,-- 接单时间complete_timeINTEGER,-- 完成时间FOREIGNKEY(recipe_id)REFERENCESrecipe(id)ONDELETECASCADE)2.2.4 美食相册表gallery_imgCREATETABLEIFNOTEXISTSgallery_img(idINTEGERPRIMARYKEYAUTOINCREMENT,imageTEXTNOTNULL,-- 图片路径descriptionTEXT,-- 图片描述create_timeINTEGERNOTNULL-- 创建时间)三、角色管理功能实现3.1 启动页设计启动页负责初始化数据库检查用户角色状态路由到对应页面// SplashPage.ets 核心逻辑asyncaboutToAppear(){// 初始化数据库awaitRdbUtil.init(this.context)// 检查角色状态constroleawaitPreferencesUtil.get(current_role,)if(rolechef){// 主厨角色 - 跳转主厨首页router.replaceUrl({url:pages/ChefHomePage})}elseif(rolediner){// 食客角色 - 跳转食客首页router.replaceUrl({url:pages/DinerHomePage})}else{// 无角色 - 跳转角色选择页router.replaceUrl({url:pages/RoleSelectPage})}}3.2 角色选择页面角色选择页面功能输入空间名称情侣专属空间输入主厨昵称输入食客昵称选择角色主厨/食客保存配置并跳转3.2.1 页面布局// 核心UI结构Column(){// 标题Text(创建美食空间).fontSize(28).fontWeight(FontWeight.Bold)// 表单输入TextInput({placeholder:请输入空间名称}).onChange((value)this.spaceNamevalue)TextInput({placeholder:请输入主厨昵称}).onChange((value)this.chefNamevalue)TextInput({placeholder:请输入食客昵称}).onChange((value)this.dinerNamevalue)// 角色选择Row(){Button(我是主厨).onClick(()this.selectRole(chef))Button(我是食客).onClick(()this.selectRole(diner))}}3.2.2 数据保存逻辑asyncselectRole(role:string){// 1. 构建配置数据constvalues:relationalStore.ValuesBucket{space_name:this.spaceName.trim(),chef_name:this.chefName.trim(),diner_name:this.dinerName.trim(),create_time:Date.now()}// 2. 检查是否已有配置constpredicatesnewrelationalStore.RdbPredicates(couple_config)constresultSetawaitRdbUtil.query(predicates)consthasExistingresultSet.rowCount0resultSet.close()// 3. 保存到数据库if(hasExisting){awaitRdbUtil.update(couple_config,values,predicates)}else{awaitRdbUtil.insert(couple_config,values)}// 4. 保存角色到偏好设置awaitPreferencesUtil.put(current_role,role)// 5. 跳转到对应首页consttargetPagerolechef?pages/ChefHomePage:pages/DinerHomePagerouter.replaceUrl({url:targetPage})}3.3 角色持久化机制3.3.1 为什么需要持久化用户选择角色后希望下次打开应用时自动进入对应页面无需重复选择。这需要将角色信息持久化存储。3.3.2 持久化方案使用Preferences存储角色信息// PreferencesUtil.etsexportclassPreferencesUtil{privatestaticpreferences:preferences.Preferences|nullnull// 初始化staticasyncinit(context:Context){PreferencesUtil.preferencesawaitpreferences.getPreferences(context,my_preferences)}// 保存数据staticasyncput(key:string,value:string){awaitPreferencesUtil.preferences?.put(key,value)awaitPreferencesUtil.preferences?.flush()}// 读取数据staticasyncget(key:string,defaultValue:string){returnawaitPreferencesUtil.preferences?.get(key,defaultValue)asstring}}四、首页功能实现4.1 主厨首页主厨首页包含四个功能模块菜谱管理订单管理美食相册设置// ChefHomePage.ets 核心结构EntryComponentstruct ChefHomePage{StatecoupleConfig:CoupleConfig{id:0,space_name:,chef_name:未命名,diner_name:未命名,create_time:0}asyncaboutToAppear(){awaitthis.loadCoupleConfig()}asyncloadCoupleConfig(){constpredicatesnewrelationalStore.RdbPredicates(couple_config)constresultSetawaitRdbUtil.query(predicates)if(resultSet.goToFirstRow()){this.coupleConfig{id:resultSet.getLong(resultSet.getColumnIndex(id)),space_name:resultSet.getString(resultSet.getColumnIndex(space_name)),chef_name:resultSet.getString(resultSet.getColumnIndex(chef_name)),diner_name:resultSet.getString(resultSet.getColumnIndex(diner_name)),create_time:resultSet.getLong(resultSet.getColumnIndex(create_time))}}resultSet.close()}build(){Column(){// 顶部标题栏Row(){Text(主厨${this.coupleConfig.chef_name}).fontSize(18).fontWeight(FontWeight.Bold)Blank()Text(this.coupleConfig.space_name).fontSize(16).fontColor(#666666)}.width(100%).padding(16)// 功能模块网格Grid(){GridItem(){this.MenuItem(菜谱管理,$r(app.media.ic_recipe))}.onClick((){router.pushUrl({url:pages/RecipeManagePage})})GridItem(){this.MenuItem(订单管理,$r(app.media.ic_order))}.onClick((){router.pushUrl({url:pages/OrderManagePage})})GridItem(){this.MenuItem(美食相册,$r(app.media.ic_gallery))}.onClick((){router.pushUrl({url:pages/GalleryPage})})GridItem(){this.MenuItem(设置,$r(app.media.ic_settings))}.onClick((){router.pushUrl({url:pages/SettingsPage})})}.columnsTemplate(1fr 1fr).rowsTemplate(1fr 1fr)}}}4.2 食客首页食客首页与主厨首页类似但功能权限不同菜谱浏览只读点餐下单美食相册设置五、遇到的问题与解决方案5.1 问题角色选择后显示未命名问题描述选择角色并提交后跳转到首页左上角显示主厨未命名或食客未命名但数据库中已有数据。问题分析数据库表结构与代码模型不匹配原表缺少space_name字段数据插入失败但未报错解决方案步骤1修正数据库表结构-- 修改前CREATETABLEIFNOTEXISTScouple_config(idINTEGERPRIMARYKEYAUTOINCREMENT,chef_nameTEXTNOTNULL,diner_nameTEXTNOTNULL,chef_avatarTEXT,diner_avatarTEXT,create_timeINTEGERNOTNULL,update_timeINTEGERNOTNULL)-- 修改后CREATETABLEIFNOTEXISTScouple_config(idINTEGERPRIMARYKEYAUTOINCREMENT,space_nameTEXTNOTNULL,-- ✅ 新增字段chef_nameTEXTNOTNULL,diner_nameTEXTNOTNULL,create_timeINTEGERNOTNULL)步骤2添加强制重建数据库逻辑// RdbUtil.etsstaticasyncinit(context:Context):Promisevoid{// 删除旧数据库强制重建开发阶段try{awaitrelationalStore.deleteRdbStore(context,CommonConstant.DB_NAME)LogUtil.info(RdbUtil.TAG,已删除旧数据库将重新创建)}catch(err){LogUtil.info(RdbUtil.TAG,数据库不存在或删除失败继续创建新数据库)}// 创建新数据库RdbUtil.rdbStoreawaitrelationalStore.getRdbStore(context,config)awaitRdbUtil.createTables()}5.2 问题清除缓存后角色丢失问题描述用户清除应用缓存后preferences被清除但数据库数据还在导致角色丢失但配置仍存在。解决方案在角色选择页加载已有配置自动填充表单// RoleSelectPage.etsasyncloadExistingConfig(){constpredicatesnewrelationalStore.RdbPredicates(couple_config)constresultSetawaitRdbUtil.query(predicates)if(resultSet.goToFirstRow()){this.spaceNameresultSet.getString(resultSet.getColumnIndex(space_name))this.chefNameresultSet.getString(resultSet.getColumnIndex(chef_name))this.dinerNameresultSet.getString(resultSet.getColumnIndex(diner_name))LogUtil.info(RoleSelectPage,已加载历史配置)}resultSet.close()}六、总结本篇文章介绍了情侣美食管理应用的整体架构设计和角色管理功能的实现。主要内容包括项目架构清晰的目录结构模块化设计数据库设计四张核心表满足业务需求角色管理启动页、角色选择页、持久化机制问题解决数据库表结构修正、强制重建机制下一篇文章将详细介绍菜谱管理和订单系统的实现包括菜谱的增删改查图片上传与展示订单流程管理状态同步机制

最新新闻

日新闻

周新闻

月新闻