基于HarmonyOS的情侣美食管理应用开发实战(十)- 点餐清单与提交订单

0 阅读4分钟

基于HarmonyOS的情侣美食管理应用开发实战(十)- 点餐清单与提交订单

📖 系列文章目录

  • (一)项目设计与角色管理
  • (二)菜谱管理与订单系统
  • (三)美食相册与设置功能
  • (四)数据库优化与问题解决
  • (五)数据持久化问题修复
  • (六)图片显示问题修复
  • (七)菜谱详情页面开发
  • (八)收藏功能实现
  • (九)食客菜谱浏览功能
  • (十)点餐清单与提交订单(本文)
  • (十一)主厨订单处理功能
  • (十二)双向订单记录查询

一、功能概述

1.1 需求分析

食客在浏览菜谱后,需要能够发起正式的点餐请求。本章节将实现完整的点餐流程,包括:

  • 菜谱详情展示:展示菜谱的完整信息(食材、步骤)
  • 备注功能:食客可以添加口味偏好和特殊要求
  • 快捷备注:提供常用备注选项,一键添加
  • 订单提交:将点餐信息保存到数据库

1.2 功能特点

信息完整:展示菜谱的所有相关信息
备注灵活:支持自定义备注和快捷选择
交互友好:卡片式布局,操作便捷
数据准确:订单信息完整保存到数据库


二、订单数据模型

2.1 Order模型定义

export class Order {
  id: number = 0
  recipeId: number = 0           // 菜谱ID
  recipeName: string = ''        // 菜谱名称
  recipeImage: string = ''       // 菜谱图片
  status: number = 0             // 订单状态
  remark: string = ''            // 口味备注
  orderTime: number = 0          // 下单时间
  acceptTime: number = 0         // 接单时间
  completeTime: number = 0       // 完成时间
  createTime: number = 0         // 创建时间
  updateTime: number = 0         // 更新时间
}

2.2 订单状态定义

在CommonConstant中定义订单状态常量:

/**
 * 订单状态
 */
export const ORDER_STATUS_PENDING = 0     // 待处理
export const ORDER_STATUS_ACCEPTED = 1    // 已接受
export const ORDER_STATUS_COOKING = 2     // 制作中
export const ORDER_STATUS_COMPLETED = 3   // 已完成
export const ORDER_STATUS_CANCELLED = 4   // 已取消

三、页面结构设计

3.1 页面布局

【点餐页面整体布局图】

┌─────────────────────────────┐
│   导航栏(返回 + 菜名)      │
├─────────────────────────────┤
│   菜谱图片                   │
├─────────────────────────────┤
│   基本信息                   │
│   - 菜名、类型、烹饪时长     │
│   - 描述                     │
├─────────────────────────────┤
│   食材列表                   │
│   - 食材名称 + 用量          │
├─────────────────────────────┤
│   制作步骤                   │
│   - 步骤编号 + 描述          │
├─────────────────────────────┤
│   口味备注                   │
│   - 备注输入框               │
│   - 快捷备注按钮             │
├─────────────────────────────┤
│   提交订单按钮               │
└─────────────────────────────┘

3.2 状态变量定义

@Entry
@Component
struct DinerOrderPage {
  @State recipe: Recipe | null = null
  @State remark: string = ''              // 备注内容
  @State quickRemarks: string[] = [       // 快捷备注选项
    '少辣', '不辣', '多放葱', '不要香菜', '少盐'
  ]
  @State selectedQuickRemarks: string[] = []  // 已选快捷备注
  private recipeId: number = 0
  private context: common.UIAbilityContext | null = null
}

四、菜谱信息加载

4.1 数据库查询方法

在RdbUtil中添加根据ID查询菜谱的方法:

static async queryRecipeById(id: number): Promise<Recipe | null> {
  try {
    const predicates = new relationalStore.RdbPredicates('recipe')
    predicates.equalTo('id', id)
    
    const resultSet = await this.rdbStore.query(predicates)
    
    if (resultSet.goToFirstRow()) {
      const recipe = Recipe.fromJson({...})
      resultSet.close()
      return recipe
    }
    
    resultSet.close()
    return null
  } catch (err) {
    LogUtil.error('RdbUtil', `查询菜谱失败: ${err}`)
    return null
  }
}

4.2 页面初始化

aboutToAppear() {
  try {
    this.context = getContext(this) as common.UIAbilityContext
    
    // 获取路由参数
    const params = router.getParams() as Record<string, Object>
    if (params && params['recipeId']) {
      this.recipeId = params['recipeId'] as number
      this.loadRecipe()
    }
  } catch (err) {
    LogUtil.error('DinerOrderPage', `初始化失败: ${err}`)
  }
}

五、备注功能实现

5.1 备注输入框

**【备注输入区域效果图】 **

@Builder
RemarkSection() {
  Column() {
    Text('口味备注')
      .fontSize(18)
      .fontWeight(FontWeight.Bold)
      .fontColor(CommonStyle.TEXT_COLOR_PRIMARY)
      .width('100%')
    
    // 备注输入框
    TextArea({ placeholder: '请输入口味偏好或特殊要求...', text: this.remark })
      .width('100%')
      .height(80)
      .backgroundColor(CommonStyle.BG_COLOR_GRAY)
      .borderRadius(CommonStyle.BORDER_RADIUS_MD)
      .onChange((value: string) => {
        this.remark = value
      })
      .margin({ top: 12 })
    
    // 快捷备注
    Row() {
      ForEach(this.quickRemarks, (item: string) => {
        Text(item)
          .fontSize(14)
          .fontColor(this.selectedQuickRemarks.includes(item) ? 
            CommonStyle.TEXT_COLOR_WHITE : CommonStyle.TEXT_COLOR_PRIMARY)
          .backgroundColor(this.selectedQuickRemarks.includes(item) ? 
            RoleStyle.DINER_COLOR : CommonStyle.BG_COLOR_GRAY)
          .borderRadius(CommonStyle.BORDER_RADIUS_ROUND)
          .padding({ left: 12, right: 12, top: 6, bottom: 6 })
          .onClick(() => {
            this.toggleQuickRemark(item)
          })
      })
    }
    .width('100%')
    .justifyContent(FlexAlign.Start)
    .margin({ top: 8 })
  }
  .width('100%')
  .padding(16)
  .backgroundColor(CommonStyle.BG_COLOR_WHITE)
  .borderRadius(CommonStyle.BORDER_RADIUS_MD)
  .margin({ top: 12 })
}

5.2 快捷备注逻辑

toggleQuickRemark(remark: string) {
  const index = this.selectedQuickRemarks.indexOf(remark)
  
  if (index > -1) {
    // 已选中,取消选择
    this.selectedQuickRemarks.splice(index, 1)
  } else {
    // 未选中,添加选择
    this.selectedQuickRemarks.push(remark)
  }
  
  // 更新备注内容
  this.updateRemarkContent()
}

六、订单提交功能

6.1 订单插入方法

在RdbUtil中添加插入订单的方法:

static async insertOrder(order: Order): Promise<boolean> {
  try {
    const valueBucket: relationalStore.ValuesBucket = {
      'recipe_id': order.recipeId,
      'recipe_name': order.recipeName,
      'recipe_image': order.recipeImage,
      'status': order.status,
      'remark': order.remark,
      'order_time': order.orderTime,
      'accept_time': order.acceptTime,
      'complete_time': order.completeTime,
      'create_time': Date.now(),
      'update_time': Date.now()
    }
    
    const rowId = await this.rdbStore.insert('order', valueBucket)
    return rowId > 0
  } catch (err) {
    LogUtil.error('RdbUtil', `插入订单失败: ${err}`)
    return false
  }
}

6.2 提交订单逻辑

**【提交订单按钮效果图】 **

async submitOrder() {
  if (!this.recipe) {
    promptAction.showToast({
      message: '菜谱信息加载失败',
      duration: 2000
    })
    return
  }
  
  // 创建订单对象
  const order = new Order()
  order.recipeId = this.recipe.id
  order.recipeName = this.recipe.name
  order.recipeImage = this.recipe.image || ''
  order.status = CommonConstant.ORDER_STATUS_PENDING  // 待处理
  order.remark = this.remark
  order.orderTime = Date.now()
  order.acceptTime = 0
  order.completeTime = 0
  
  try {
    const success = await RdbUtil.insertOrder(order)
    
    if (success) {
      promptAction.showToast({
        message: '下单成功!',
        duration: 2000
      })
      
      // 返回上一页
      router.back()
    }
  } catch (err) {
    LogUtil.error('DinerOrderPage', `提交订单失败: ${err}`)
  }
}

七、技术要点总结

7.1 路由参数传递

// 发送方
router.pushUrl({
  url: 'pages/DinerOrderPage',
  params: { recipeId: recipe.id }
})

// 接收方
const params = router.getParams() as Record<string, Object>
if (params && params['recipeId']) {
  this.recipeId = params['recipeId'] as number
}

7.2 快捷备注交互

设计思路:

  • 提供常用备注选项,减少输入
  • 支持多选,自动拼接
  • 点击切换选中状态
  • 实时更新备注内容

7.3 订单状态初始化

order.status = CommonConstant.ORDER_STATUS_PENDING  // 待处理
order.orderTime = Date.now()  // 当前时间戳
order.acceptTime = 0  // 未接单
order.completeTime = 0  // 未完成

八、总结

通过本篇文章,我们完成了点餐清单与提交订单功能的开发:

菜谱详情完整展示:图片、信息、食材、步骤
备注功能灵活:支持自定义和快捷选择
订单提交可靠:数据完整保存到数据库
交互体验友好:卡片式布局,操作便捷

下一篇文章将介绍主厨订单处理功能的实现,敬请期待!