news 2026/9/9 19:00:05

鸿蒙原生应用 HarmonyOS 6.0实战:拆解 —— 设备详情页的参数表与近期预约时段卡

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
鸿蒙原生应用 HarmonyOS 6.0实战:拆解 —— 设备详情页的参数表与近期预约时段卡

鸿蒙原生应用 HarmonyOS 6.0实战:拆解 —— 设备详情页的参数表与近期预约时段卡

App 23「实验室设备预约」设备 Tab(Func1Tab),是设备详情页——4 卡结构:InfoCard(🔬 120 高图标块 + 高倍显微镜 + 空闲标签 + 位置)+ SpecCard(设备参数表:型号/倍率/光源/模式)+ GuideCard(使用说明 4 条)+ BookingList(近期预约 2 时段 + "预约该时段"按钮)。本篇基于23-lab-booking/entry/src/main/ets/pages/Func1Tab.ets(约 145 行)逐段拆解,附 4 张实机截图。

一、整体结构:4 卡详情页

Func1Tab 是**"设备详情"的 4 卡布局**——信息/参数/说明/预约 4 层:

build() { Column() { this.Header() Scroll() { Column({ space: 16 }) { this.InfoCard() this.SpecCard() this.GuideCard() this.BookingList() } .width('100%') .padding({ left: D.pad, right: D.pad, top: 16, bottom: D.pad + this.safeBottom + 20 }) } .layoutWeight(1).scrollBar(BarState.Off).align(Alignment.Top) } .width('100%').height('100%').backgroundColor(C.bg) }

4 个块按"是什么 → 参数 → 怎么用 → 怎么约"漏斗展开

  1. InfoCard— 设备身份(大图标 + 名称 + 状态 + 位置)
  2. SpecCard— 设备参数(型号/倍率/光源/模式)
  3. GuideCard— 使用说明(4 条操作指引)
  4. BookingList— 近期预约(2 时段 + 预约按钮)

"详情页 4 卡"是设备/商品详情页的通用结构(电商商品详情 = 图片 + 参数 + 详情 + 购买;设备详情 = 图标 + 参数 + 说明 + 预约)——"详情页 = 身份 + 参数 + 指南 + 行动"

项目源码开源:https://gitee.com/codenestFlow/HarmonyOSHub

二、Header + InfoCard:设备身份卡

Header 是"设备详情"单行(系列标准)。

InfoCard是设备身份卡——大图标 + 名称 + 状态 + 位置:

@Builder InfoCard() { Column({ space: 12 }) { Row() { Text('🔬').fontSize(48) } .width('100%').height(120) .backgroundColor(C.primarySoft).borderRadius(D.rLg) .justifyContent(FlexAlign.Center) Text('高倍显微镜').fontSize(18).fontWeight(FontWeight.Bold).fontColor(C.text).width('100%') Row({ space: 8 }) { Text('空闲').fontSize(12).fontColor('#FFFFFF') .padding({ left: 8, right: 8, top: 3, bottom: 3 }) .backgroundColor(C.ok).borderRadius(4) Text('位于 B 楼 302').fontSize(12).fontColor(C.textDim) } .width('100%') } .width('100%') .padding(16) .backgroundColor(C.card) .borderRadius(D.rLg) .border({ width: 1, color: C.stroke }) }

4 元素

  1. 120 高 emoji 图标块C.primarySoft浅青底 + 🔬 48sp)——全宽大图标(120vp 高是全页最高图标块)
  2. 设备名称(18sp 加粗)
  3. 空闲标签(白字绿底 +C.ok)+位置("位于 B 楼 302"灰字)——状态 + 位置双信息

"空闲标签"用C.ok绿底白字——与首页状态色一致(绿=空闲)——"跨页状态色统一"

"位于 B 楼 302"——设备位置(实验室物理位置)——"设备详情必须含位置"(用户要去实体实验室用设备)。

三、SpecCard:设备参数表

SpecCard 是"标签 + 值"参数表——4 行参数:

@Builder SpecCard() { Column({ space: 10 }) { Text('设备参数').fontSize(15).fontWeight(FontWeight.Bold).fontColor(C.text).width('100%') Row({ space: 8 }) { Text('型号').fontSize(13).fontColor(C.textDim).width(60) Text('Olympus BX53').fontSize(13).fontColor(C.text).layoutWeight(1) } .width('100%') Row({ space: 8 }) { Text('倍率').fontSize(13).fontColor(C.textDim).width(60) Text('40x - 1000x').fontSize(13).fontColor(C.text).layoutWeight(1) } .width('100%') Row({ space: 8 }) { Text('光源').fontSize(13).fontColor(C.textDim).width(60) Text('LED 冷光源').fontSize(13).fontColor(C.text).layoutWeight(1) } .width('100%') Row({ space: 8 }) { Text('模式').fontSize(13).fontColor(C.textDim).width(60) Text('明场 / 偏光 / 荧光').fontSize(13).fontColor(C.text).layoutWeight(1) } .width('100%') } .width('100%') .padding(16) .backgroundColor(C.card) .borderRadius(D.rLg) .border({ width: 1, color: C.stroke }) }

4 行"标签 + 值"

标签
型号Olympus BX53
倍率40x - 1000x
光源LED 冷光源
模式明场 / 偏光 / 荧光

"标签 60vp 固定宽 + 值 layoutWeight"——4 行标签右对齐、值左对齐——"参数表的标准布局"(标签列固定宽保证对齐)。

参数是"真实显微镜参数"——Olympus BX53 是真实显微镜型号(奥林巴斯生物显微镜)、40x-1000x 是标准倍率、明场/偏光/荧光是显微镜 3 种模式——"参数真实性 = 详情可信度"

参数表的"键值对"模式——Row(标签 + 值)重复 4 次——真实项目应改为"数据驱动"

private specs: SpecItem[] = [ { label: '型号', value: 'Olympus BX53' }, { label: '倍率', value: '40x - 1000x' }, ... ]; // ForEach 渲染

"参数表数据化"——加参数只需往数组加一项,不用复制粘贴 Row——"4 行参数"用数据驱动是更好的工程实践(本页手写 4 个 Row 是 demo 简化)。

四、GuideCard:使用说明

GuideCard 是4 条使用说明(操作指引):

@Builder GuideCard() { Column({ space: 10 }) { Text('使用说明').fontSize(15).fontWeight(FontWeight.Bold).fontColor(C.text).width('100%') Text('1. 预约后请在指定时间到达实验室').fontSize(13).fontColor(C.textSub).width('100%') Text('2. 使用前检查设备状态并登记').fontSize(13).fontColor(C.textSub).width('100%') Text('3. 使用后清洁镜头并归位').fontSize(13).fontColor(C.textSub).width('100%') Text('4. 如有故障请联系实验室管理员').fontSize(13).fontColor(C.textSub).width('100%') } .width('100%') .padding(16) .backgroundColor(C.card) .borderRadius(D.rLg) .border({ width: 1, color: C.stroke }) }

4 条说明的"操作流程"

  1. 预约后准时到达(预约 → 到达
  2. 使用前检查登记(检查 → 登记
  3. 使用后清洁归位(清洁 → 归位
  4. 故障联系管理员(异常 → 求助

"编号 + 说明"(1./2./3./4.)——"编号让说明有序"——**用户按编号执行"预约→到达→检查→使用→清洁→归位→求助"**完整流程。

"实验室安全规范"——清洁归位/故障上报是实验室礼仪——"使用说明 = 实验室规章制度"——真实项目应加"安全须知"(戴手套/护目镜等)。

五、BookingList:近期预约 + 预约按钮

BookingList 是2 时段预约 + "预约该时段"按钮

@Builder BookingList() { Column({ space: 12 }) { Text('近期预约').fontSize(15).fontWeight(FontWeight.Bold).fontColor(C.text).width('100%') Row({ space: 8 }) { Text('今天 14:00-16:00').fontSize(13).fontColor(C.text).layoutWeight(1) Text('已被预约').fontSize(11).fontColor(C.warn) } .width('100%').padding(10) .backgroundColor(C.cardSoft).borderRadius(D.rSm) Row({ space: 8 }) { Text('明天 09:00-11:00').fontSize(13).fontColor(C.text).layoutWeight(1) Text('空闲').fontSize(11).fontColor(C.ok) } .width('100%').padding(10) .backgroundColor(C.primarySoft).borderRadius(D.rSm) Button('预约该时段') .width('100%').height(44) .fontSize(14).fontColor('#FFFFFF').backgroundColor(C.primary) .borderRadius(D.rMd) .onClick(() => { promptAction.showToast({ message: '预约成功' }); }) } .width('100%') .padding(16) .backgroundColor(C.card) .borderRadius(D.rLg) .border({ width: 1, color: C.stroke }) }

2 时段 + 状态

  • 今天 14:00-16:00(已被预约,橙)——C.cardSoft浅灰底
  • 明天 09:00-11:00(空闲,绿)——C.primarySoft浅青底(可预约的时段用品牌浅色高亮)

"可预约时段用浅青底、已被约时段用浅灰底"——"可预约性通过底色区分"(比只靠状态字更直观)。

"预约该时段"按钮——44vp 深青底白字——点击弹 Toast "预约成功"——"预约 = 一键完成"

注意:demo 未绑定"哪个时段可预约"——按钮无论"今天已被约"还是"明天空闲"都显示"预约该时段"——真实项目应"选中空闲时段 → 按钮变'预约 09:00-11:00'"(与 App 14 场地预约的动态按钮同款)。

六、@State 数量 = 0

Func1Tab0 个 @State——所有内容硬编码(高倍显微镜/Olympus BX53/使用说明/近期预约)——"纯展示详情页"

真实项目应数据化:设备信息来自首页点击的设备(@Prop device或路由传参)——"首页点设备 → 详情页显示该设备"——本页硬编码"高倍显微镜"是 demo 简化(首页 6 台设备都能点,但详情页永远显示显微镜)。

七、"详情页 4 卡"模板的可复用性

App 23 设备详情页的"4 卡"是详情页通用模板

InfoCard(身份:大图 + 名称 + 状态 + 位置) + SpecCard(参数表:标签 + 值) + GuideCard(说明:编号 + 指引) + BookingList(行动:时段 + 预约按钮)

"详情页 4 卡"可复用到

  • 商品详情(图片 + 参数 + 详情 + 购买)
  • 场馆详情(封面 + 设施 + 规则 + 预订)
  • 课程详情(封面 + 大纲 + 须知 + 报名)
  • 房间详情(图片 + 配置 + 须知 + 预订)

"身份 + 参数 + 指南 + 行动"4 层是详情页的通用信息架构——读者做任何"详情页"都可参考

八、"参数表"的 3 种信息展示方式

App 23 的 SpecCard 用"标签 + 值"键值对表——真实设备/商品详情页的"参数展示"有 3 种方式:

1. 键值对表(App 23 当前):

型号 | Olympus BX53 倍率 | 40x - 1000x

——适合"参数数量中等(4-8 项)",一列一值,清晰易读。

2. 分组表(真实产品):

【光学参数】倍率 40x-1000x / 物镜 4x/10x/40x 【电学参数】电压 220V / 功率 100W

——适合"参数多(10+)",分组避免堆砌。

3. 卡片式(规格说明):

🔬 高倍显微镜 1000x 偏光 · LED冷光源 · 明场/偏光/荧光

——适合"参数少(2-3 项)",一行概括。

"参数数量决定展示方式"——4-8 项用键值对、10+ 用分组、3 项内用卡片。

真实设备的"参数表"数据源

// 设备参数从后端 API 拉取 interface DeviceSpec { label: string; value: string; } private specs: DeviceSpec[] = await getDeviceSpecs(deviceId);

"参数表数据化"——参数从数据源来,不是硬编码——"详情页的参数是设备的元数据"(同一设备类型的设备共享参数模板)。

九、"使用说明"的 4 种场景应用

App 23 的 GuideCard 是"使用说明 4 条"——"说明/须知"类内容在 App 中的 4 种场景:

1. 操作步骤(App 23)——"预约→到达→检查→使用→清洁→归位"——编号有序,用户按序执行。

2. 安全须知(实验室进阶)——"戴护目镜""禁饮食""紧急开关位置"——警示性内容,用红色/黄色强调。

3. 常见问题 FAQ——"如何预约?""设备坏了找谁?"——问答形式,可展开/折叠。

4. 免责声明——"使用者自行承担损坏责任"——法律文本,小字灰底。

"说明内容决定 UI 形态"

  • 操作步骤 → 编号列表(App 23)
  • 安全须知 → 警示色卡片
  • FAQ → 折叠面板
  • 声明 → 小字灰底

"使用说明"是设备/商品详情页的标配——"说明清晰 = 减少客服压力"(用户看完说明能自己操作,不用问管理员)。

十、"预约时段"的冲突检测

App 23 的 BookingList 展示"今天已被预约/明天空闲"——真实项目的"预约时段冲突检测"

// 时段冲突检测 function isSlotBooked(deviceId: number, date: string, slot: string): boolean { return bookings.some(b => b.deviceId === deviceId && b.date === date && b.slot === slot ); }

"预约冲突"的 3 层处理

  1. 前端禁用(当前实现):已被约的时段置灰/显示"已被预约"
  2. 前端提示:用户点"已被约"时段 → 弹 Toast "该时段已被预约"
  3. 后端校验(最终防线):提交时服务端验证"无冲突"(防止并发抢同一时段)

"冲突检测"是预约系统的核心——"并发预约"是最难处理的场景(两人同时约同一时段)——后端乐观锁/数据库唯一约束是解决方案。

App 23 的简化:时段状态是硬编码("今天已被预约"写死)——真实项目从"预约表"实时计算——"时段状态 = 预约记录的聚合"

十一、"设备详情"的路由传参设计

App 23 设备详情页硬编码"高倍显微镜"——真实项目应"首页点设备 → 详情页显示该设备"——路由传参是核心机制:

方案 1:路由参数

// 首页点击设备 → 跳转详情页 router.pushUrl({ url: 'pages/DeviceDetail', params: { deviceId: d.id } }); // 详情页接收 onPageLoad() { const params = router.getParams() as Record<string, number>; this.deviceId = params.deviceId; this.loadDevice(this.deviceId); }

方案 2:AppStorage 全局

// 首页 AppStorage.setOrCreate('currentDevice', d.id); // 详情页 @StorageProp('currentDevice') deviceId: number;

方案 3:@Prop 子组件(Tab 结构内传递):

// 首页 Tab 与设备 Tab 是平级,用 AppStorage 或路由最合适

"路由传参"让详情页数据化——首页 6 台设备点击都进详情页,显示对应设备——**"详情页从硬编码变为动态"**是 demo 到产品的关键改进。

十二、"使用说明"的版本管理与审核

App 23 的 GuideCard 是静态 4 条说明——真实实验室的"使用说明"需要版本管理

"使用说明"的 3 层管理

  1. 版本——设备操作流程更新(如新操作规程)→ 说明 v1.2 替换 v1.1
  2. 审核——说明变更需管理员审核(安全规范不能随便改)
  3. 追溯——"操作事故"时能查"当时用的是哪个版本的说明"

"使用说明 = 设备文档"——真实项目应:

interface GuideVersion { version: string; content: string[]; effectiveDate: string; approvedBy: string; }

"说明版本化"是设备管理(尤其医疗/科研)的合规要求——操作事故追责时需要"当时版本"

App 23 的简化:说明硬编码 4 条——读者做实验室/医疗设备管理时,说明应支持"版本 + 审核 + 追溯"。

十三、"设备状态"与"详情页状态色"的一致性

App 23 详情页的"空闲"标签(绿底白字)与首页设备卡的"空闲"状态色(C.ok绿字)颜色语义一致

首页设备卡Text(d.status).fontColor(d.statusColor)(绿字)详情页标签Text('空闲').backgroundColor(C.ok)(绿底白字)

"同状态同颜色、不同形态"

  • 首页:状态色文字(列表紧凑,文字色省空间)
  • 详情页:状态色标签(详情宽松,色块更醒目)

"状态色跨页一致"是设计系统原则——用户在首页看到"绿色 = 空闲",到详情页看到绿色标签自动理解"空闲"——"颜色语义全局统一"

"色字 vs 色块"的选择

  • 列表卡(信息多):状态用"色字"(不占空间)
  • 详情卡(信息少):状态用"色块标签"(醒目)

"状态展示形态 = 页面空间"——读者做自己的设计系统时,"同状态同色、形态随空间"是标准。

十四、"详情页"的返回与导航

App 23 详情页是 Tab 内页面(Func1Tab),无返回按钮——真实项目的"详情页"有返回导航

"页面层级"导航

首页(Tab)→ 点击设备 → 设备详情(push)→ 返回

ArkUI 页面导航

// push 进入详情页 router.pushUrl({ url: 'pages/DeviceDetail', params: { id: 1 } }); // 详情页返回 router.back();

"详情页 3 要素"(导航相关):

  1. 返回按钮(左上角"←")——回到列表
  2. 面包屑/标题——"设备详情"标题
  3. 底部操作——"预约该时段"(App 23 的"预约"按钮是详情页的"行动锚点")

App 23 的简化:详情页是 Tab 内页面(无 push/back)——真实项目"详情页"通常独立路由——"Tab 详情 vs 路由详情"是两种导航模式(Tab 详情简单、路由详情灵活)。

十五、"预约按钮"的动态化与状态联动

App 23 详情页底部的"预约"按钮是静态按钮——无论设备状态如何,按钮始终可点击。真实项目中,预约按钮应与设备状态联动

"按钮状态机"设计

  • 空闲→ 按钮可点击,文案"立即预约",主色背景
  • 使用中→ 按钮禁用,文案"使用中",灰色背景
  • 维护中→ 按钮禁用,文案"维护中",橙色背景

真实项目的动态按钮

// 按钮状态跟随设备状态 Button(this.getBtnText(device.status)) .enabled(device.status === '空闲') .backgroundColor(device.status === '空闲' ? C.primary : C.textDim) .onClick(() => { /* 跳转预约页 */ })

"按钮 = 状态的可操作化"——按钮不仅是入口,更是状态的视觉反馈——**"状态 → 按钮 → 行动"**是详情页的核心交互链路。读者做设备/场地预约类 App 时,务必让按钮跟随状态变化,避免用户点击后才发现"不可预约"。

十六、总结

App 23 设备详情页解析完毕。4 卡结构(身份/参数/说明/预约)+ 大图标 + 参数表 + 可预约性底色区分是核心组件。**"详情页 4 卡 = 身份 + 参数 + 指南 + 行动"是详情页通用模板。"状态色跨页一致"、"路由传参"、"页面导航"、"按钮动态化"是真实项目的进阶能力。"参数表数据化"和"预约按钮动态化"**是具体改进方向。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/9 18:59:40

如何给AI Agent接入微信通知?企业微信Webhook推送服务实践

1. 为什么需要给 Agent 加一个“通知”能力&#xff1f;如果你最近在折腾 AI Agent&#xff0c;大概率会遇到一个非常真实的尴尬场景&#xff1a;你精心设计了一个 Agent&#xff0c;给它配好了工具&#xff0c;输入了任务&#xff0c;然后它开始吭哧吭哧地跑。跑批任务、循环调…

作者头像 李华
网站建设 2026/9/9 18:58:00

Java社区应急管理系统设计与实现:从状态流转到答辩避坑

刚带完一届毕设答辩&#xff0c;几乎每次都有学生拿“社区应急管理系统”这类题目来问。说实话&#xff0c;这个选题在Java毕设里属于经典中的经典——业务不算复杂但五脏俱全&#xff0c;既有基础CRUD&#xff0c;又有流程状态流转、消息通知、权限控制这些能拿得出手的“进阶…

作者头像 李华
网站建设 2026/9/9 18:55:23

Unity6美食经营游戏开发:订单、顾客与任务系统架构全解析

做美食经营类项目时&#xff0c;很多开发者会陷入一个共同的困境&#xff1a;单个功能怎么看都简单&#xff0c;比如“生成一个顾客”“炒一份菜”“弹一个订单面板”&#xff0c;但要把它们串成一套完整的经营循环&#xff0c;代码就开始失控了——脚本之间互相引用、状态到处…

作者头像 李华
网站建设 2026/9/9 18:54:18

HarmonyOS开发工程师转型指南:技能拆解、实操路线与面试考点全解析

看到HarmonyOS开发工程师这个岗位的讨论热度持续走高&#xff0c;不少朋友私信问我“到底值不值得转”“面试都考什么”。我在移动端这块摸爬滚打了十多年&#xff0c;这两年也完整经历了从传统App开发转向鸿蒙生态的全过程&#xff0c;踩过不少坑&#xff0c;也拿过几个还不错…

作者头像 李华