鸿蒙全球性项目实战 -跨过商品账单综合格式化-页面设计

发布时间:2026/8/22 1:04:04
鸿蒙全球性项目实战 -跨过商品账单综合格式化-页面设计 一、设计目标本应用是本系列的毕业设计——前 12 个应用分别攻克文案、数字、货币、日期、复数、日历、时区等单点本应用把它们全部塞进一个真实的跨境购物场景语言、币种、金额、数量、税费、运费、时间戳、订单号同时参与界面渲染。UI 设计要回答三个问题语言与币种是两个独立开关用户可以把界面设成英文、结算币种选日元JPY 零小数位——两个维度自由组合UI 如何让用户不困惑金额的正确性必须可感知¥1,299 的耳机换成 $181.86、€168.87、¥27,928日元无小数——换算结果要让人觉得对而不是一堆裸数字信息层级在结算页必须零歧义小计、税费、运费、满减、合计五层费用加上支付状态切换待支付→处理中→已支付UI 要保证用户永远知道现在该看哪里。因此本页 UI 的核心原则是两个全局状态语言/币种 一套金额管线——所有价格永远走fmtMoney()生成界面只负责层级与反馈。二、页面信息架构组件树BillFormatPageEntry 根组件 └─ Column高 100%背景 #F8FAFC ├─ Row标题栏环球购 副标题 ️ 图标 ├─ Column语言 币种选择卡白色卡片两行 │ ├─ Row界面语言标签 5 个徽章选中 teal #0F766E │ └─ Row结算币种标签 4 个徽章选中 amber #D97706 ├─ Row汇率提示条 文案 1 CNY ≈ $0.14琥珀底 #FEF3C7 ├─ RowTab 切换商品市场 / 购物车 (n)下划线分隔 └─ 内容区二选一 ├─ MarketView6 张商品卡emoji 名称 描述 单价 加购按钮 └─ CartView购物车行 费用明细卡 支付状态横幅 底部结算栏架构要点选择器语言/币种全局常驻顶部Tab 之下是内容区——两个全局状态的变化会同时驱动两个 Tab 的重渲染用户在任何页面都能感知我换了语言/币种。三、色彩与字号规范本页用双强调色——语言用 teal青绿、币种用 amber琥珀两组选择器并排不混淆元素色值字号字重页面标题#0F172A22Bold副标题#94A3B812Normal选择器标签#64748B12Normal语言选中徽章文字 #FFF / 底 #0F766E11Normal币种选中徽章文字 #FFF / 底 #D9770611Normal未选中徽章文字 #475569 / 底 #E2E8F011Normal商品名#0F172A15Bold商品描述#64748B12Normal单价/金额琥珀#D9770616~22Bold加购按钮底 #0F766E / 已加 #10B98112Normal费用明细行标签 #64748B / 值 #33415513~14Normal满减红#DC262614Normal汇率提示条文字 #92400E / 底 #FEF3C710Normal费用卡背景#FFF7ED——支付成功横幅文字 #065F46 / 底 #D1FAE511~14—色彩规则语言青绿、币种琥珀、金额琥珀加粗、负向(满减)红、正向反馈(免运/已付)绿——五色语义全页一致与系列选中强调色的约定对齐。四、双选择器语言与币种的分离设计Column({space:8}){Row(){Text(this.T(K.langLabel)).fontSize(12).fontColor(#64748B).width(70)Flex({wrap:FlexWrap.Wrap,justifyContent:FlexAlign.Start}){ForEach(LANGS,(l:LangCfg){Text(${l.flag}${l.name}).fontSize(11).padding({left:8,right:8,top:4,bottom:4}).borderRadius(12).backgroundColor(this.currentLocalel.code?#0F766E:#E2E8F0).fontColor(this.currentLocalel.code?Color.White:#475569).onClick((){this.currentLocalel.code;})},(l:LangCfg)l.code)}.layoutWeight(1)}.width(100%)Row(){Text(this.T(K.currencyLabel)).fontSize(12).fontColor(#64748B).width(70)Flex({wrap:FlexWrap.Wrap,justifyContent:FlexAlign.Start}){ForEach(CURRENCIES,(c:CurrencyCfg){Text(${c.symbol}${c.code}).fontSize(11).padding({left:10,right:10,top:4,bottom:4}).borderRadius(12).backgroundColor(this.currentCurrencyc.code?#D97706:#E2E8F0).fontColor(this.currentCurrencyc.code?Color.White:#475569).onClick((){this.currentCurrencyc.code;})},(c:CurrencyCfg)c.code)}.layoutWeight(1)}.width(100%)}.width(94%).padding(12).backgroundColor(Color.White).borderRadius(14).margin({top:8})设计要点标签固定宽 70 左对齐徽章区layoutWeight(1)弹性换行——语言名简体中文与币种码JPY长度差异不挤乱右侧双色区分维度青绿语言、琥珀币种——用户记住颜色维度后两排徽章互不干扰币种徽章带符号¥ CNY/$ USD/€ EUR/¥ JPY——CNY 与 JPY 符号相同¥必须靠代码区分两个状态都持久化StorageLink(STORAGE_LOCALE)StorageLink(STORAGE_CURRENCY)各自落盘重启保持中文界面 美元结算的组合记忆。五、汇率提示条把隐含规则显性化Row({space:6}){Text().fontSize(13)Text(${this.T(K.rateTip)}· 1 CNY ≈${this.curCfg().symbol}${this.curCfg().rate}).fontSize(10).fontColor(#92400E).layoutWeight(1).textAlign(TextAlign.Start)}.width(94%).padding(8).backgroundColor(#FEF3C7).borderRadius(10).margin({top:8})琥珀底 深棕字#FEF3C7/#92400E延续警示/说明语义与 01 的 RTL 提示条同族内容包含当前汇率1 CNY ≈ $0.14与免责声明“汇率为演示固定值”——用户看到金额变化时能定位原因这是 09体系显性化设计模式在货币维度的复用用户切币种发现 ¥1,299 变 $181.86提示条告诉他因为汇率是 0.14。六、商品市场卡名称/描述/单价三层本地化ForEach(PRODUCTS,(p:Product,i:number){Column(){Row(){Text(p.emoji).fontSize(30)Column({space:4}){Row({space:6}){Text(productName(this.currentLocale,p)).fontSize(15).fontWeight(FontWeight.Bold).fontColor(#0F172A)if(p.tag!){Text(p.tag).fontSize(11)}}.width(100%).justifyContent(FlexAlign.Start)Text(productDesc(this.currentLocale,p)).fontSize(12).fontColor(#64748B).textAlign(TextAlign.Start).width(100%)}.alignItems(HorizontalAlign.Start).layoutWeight(1).margin({left:10})}.width(100%).alignItems(VerticalAlign.Top)Row(){Text(${this.T(K.unitPrice)}).fontSize(12).fontColor(#64748B)Text(this.fmtMoney(p.priceCents)).fontSize(16).fontWeight(FontWeight.Bold).fontColor(#D97706)Blank()Button(this.qty[i]0?this.T(K.inCart):this.T(K.addCart)).fontSize(12).backgroundColor(this.qty[i]0?#10B981:#0F766E).fontColor(Color.White).height(30).padding({left:14,right:14}).onClick((){this.addToCart(i);})}.width(100%).margin({top:8})}.width(94%).padding(14).backgroundColor(Color.White).borderRadius(14)},(p:Product)p.key)设计要点emoji 商品图⌨️✍️⌚ 作为产品视觉规避真实图片资源的本地化问题图片文字不可翻译名称走 5 语言 Map、描述同步切换——“Noise-cancelling Headphones” 与「ノイズキャンセリングヘッドホン」长度差一倍layoutWeight(1)保证不溢出单价用fmtMoney()同一priceCents129900 分在不同币种下显示¥1,299.00/$181.86/€168.87/¥27,928——数字与符号全部由格式化器生成按钮双态未加购 teal加入购物车、已加购绿已加入——点击后即时反馈且价格行与按钮通过Blank()两端对齐。七、购物车费用五层 结算状态机购物车费用明细卡是 i18n 综合呈现的核心区Column({space:8}){Row(){Text(this.T(K.subtotal)).fontSize(13).fontColor(#64748B).layoutWeight(1)Text(this.fmtMoney(this.goodsTotalCents())).fontSize(14).fontColor(#334155)}.width(100%)Row(){Text(${this.T(K.taxRate)}(${TAX_RATE_PERCENT}%)).fontSize(13).fontColor(#64748B).layoutWeight(1)Text(this.fmtMoney(this.taxCents())).fontSize(14).fontColor(#334155)}.width(100%)Row(){Text(this.T(K.shipping)).fontSize(13).fontColor(#64748B).layoutWeight(1)Text(this.shippingCents()0?${this.T(K.shippingFree)}${this.T(K.freeTip)}:this.fmtMoney(this.shippingCents())).fontSize(13).fontColor(this.shippingCents()0?#10B981:#334155).textAlign(TextAlign.End)}.width(100%)if(this.discountCents()0){Row(){Text(this.T(K.discount)).fontSize(13).fontColor(#64748B).layoutWeight(1)Text(-${this.fmtMoney(this.discountCents())}).fontSize(14).fontColor(#DC2626)}.width(100%)}Divider().color(#E2E8F0)Row(){Text(this.T(K.total)).fontSize(15).fontWeight(FontWeight.Bold).fontColor(#0F172A).layoutWeight(1)Text(this.fmtMoney(this.totalCents())).fontSize(22).fontWeight(FontWeight.Bold).fontColor(#D97706)}.width(100%)}.width(94%).padding(14).backgroundColor(#FFF7ED).borderRadius(14)设计要点五层费用从灰到琥珀小计/税费/运费普通灰满减红色负号-¥50.00合计 22 号琥珀加粗——视觉焦点永远落在合计免运费态本地化免运费 满 ¥300 免运费未满收 ¥12英文 “Free · Free shipping over ¥300, otherwise ¥12”——条件文案整句从文案表取不是拼接条件行用if渲染满减不满足时不显示该行Divider与合计之间层级干净底部结算栏清空按钮 合计 支付按钮enabled控制禁用态支付状态机三态——待支付琥珀/处理中橙/已支付绿每个状态都有对应文案与颜色。八、支付成功横幅时间/订单号的综合本地化if(this.paidAt!-1){Column({space:4}){Text(${this.T(K.paySuccess)}).fontSize(14).fontWeight(FontWeight.Bold).fontColor(#065F46)Text(this.T(K.paySuccessDesc)).fontSize(11).fontColor(#047857).textAlign(TextAlign.Center)Row(){Text(${this.T(K.orderNo)}:${this.fmtOrderNo()}).fontSize(11).fontColor(#065F46)}.width(100%).justifyContent(FlexAlign.Center).margin({top:4})Row(){Text(${this.T(K.orderTime)}:${this.fmtTime(this.paidAt)}).fontSize(11).fontColor(#065F46)}.width(100%).justifyContent(FlexAlign.Center)Row(){Text(${this.T(K.status)}:${this.T(K.statusPaid)}).fontSize(11).fontColor(#065F46)}.width(100%).justifyContent(FlexAlign.Center)}.width(94%).padding(12).backgroundColor(#D1FAE5).borderRadius(12)}订单号走NumberFormat2026081912345678在英文下显示20,260,819,123,456,78带千分位——数字分组也是本地化的一部分下单时间走DateTimeFormat中文2026年8月19日 14:30、英文 “August 19, 2026 at 2:30 PM”——日期时间风格long short由语言模板决定**绿底横幅#D1FAE5**与已支付按钮绿色呼应成功语义全页一致。九、排版验证清单多语言下自查检查项方法验证结果金额随币种fmtMoney()走style:currency¥1,299 → $181.86 / €168.87 / ¥27,928日元零小数CURRENCIES配置digits: 0JPY 显示 ¥27,928 无 .00商品名随语言productName()5 语言 Map日文名称不溢出卡片复数规则fmtQty()用PluralRules英文 “1 item” / “3 items”订单号分组NumberFormat英文带千分位逗号时间随语言fmtTime()dateStyle:long中英日三格式正确免运费态条件文案从文案表整体取满 ¥300 免运费整句本地化空购物车态cartCount() 0分支空态文案 去逛逛按钮十、可访问性多语言 UI 加分项双选择器不靠单色语言青绿、币种琥珀且徽章带文字 简体中文 / $ USD——色弱用户靠文字区分维度金额颜色 字号双编码合计 22 号琥珀 vs 小计 14 号灰——不只看颜色也能靠字号定位重点状态机反馈完整支付按钮禁用态enabled 文案变化立即支付→支付处理中→已支付视觉与文本双重反馈对比度琥珀 #D97706 on 白 ≈ 3.9:1大字 16 满足 AA Large、teal #0F766E on 白 ≈ 5.9:1、绿 #10B981 on 白 ≈ 3.0:1用于大字/底金额可朗读fmtMoney输出带符号与货币码的完整字符串朗读器读出 “美元 181 点 86” 而非裸数字。十一、小结本页 UI 是系列 13 个应用的综合验收语言徽章01 模式、币种徽章03 模式、金额管线09 模式、复数数量05 模式、时间订单号02 模式、状态机反馈通用模式在一屏内协同工作。设计上最大的成功是双选择器 一条金额管线——用户只操作两个开关全页几百个数字全部正确刷新这正是状态驱动 UI的威力。下一篇文章深入技术实现讲解整数分存储、汇率换算、货币格式化的完整链路。