HarmonyOS PC 订单卡片设计——数据驱动多态样式的实战指南
文章目录一套代码渲染多种状态数据模型设计完整 Demo数据驱动多态样式的三个关键点1. 枚举定义状态避免魔法字符串2. 映射表集中管理样式配置3. 金额格式化在方法层处理小结一套代码渲染多种状态做过电商或者企业应用的都知道订单卡片是个麻烦事同样一张卡片待付款是橙色、处理中是蓝色、已完成是绿色、已取消是灰色。商品名可能很短也可能很长。价格格式要固定。操作按钮根据状态不一样……如果你的思路是每种状态写一个卡片样式代码量会爆炸后续改一个颜色要改四处。正确的做法是设计好数据模型用数据驱动样式。颜色是数据的映射按钮是状态的映射文字是字段的格式化。HarmonyOS PC 端的订单管理场景比手机端更复杂——PC 端通常在一个页面里显示更多的订单信息支持多选、批量操作行高和信息密度也更高。本文就从数据模型出发把多态样式绑定讲清楚。数据模型设计好的数据模型让后面的渲染代码简单很多。先定义订单的枚举和接口// 订单状态枚举enumOrderStatus{PENDING_PAYMENTpending_payment,// 待付款PROCESSINGprocessing,// 处理中SHIPPINGshipping,// 配送中COMPLETEDcompleted,// 已完成CANCELLEDcancelled,// 已取消REFUNDINGrefunding,// 退款中}// 订单数据接口interfaceOrderItem{id:stringtitle:string// 商品名subtitle:string// 副标题/规格price:number// 金额分quantity:number// 数量status:OrderStatus// 订单状态createdAt:string// 创建时间imageUrl?:string// 商品图可选}// 订单卡片展示用的样式配置interfaceStatusConfig{label:string// 状态文字color:string// 主色bgColor:string// 背景色actions:string[]// 可用操作按钮}把状态→样式配置的映射关系集中维护是多态卡片设计的关键constSTATUS_CONFIG:Recordstring,StatusConfig{pending_payment:{label:待付款,color:#FF7A00,bgColor:#FFF3E8,actions:[立即付款,取消订单]},processing:{label:处理中,color:#0A59F7,bgColor:#EBF2FF,actions:[查看详情]},shipping:{label:配送中,color:#00B578,bgColor:#E8FFF4,actions:[查看物流,确认收货]},completed:{label:已完成,color:#00B578,bgColor:#E8FFF4,actions:[再次购买,申请退款]},cancelled:{label:已取消,color:#999999,bgColor:#F5F5F5,actions:[删除记录]},refunding:{label:退款中,color:#FF4040,bgColor:#FFF0F0,actions:[查看进度]},}完整 Demo新建文件PcOrderCardPage.etsenumOrderStatus{PENDING_PAYMENTpending_payment,PROCESSINGprocessing,SHIPPINGshipping,COMPLETEDcompleted,CANCELLEDcancelled,REFUNDINGrefunding,}interfaceOrderItem{id:stringtitle:stringsubtitle:stringprice:numberquantity:numberstatus:OrderStatus createdAt:string}classStatusConfig{label:stringcolor:stringbgColor:stringactions:string[]constructor(label:string,color:string,bgColor:string,actions:string[]){this.labellabelthis.colorcolorthis.bgColorbgColorthis.actionsactions}}interfaceFilterItem{id:stringlabel:string}EntryComponentstruct PcOrderCardPage{StateactiveFilter:stringallStateselectedIds:string[][]privateorders:OrderItem[][{id:ORD-20250601-001,title:HarmonyOS 开发者套件专业版,subtitle:颜色: 星空黑 / 版本: 专业版,price:129900,quantity:1,status:OrderStatus.SHIPPING,createdAt:2025-06-01 10:30},{id:ORD-20250530-002,title:ArkUI 组件开发实战课程,subtitle:在线课程 / 永久有效,price:29900,quantity:1,status:OrderStatus.COMPLETED,createdAt:2025-05-30 14:22},{id:ORD-20250528-003,title:华为 MatePad Pro 11 智能键盘保护套,subtitle:适配 MatePad Pro 11 2024款,price:49900,quantity:2,status:OrderStatus.PENDING_PAYMENT,createdAt:2025-05-28 09:15},{id:ORD-20250525-004,title:开发者技术交流年会入场券,subtitle:2025 HarmonyOS 开发者峰会,price:0,quantity:1,status:OrderStatus.CANCELLED,createdAt:2025-05-25 16:40},{id:ORD-20250520-005,title:鸿蒙应用商店推广套餐,subtitle:企业版 / 3个月,price:299900,quantity:1,status:OrderStatus.PROCESSING,createdAt:2025-05-20 11:08},{id:ORD-20250515-006,title:华为云开发者存储套餐,subtitle:500GB / 一年,price:59900,quantity:1,status:OrderStatus.REFUNDING,createdAt:2025-05-15 08:30},]privatefilters:FilterItem[][{id:all,label:全部},{id:pending_payment,label:待付款},{id:processing,label:处理中},{id:shipping,label:配送中},{id:completed,label:已完成},]privategetFilteredOrders():OrderItem[]{if(this.activeFilterall){returnthis.orders}returnthis.orders.filter((order:OrderItem)order.statusthis.activeFilter)}// 格式化金额分 → 元privateformatPrice(cents:number):string{if(cents0){return免费}return¥${(cents/100).toFixed(2)}}privategetStatusConfig(status:OrderStatus):StatusConfig{switch(status){caseOrderStatus.PENDING_PAYMENT:returnnewStatusConfig(待付款,#FF7A00,#FFF3E8,[立即付款,取消订单])caseOrderStatus.PROCESSING:returnnewStatusConfig(处理中,#0A59F7,#EBF2FF,[查看详情])caseOrderStatus.SHIPPING:returnnewStatusConfig(配送中,#00B578,#E8FFF4,[查看物流,确认收货])caseOrderStatus.COMPLETED:returnnewStatusConfig(已完成,#00B578,#E8FFF4,[再次购买,申请退款])caseOrderStatus.CANCELLED:returnnewStatusConfig(已取消,#999999,#F5F5F5,[删除记录])caseOrderStatus.REFUNDING:returnnewStatusConfig(退款中,#FF4040,#FFF0F0,[查看进度])default:returnnewStatusConfig(未知,#999999,#F5F5F5,[])}}build(){Column(){// ── 顶部标题栏 ──Row(){Text(订单管理).fontSize(18).fontWeight(FontWeight.Bold).fontColor(#1A1A1A)Blank()Text(共${this.getFilteredOrders().length}笔).fontSize(13).fontColor(#AAAAAA)}.width(100%).padding({left:24,right:24,top:20,bottom:12})// ── 状态筛选 Tab ──Row({space:4}){ForEach(this.filters,(f:FilterItem){Text(f.label).fontSize(14).fontColor(this.activeFilterf.id?#0A59F7:#666666).fontWeight(this.activeFilterf.id?FontWeight.Bold:FontWeight.Normal).padding({left:16,right:16,top:6,bottom:6}).backgroundColor(this.activeFilterf.id?#EBF2FF:transparent).borderRadius(20).onClick((){this.activeFilterf.id})})}.width(100%).padding({left:16,right:16,bottom:12})Divider().color(#EEEEEE)// ── 订单列表 ──Scroll(){Column({space:12}){ForEach(this.getFilteredOrders(),(order:OrderItem){this.buildOrderCard(order)})}.padding({left:16,right:16,top:12,bottom:24})}.layoutWeight(1).scrollBar(BarState.Auto)}.width(100%).height(100%).backgroundColor(#F5F6F8)}// ── 订单卡片 ──BuilderbuildOrderCard(order:OrderItem){// ── 卡片头部订单号 状态标签 ──Row(){Text(order.id).fontSize(12).fontColor(#AAAAAA).layoutWeight(1)Text(this.getStatusConfig(order.status).label).fontSize(12).fontColor(this.getStatusConfig(order.status).color).backgroundColor(this.getStatusConfig(order.status).bgColor).padding({left:8,right:8,top:3,bottom:3}).borderRadius(4)}.width(100%).padding({left:16,right:16,top:12,bottom:10})Divider().color(#F0F0F0)// ── 卡片主体商品信息 ──Row({space:12}){// 商品图占位Column().width(56).height(56).backgroundColor(#F0F0F0).borderRadius(6)// 商品名 规格Column({space:4}){Text(order.title).fontSize(14).fontColor(#1A1A1A).maxLines(2).textOverflow({overflow:TextOverflow.Ellipsis})Text(order.subtitle).fontSize(12).fontColor(#AAAAAA).maxLines(1).textOverflow({overflow:TextOverflow.Ellipsis})Text(order.createdAt).fontSize(11).fontColor(#CCCCCC)}.layoutWeight(1).alignItems(HorizontalAlign.Start)// 金额 数量Column({space:4}){Text(this.formatPrice(order.price)).fontSize(16).fontColor(#1A1A1A).fontWeight(FontWeight.Bold)Text(x${order.quantity}).fontSize(12).fontColor(#AAAAAA)}.alignItems(HorizontalAlign.End)}.width(100%).padding({left:16,right:16,top:12,bottom:12})Divider().color(#F0F0F0)// ── 操作按钮区按钮由状态的 actions 数据驱动 ──Row({space:8}){Blank()ForEach(this.getStatusConfig(order.status).actions,(action:string,index:number){Button(action).height(32).padding({left:16,right:16}).fontSize(13).borderRadius(6).backgroundColor(index0?#0A59F7:transparent).fontColor(index0?#FFFFFF:#0A59F7).onClick((){console.log(订单${order.id}操作:${action})})})}.width(100%).padding({left:16,right:16,top:10,bottom:12}).backgroundColor(#FFFFFF).borderRadius(12).shadow({radius:4,color:rgba(0,0,0,0.06),offsetX:0,offsetY:2})}}数据驱动多态样式的三个关键点1. 枚举定义状态避免魔法字符串// ❌ 不好的做法if(order.statusshipping){...}// ✅ 推荐的做法enumOrderStatus{SHIPPINGshipping}if(order.statusOrderStatus.SHIPPING){...}枚举让代码可读性更高也有 IDE 的类型提示。2. 映射表集中管理样式配置所有状态 → 颜色/文字/按钮的映射放在一个Record里统一维护。新增一个状态只需要在映射表里加一条渲染代码不用改。3. 金额格式化在方法层处理不要在模板里写(price / 100).toFixed(2)抽成一个formatPrice()方法逻辑集中好测试好维护。小结多态卡片的本质是状态 → 样式的映射。把这个映射关系从渲染代码里抽出来用Record集中管理渲染层就变得非常干净卡片不关心待付款是什么颜色只管从 config 里取颜色用。这个思路在 PC 端更有价值——PC 端的状态种类通常更多信息密度更高如果不做好数据和渲染的分离代码会很快失控。