鸿蒙原生应用 ArkUI 实战:三列汇总卡 + 三态过保列表 —— 保修管理首页的告警总览架构

App 53「保修期管理」首页(HomeTab),主题色 #00A862 生态绿,4 个 Tab 分别为首页(🔧)、商品(📦)、保修(⏰)、我的(👤)。本篇基于 53-warranty-mgr/entry/src/main/ets/pages/HomeTab.ets(共 108 行)逐段拆解,附 4 张实机截图。

首页整体布局

一、整体结构:三区"Header + 汇总卡 + 列表"布局

首页是"品牌头部 + 保修统计 + 商品列表"的三区布局——3 个 @Builder 块:

build() {
  Column() {
    this.Header()
    Scroll() {
      Column({ space: 14 }) {
        this.SummaryCard()
        this.SectionTitle('即将过保')
        this.ProductList()
      }
      .width('100%')
      .padding({ left: D.pad, right: D.pad, top: 14, bottom: D.pad + this.safeBottom + 20 })
    }
    .layoutWeight(1).scrollBar(BarState.Off).align(Alignment.Top)
  }
  .width('100%').height('100%').backgroundColor(C.bg)
}

3 块结构:Header(单行品牌头)→ SummaryCard(绿色渐变三列汇总卡)→ ProductList(4 条三态商品卡片)。首页是"保修总览页"——先亮出三类核心数据(8 件商品、2 件临期、1 件过保),再列出商品保修状态明细。相比 App 52 票据的"金额总览",本页是"时间总览"——保修管理关心的核心是"还剩多少天"。

二、Header:单行品牌头

Header() {
  Column() {
    Text('保修期管理').fontSize(22).fontWeight(FontWeight.Bold).fontColor(C.text)
      .width('100%').padding({ top: this.safeTop + 10, left: D.pad, right: D.pad, bottom: 12 })
  }.width('100%').backgroundColor(C.card)
}

22 号加粗、safeTop + 10 避让状态栏、白底全宽。与系列工具型首页(App 45/App 47/App 52)同款单行标题范式。

三、SummaryCard:三列渐变汇总卡

SummaryCard() {
  Row() {
    Column({ space: 4 }) {
      Text('8').fontSize(24).fontWeight(FontWeight.Bold).fontColor('#FFFFFF')
      Text('商品总数').fontSize(12).fontColor('#FFFFFF').opacity(0.9)
    }.alignItems(HorizontalAlign.Start).layoutWeight(1)
    Column({ space: 4 }) {
      Text('2').fontSize(24).fontWeight(FontWeight.Bold).fontColor('#FFFFFF')
      Text('即将过保').fontSize(12).fontColor('#FFFFFF').opacity(0.9)
    }.alignItems(HorizontalAlign.Start).layoutWeight(1)
    Column({ space: 4 }) {
      Text('1').fontSize(24).fontWeight(FontWeight.Bold).fontColor('#FFFFFF')
      Text('已过保').fontSize(12).fontColor('#FFFFFF').opacity(0.9)
    }.alignItems(HorizontalAlign.Start).layoutWeight(1)
  }
  .width('100%').padding(20).borderRadius(D.rLg)
  .linearGradient({ angle: 135, colors: [[C.primary, 0.0], [C.accent, 1.0]] })
}

逐点拆解:

  1. 绿色渐变:linearGradient 从 #00A862 生态绿渐变到 #4BC98A 亮绿——绿色传达"安全/在保"的心理暗示,保修管理用绿色表达"一切尽在掌握"。
  2. 三列均分:Row + 三个 layoutWeight(1) Column——商品总数(8)/ 即将过保(2)/ 已过保(1)三列 1:1:1,每列 24 号 Bold 白字数值 + 12 号 90% 白字标签。
  3. 与 App 52 的差异:52 是"两列副统计 + 大金额主数字"(一主二副),53 是"三列平级统计"——52 有唯一焦点(金额),53 三个数字同等重要(总数、临期、过保是三个不同告警维度),平级呈现让用户同时看到三个关键数。
  4. 标签透明度 0.9:小标签 90% 透明度弱化、数值 1.0 强调——"标签轻、数值重"的层级。

四、Product 数据模型 + SectionTitle

interface Product {
  id: number;
  emoji: string;
  name: string;
  daysLeft: number;
  expired: boolean;
}
private products: Product[] = [
  { id: 1, emoji: '📱', name: 'iPhone 15 Pro', daysLeft: 45, expired: false },
  { id: 2, emoji: '💻', name: 'MacBook Air', daysLeft: 12, expired: false },
  { id: 3, emoji: '🎧', name: 'AirPods Pro', daysLeft: -30, expired: true },
  { id: 4, emoji: '⌚', name: 'Apple Watch', daysLeft: 180, expired: false }
];

Product 五字段:emoji(设备图标)、name(名称)、daysLeft(剩余天数,过保为负)、expired(是否过保)。4 件商品覆盖三态:iPhone 45 天(在保)、MacBook 12 天(临期)、AirPods -30 天(过保)、Apple Watch 180 天(在保)。

SectionTitle(title: string) {
  Row() {
    Text(title).fontSize(16).fontWeight(FontWeight.Bold).fontColor(C.text)
    Blank()
    Text('全部 >').fontSize(12).fontColor(C.textDim)
  }.width('100%')
}

Blank() 撑开中间空间——左侧标题 + 右侧"全部 >"入口,与 App 52 同款弹性占位范式。

五、ProductList:三态商品卡片列表

ProductList() {
  Column({ space: 10 }) {
    ForEach(this.products, (p: Product) => {
      Row({ space: 12 }) {
        Row() { Text(p.emoji).fontSize(26) }
        .width(50).height(50).backgroundColor(C.primarySoft).borderRadius(D.rSm).justifyContent(FlexAlign.Center)
        Column({ space: 4 }) {
          Text(p.name).fontSize(14).fontWeight(FontWeight.Medium).fontColor(C.text)
          if (p.expired) {
            Text('已过保 ' + (-p.daysLeft) + ' 天').fontSize(12).fontColor(C.danger)
          } else if (p.daysLeft <= 30) {
            Text('还剩 ' + p.daysLeft + ' 天过保').fontSize(12).fontColor(C.warn)
          } else {
            Text('还剩 ' + p.daysLeft + ' 天过保').fontSize(12).fontColor(C.ok)
          }
        }.alignItems(HorizontalAlign.Start).layoutWeight(1)
        Text(p.expired ? '过保' : (p.daysLeft <= 30 ? '临期' : '在保')).fontSize(11)
          .fontColor(p.expired ? C.danger : (p.daysLeft <= 30 ? C.warn : C.ok))
          .padding({ left: 10, right: 10, top: 4, bottom: 4 })
          .backgroundColor(p.expired ? '#FDEAEA' : (p.daysLeft <= 30 ? '#FEF3E0' : '#E8F7EE')).borderRadius(D.rSm)
      }
      .width('100%').padding(12).backgroundColor(C.card).borderRadius(D.rMd).border({ width: 1, color: C.stroke })
      .onClick(() => { promptAction.showToast({ message: p.name }); })
    }, (p: Product) => p.id.toString())
  }.width('100%')
}

逐点拆解:

  1. 50×50 主色软底图标块:C.primarySoft(#E0F5EB)淡绿圆角底 + 26 号 emoji——每件商品一个专属 emoji(📱💻🎧⌚),扫一眼识别设备类型。
  2. 三态状态机(90-96 行):if (p.expired) 显示红字"已过保 30 天"(取 -p.daysLeft 转正);否则 p.daysLeft <= 30 显示橙字"还剩 12 天过保";否则绿字"还剩 45 天过保"——同一行文案用三元状态机渲染,三种状态三种颜色(红/橙/绿 = 危险/警告/正常)。
  3. 右侧状态胶囊(98-101 行):'过保' / '临期' / '在保' 三态胶囊——字色 + 底色双变化(红字粉底 #FDEAEA / 橙字黄底 #FEF3E0 / 绿字绿底 #E8F7EE),状态一眼可辨。
  4. 临期阈值 30 天:daysLeft <= 30 判定临期——与我的页"过保前 30 天提醒"阈值一致,30 天是全局统一告警阈值。
  5. 整卡点击:onClick 弹 Toast 商品名——产品化后跳商品详情页。

点击商品卡片弹出提示

六、数据自洽:汇总 = 列表分项之和

        Text('8').fontSize(24).fontWeight(FontWeight.Bold).fontColor('#FFFFFF')
  { id: 1, emoji: '📱', name: 'iPhone 15 Pro', daysLeft: 45, expired: false },
  { id: 2, emoji: '💻', name: 'MacBook Air', daysLeft: 12, expired: false },
  { id: 3, emoji: '🎧', name: 'AirPods Pro', daysLeft: -30, expired: true },
  { id: 4, emoji: '⌚', name: 'Apple Watch', daysLeft: 180, expired: false }

汇总卡 8 件商品 = 列表 4 件 + 未展示 4 件;2 件临期(MacBook 12 天 + 未展示 1 件)、1 件过保(AirPods -30 天)——汇总 = 列表分项之和,演示数据自洽。同时首页"iPhone 45 天"与保修页"剩余 45 天"完全一致,四页同源。

首页列表与交互

七、生态绿主题的视觉策略

export class C {
  static readonly bg: string = '#F2F5FB';
  static readonly card: string = '#FFFFFF';
  static readonly cardSoft: string = '#F4F6FB';
  static readonly stroke: string = '#EAEEF6';
  static readonly text: string = '#1C2333';
  static readonly textSub: string = '#5A6483';
  static readonly textDim: string = '#9AA3BC';
  static readonly primary: string = '#00A862';
  static readonly primarySoft: string = '#E0F5EB';
  static readonly accent: string = '#4BC98A';
  static readonly warn: string = '#FF9F1C';
  static readonly danger: string = '#FF5A6E';
  static readonly ok: string = '#2BB673';
}

逐点拆解:

  1. primary = #00A862:生态绿传达"安全/正常/健康"气质——与 App 47 班费绿(#00A862 同色)一致,但 47 管"钱"(余额)、53 管"时间"(剩余天数),同色不同义。
  2. accent = #4BC98A:亮绿渐变终点——绿系渐变是"在保 = 安全"的视觉标识。
  3. 三态语义色:ok = #2BB673(在保绿)、warn = #FF9F1C(临期橙)、danger = #FF5A6E(过保红)——三色与列表状态机一一对应,全页统一引用。

八、系列横向对比:绿系工具首页三剑客

工具首页代表 App首页焦点核心动作主题色
时间告警App 53 保修三列汇总 + 三态列表看剩余天数 → 处理临期#00A862 生态绿
金额汇总App 52 票据渐变汇总卡 + 票据列表看总额 → 查明细#0066CC 科技蓝
账务余额App 47 班费余额卡 + 收支动态看账#00A862 翡翠绿

差异点:App 53 的"三态状态机"是系列中少见的"状态型列表"——其他列表多为静态数据展示,53 的列表随剩余天数动态变色(在保绿/临期橙/过保红),是"防漏保"告警的视觉化表达。

滚动查看全部商品状态

九、开发者视角:调试与验证技巧

  1. 负数转正:过保商品 daysLeft 存负值(-30),展示时用 -p.daysLeft 转正——数据层用负数表示"已超期天数",判断状态用正负、展示文案用绝对值,约定要在数据层注释清楚。
  2. 三态判定顺序:先判 expired(过保)、再判 daysLeft <= 30(临期)、最后默认在保——判定顺序不可颠倒(若先判临期,过保商品 -30 也满足 <= 30 会被误判为临期),布尔过期标志 + 天数阈值两级判断是正确写法。
  3. 颜色语义统一:红 = 过保(danger)、橙 = 临期(warn)、绿 = 在保(ok)——三色语义与主题常量一一对应,后续所有页面都要沿用这套语义色,不能自行换色。
  4. 胶囊底色与字色:胶囊用浅色底 + 深色字(#FDEAEA/#FEF3E0/#E8F7EE)——比"深色底白字"更柔和,适合列表中的小标签;注意三色浅底要能区分(都接近白色时用户无法辨识)。

十、演进方向

方向当前状态产品化演进
天数动态计算硬编码 45/12/-30/180到期日 - 今日 实时计算,每天自动更新
列表排序数组声明顺序按剩余天数升序,最紧急置顶
商品详情Toast"iPhone 15 Pro"跳商品详情页(保修卡/凭证/售后电话)
过保分区混在同一列表过保商品单独成区或灰置
临期阈值固定 30 天用户可配置(7/15/30/60 天)

十一、一句话总结

首页以"三列渐变汇总卡 + 三态商品列表"完成了保修管理的告警总览。linearGradient 生态绿渐变汇总卡(三列平级 8/2/1)、50×50 淡绿底 emoji 图标块、三元状态机渲染(在保绿/临期橙/过保红 + 状态胶囊字色底色双变化)、Blank() 弹性占位 SectionTitle——108 行代码,一个"看总量 → 盯临期 → 处理过保"的保修总览页,也是"时间管理"型首页的标准范式。

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

Logo

作为“人工智能6S店”的官方数字引擎,为AI开发者与企业提供一个覆盖软硬件全栈、一站式门户。

更多推荐