引言

在这里插入图片描述

经典老爷车收藏是一个融合了历史情怀、机械美学和投资价值的小众但高净值垂直领域。从1965年的大众甲壳虫到1990年的保时捷911 964,每一台经典车都承载着特定时代的设计语言与工业记忆。将这样一个需要兼顾专业鉴定信息、修复工程管理、配件交易和藏家社区社交的复杂业务场景,转化为一个移动应用页面,对开发者的数据建模能力、信息架构设计能力和交互流程编排能力都提出了极高的要求。本文将深入解析一款基于HarmonyOS ArkTS声明式UI框架构建的复古经典车馆应用页面,该页面以复古红、黄铜金、米白和墨绿四色构建了浓郁的怀旧视觉基调。

从技术架构层面分析,该应用采用HarmonyOS ArkTS的@Entry+@Component标准入口组件结构,通过@State装饰器管理十余个响应式状态变量。应用以统一的GoodsItem接口描述六类业务数据——经典车展、老爷车市、修复工坊、配件集市、车友会和消息通知——共78条数据记录。页面以七Tab导航为核心框架,配合五种弹窗(发布藏车、修复评估、配件求购、删除确认、车辆详情)实现完整的"浏览-鉴定-修复-求购-收藏"业务闭环。整个应用以单文件结构完成所有功能逻辑和UI渲染,体现了ArkTS声明式编程在中等复杂度业务场景下的适用性。

在视觉设计层面,应用采用了复古红(#8D2F2F)作为主品牌色,黄铜金(#A1887F)作为辅助色和装饰色,米白(#FAF3E8)作为浅色背景和文字色,墨绿(#3E5641)作为修复工坊模块的主题色,警示红(#E53935)作为价格和警示信息色。这套配色方案精准地还原了经典车时代的色彩记忆——复古红让人联想到上世纪的汽车广告海报,黄铜金呼应了老车的镀铬装饰件,米白如同泛黄的老照片纸张,墨绿则暗示了修复车间的工业氛围。应用在多个关键元素上使用了700毫秒无限循环的EaseInOut脉冲缩放动画,为静态的怀旧页面注入了微妙的动态呼吸感。

数据接口与状态管理

在这里插入图片描述

应用首先定义了全局数据接口GoodsItem,随后在主组件中声明了状态变量和多组业务数据源,构成了页面的数据基础。

interface GoodsItem {
  name: string
  price: number
  desc: string
  score: number
  num: number
  tag: string
  hot: string
}

@Entry
@Component
struct Index {
  @State currentTab: number = 0
  @State showAddModal: boolean = false
  @State showFixModal: boolean = false
  @State showWantModal: boolean = false
  @State showDeleteModal: boolean = false
  @State showDetailModal: boolean = false
  @State selectedItem: GoodsItem | null = null
  @State chipA: number = 0
  @State chipB: number = 0
  @State stepNum: number = 1
  @State inputDesc: string = ''

  private tabs: string[] = ['经典车展', '老爷车市', '修复工坊', '配件集市', '车友会', '消息', '我的']
  private eraChips: string[] = ['1950前', '1951-1970', '1971-1990', '1991-2000']
  private condChips: string[] = ['原版未修', '修复翻新', '改装升级']
  private fixItemChips: string[] = ['发动机大修', '内饰翻新', '车漆修复', '底盘整备']
  private fixDurChips: string[] = ['1个月', '3个月', '6个月', '1年']
  private partTypeChips: string[] = ['发动机件', '内饰件', '外观件', '电气件']
  private wantEraChips: string[] = ['1950前', '1970前', '1990前', '2000前']
  private topicChips: string[] = ['五十年代', '六十年代', '七十年代', '肌肉车', '欧陆经典', '东方记忆']
  private historyChips: string[] = ['原厂档案', '两次过户', '全程养护', '老照片']
  private menuList: string[] = ['我的藏车', '修复订单', '求购配件', '发布藏车', '展会门票', '账号设置']

GoodsItem接口的七个字段在不同列表中承载了差异化的业务语义。在mainList中,price为车辆价格(最高达360万元),score为稀有度百分比,num为车龄年数;在vinList中,num同样为车龄年数,tag为年代分类;在fixList中,num为工期天数,tag为修复项目类别;在partList中,num为库存件数,score为稀有度指数;在clubList中,price为点赞数,num为阅读量;在msgList中,price为关联数值,num为阅读量,hot标记未读/已读状态。这种高复用的数据接口设计在减少接口定义数量的同时,也要求开发者在渲染逻辑中清晰地处理字段语义的切换。

状态变量方面,currentTab控制Tab切换,五个show*Modal布尔值控制弹窗显隐。chipAchipB作为通用选择索引被多个弹窗复用——发布藏车弹窗中分别记录年代选择和车况选择,修复评估弹窗中记录修复项目和期望工期,配件求购弹窗中记录配件类型和适配年代。stepNum为求购数量步进器,inputDesc绑定描述输入框文本。修复评估弹窗的报价计算由fixQuote()方法根据chipAchipB的组合动态返回,体现了状态驱动的业务逻辑计算模式。

核心数据源:24台传世经典车

在这里插入图片描述

经典车展主列表是应用的核心数据资产,包含24台横跨1957年至1990年的传世经典车型。

  // 经典车展主列表:24 条传世经典车
  private mainList: GoodsItem[] = [
    { name: '1965 大众甲壳虫 1200', price: 128000, desc: '1965年 · 德国原版 · 手动挡', score: 96, num: 61, tag: '稀有', hot: '藏' },
    { name: '1978 奔驰 W123 230E', price: 96000, desc: '1978年 · 德系耐用典范', score: 88, num: 48, tag: '经典', hot: '热' },
    { name: '1972 宝马 2002', price: 185000, desc: '1972年 · 巴伐利亚运动轿车', score: 92, num: 54, tag: '稀有', hot: '热' },
    { name: '1963 捷豹 E-Type S1', price: 1380000, desc: '1963年 · 英伦跑车美学巅峰', score: 98, num: 63, tag: '殿堂', hot: '藏' },
    { name: '1990 保时捷 911 964', price: 890000, desc: '1990年 · 末代风冷手动挡', score: 94, num: 36, tag: '稀有', hot: '热' },
    { name: '1985 伏尔加 嘎斯24', price: 68000, desc: '1985年 · 苏联公务车代表', score: 78, num: 41, tag: '情怀', hot: '冷' },
    { name: '1965 红旗 CA72', price: 2680000, desc: '1965年 · 国礼级检阅车', score: 99, num: 61, tag: '国宝', hot: '藏' },
    { name: '1976 上海 SH760A', price: 155000, desc: '1976年 · 沪上制造记忆', score: 86, num: 50, tag: '情怀', hot: '热' },
    { name: '1969 丰田 2000GT', price: 3600000, desc: '1969年 · 东瀛第一超跑', score: 99, num: 57, tag: '殿堂', hot: '藏' },
    { name: '1961 福特 雷鸟', price: 210000, desc: '1961年 · 美式敞篷豪华', score: 84, num: 65, tag: '经典', hot: '冷' },
    { name: '1970 雪铁龙 DS21', price: 480000, desc: '1970年 · 液压悬挂传奇', score: 93, num: 56, tag: '稀有', hot: '热' },
    { name: '1980 菲亚特 124', price: 72000, desc: '1980年 · 意式家用后驱', score: 74, num: 46, tag: '经典', hot: '冷' },
    { name: '1967 阿尔法·罗密欧 Giulia', price: 520000, desc: '1967年 · 米兰弯道精灵', score: 91, num: 59, tag: '稀有', hot: '热' },
    { name: '1974 沃尔沃 P1800', price: 260000, desc: '1974年 · 北欧长寿纪录', score: 85, num: 52, tag: '经典', hot: '冷' },
    { name: '1958 凯迪拉克 Eldorado', price: 720000, desc: '1958年 · 尾翼时代巅峰', score: 95, num: 68, tag: '稀有', hot: '藏' },
    { name: '1988 宝马 M3 E30', price: 1150000, desc: '1988年 · 直六赛化机器', score: 97, num: 38, tag: '殿堂', hot: '热' },
    { name: '1969 日产 费尔雷迪 Z432', price: 980000, desc: '1969年 · 东瀛S20名机', score: 94, num: 57, tag: '稀有', hot: '藏' },
    { name: '1975 标致 504', price: 58000, desc: '1975年 · 非洲拉力常胜', score: 72, num: 51, tag: '情怀', hot: '冷' },
    { name: '1957 菲亚特 500', price: 165000, desc: '1957年 · 意大利国民小车', score: 87, num: 69, tag: '经典', hot: '热' },
    { name: '1962 奔驰 190SL', price: 880000, desc: '1962年 · 斯图加特敞篷', score: 92, num: 64, tag: '稀有', hot: '藏' },
    { name: '1979 拉达 2101', price: 38000, desc: '1979年 · 战斗民族国民车', score: 66, num: 47, tag: '情怀', hot: '冷' },
    { name: '1984 北京 BJ212', price: 46000, desc: '1984年 · 国产越野活化石', score: 76, num: 42, tag: '情怀', hot: '热' },
    { name: '1968 庞蒂亚克 GTO', price: 960000, desc: '1968年 · 肌肉车鼻祖', score: 95, num: 58, tag: '殿堂', hot: '藏' },
    { name: '1986 丰田 FJ60', price: 235000, desc: '1986年 · 方盒子越野经典', score: 83, num: 40, tag: '经典', hot: '热' }
  ]

24台经典车覆盖了德系(大众甲壳虫、奔驰W123/190SL、宝马2002/M3 E30)、英系(捷豹E-Type、沃克斯豪尔Victor)、意系(菲亚特124/500、阿尔法·罗密欧Giulia、标致504)、美系(福特雷鸟、凯迪拉克Eldorado、庞蒂亚克GTO)、日系(丰田2000GT、日产Z432、丰田FJ60)、苏系(伏尔加嘎斯24、拉达2101)和国产(红旗CA72、上海SH760A、北京BJ212)七大车系,价格从3.8万元的拉达2101到360万元的丰田2000GT,稀有度评分从66到99分。tag字段使用"稀有"“经典”“殿堂”“情怀”“国宝"五个等级标签,hot字段使用"藏”“热”"冷"三个字标记市场热度,这些信息在列表渲染中会以彩色标签的形式直观呈现。每条数据的num字段为车龄年数(36-69年),在Tab1页面的列表中以"车龄XX年"的形式展示。

专业数据源:老爷车市、修复工坊与配件集市

在这里插入图片描述

除主列表外,应用还定义了老爷车市、修复工坊和配件集市三个专业数据源。

  // 老爷车市:12 条待售经典车,num 为车龄年
  private vinList: GoodsItem[] = [
    { name: '1972 奔驰 280SE 3.5', price: 385000, desc: '1972年 · V8豪华轿跑', score: 90, num: 54, tag: '七十年代', hot: '售' },
    { name: '1966 福特 野马 GT', price: 620000, desc: '1966年 · 美式肌肉代表', score: 92, num: 60, tag: '六十年代', hot: '售' },
    { name: '1983 丰田 AE86', price: 520000, desc: '1983年 · 秋名山传说', score: 93, num: 43, tag: '八十年代', hot: '售' },
    { name: '1977 凯迪拉克 弗利特伍德', price: 298000, desc: '1977年 · 陆地游艇', score: 85, num: 49, tag: '七十年代', hot: '售' },
    { name: '1969 大众 T2 面包车', price: 345000, desc: '1969年 · 嬉皮士之车', score: 89, num: 57, tag: '六十年代', hot: '售' },
    { name: '1985 奔驰 W126 560SEC', price: 210000, desc: '1985年 · 元首级双门', score: 82, num: 41, tag: '八十年代', hot: '售' },
    { name: '1963 沃克斯豪尔 Victor', price: 128000, desc: '1963年 · 英伦家用经典', score: 75, num: 63, tag: '六十年代', hot: '售' },
    { name: '1974 阿尔法·罗密欧 GTV', price: 265000, desc: '1974年 · 意式双门轿跑', score: 88, num: 52, tag: '七十年代', hot: '售' },
    { name: '1990 日产 Skyline R32', price: 680000, desc: '1990年 · 战神GT-R', score: 95, num: 36, tag: '九十年代', hot: '售' },
    { name: '1968 福特 F-100 皮卡', price: 188000, desc: '1968年 · 美式工具车', score: 78, num: 58, tag: '六十年代', hot: '售' },
    { name: '1979 铃木 吉姆尼 SJ10', price: 86000, desc: '1979年 · 轻越野鼻祖', score: 72, num: 47, tag: '七十年代', hot: '售' },
    { name: '1956 雪佛兰 贝莱尔', price: 720000, desc: '1956年 · 美国梦象征', score: 94, num: 70, tag: '五十年代', hot: '售' }
  ]

  // 修复工坊:10 条修复项目,num 为工期天数
  private fixList: GoodsItem[] = [
    { name: '1966 福特 野马整车修复', price: 268000, desc: '发动机与车漆全流程', score: 96, num: 180, tag: '精修', hot: '急' },
    { name: '1975 奔驰 W115 底盘整备', price: 68000, desc: '悬挂与制动重建', score: 90, num: 45, tag: '底盘', hot: '缓' },
    { name: '1962 捷豹 XK150 车漆复原', price: 158000, desc: '九道工序手工漆', score: 93, num: 120, tag: '车漆', hot: '急' },
    { name: '1959 凯迪拉克内饰翻新', price: 120000, desc: '真皮与镀铬件重制', score: 88, num: 90, tag: '内饰', hot: '缓' },
    { name: '1970 雪铁龙 DS 液压系统', price: 96000, desc: '液气悬挂专项', score: 91, num: 60, tag: '底盘', hot: '急' },
    { name: '1983 丰田 AE86 车架校正', price: 88000, desc: '事故车回归赛道', score: 87, num: 75, tag: '车架', hot: '缓' },
    { name: '1968 红旗 CA770 内饰复原', price: 320000, desc: '国车级翻新工程', score: 98, num: 300, tag: '精修', hot: '急' },
    { name: '1972 宝马 2002 发动机大修', price: 76000, desc: '化油器重新调校', score: 89, num: 50, tag: '发动机', hot: '缓' },
    { name: '1957 菲亚特 500 电路改造', price: 36000, desc: '全车电路升级', score: 82, num: 40, tag: '电气', hot: '缓' },
    { name: '1979 拉达 2101 钣金修复', price: 28000, desc: '锈蚀面板更换', score: 80, num: 40, tag: '钣金', hot: '急' }
  ]

  // 配件集市:10 条稀有配件,num 为库存件数
  private partList: GoodsItem[] = [
    { name: '化油器 Weber 40DCOE', price: 6800, desc: '适配阿尔法与宝马', score: 96, num: 48, tag: '欧系', hot: '珍' },
    { name: '红旗 CA72 原厂大灯总成', price: 15800, desc: '适配红旗CA72', score: 99, num: 60, tag: '国产', hot: '孤品' },
    { name: '捷豹 E-Type 木纹方向盘', price: 9200, desc: '适配E-Type S1', score: 94, num: 45, tag: '英系', hot: '珍' },
    { name: '奔驰 W123 全套镀铬饰条', price: 4200, desc: '适配W123轿车', score: 78, num: 120, tag: '欧系', hot: '常' },
    { name: '甲壳虫 原厂帆布车顶', price: 3600, desc: '适配1200敞篷版', score: 85, num: 90, tag: '欧系', hot: '常' },
    { name: '凯迪拉克 尾翼装饰件', price: 7800, desc: '适配1958年款', score: 92, num: 50, tag: '美系', hot: '珍' },
    { name: '伏尔加 前格栅总成', price: 2900, desc: '适配嘎斯24', score: 74, num: 110, tag: '苏系', hot: '常' },
    { name: '菲亚特 500 里程表芯', price: 880, desc: '适配500全系列', score: 68, num: 200, tag: '意系', hot: '常' },
    { name: '宝马 2002 圆灯支架', price: 1500, desc: '适配2002轿车', score: 72, num: 150, tag: '欧系', hot: '常' },
    { name: '上海 SH760 门把手', price: 1200, desc: '适配SH760A', score: 88, num: 70, tag: '国产', hot: '珍' }
  ]

老爷车市列表中tag字段按年代分类(五十年代至九十年代),hot字段统一标记为"售"。修复工坊列表中num为工期天数(40-300天),tag为修复项目类别(精修、底盘、车漆、内饰等),hot使用"急"“缓"标记紧迫度。配件集市列表中num为库存件数,score为稀有度指数(68-99),hot使用"珍”“孤品”"常"标记稀有级别。这些差异化的字段语义在各自Tab页面的渲染逻辑中被精确处理,确保了数据的正确呈现。

辅助方法与报价计算引擎

在这里插入图片描述

应用定义了一组辅助方法,其中priceText方法用于价格格式化和fixQuote方法用于修复报价动态计算,是本应用最具业务价值的方法设计。

  selName(): string {
    if (this.selectedItem !== null) {
      return this.selectedItem.name
    }
    return ''
  }

  selPrice(): number {
    if (this.selectedItem !== null) {
      return this.selectedItem.price
    }
    return 0
  }

  selDesc(): string {
    if (this.selectedItem !== null) {
      return this.selectedItem.desc
    }
    return ''
  }

  selScore(): number {
    if (this.selectedItem !== null) {
      return this.selectedItem.score
    }
    return 0
  }

  selTag(): string {
    if (this.selectedItem !== null) {
      return this.selectedItem.tag
    }
    return ''
  }

  selHot(): string {
    if (this.selectedItem !== null) {
      return this.selectedItem.hot
    }
    return ''
  }

  maxNumOf(list: GoodsItem[]): number {
    let m: number = 1
    for (let i = 0; i < list.length; i++) {
      if (list[i].num > m) {
        m = list[i].num
      }
    }
    return m
  }

  priceText(p: number): string {
    let w: number = Math.floor(p / 10000)
    let k: number = Math.floor((p % 10000) / 1000)
    return w + '.' + k + '万'
  }

  fixQuote(): number {
    let base: number = 68000
    if (this.chipA === 1) {
      base = 42000
    } else if (this.chipA === 2) {
      base = 26000
    } else if (this.chipA === 3) {
      base = 35000
    }
    let factor: number = 1.0
    if (this.chipB === 1) {
      factor = 1.6
    } else if (this.chipB === 2) {
      factor = 2.4
    } else if (this.chipB === 3) {
      factor = 3.8
    }
    return Math.floor(base * factor)
  }

六个sel*方法遵循统一的防御性编程模式,确保在selectedItem为空时返回安全默认值。maxNumOf方法用于柱状图的归一化计算。priceText方法将数值价格转换为"万"单位的中文价格格式——通过Math.floor(p / 10000)取万位整数,Math.floor((p % 10000) / 1000)取千位整数,拼接为如"138.0万""3.6万"的格式,这种格式化在经典车交易场景中符合中文用户的阅读习惯。

fixQuote方法是修复评估弹窗的核心业务逻辑。它根据chipA(修复项目)确定基础报价(发动机大修68000、内饰翻新42000、车漆修复26000、底盘整备35000),再根据chipB(期望工期)确定乘数因子(3个月1.6倍、6个月2.4倍、1年3.8倍),最终通过Math.floor(base * factor)计算预估报价。这种"基础价+工期系数"的报价模型虽然简化,但清晰地展示了状态驱动业务计算的设计模式——当用户在弹窗中选择不同的修复项目和工期时,报价数字会实时变化并触发UI刷新。

静态头部与底部导航

在这里插入图片描述

头部组件集成了品牌标识、搜索入口和消息通知功能,底部导航栏实现七Tab切换。

  // 静态头部:标题行 + 搜索胶囊 + 展会信息条
  @Builder headerBuilder() {
    Column() {
      Row() {
        Row({ space: 8 }) {
          Column() {
            Text('经').fontSize(12).fontColor('#FFFFFF').fontWeight(FontWeight.Bold)
          }.width(26).height(26).borderRadius(6).backgroundColor('#A1887F')
          .justifyContent(FlexAlign.Center).alignItems(HorizontalAlign.Center)

          Text('复古经典车馆').fontSize(18).fontColor('#FFFFFF').fontWeight(FontWeight.Bold)
        }.alignItems(VerticalAlign.Center)

        Column().layoutWeight(1)

        Row({ space: 14 }) {
          Text('🔨').fontSize(16)
            .onClick(() => { this.chipA = 0; this.chipB = 0; this.showAddModal = true })

          Stack() {
            Text('✉').fontSize(16)
            Text('6').fontSize(8).fontColor('#FFFFFF').fontWeight(FontWeight.Bold)
              .padding({ left: 4, right: 4, top: 1, bottom: 1 }).borderRadius(8).backgroundColor('#E53935')
              .offset({ x: 8, y: -8 })
          }.width(24).height(24)
          .onClick(() => { this.currentTab = 5 })
        }.alignItems(VerticalAlign.Center)
      }.width('100%').padding({ left: 16, right: 16, top: 10, bottom: 10 }).alignItems(VerticalAlign.Center)

      Row({ space: 8 }) {
        Text('🚗').fontSize(14)
        Text('搜经典车/配件').fontSize(12).fontColor('#B8A98F').layoutWeight(1)
        Text('🔍').fontSize(12)
      }.width('100%').height(36).borderRadius(18).backgroundColor('#FAF3E8')
      .padding({ left: 14, right: 14 }).alignItems(VerticalAlign.Center)

      Row({ space: 8 }) {
        Column().width(4).height(12).borderRadius(2).backgroundColor('#A1887F')
        Text('秋季经典车展 · 展车征集截止本月底').fontSize(11).fontColor('#FAF3E8').layoutWeight(1)
        Text('查看 ›').fontSize(10).fontColor('#A1887F')
      }.width('100%').padding({ top: 10, bottom: 4 }).alignItems(VerticalAlign.Center)
    }.width('100%').backgroundColor('#8D2F2F')
    .padding({ left: 14, right: 14, top: 6, bottom: 10 })
  }

头部以复古红#8D2F2F为背景,采用三层垂直布局。顶部标题行左侧为黄铜金#A1887F色方块标识(内含"经"字)和"复古经典车馆"品牌名,右侧为修复锤子按钮(绑定发布藏车弹窗)和消息按钮(通过Stack叠加红色未读角标,绑定跳转到消息Tab)。中间搜索胶囊条使用米白色#FAF3E8背景。底部展会信息条以黄铜金色条标识开头,展示秋季车展征集信息。offset({ x: 8, y: -8 })用于将未读角标偏移到消息图标的右上角位置。

  // 底部七个页签
  @Builder bottomBuilder() {
    Row() {
      ForEach(this.tabs, (tab: string, index: number) => {
        Column({ space: 2 }) {
          Text(tab).fontSize(10).fontColor(this.currentTab === index ? '#8D2F2F' : '#999999')
          Column().width(18).height(3).borderRadius(2)
            .backgroundColor(this.currentTab === index ? '#8D2F2F' : '#FFFFFF00')
        }.onClick(() => { this.currentTab = index })
      }, (tab: string) => tab)
    }.width('100%').height(56).backgroundColor('#FFFFFF')
  }

底部导航栏的选中Tab使用复古红#8D2F2F文字和指示条,未选中Tab使用灰色#999999文字和透明指示条。

经典车展Tab:横幅卡片与列表

在这里插入图片描述

经典车展是首页Tab,展示了秋季车展横幅卡片和24台经典车的列表。

  // Tab1 经典车展:横幅大卡 + 24 条经典车行式列表
  @Builder tab0() {
    Column({ space: 10 }) {
      Row({ space: 10 }) {
        Column({ space: 6 }) {
          Text('秋季经典车展 · 第38届').fontSize(17).fontColor('#FFFFFF').fontWeight(FontWeight.Bold)
          Text('300台传世经典车集结 · 现场拍卖专场').fontSize(11).fontColor('#FAF3E8')
          Row({ space: 8 }) {
            Text('免票预约').fontSize(10).fontColor('#8D2F2F')
              .padding({ left: 10, right: 10, top: 4, bottom: 4 }).borderRadius(10).backgroundColor('#FAF3E8')
            Text('本月截止').fontSize(10).fontColor('#FAF3E8')
              .padding({ left: 10, right: 10, top: 4, bottom: 4 }).borderRadius(10)
              .border({ width: 1, color: '#FAF3E8' })
          }.alignItems(VerticalAlign.Center)
        }.alignItems(HorizontalAlign.Start).layoutWeight(1)

        Text('🏎').fontSize(38)
          .scale({ x: 1.05, y: 1.05 }).animation({ duration: 700, iterations: -1, curve: Curve.EaseInOut })
      }.width('100%').padding(16).borderRadius(14).alignItems(VerticalAlign.Center)
      .linearGradient({ angle: 135, colors: [['#8D2F2F', 0], ['#B04A4A', 1]] })

横幅卡片使用了linearGradient线性渐变背景,135度角从复古红#8D2F2F渐变到较浅的红色#B04A4A,营造了车展海报般的视觉氛围。左侧为展会信息文字和两个操作按钮(免票预约以米白底色填充、本月截止以米白描边),右侧为赛车Emoji图标并添加了脉冲缩放动画。linearGradientcolors参数接收一个二维数组,每个子数组的第一个元素为颜色值,第二个元素为渐变位置(0到1),这种声明式的渐变定义方式简洁直观。

      ForEach(this.mainList, (item: GoodsItem) => {
        Row({ space: 10 }) {
          Column() {
            Text(item.name.substring(0, 1)).fontSize(16).fontColor('#FFFFFF').fontWeight(FontWeight.Bold)
          }.width(42).height(42).borderRadius(21).backgroundColor('#8D2F2F')
          .justifyContent(FlexAlign.Center).alignItems(HorizontalAlign.Center)

          Column({ space: 3 }) {
            Text(item.name).fontSize(13).fontColor('#333333').fontWeight(FontWeight.Bold).maxLines(1)
            Text(item.desc).fontSize(9).fontColor('#999999').maxLines(1)
            Row() {
              Column().height(4).borderRadius(2).backgroundColor('#A1887F').width(item.score + '%')
            }.width(100).height(4).borderRadius(2).backgroundColor('#F0E6D8')
            Text('稀有度 ' + item.score + '% · ' + item.tag + ' · 车龄 ' + item.num + '年')
              .fontSize(8).fontColor('#A1887F')
          }.alignItems(HorizontalAlign.Start).layoutWeight(1)

          Column({ space: 5 }) {
            Text('¥' + this.priceText(item.price)).fontSize(12).fontColor('#E53935').fontWeight(FontWeight.Bold)
            Text('热度 ' + item.hot).fontSize(8).fontColor('#999999')
            if (item.score > 95) {
              Text('榜').fontSize(8).fontColor('#FFFFFF')
                .padding({ left: 5, right: 5, top: 1, bottom: 1 }).borderRadius(8).backgroundColor('#E53935')
                .scale({ x: 1.05, y: 1.05 }).animation({ duration: 700, iterations: -1, curve: Curve.EaseInOut })
            }
          }.alignItems(HorizontalAlign.End)
        }.width('100%').padding(10).backgroundColor('#FFFFFF').borderRadius(12)
        .onClick(() => { this.selectedItem = item; this.showDetailModal = true })
      }, (item: GoodsItem) => item.name)
    }.width('100%').padding(12)
  }

经典车列表每行卡片采用三段式布局。左侧为42x42圆形头像,使用车名首字符item.name.substring(0, 1)作为显示文字。中间信息区包含车名、描述、稀有度进度条(黄铜金填充色、米色背景#F0E6D8)和综合信息文字。右侧价格区使用priceText方法格式化价格,并在稀有度评分超过95分时条件渲染"榜"字标签(带脉冲动画)。if (item.score > 95)的条件渲染是ArkTS声明式UI的重要特性,允许根据数据条件动态控制UI元素的显示与隐藏。

页面交互流程图

以下是用户从浏览经典车到完成修复评估的完整交互流程:

经典车展

老爷车市

修复工坊

配件集市

车友会

消息

我的

预约看车

移出收藏

关闭返回

应用启动

经典车展首页

用户选择Tab

浏览24台传世经典车

查看车龄分布图

查看工期一览图

查看稀有度指数图

浏览藏车故事帖

查看消息通知

个人中心

点击车辆卡片

点击待售车辆

详情弹窗右滑展开

用户决策

关闭详情弹窗

删除确认弹窗

点击立即评估

修复评估弹窗

选择修复项目

选择期望工期

查看动态报价

提交评估

点击我要求购

配件求购弹窗

选择配件类型

选择适配年代

设置求购数量

发布求购

点击发布藏车

发布藏车弹窗

选择年代与车况

填写描述发布

老爷车市与修复工坊Tab

老爷车市Tab展示了车龄分布柱状图和12台待售经典车的双列网格;修复工坊Tab展示了墨绿色统计卡片、工期柱状图和横向滑动的修复案例卡片。

  // Tab2 老爷车市:车龄柱状图 + 12 条待售双列网格
  @Builder tab1() {
    Column({ space: 12 }) {
      Column({ space: 10 }) {
        Row() {
          Text('在售车龄分布').fontSize(14).fontColor('#333333').fontWeight(FontWeight.Bold)
          Column().layoutWeight(1)
          Text('HOT').fontSize(9).fontColor('#FFFFFF')
            .padding({ left: 6, right: 6, top: 2, bottom: 2 }).borderRadius(8).backgroundColor('#E53935')
            .scale({ x: 1.05, y: 1.05 }).animation({ duration: 700, iterations: -1, curve: Curve.EaseInOut })
        }.width('100%').alignItems(VerticalAlign.Center)

        Row() {
          ForEach(this.vinList, (item: GoodsItem) => {
            Column({ space: 4 }) {
              Column().width(16).borderRadius(3).backgroundColor('#8D2F2F')
                .height(item.num / this.maxNumOf(this.vinList) * 120)
              Text(item.num + '').fontSize(8).fontColor('#999999')
            }.alignItems(HorizontalAlign.Center)
          }, (item: GoodsItem) => item.name)
        }.width('100%').alignItems(VerticalAlign.End).justifyContent(FlexAlign.SpaceBetween)
      }.width('100%').padding(12).backgroundColor('#FFFFFF').borderRadius(12)

车龄分布柱状图使用复古红#8D2F2F柱条,高度公式为item.num / this.maxNumOf(this.vinList) * 120,通过justifyContent(FlexAlign.SpaceBetween)实现柱条均匀分布。柱状图标题右侧的"HOT"标签添加了脉冲动画以吸引视觉注意。

      Flex({ wrap: FlexWrap.Wrap, justifyContent: FlexAlign.SpaceBetween }) {
        ForEach(this.vinList, (item: GoodsItem) => {
          Column({ space: 8 }) {
            Row() {
              Text(item.tag).fontSize(8).fontColor('#FFFFFF')
                .padding({ left: 6, right: 6, top: 2, bottom: 2 }).borderRadius(6).backgroundColor('#3E5641')
              Column().layoutWeight(1)
              Text(item.hot + '·' + item.num + '年').fontSize(8).fontColor('#A1887F')
            }.width('100%').alignItems(VerticalAlign.Center)

            Column() {
              Text(item.name.substring(0, 1)).fontSize(22).fontColor('#FAF3E8').fontWeight(FontWeight.Bold)
            }.width('100%').height(64).borderRadius(8).backgroundColor('#A1887F')
            .justifyContent(FlexAlign.Center).alignItems(HorizontalAlign.Center)

            Text(item.name).fontSize(12).fontColor('#333333').fontWeight(FontWeight.Bold).maxLines(1)
            Text(item.desc).fontSize(9).fontColor('#999999').maxLines(1)

            Row() {
              Text('¥' + this.priceText(item.price)).fontSize(13).fontColor('#E53935').fontWeight(FontWeight.Bold)
              Column().layoutWeight(1)
              if (item.score > 92) {
                Text('稀').fontSize(8).fontColor('#FFFFFF')
                  .padding({ left: 5, right: 5, top: 1, bottom: 1 }).borderRadius(8).backgroundColor('#E53935')
                  .scale({ x: 1.05, y: 1.05 }).animation({ duration: 700, iterations: -1, curve: Curve.EaseInOut })
              }
            }.width('100%').alignItems(VerticalAlign.Center)
          }.width('48%').padding(10).backgroundColor('#FFFFFF').borderRadius(12)
          .onClick(() => { this.selectedItem = item; this.showDetailModal = true })
        }, (item: GoodsItem) => item.name)
      }.width('100%')
    }.width('100%').padding(12)
  }

老爷车市双列网格中每张卡片宽度为48%。卡片顶部年代标签使用墨绿#3E5641背景,中间为黄铜金色车辆首字符大图区域(64像素高),下方为车名、描述和价格行。当item.score > 92时条件渲染"稀"字稀有标签(带脉冲动画),帮助用户快速识别高评分稀有车辆。

修复工坊Tab是应用中最具业务深度的页面,包含墨绿色统计卡(展示本月完工38台、在修12项、藏家满意96%三栏数据)、工期柱状图和横向滑动的修复案例卡片(含前后对比"前→后"视觉设计)。

配件集市与车友会Tab

配件集市Tab展示稀有度柱状图和10条配件列表;车友会Tab以社交信息流形式展示藏车故事帖。

  // Tab4 配件集市:稀有度柱状图 + 10 条稀有配件列表
  @Builder tab3() {
    Column({ space: 12 }) {
      Column({ space: 10 }) {
        Row() {
          Text('稀有度指数').fontSize(14).fontColor('#333333').fontWeight(FontWeight.Bold)
          Column().layoutWeight(1)
          Text('我要求购').fontSize(11).fontColor('#FFFFFF')
            .padding({ left: 12, right: 12, top: 5, bottom: 5 }).borderRadius(12).backgroundColor('#8D2F2F')
            .onClick(() => { this.chipA = 0; this.chipB = 0; this.stepNum = 1; this.showWantModal = true })
        }.width('100%').alignItems(VerticalAlign.Center)

        Row() {
          ForEach(this.partList, (item: GoodsItem) => {
            Column({ space: 3 }) {
              Column().width(16).borderRadius(3).backgroundColor('#A1887F').height(item.score / 100 * 120)
              Text(item.num + '').fontSize(8).fontColor('#999999')
            }.alignItems(HorizontalAlign.Center)
          }, (item: GoodsItem) => item.name)
        }.width('100%').alignItems(VerticalAlign.End).justifyContent(FlexAlign.SpaceBetween)
      }.width('100%').padding(12).backgroundColor('#FFFFFF').borderRadius(12)

      ForEach(this.partList, (item: GoodsItem, index: number) => {
        Row({ space: 10 }) {
          Column().width(4).height(46).borderRadius(2)
            .backgroundColor(index % 3 === 0 ? '#8D2F2F' : (index % 3 === 1 ? '#A1887F' : '#3E5641'))

          Column({ space: 3 }) {
            Text(item.name).fontSize(13).fontColor('#333333').fontWeight(FontWeight.Bold).maxLines(1)
            Text(item.desc).fontSize(9).fontColor('#999999').maxLines(1)
            Row() {
              Column().height(4).borderRadius(2).backgroundColor('#A1887F').width(item.score + '%')
            }.width(110).height(4).borderRadius(2).backgroundColor('#F0E6D8')
            Text('稀有度 ' + item.score + '% · 库存 ' + item.num + ' 件 · ' + item.tag + '件')
              .fontSize(8).fontColor('#A1887F')
          }.alignItems(HorizontalAlign.Start).layoutWeight(1)

          Column({ space: 5 }) {
            Text('¥' + Math.floor(item.price)).fontSize(12).fontColor('#E53935').fontWeight(FontWeight.Bold)
            if (item.score > 90) {
              Text(item.hot).fontSize(8).fontColor('#FFFFFF')
                .padding({ left: 5, right: 5, top: 1, bottom: 1 }).borderRadius(8).backgroundColor('#E53935')
                .scale({ x: 1.05, y: 1.05 }).animation({ duration: 700, iterations: -1, curve: Curve.EaseInOut })
            } else {
              Text(item.hot).fontSize(8).fontColor('#A1887F')
            }
          }.alignItems(HorizontalAlign.End)
        }.width('100%').padding(10).backgroundColor('#FFFFFF').borderRadius(12)
      }, (item: GoodsItem) => item.name)
    }.width('100%').padding(12)
  }

配件集市Tab的稀有度柱状图使用黄铜金#A1887F柱条,高度公式为item.score / 100 * 120——直接除以100而非maxNumOf返回值,因为score字段本身就是0-100的百分比值。配件列表左侧色条使用index % 3循环取色(复古红、黄铜金、墨绿三色交替),为列表增添了视觉色彩节奏。右侧稀有标签使用条件渲染——当item.score > 90时以警示红背景脉冲动画展示,否则以黄铜金色静态展示,实现了稀有级别的视觉分级。

  // Tab5 车友会:年代话题 + 10 条藏车故事帖
  @Builder tab4() {
    Column({ space: 12 }) {
      Flex({ wrap: FlexWrap.Wrap }) {
        ForEach(this.topicChips, (t: string, i: number) => {
          Text('# ' + t).fontSize(11).fontColor(i % 2 === 0 ? '#8D2F2F' : '#3E5641')
            .padding({ left: 10, right: 10, top: 5, bottom: 5 }).borderRadius(14)
            .backgroundColor(i % 2 === 0 ? '#F6E4E4' : '#E4EDE6')
            .margin({ right: 8, bottom: 6 })
        }, (t: string) => t)
      }.width('100%')

      ForEach(this.clubList, (item: GoodsItem) => {
        Column({ space: 8 }) {
          Row({ space: 8 }) {
            Column() {
              Text(item.name.substring(0, 1)).fontSize(15).fontColor('#FFFFFF').fontWeight(FontWeight.Bold)
            }.width(36).height(36).borderRadius(18).backgroundColor('#3E5641')
            .justifyContent(FlexAlign.Center).alignItems(HorizontalAlign.Center)

            Column({ space: 2 }) {
              Text(item.name).fontSize(12).fontColor('#333333').fontWeight(FontWeight.Bold)
              Text(item.tag + ' 车主 · 声望 ' + item.score).fontSize(8).fontColor('#999999')
            }.alignItems(HorizontalAlign.Start).layoutWeight(1)

            Text('关注').fontSize(10).fontColor('#8D2F2F')
              .padding({ left: 10, right: 10, top: 3, bottom: 3 }).borderRadius(10).backgroundColor('#F6E4E4')
          }.alignItems(VerticalAlign.Center)

          Text(item.desc).fontSize(11).fontColor('#444444').maxLines(2).lineHeight(16)

          Row({ space: 6 }) {
            Column().layoutWeight(1).height(64).borderRadius(8).backgroundColor('#A1887F')
            Column().layoutWeight(1).height(64).borderRadius(8).backgroundColor('#C9B8A3')
            Column().layoutWeight(1).height(64).borderRadius(8).backgroundColor('#8D2F2F')
          }.width('100%')

          Row() {
            Text('阅读 ' + item.num + ' · ' + item.hot + '华帖').fontSize(9).fontColor('#999999')
            Column().layoutWeight(1)
            Row({ space: 4 }) {
              Text('👍').fontSize(12)
              Text(item.price + '').fontSize(11).fontColor('#8D2F2F').fontWeight(FontWeight.Bold)
                .scale({ x: 1.05, y: 1.05 }).animation({ duration: 700, iterations: -1, curve: Curve.EaseInOut })
            }.alignItems(VerticalAlign.Center)
          }.width('100%')
        }.width('100%').padding(12).backgroundColor('#FFFFFF').borderRadius(12)
      }, (item: GoodsItem) => item.name)
    }.width('100%').padding(12)
  }

车友会Tab的话题标签栏使用i % 2奇偶取色——偶数索引为复古红浅色#F6E4E4,奇数索引为墨绿浅色#E4EDE6,形成了双色交替的话题标签效果。每个藏车故事帖包含墨绿色头像、用户名与声望信息、故事描述(两行省略)、三列图片占位区(黄铜金、浅褐色、复古红三色背景)和底部互动栏。点赞数item.price添加了脉冲动画,阅读量和华帖标记在左侧展示。这种社交信息流设计为藏家社区提供了交流展示的平台。

消息与个人中心Tab

消息Tab以通知列表展示12条消息,通过未读红点脉冲动画提醒用户注意;个人中心Tab展示用户信息和功能菜单。

  // Tab6 消息:12 条通知列表,未读红点带脉冲
  @Builder tab5() {
    Column({ space: 10 }) {
      Row() {
        Text('消息中心').fontSize(16).fontColor('#333333').fontWeight(FontWeight.Bold)
        Column().layoutWeight(1)
        Text('全部已读').fontSize(10).fontColor('#A1887F')
      }.width('100%').padding({ left: 2, right: 2 })

      ForEach(this.msgList, (item: GoodsItem) => {
        Row({ space: 10 }) {
          Column() {
            Text(item.name.substring(0, 1)).fontSize(14).fontColor('#FFFFFF').fontWeight(FontWeight.Bold)
          }.width(40).height(40).borderRadius(20)
          .backgroundColor(item.hot === '未' ? '#8D2F2F' : '#B8A98F')
          .justifyContent(FlexAlign.Center).alignItems(HorizontalAlign.Center)

          Column({ space: 3 }) {
            Row() {
              Text(item.name).fontSize(13).fontColor('#333333').fontWeight(FontWeight.Bold).maxLines(1)
              Column().layoutWeight(1)
              Text(item.tag).fontSize(8).fontColor('#BBBBBB')
            }.width('100%').alignItems(VerticalAlign.Center)

            Text(item.desc).fontSize(10).fontColor('#999999').maxLines(1)
          }.alignItems(HorizontalAlign.Start).layoutWeight(1)

          if (item.hot === '未') {
            Column().width(8).height(8).borderRadius(4).backgroundColor('#E53935')
              .scale({ x: 1.05, y: 1.05 }).animation({ duration: 700, iterations: -1, curve: Curve.EaseInOut })
          }
        }.width('100%').padding(12).backgroundColor('#FFFFFF').borderRadius(12)
        .onClick(() => { this.selectedItem = item; this.showDetailModal = true })
      }, (item: GoodsItem) => item.name)
    }.width('100%').padding(12)
  }

消息列表中头像背景色根据item.hot字段动态切换——未读消息使用复古红#8D2F2F背景,已读消息使用浅褐色#B8A98F背景。未读消息右侧条件渲染一个8x8的警示红圆点,添加了脉冲缩放动画效果。这种通过hot字段值(“未"或"已”)驱动视觉差异的设计,简洁有效地实现了消息状态的可视化区分。

  // Tab7 我的:墨绿个人卡 + 三格统计 + 六行菜单
  @Builder tab6() {
    Column({ space: 12 }) {
      Row({ space: 12 }) {
        Column() {
          Text('藏').fontSize(20).fontColor('#FAF3E8').fontWeight(FontWeight.Bold)
        }.width(60).height(60).borderRadius(30).backgroundColor('#A1887F')
        .justifyContent(FlexAlign.Center).alignItems(HorizontalAlign.Center)

        Column({ space: 4 }) {
          Text('老陈的车库').fontSize(16).fontColor('#FFFFFF').fontWeight(FontWeight.Bold)
          Text('LV.8 资深经典车收藏家').fontSize(10).fontColor('#CFE0CF')
          Text('收藏 38 年 · 主修欧系与国产老车').fontSize(9).fontColor('#CFE0CF')
        }.alignItems(HorizontalAlign.Start).layoutWeight(1)

        Text('›').fontSize(18).fontColor('#CFE0CF')
      }.width('100%').padding(16).borderRadius(14).backgroundColor('#3E5641').alignItems(VerticalAlign.Center)

      Row() {
        Column({ space: 2 }) {
          Text('12').fontSize(16).fontColor('#8D2F2F').fontWeight(FontWeight.Bold)
          Text('我的藏车').fontSize(9).fontColor('#999999')
        }.alignItems(HorizontalAlign.Center).layoutWeight(1)

        Column().width(1).height(26).backgroundColor('#F0E6D8')

        Column({ space: 2 }) {
          Text('3').fontSize(16).fontColor('#8D2F2F').fontWeight(FontWeight.Bold)
          Text('修复订单').fontSize(9).fontColor('#999999')
        }.alignItems(HorizontalAlign.Center).layoutWeight(1)

        Column().width(1).height(26).backgroundColor('#F0E6D8')

        Column({ space: 2 }) {
          Text('5').fontSize(16).fontColor('#8D2F2F').fontWeight(FontWeight.Bold)
          Text('展会门票').fontSize(9).fontColor('#999999')
        }.alignItems(HorizontalAlign.Center).layoutWeight(1)
      }.width('100%').padding(14).backgroundColor('#FFFFFF').borderRadius(12)

个人中心Tab的顶部为墨绿色#3E5641个人卡,包含黄铜金色头像、用户名"老陈的车库"、等级和收藏信息。下方为三栏统计数据(藏车12台、修复订单3个、展会门票5张),栏间使用1像素宽的米色分隔线。功能菜单通过ForEach渲染menuList数组,每行菜单根据索引i条件渲染不同的Emoji图标和附加信息,点击时根据菜单类型跳转到不同Tab或打开不同弹窗。

弹窗系统:发布藏车与修复评估

应用设计了五类弹窗,以下展示发布藏车弹窗和修复评估弹窗的核心实现。

  // 弹框一:发布藏车(底部弹出)
  @Builder addModal() {
    Column() {
      Column().layoutWeight(1)

      Column({ space: 14 }) {
        Row() {
          Column().width(4).height(16).borderRadius(2).backgroundColor('#8D2F2F')
          Text('发布经典车').fontSize(16).fontColor('#333333').fontWeight(FontWeight.Bold)
          Column().layoutWeight(1)
          Text('×').fontSize(18).fontColor('#999999').padding(4)
            .onClick(() => { this.showAddModal = false })
        }.width('100%').alignItems(VerticalAlign.Center)

        Text('出厂年代').fontSize(12).fontColor('#666666').width('100%')
        Flex({ wrap: FlexWrap.Wrap }) {
          ForEach(this.eraChips, (c: string, i: number) => {
            Text(c).fontSize(12).fontColor(this.chipA === i ? '#FFFFFF' : '#666666')
              .padding({ left: 14, right: 14, top: 6, bottom: 6 }).borderRadius(14)
              .backgroundColor(this.chipA === i ? '#8D2F2F' : '#F5EFE3')
              .margin({ right: 8, bottom: 6 })
              .onClick(() => { this.chipA = i })
          }, (c: string) => c)
        }.width('100%')

        Text('当前车况').fontSize(12).fontColor('#666666').width('100%')
        Flex({ wrap: FlexWrap.Wrap }) {
          ForEach(this.condChips, (c: string, i: number) => {
            Text(c).fontSize(12).fontColor(this.chipB === i ? '#FFFFFF' : '#666666')
              .padding({ left: 14, right: 14, top: 6, bottom: 6 }).borderRadius(14)
              .backgroundColor(this.chipB === i ? '#A1887F' : '#F5EFE3')
              .margin({ right: 8, bottom: 6 })
              .onClick(() => { this.chipB = i })
          }, (c: string) => c)
        }.width('100%')

        Text('车辆描述').fontSize(12).fontColor('#666666').width('100%')
        TextInput({ placeholder: '车况、里程、过户次数等', text: this.inputDesc })
          .fontSize(12).height(40).backgroundColor('#F5EFE3').borderRadius(8)
          .padding({ left: 10, right: 10 })
          .onChange((value: string) => { this.inputDesc = value })

        Text('立即发布').fontSize(14).fontColor('#FFFFFF').fontWeight(FontWeight.Bold)
          .width('100%').textAlign(TextAlign.Center)
          .padding({ top: 10, bottom: 10 }).borderRadius(20).backgroundColor('#8D2F2F')
          .onClick(() => { this.showAddModal = false })
      }.width('100%').padding(16).backgroundColor('#FFFFFF')
      .borderRadius({ topLeft: 16, topRight: 16 })
      .constraintSize({ maxHeight: '80%' })
      .onClick((event: ClickEvent) => { event.stopPropagation() })
    }.width('100%').height('100%').backgroundColor('rgba(0,0,0,0.5)')
    .onClick(() => { this.showAddModal = false })
  }

发布藏车弹窗采用底部弹出模式。标题行左侧使用4x16的复古红色条作为标题装饰标识。弹窗包含两组芯片选择器——出厂年代(复古红选中色)和当前车况(黄铜金选中色),两种芯片使用不同选中色帮助用户区分不同维度的选择。TextInput绑定inputDesc状态变量实现双向数据流,onChange回调实时更新状态。constraintSize({ maxHeight: '80%' })限制弹窗最大高度为屏幕的80%。

  // 弹框二:修复评估(底部弹出,报价带脉冲)
  @Builder fixModal() {
    Column() {
      Column().layoutWeight(1)

      Column({ space: 14 }) {
        Row() {
          Column().width(4).height(16).borderRadius(2).backgroundColor('#3E5641')
          Text('修复评估').fontSize(16).fontColor('#333333').fontWeight(FontWeight.Bold)
          Column().layoutWeight(1)
          Text('×').fontSize(18).fontColor('#999999').padding(4)
            .onClick(() => { this.showFixModal = false })
        }.width('100%').alignItems(VerticalAlign.Center)

        Text('修复项目').fontSize(12).fontColor('#666666').width('100%')
        Flex({ wrap: FlexWrap.Wrap }) {
          ForEach(this.fixItemChips, (c: string, i: number) => {
            Text(c).fontSize(12).fontColor(this.chipA === i ? '#FFFFFF' : '#666666')
              .padding({ left: 14, right: 14, top: 6, bottom: 6 }).borderRadius(14)
              .backgroundColor(this.chipA === i ? '#3E5641' : '#F5EFE3')
              .margin({ right: 8, bottom: 6 })
              .onClick(() => { this.chipA = i })
          }, (c: string) => c)
        }.width('100%')

        Text('期望工期').fontSize(12).fontColor('#666666').width('100%')
        Flex({ wrap: FlexWrap.Wrap }) {
          ForEach(this.fixDurChips, (c: string, i: number) => {
            Text(c).fontSize(12).fontColor(this.chipB === i ? '#FFFFFF' : '#666666')
              .padding({ left: 14, right: 14, top: 6, bottom: 6 }).borderRadius(14)
              .backgroundColor(this.chipB === i ? '#A1887F' : '#F5EFE3')
              .margin({ right: 8, bottom: 6 })
              .onClick(() => { this.chipB = i })
          }, (c: string) => c)
        }.width('100%')

        Column({ space: 6 }) {
          Row() {
            Text('预估报价').fontSize(12).fontColor('#666666')
            Column().layoutWeight(1)
            Text('¥' + this.priceText(this.fixQuote())).fontSize(22).fontColor('#E53935').fontWeight(FontWeight.Bold)
              .scale({ x: 1.05, y: 1.05 }).animation({ duration: 700, iterations: -1, curve: Curve.EaseInOut })
          }.width('100%').alignItems(VerticalAlign.Center)

          Text('报价随项目与工期浮动,最终以实车勘验为准').fontSize(9).fontColor('#999999').width('100%')
        }.width('100%').padding(12).borderRadius(10).backgroundColor('#F5EFE3')

        Text('提交评估').fontSize(14).fontColor('#FFFFFF').fontWeight(FontWeight.Bold)
          .width('100%').textAlign(TextAlign.Center)
          .padding({ top: 10, bottom: 10 }).borderRadius(20).backgroundColor('#3E5641')
          .onClick(() => { this.showFixModal = false })
      }.width('100%').padding(16).backgroundColor('#FFFFFF')
      .borderRadius({ topLeft: 16, topRight: 16 })
      .constraintSize({ maxHeight: '80%' })
      .onClick((event: ClickEvent) => { event.stopPropagation() })
    }.width('100%').height('100%').backgroundColor('rgba(0,0,0,0.5)')
    .onClick(() => { this.showFixModal = false })
  }

修复评估弹窗是应用中最具业务深度的弹窗。修复项目选择使用墨绿#3E5641选中色,期望工期选择使用黄铜金#A1887F选中色。预估报价通过this.priceText(this.fixQuote())方法链式调用——先调用fixQuote()根据当前chipAchipB计算报价数值,再调用priceText()格式化为"万"单位中文价格。报价数字添加了脉冲缩放动画以强调其动态变化的特性,下方还有一行说明文字"报价随项目与工期浮动,最终以实车勘验为准"。这种"状态选择驱动报价计算"的设计模式是声明式UI在业务逻辑层面的典型应用——用户每次切换修复项目或期望工期,chipAchipB状态变更自动触发fixQuote()重新计算,UI自动刷新报价显示。

配件求购弹窗与详情弹窗

配件求购弹窗包含步进器用于设置求购数量,详情弹窗采用右侧滑出全高面板展示车辆详细信息。

  // 弹框三:配件求购(底部弹出,含数量步进器)
  @Builder wantModal() {
    Column() {
      Column().layoutWeight(1)

      Column({ space: 14 }) {
        Row() {
          Column().width(4).height(16).borderRadius(2).backgroundColor('#A1887F')
          Text('配件求购').fontSize(16).fontColor('#333333').fontWeight(FontWeight.Bold)
          Column().layoutWeight(1)
          Text('×').fontSize(18).fontColor('#999999').padding(4)
            .onClick(() => { this.showWantModal = false })
        }.width('100%').alignItems(VerticalAlign.Center)

        Text('配件类型').fontSize(12).fontColor('#666666').width('100%')
        Flex({ wrap: FlexWrap.Wrap }) {
          ForEach(this.partTypeChips, (c: string, i: number) => {
            Text(c).fontSize(12).fontColor(this.chipA === i ? '#FFFFFF' : '#666666')
              .padding({ left: 14, right: 14, top: 6, bottom: 6 }).borderRadius(14)
              .backgroundColor(this.chipA === i ? '#8D2F2F' : '#F5EFE3')
              .margin({ right: 8, bottom: 6 })
              .onClick(() => { this.chipA = i })
          }, (c: string) => c)
        }.width('100%')

        Text('适配年代').fontSize(12).fontColor('#666666').width('100%')
        Flex({ wrap: FlexWrap.Wrap }) {
          ForEach(this.wantEraChips, (c: string, i: number) => {
            Text(c).fontSize(12).fontColor(this.chipB === i ? '#FFFFFF' : '#666666')
              .padding({ left: 14, right: 14, top: 6, bottom: 6 }).borderRadius(14)
              .backgroundColor(this.chipB === i ? '#A1887F' : '#F5EFE3')
              .margin({ right: 8, bottom: 6 })
              .onClick(() => { this.chipB = i })
          }, (c: string) => c)
        }.width('100%')

        Row() {
          Text('求购数量').fontSize(12).fontColor('#666666')
          Column().layoutWeight(1)
          Text('-').fontSize(14).fontColor(this.stepNum <= 1 ? '#CCCCCC' : '#8D2F2F')
            .width(30).height(30).borderRadius(15).textAlign(TextAlign.Center).backgroundColor('#F5EFE3')
            .onClick(() => { if (this.stepNum > 1) { this.stepNum = this.stepNum - 1 } })
          Text(this.stepNum + ' 件').fontSize(13).fontColor('#333333').fontWeight(FontWeight.Bold)
            .width(56).textAlign(TextAlign.Center)
          Text('+').fontSize(14).fontColor(this.stepNum >= 10 ? '#CCCCCC' : '#8D2F2F')
            .width(30).height(30).borderRadius(15).textAlign(TextAlign.Center).backgroundColor('#F5EFE3')
            .onClick(() => { if (this.stepNum < 10) { this.stepNum = this.stepNum + 1 } })
        }.width('100%').alignItems(VerticalAlign.Center)

        Text('发布求购').fontSize(14).fontColor('#FFFFFF').fontWeight(FontWeight.Bold)
          .width('100%').textAlign(TextAlign.Center)
          .padding({ top: 10, bottom: 10 }).borderRadius(20).backgroundColor('#A1887F')
          .onClick(() => { this.showWantModal = false })
      }.width('100%').padding(16).backgroundColor('#FFFFFF')
      .borderRadius({ topLeft: 16, topRight: 16 })
      .constraintSize({ maxHeight: '80%' })
      .onClick((event: ClickEvent) => { event.stopPropagation() })
    }.width('100%').height('100%').backgroundColor('rgba(0,0,0,0.5)')
    .onClick(() => { this.showWantModal = false })
  }

配件求购弹窗的步进器设计了一个细节:减号和加号按钮的字体颜色根据当前值动态变化——当stepNum <= 1时减号变为灰色#CCCCCC表示不可再减,当stepNum >= 10时加号变为灰色表示不可再加。这种基于状态的条件着色为用户提供了直观的操作边界反馈。步进范围设定为1-10件,覆盖了配件求购的典型数量需求。

  // 弹框五:车辆详情(右侧滑出全高面板)
  @Builder detailModal() {
    Column() {
      Column({ space: 12 }) {
        Stack() {
          Column().width('100%').height(190).borderRadius(12)
            .linearGradient({ angle: 135, colors: [['#8D2F2F', 0], ['#5E1F1F', 1]] })

          Column({ space: 6 }) {
            Text('传世经典').fontSize(11).fontColor('#FAF3E8')
              .padding({ left: 10, right: 10, top: 3, bottom: 3 }).borderRadius(10)
              .border({ width: 1, color: '#A1887F' })
              .scale({ x: 1.05, y: 1.05 }).animation({ duration: 700, iterations: -1, curve: Curve.EaseInOut })
            Text(this.selName().substring(0, 1)).fontSize(52).fontColor('#FAF3E8').fontWeight(FontWeight.Bold)
          }.height(190).justifyContent(FlexAlign.Center)
        }.width('100%')

        Text(this.selName()).fontSize(17).fontColor('#333333').fontWeight(FontWeight.Bold).width('100%')
        Text(this.selDesc()).fontSize(10).fontColor('#999999').width('100%')

        Row() {
          Text('¥' + this.priceText(this.selPrice())).fontSize(24).fontColor('#E53935').fontWeight(FontWeight.Bold)
          Column().layoutWeight(1)
          Text(this.selTag() + ' · 热度 ' + this.selHot()).fontSize(10).fontColor('#A1887F')
        }.width('100%').alignItems(VerticalAlign.Bottom)

        Column({ space: 5 }) {
          Text('稀有度 ' + this.selScore() + '%').fontSize(10).fontColor('#666666').width('100%')
          Row() {
            Column().height(6).borderRadius(3).backgroundColor('#A1887F').width(this.selScore() + '%')
          }.width('100%').height(6).borderRadius(3).backgroundColor('#F0E6D8')
        }.width('100%')

        Text('历史档案').fontSize(12).fontColor('#666666').width('100%')
        Flex({ wrap: FlexWrap.Wrap }) {
          ForEach(this.historyChips, (c: string) => {
            Text(c).fontSize(10).fontColor('#3E5641')
              .padding({ left: 10, right: 10, top: 4, bottom: 4 }).borderRadius(10)
              .backgroundColor('#E4EDE6')
              .margin({ right: 8, bottom: 6 })
          }, (c: string) => c)
        }.width('100%')

        Column().layoutWeight(1)

        Text('移出收藏').fontSize(12).fontColor('#999999').width('100%').textAlign(TextAlign.Center)
          .padding({ top: 8, bottom: 8 }).borderRadius(18)
          .onClick(() => { this.showDeleteModal = true })

        Text('预约看车').fontSize(14).fontColor('#FFFFFF').fontWeight(FontWeight.Bold)
          .width('100%').textAlign(TextAlign.Center)
          .padding({ top: 10, bottom: 10 }).borderRadius(20).backgroundColor('#8D2F2F')
          .onClick(() => { this.showDetailModal = false })
      }.width('80%').height('100%').padding(14).backgroundColor('#FFFFFF')
      .onClick((event: ClickEvent) => { event.stopPropagation() })
    }.width('100%').height('100%').backgroundColor('rgba(0,0,0,0.5)')
    .justifyContent(FlexAlign.End).alignItems(HorizontalAlign.End)
    .onClick(() => { this.showDetailModal = false })
  }

详情弹窗的面板宽度为80%,通过justifyContent(FlexAlign.End)alignItems(HorizontalAlign.End)定位到屏幕右侧。顶部为190像素高的Stack容器,底层使用linearGradient实现复古红到深红色#5E1F1F的135度渐变背景,上层叠加"传世经典"标签(带脉冲动画和黄铜金描边)和车名首字符大字。中间展示车名、描述、价格(使用priceText格式化)、稀有度进度条和历史档案标签组(墨绿浅色背景#E4EDE6)。底部为"移出收藏"链接(绑定删除确认弹窗)和"预约看车"按钮(关闭详情弹窗)。

主页面构建

  build() {
    Stack() {
      Column() {
        this.headerBuilder()
        Scroll() {
          Column() {
            if (this.currentTab === 0) {
              this.tab0()
            } else if (this.currentTab === 1) {
              this.tab1()
            } else if (this.currentTab === 2) {
              this.tab2()
            } else if (this.currentTab === 3) {
              this.tab3()
            } else if (this.currentTab === 4) {
              this.tab4()
            } else if (this.currentTab === 5) {
              this.tab5()
            } else {
              this.tab6()
            }
          }.width('100%')
        }.layoutWeight(1).width('100%')
        this.bottomBuilder()
      }.width('100%').height('100%')

      if (this.showAddModal) {
        this.addModal()
      }
      if (this.showFixModal) {
        this.fixModal()
      }
      if (this.showWantModal) {
        this.wantModal()
      }
      if (this.showDeleteModal) {
        this.deleteModal()
      }
      if (this.showDetailModal) {
        this.detailModal()
      }
    }.width('100%').height('100%')
  }
}

build方法以Stack为根容器,内部先放置主内容区(头部+可滚动内容区+底部导航栏),然后通过五个独立的if条件块叠加弹窗组件。Tab切换通过if-else条件链实现,每个条件分支调用对应的@Builder方法渲染Tab页面。Scroll组件包裹Tab内容区实现纵向滚动,layoutWeight(1)使其占据头部和底部导航栏之间的全部剩余空间。这种架构确保了主内容与弹窗之间的独立渲染层级,弹窗通过状态变量控制显隐,不影响主内容区的布局和渲染。

技术点对比

技术维度 实现方式 设计特点 适用场景
配色体系 复古红+黄铜金+米白+墨绿四色 怀旧主题色系,模块化色彩分配 情怀类垂直领域应用
渐变背景 linearGradient(135deg,colors) 声明式渐变定义,海报级视觉效果 横幅卡片与详情头部
报价引擎 fixQuote()方法+chipA/chipB状态 基础价+工期系数动态计算模型 修复评估等参数化报价场景
价格格式化 priceText()方法 万+千位拼接中文价格格式 高客单价商品展示
条件渲染 if(item.score>95)动态标签 稀有度/库存分级标签动态展示 数据分级视觉标识
柱状图归一化 score/100*120直接百分比 百分比值直接映射柱条高度 0-100评分类数据可视化
三色交替 index%3循环取色色条 复古红/黄铜金/墨绿三色节奏 列表项色彩分区
未读状态 hot字段值驱动背景色切换 “未”/"已"字符串条件分支 消息列表状态区分
步进器边界 stepNum<=1/>=10条件着色 灰色禁用态视觉反馈 数量步进交互控制
弹窗层叠 Stack+五独立if条件块 弹窗独立判断、互不干扰 多类型弹窗并存管理

安装DevEco Studio程序

在这里插入图片描述
选择目标安装目录:

在这里插入图片描述
设置环境变量,但是需要重启一下:

在这里插入图片描述
新建一个空白模板:

在这里插入图片描述
设置API为24的模板项目:
在这里插入图片描述
初始化项目,自动下载相关依赖:

在这里插入图片描述


完整代码:

// 复古经典车馆 · 汽车之家风格经典老爷车收藏场景
// 配色:复古红 8D2F2F / 黄铜金 A1887F / 米白 FAF3E8 / 墨绿 3E5641 / 警示红 E53935

interface GoodsItem {
  name: string
  price: number
  desc: string
  score: number
  num: number
  tag: string
  hot: string
}

@Entry
@Component
struct Index {
  @State currentTab: number = 0
  @State showAddModal: boolean = false
  @State showFixModal: boolean = false
  @State showWantModal: boolean = false
  @State showDeleteModal: boolean = false
  @State showDetailModal: boolean = false
  @State selectedItem: GoodsItem | null = null
  @State chipA: number = 0
  @State chipB: number = 0
  @State stepNum: number = 1
  @State inputDesc: string = ''

  private tabs: string[] = ['经典车展', '老爷车市', '修复工坊', '配件集市', '车友会', '消息', '我的']
  private eraChips: string[] = ['1950前', '1951-1970', '1971-1990', '1991-2000']
  private condChips: string[] = ['原版未修', '修复翻新', '改装升级']
  private fixItemChips: string[] = ['发动机大修', '内饰翻新', '车漆修复', '底盘整备']
  private fixDurChips: string[] = ['1个月', '3个月', '6个月', '1年']
  private partTypeChips: string[] = ['发动机件', '内饰件', '外观件', '电气件']
  private wantEraChips: string[] = ['1950前', '1970前', '1990前', '2000前']
  private topicChips: string[] = ['五十年代', '六十年代', '七十年代', '肌肉车', '欧陆经典', '东方记忆']
  private historyChips: string[] = ['原厂档案', '两次过户', '全程养护', '老照片']
  private menuList: string[] = ['我的藏车', '修复订单', '求购配件', '发布藏车', '展会门票', '账号设置']

  // 经典车展主列表:24 条传世经典车
  private mainList: GoodsItem[] = [
    { name: '1965 大众甲壳虫 1200', price: 128000, desc: '1965年 · 德国原版 · 手动挡', score: 96, num: 61, tag: '稀有', hot: '藏' },
    { name: '1978 奔驰 W123 230E', price: 96000, desc: '1978年 · 德系耐用典范', score: 88, num: 48, tag: '经典', hot: '热' },
    { name: '1972 宝马 2002', price: 185000, desc: '1972年 · 巴伐利亚运动轿车', score: 92, num: 54, tag: '稀有', hot: '热' },
    { name: '1963 捷豹 E-Type S1', price: 1380000, desc: '1963年 · 英伦跑车美学巅峰', score: 98, num: 63, tag: '殿堂', hot: '藏' },
    { name: '1990 保时捷 911 964', price: 890000, desc: '1990年 · 末代风冷手动挡', score: 94, num: 36, tag: '稀有', hot: '热' },
    { name: '1985 伏尔加 嘎斯24', price: 68000, desc: '1985年 · 苏联公务车代表', score: 78, num: 41, tag: '情怀', hot: '冷' },
    { name: '1965 红旗 CA72', price: 2680000, desc: '1965年 · 国礼级检阅车', score: 99, num: 61, tag: '国宝', hot: '藏' },
    { name: '1976 上海 SH760A', price: 155000, desc: '1976年 · 沪上制造记忆', score: 86, num: 50, tag: '情怀', hot: '热' },
    { name: '1969 丰田 2000GT', price: 3600000, desc: '1969年 · 东瀛第一超跑', score: 99, num: 57, tag: '殿堂', hot: '藏' },
    { name: '1961 福特 雷鸟', price: 210000, desc: '1961年 · 美式敞篷豪华', score: 84, num: 65, tag: '经典', hot: '冷' },
    { name: '1970 雪铁龙 DS21', price: 480000, desc: '1970年 · 液压悬挂传奇', score: 93, num: 56, tag: '稀有', hot: '热' },
    { name: '1980 菲亚特 124', price: 72000, desc: '1980年 · 意式家用后驱', score: 74, num: 46, tag: '经典', hot: '冷' },
    { name: '1967 阿尔法·罗密欧 Giulia', price: 520000, desc: '1967年 · 米兰弯道精灵', score: 91, num: 59, tag: '稀有', hot: '热' },
    { name: '1974 沃尔沃 P1800', price: 260000, desc: '1974年 · 北欧长寿纪录', score: 85, num: 52, tag: '经典', hot: '冷' },
    { name: '1958 凯迪拉克 Eldorado', price: 720000, desc: '1958年 · 尾翼时代巅峰', score: 95, num: 68, tag: '稀有', hot: '藏' },
    { name: '1988 宝马 M3 E30', price: 1150000, desc: '1988年 · 直六赛化机器', score: 97, num: 38, tag: '殿堂', hot: '热' },
    { name: '1969 日产 费尔雷迪 Z432', price: 980000, desc: '1969年 · 东瀛S20名机', score: 94, num: 57, tag: '稀有', hot: '藏' },
    { name: '1975 标致 504', price: 58000, desc: '1975年 · 非洲拉力常胜', score: 72, num: 51, tag: '情怀', hot: '冷' },
    { name: '1957 菲亚特 500', price: 165000, desc: '1957年 · 意大利国民小车', score: 87, num: 69, tag: '经典', hot: '热' },
    { name: '1962 奔驰 190SL', price: 880000, desc: '1962年 · 斯图加特敞篷', score: 92, num: 64, tag: '稀有', hot: '藏' },
    { name: '1979 拉达 2101', price: 38000, desc: '1979年 · 战斗民族国民车', score: 66, num: 47, tag: '情怀', hot: '冷' },
    { name: '1984 北京 BJ212', price: 46000, desc: '1984年 · 国产越野活化石', score: 76, num: 42, tag: '情怀', hot: '热' },
    { name: '1968 庞蒂亚克 GTO', price: 960000, desc: '1968年 · 肌肉车鼻祖', score: 95, num: 58, tag: '殿堂', hot: '藏' },
    { name: '1986 丰田 FJ60', price: 235000, desc: '1986年 · 方盒子越野经典', score: 83, num: 40, tag: '经典', hot: '热' }
  ]

  // 老爷车市:12 条待售经典车,num 为车龄年
  private vinList: GoodsItem[] = [
    { name: '1972 奔驰 280SE 3.5', price: 385000, desc: '1972年 · V8豪华轿跑', score: 90, num: 54, tag: '七十年代', hot: '售' },
    { name: '1966 福特 野马 GT', price: 620000, desc: '1966年 · 美式肌肉代表', score: 92, num: 60, tag: '六十年代', hot: '售' },
    { name: '1983 丰田 AE86', price: 520000, desc: '1983年 · 秋名山传说', score: 93, num: 43, tag: '八十年代', hot: '售' },
    { name: '1977 凯迪拉克 弗利特伍德', price: 298000, desc: '1977年 · 陆地游艇', score: 85, num: 49, tag: '七十年代', hot: '售' },
    { name: '1969 大众 T2 面包车', price: 345000, desc: '1969年 · 嬉皮士之车', score: 89, num: 57, tag: '六十年代', hot: '售' },
    { name: '1985 奔驰 W126 560SEC', price: 210000, desc: '1985年 · 元首级双门', score: 82, num: 41, tag: '八十年代', hot: '售' },
    { name: '1963 沃克斯豪尔 Victor', price: 128000, desc: '1963年 · 英伦家用经典', score: 75, num: 63, tag: '六十年代', hot: '售' },
    { name: '1974 阿尔法·罗密欧 GTV', price: 265000, desc: '1974年 · 意式双门轿跑', score: 88, num: 52, tag: '七十年代', hot: '售' },
    { name: '1990 日产 Skyline R32', price: 680000, desc: '1990年 · 战神GT-R', score: 95, num: 36, tag: '九十年代', hot: '售' },
    { name: '1968 福特 F-100 皮卡', price: 188000, desc: '1968年 · 美式工具车', score: 78, num: 58, tag: '六十年代', hot: '售' },
    { name: '1979 铃木 吉姆尼 SJ10', price: 86000, desc: '1979年 · 轻越野鼻祖', score: 72, num: 47, tag: '七十年代', hot: '售' },
    { name: '1956 雪佛兰 贝莱尔', price: 720000, desc: '1956年 · 美国梦象征', score: 94, num: 70, tag: '五十年代', hot: '售' }
  ]

  // 修复工坊:10 条修复项目,num 为工期天数
  private fixList: GoodsItem[] = [
    { name: '1966 福特 野马整车修复', price: 268000, desc: '发动机与车漆全流程', score: 96, num: 180, tag: '精修', hot: '急' },
    { name: '1975 奔驰 W115 底盘整备', price: 68000, desc: '悬挂与制动重建', score: 90, num: 45, tag: '底盘', hot: '缓' },
    { name: '1962 捷豹 XK150 车漆复原', price: 158000, desc: '九道工序手工漆', score: 93, num: 120, tag: '车漆', hot: '急' },
    { name: '1959 凯迪拉克内饰翻新', price: 120000, desc: '真皮与镀铬件重制', score: 88, num: 90, tag: '内饰', hot: '缓' },
    { name: '1970 雪铁龙 DS 液压系统', price: 96000, desc: '液气悬挂专项', score: 91, num: 60, tag: '底盘', hot: '急' },
    { name: '1983 丰田 AE86 车架校正', price: 88000, desc: '事故车回归赛道', score: 87, num: 75, tag: '车架', hot: '缓' },
    { name: '1968 红旗 CA770 内饰复原', price: 320000, desc: '国车级翻新工程', score: 98, num: 300, tag: '精修', hot: '急' },
    { name: '1972 宝马 2002 发动机大修', price: 76000, desc: '化油器重新调校', score: 89, num: 50, tag: '发动机', hot: '缓' },
    { name: '1957 菲亚特 500 电路改造', price: 36000, desc: '全车电路升级', score: 82, num: 40, tag: '电气', hot: '缓' },
    { name: '1979 拉达 2101 钣金修复', price: 28000, desc: '锈蚀面板更换', score: 80, num: 40, tag: '钣金', hot: '急' }
  ]

  // 配件集市:10 条稀有配件,num 为库存件数
  private partList: GoodsItem[] = [
    { name: '化油器 Weber 40DCOE', price: 6800, desc: '适配阿尔法与宝马', score: 96, num: 48, tag: '欧系', hot: '珍' },
    { name: '红旗 CA72 原厂大灯总成', price: 15800, desc: '适配红旗CA72', score: 99, num: 60, tag: '国产', hot: '孤品' },
    { name: '捷豹 E-Type 木纹方向盘', price: 9200, desc: '适配E-Type S1', score: 94, num: 45, tag: '英系', hot: '珍' },
    { name: '奔驰 W123 全套镀铬饰条', price: 4200, desc: '适配W123轿车', score: 78, num: 120, tag: '欧系', hot: '常' },
    { name: '甲壳虫 原厂帆布车顶', price: 3600, desc: '适配1200敞篷版', score: 85, num: 90, tag: '欧系', hot: '常' },
    { name: '凯迪拉克 尾翼装饰件', price: 7800, desc: '适配1958年款', score: 92, num: 50, tag: '美系', hot: '珍' },
    { name: '伏尔加 前格栅总成', price: 2900, desc: '适配嘎斯24', score: 74, num: 110, tag: '苏系', hot: '常' },
    { name: '菲亚特 500 里程表芯', price: 880, desc: '适配500全系列', score: 68, num: 200, tag: '意系', hot: '常' },
    { name: '宝马 2002 圆灯支架', price: 1500, desc: '适配2002轿车', score: 72, num: 150, tag: '欧系', hot: '常' },
    { name: '上海 SH760 门把手', price: 1200, desc: '适配SH760A', score: 88, num: 70, tag: '国产', hot: '珍' }
  ]

  // 车友会:10 条藏车故事帖,price 为点赞数,num 为阅读量
  private clubList: GoodsItem[] = [
    { name: '老周藏车', price: 328, desc: '我的甲壳虫开了三十年,从校门一直开到女儿婚礼现场,方向盘磨出了包浆。', score: 96, num: 486, tag: '甲壳虫', hot: '精' },
    { name: '锡兰骑士', price: 214, desc: '捷豹E-Type修复日记第十二篇:等了半年的木纹方向盘终于到货,装上的瞬间眼眶湿了。', score: 92, num: 452, tag: 'E-Type', hot: '热' },
    { name: '北岭老爷子', price: 176, desc: '红旗CA72的每一颗螺丝,都是那个年代的自豪,拆装全程我做了三本笔记。', score: 98, num: 500, tag: '红旗CA72', hot: '精' },
    { name: 'V24车库', price: 198, desc: '伏尔加在东北零下三十度一次点火成功,化油器预热改装立了大功。', score: 80, num: 361, tag: '嘎斯24', hot: '热' },
    { name: '胶片公路', price: 245, desc: '开着W123走了一趟川藏线,老车比想象中可靠,全程只补了一次机油。', score: 88, num: 428, tag: 'W123', hot: '热' },
    { name: '沪上司机', price: 132, desc: '上海SH760的方向盘上还留着父亲的掌温,这台车我们家守了三代。', score: 90, num: 297, tag: 'SH760', hot: '温' },
    { name: '弯道信徒', price: 289, desc: '阿尔法Giulia的化油器声浪,值得凌晨四点起床去山路跑一圈。', score: 93, num: 465, tag: 'Giulia', hot: '精' },
    { name: '尾翼时代', price: 167, desc: '凯迪拉克Eldorado的尾翼,是火箭时代留给公路的浪漫,没有之一。', score: 95, num: 388, tag: 'Eldorado', hot: '热' },
    { name: '风冷教徒', price: 203, desc: '964跑了一趟草原,风冷机的味道混着草香,那就是自由的味道。', score: 91, num: 410, tag: '911 964', hot: '热' },
    { name: '雪铁龙大叔', price: 158, desc: 'DS21的液压悬挂,让快七十岁的它依然会在路口优雅地跳舞。', score: 89, num: 345, tag: 'DS21', hot: '温' }
  ]

  // 消息:12 条通知,tag 为时间,hot 标记未读
  private msgList: GoodsItem[] = [
    { name: '拍卖出价助手', price: 128, desc: '您关注的甲壳虫1200出现新竞价', score: 96, num: 420, tag: '刚刚', hot: '未' },
    { name: '修复工坊王师傅', price: 96, desc: '您的车漆复原进度已过半', score: 90, num: 388, tag: '09:12', hot: '未' },
    { name: '配件集市', price: 64, desc: '您求购的化油器已到货一件', score: 84, num: 350, tag: '昨天', hot: '未' },
    { name: '车友会通知', price: 210, desc: '周末老城巡游活动开始报名', score: 88, num: 468, tag: '昨天', hot: '未' },
    { name: '藏家老周', price: 56, desc: '那台伏尔加我朋友有兴趣,聊聊?', score: 80, num: 300, tag: '周四', hot: '已' },
    { name: '展会组委会', price: 88, desc: '您的展车资料审核已通过', score: 92, num: 410, tag: '周四', hot: '未' },
    { name: '修复工坊李工', price: 45, desc: '底盘整备方案已发送至车库', score: 82, num: 280, tag: '周三', hot: '已' },
    { name: '配件集市', price: 72, desc: '红旗CA72大灯总成补货提醒', score: 90, num: 366, tag: '08-20', hot: '未' },
    { name: '车友弯道信徒', price: 39, desc: '周末山路小聚,带上你的Giulia', score: 78, num: 260, tag: '08-19', hot: '已' },
    { name: '拍卖保证金通知', price: 120, desc: '保证金已退还至原支付账户', score: 86, num: 395, tag: '08-18', hot: '已' },
    { name: '车友尾翼时代', price: 51, desc: '分享一张Eldorado的绝美照片', score: 76, num: 240, tag: '08-17', hot: '已' },
    { name: '系统安全提醒', price: 66, desc: '账号于新设备登录,请确认', score: 94, num: 500, tag: '08-16', hot: '未' }
  ]

  // 以下为取值辅助函数
  selName(): string {
    if (this.selectedItem !== null) {
      return this.selectedItem.name
    }
    return ''
  }

  selPrice(): number {
    if (this.selectedItem !== null) {
      return this.selectedItem.price
    }
    return 0
  }

  selDesc(): string {
    if (this.selectedItem !== null) {
      return this.selectedItem.desc
    }
    return ''
  }

  selScore(): number {
    if (this.selectedItem !== null) {
      return this.selectedItem.score
    }
    return 0
  }

  selTag(): string {
    if (this.selectedItem !== null) {
      return this.selectedItem.tag
    }
    return ''
  }

  selHot(): string {
    if (this.selectedItem !== null) {
      return this.selectedItem.hot
    }
    return ''
  }

  maxNumOf(list: GoodsItem[]): number {
    let m: number = 1
    for (let i = 0; i < list.length; i++) {
      if (list[i].num > m) {
        m = list[i].num
      }
    }
    return m
  }

  priceText(p: number): string {
    let w: number = Math.floor(p / 10000)
    let k: number = Math.floor((p % 10000) / 1000)
    return w + '.' + k + '万'
  }

  fixQuote(): number {
    let base: number = 68000
    if (this.chipA === 1) {
      base = 42000
    } else if (this.chipA === 2) {
      base = 26000
    } else if (this.chipA === 3) {
      base = 35000
    }
    let factor: number = 1.0
    if (this.chipB === 1) {
      factor = 1.6
    } else if (this.chipB === 2) {
      factor = 2.4
    } else if (this.chipB === 3) {
      factor = 3.8
    }
    return Math.floor(base * factor)
  }

  // 静态头部:标题行 + 搜索胶囊 + 展会信息条
  @Builder headerBuilder() {
    Column() {
      Row() {
        Row({ space: 8 }) {
          Column() {
            Text('经').fontSize(12).fontColor('#FFFFFF').fontWeight(FontWeight.Bold)
          }.width(26).height(26).borderRadius(6).backgroundColor('#A1887F')
          .justifyContent(FlexAlign.Center).alignItems(HorizontalAlign.Center)

          Text('复古经典车馆').fontSize(18).fontColor('#FFFFFF').fontWeight(FontWeight.Bold)
        }.alignItems(VerticalAlign.Center)

        Column().layoutWeight(1)

        Row({ space: 14 }) {
          Text('🔨').fontSize(16)
            .onClick(() => { this.chipA = 0; this.chipB = 0; this.showAddModal = true })

          Stack() {
            Text('✉').fontSize(16)
            Text('6').fontSize(8).fontColor('#FFFFFF').fontWeight(FontWeight.Bold)
              .padding({ left: 4, right: 4, top: 1, bottom: 1 }).borderRadius(8).backgroundColor('#E53935')
              .offset({ x: 8, y: -8 })
          }.width(24).height(24)
          .onClick(() => { this.currentTab = 5 })
        }.alignItems(VerticalAlign.Center)
      }.width('100%').padding({ left: 16, right: 16, top: 10, bottom: 10 }).alignItems(VerticalAlign.Center)

      Row({ space: 8 }) {
        Text('🚗').fontSize(14)
        Text('搜经典车/配件').fontSize(12).fontColor('#B8A98F').layoutWeight(1)
        Text('🔍').fontSize(12)
      }.width('100%').height(36).borderRadius(18).backgroundColor('#FAF3E8')
      .padding({ left: 14, right: 14 }).alignItems(VerticalAlign.Center)

      Row({ space: 8 }) {
        Column().width(4).height(12).borderRadius(2).backgroundColor('#A1887F')
        Text('秋季经典车展 · 展车征集截止本月底').fontSize(11).fontColor('#FAF3E8').layoutWeight(1)
        Text('查看 ›').fontSize(10).fontColor('#A1887F')
      }.width('100%').padding({ top: 10, bottom: 4 }).alignItems(VerticalAlign.Center)
    }.width('100%').backgroundColor('#8D2F2F')
    .padding({ left: 14, right: 14, top: 6, bottom: 10 })
  }

  // 底部七个页签
  @Builder bottomBuilder() {
    Row() {
      ForEach(this.tabs, (tab: string, index: number) => {
        Column({ space: 2 }) {
          Text(tab).fontSize(10).fontColor(this.currentTab === index ? '#8D2F2F' : '#999999')
          Column().width(18).height(3).borderRadius(2)
            .backgroundColor(this.currentTab === index ? '#8D2F2F' : '#FFFFFF00')
        }.onClick(() => { this.currentTab = index })
      }, (tab: string) => tab)
    }.width('100%').height(56).backgroundColor('#FFFFFF')
  }

  // Tab1 经典车展:横幅大卡 + 24 条经典车行式列表
  @Builder tab0() {
    Column({ space: 10 }) {
      Row({ space: 10 }) {
        Column({ space: 6 }) {
          Text('秋季经典车展 · 第38届').fontSize(17).fontColor('#FFFFFF').fontWeight(FontWeight.Bold)
          Text('300台传世经典车集结 · 现场拍卖专场').fontSize(11).fontColor('#FAF3E8')
          Row({ space: 8 }) {
            Text('免票预约').fontSize(10).fontColor('#8D2F2F')
              .padding({ left: 10, right: 10, top: 4, bottom: 4 }).borderRadius(10).backgroundColor('#FAF3E8')
            Text('本月截止').fontSize(10).fontColor('#FAF3E8')
              .padding({ left: 10, right: 10, top: 4, bottom: 4 }).borderRadius(10)
              .border({ width: 1, color: '#FAF3E8' })
          }.alignItems(VerticalAlign.Center)
        }.alignItems(HorizontalAlign.Start).layoutWeight(1)

        Text('🏎').fontSize(38)
          .scale({ x: 1.05, y: 1.05 }).animation({ duration: 700, iterations: -1, curve: Curve.EaseInOut })
      }.width('100%').padding(16).borderRadius(14).alignItems(VerticalAlign.Center)
      .linearGradient({ angle: 135, colors: [['#8D2F2F', 0], ['#B04A4A', 1]] })

      ForEach(this.mainList, (item: GoodsItem) => {
        Row({ space: 10 }) {
          Column() {
            Text(item.name.substring(0, 1)).fontSize(16).fontColor('#FFFFFF').fontWeight(FontWeight.Bold)
          }.width(42).height(42).borderRadius(21).backgroundColor('#8D2F2F')
          .justifyContent(FlexAlign.Center).alignItems(HorizontalAlign.Center)

          Column({ space: 3 }) {
            Text(item.name).fontSize(13).fontColor('#333333').fontWeight(FontWeight.Bold).maxLines(1)
            Text(item.desc).fontSize(9).fontColor('#999999').maxLines(1)
            Row() {
              Column().height(4).borderRadius(2).backgroundColor('#A1887F').width(item.score + '%')
            }.width(100).height(4).borderRadius(2).backgroundColor('#F0E6D8')
            Text('稀有度 ' + item.score + '% · ' + item.tag + ' · 车龄 ' + item.num + '年')
              .fontSize(8).fontColor('#A1887F')
          }.alignItems(HorizontalAlign.Start).layoutWeight(1)

          Column({ space: 5 }) {
            Text('¥' + this.priceText(item.price)).fontSize(12).fontColor('#E53935').fontWeight(FontWeight.Bold)
            Text('热度 ' + item.hot).fontSize(8).fontColor('#999999')
            if (item.score > 95) {
              Text('榜').fontSize(8).fontColor('#FFFFFF')
                .padding({ left: 5, right: 5, top: 1, bottom: 1 }).borderRadius(8).backgroundColor('#E53935')
                .scale({ x: 1.05, y: 1.05 }).animation({ duration: 700, iterations: -1, curve: Curve.EaseInOut })
            }
          }.alignItems(HorizontalAlign.End)
        }.width('100%').padding(10).backgroundColor('#FFFFFF').borderRadius(12)
        .onClick(() => { this.selectedItem = item; this.showDetailModal = true })
      }, (item: GoodsItem) => item.name)
    }.width('100%').padding(12)
  }

  // Tab2 老爷车市:车龄柱状图 + 12 条待售双列网格
  @Builder tab1() {
    Column({ space: 12 }) {
      Column({ space: 10 }) {
        Row() {
          Text('在售车龄分布').fontSize(14).fontColor('#333333').fontWeight(FontWeight.Bold)
          Column().layoutWeight(1)
          Text('HOT').fontSize(9).fontColor('#FFFFFF')
            .padding({ left: 6, right: 6, top: 2, bottom: 2 }).borderRadius(8).backgroundColor('#E53935')
            .scale({ x: 1.05, y: 1.05 }).animation({ duration: 700, iterations: -1, curve: Curve.EaseInOut })
        }.width('100%').alignItems(VerticalAlign.Center)

        Row() {
          ForEach(this.vinList, (item: GoodsItem) => {
            Column({ space: 4 }) {
              Column().width(16).borderRadius(3).backgroundColor('#8D2F2F')
                .height(item.num / this.maxNumOf(this.vinList) * 120)
              Text(item.num + '').fontSize(8).fontColor('#999999')
            }.alignItems(HorizontalAlign.Center)
          }, (item: GoodsItem) => item.name)
        }.width('100%').justifyContent(FlexAlign.SpaceBetween)
      }.width('100%').padding(12).backgroundColor('#FFFFFF').borderRadius(12)

      Flex({ wrap: FlexWrap.Wrap, justifyContent: FlexAlign.SpaceBetween }) {
        ForEach(this.vinList, (item: GoodsItem) => {
          Column({ space: 8 }) {
            Row() {
              Text(item.tag).fontSize(8).fontColor('#FFFFFF')
                .padding({ left: 6, right: 6, top: 2, bottom: 2 }).borderRadius(6).backgroundColor('#3E5641')
              Column().layoutWeight(1)
              Text(item.hot + '·' + item.num + '年').fontSize(8).fontColor('#A1887F')
            }.width('100%').alignItems(VerticalAlign.Center)

            Column() {
              Text(item.name.substring(0, 1)).fontSize(22).fontColor('#FAF3E8').fontWeight(FontWeight.Bold)
            }.width('100%').height(64).borderRadius(8).backgroundColor('#A1887F')
            .justifyContent(FlexAlign.Center).alignItems(HorizontalAlign.Center)

            Text(item.name).fontSize(12).fontColor('#333333').fontWeight(FontWeight.Bold).maxLines(1)
            Text(item.desc).fontSize(9).fontColor('#999999').maxLines(1)

            Row() {
              Text('¥' + this.priceText(item.price)).fontSize(13).fontColor('#E53935').fontWeight(FontWeight.Bold)
              Column().layoutWeight(1)
              if (item.score > 92) {
                Text('稀').fontSize(8).fontColor('#FFFFFF')
                  .padding({ left: 5, right: 5, top: 1, bottom: 1 }).borderRadius(8).backgroundColor('#E53935')
                  .scale({ x: 1.05, y: 1.05 }).animation({ duration: 700, iterations: -1, curve: Curve.EaseInOut })
              }
            }.width('100%').alignItems(VerticalAlign.Center)
          }.width('48%').padding(10).backgroundColor('#FFFFFF').borderRadius(12)
          .onClick(() => { this.selectedItem = item; this.showDetailModal = true })
        }, (item: GoodsItem) => item.name)
      }.width('100%')
    }.width('100%').padding(12)
  }

  // Tab3 修复工坊:墨绿统计卡 + 工期柱状图 + 横向案例卡
  @Builder tab2() {
    Column({ space: 12 }) {
      Column({ space: 10 }) {
        Row({ space: 6 }) {
          Text('🔧').fontSize(18)
            .scale({ x: 1.05, y: 1.05 }).animation({ duration: 700, iterations: -1, curve: Curve.EaseInOut })
          Text('修复工坊').fontSize(15).fontColor('#FFFFFF').fontWeight(FontWeight.Bold)
          Column().layoutWeight(1)
          Text(this.item0State()).fontSize(9).fontColor('#CFE0CF')
        }.width('100%').alignItems(VerticalAlign.Center)

        Row() {
          Column({ space: 2 }) {
            Text('38').fontSize(16).fontColor('#FFFFFF').fontWeight(FontWeight.Bold)
            Text('本月完工').fontSize(9).fontColor('#CFE0CF')
          }.alignItems(HorizontalAlign.Center).layoutWeight(1)

          Column().width(1).height(28).backgroundColor('#5A7460')

          Column({ space: 2 }) {
            Text('12').fontSize(16).fontColor('#FFFFFF').fontWeight(FontWeight.Bold)
            Text('在修项目').fontSize(9).fontColor('#CFE0CF')
          }.alignItems(HorizontalAlign.Center).layoutWeight(1)

          Column().width(1).height(28).backgroundColor('#5A7460')

          Column({ space: 2 }) {
            Text('96%').fontSize(16).fontColor('#FFFFFF').fontWeight(FontWeight.Bold)
            Text('藏家满意').fontSize(9).fontColor('#CFE0CF')
          }.alignItems(HorizontalAlign.Center).layoutWeight(1)
        }.width('100%').padding({ top: 6, bottom: 6 })

        Text('立即评估').fontSize(12).fontColor('#3E5641').fontWeight(FontWeight.Bold)
          .width('100%').textAlign(TextAlign.Center)
          .padding({ top: 8, bottom: 8 }).borderRadius(16).backgroundColor('#FAF3E8')
          .onClick(() => { this.chipA = 0; this.chipB = 0; this.showFixModal = true })
      }.width('100%').padding(14).borderRadius(14).backgroundColor('#3E5641')

      Column({ space: 10 }) {
        Text('修复工期一览(天)').fontSize(14).fontColor('#333333').fontWeight(FontWeight.Bold)
        Row() {
          ForEach(this.fixList, (item: GoodsItem) => {
            Column({ space: 3 }) {
              Column().width(14).borderRadius(3).backgroundColor('#3E5641')
                .height(item.num / this.maxNumOf(this.fixList) * 100)
              Text(item.num + '').fontSize(8).fontColor('#999999')
            }.alignItems(HorizontalAlign.Center)
          }, (item: GoodsItem) => item.name)
        }.width('100%').justifyContent(FlexAlign.SpaceBetween)
      }.width('100%').padding(12).backgroundColor('#FFFFFF').borderRadius(12)

      Column({ space: 10 }) {
        Text('修复案例').fontSize(14).fontColor('#333333').fontWeight(FontWeight.Bold)
        Scroll() {
          Row({ space: 10 }) {
            ForEach(this.fixList, (item: GoodsItem) => {
              Column({ space: 6 }) {
                Row({ space: 5 }) {
                  Column() {
                    Text('前').fontSize(10).fontColor('#FFFFFF')
                  }.width(52).height(38).borderRadius(6).backgroundColor('#7A7A7A')
                  .justifyContent(FlexAlign.Center).alignItems(HorizontalAlign.Center)

                  Text('→').fontSize(10).fontColor('#A1887F')

                  Column() {
                    Text('后').fontSize(10).fontColor('#FFFFFF')
                  }.width(52).height(38).borderRadius(6).backgroundColor('#8D2F2F')
                  .justifyContent(FlexAlign.Center).alignItems(HorizontalAlign.Center)
                }.alignItems(VerticalAlign.Center)

                Text(item.name).fontSize(11).fontColor('#333333').fontWeight(FontWeight.Bold).maxLines(1)
                Text('工期 ' + item.num + '天 · ' + item.tag + ' · ' + item.hot).fontSize(8).fontColor('#999999')
                if (item.score > 92) {
                  Text('口碑精选').fontSize(8).fontColor('#FFFFFF')
                    .padding({ left: 6, right: 6, top: 1, bottom: 1 }).borderRadius(8).backgroundColor('#E53935')
                    .scale({ x: 1.05, y: 1.05 }).animation({ duration: 700, iterations: -1, curve: Curve.EaseInOut })
                }
              }.width(150).padding(10).backgroundColor('#FFFFFF').borderRadius(12)
              .onClick(() => { this.selectedItem = item; this.showDetailModal = true })
            }, (item: GoodsItem) => item.name)
          }
        }.scrollable(ScrollDirection.Horizontal).width('100%')
      }.width('100%').padding(12).backgroundColor('#FFFFFF').borderRadius(12)
    }.width('100%').padding(12)
  }

  // Tab4 配件集市:稀有度柱状图 + 10 条稀有配件列表
  @Builder tab3() {
    Column({ space: 12 }) {
      Column({ space: 10 }) {
        Row() {
          Text('稀有度指数').fontSize(14).fontColor('#333333').fontWeight(FontWeight.Bold)
          Column().layoutWeight(1)
          Text('我要求购').fontSize(11).fontColor('#FFFFFF')
            .padding({ left: 12, right: 12, top: 5, bottom: 5 }).borderRadius(12).backgroundColor('#8D2F2F')
            .onClick(() => { this.chipA = 0; this.chipB = 0; this.stepNum = 1; this.showWantModal = true })
        }.width('100%').alignItems(VerticalAlign.Center)

        Row() {
          ForEach(this.partList, (item: GoodsItem) => {
            Column({ space: 3 }) {
              Column().width(16).borderRadius(3).backgroundColor('#A1887F').height(item.score / 100 * 120)
              Text(item.num + '').fontSize(8).fontColor('#999999')
            }.alignItems(HorizontalAlign.Center)
          }, (item: GoodsItem) => item.name)
        }.width('100%').justifyContent(FlexAlign.SpaceBetween)
      }.width('100%').padding(12).backgroundColor('#FFFFFF').borderRadius(12)

      ForEach(this.partList, (item: GoodsItem, index: number) => {
        Row({ space: 10 }) {
          Column().width(4).height(46).borderRadius(2)
            .backgroundColor(index % 3 === 0 ? '#8D2F2F' : (index % 3 === 1 ? '#A1887F' : '#3E5641'))

          Column({ space: 3 }) {
            Text(item.name).fontSize(13).fontColor('#333333').fontWeight(FontWeight.Bold).maxLines(1)
            Text(item.desc).fontSize(9).fontColor('#999999').maxLines(1)
            Row() {
              Column().height(4).borderRadius(2).backgroundColor('#A1887F').width(item.score + '%')
            }.width(110).height(4).borderRadius(2).backgroundColor('#F0E6D8')
            Text('稀有度 ' + item.score + '% · 库存 ' + item.num + ' 件 · ' + item.tag + '件')
              .fontSize(8).fontColor('#A1887F')
          }.alignItems(HorizontalAlign.Start).layoutWeight(1)

          Column({ space: 5 }) {
            Text('¥' + Math.floor(item.price)).fontSize(12).fontColor('#E53935').fontWeight(FontWeight.Bold)
            if (item.score > 90) {
              Text(item.hot).fontSize(8).fontColor('#FFFFFF')
                .padding({ left: 5, right: 5, top: 1, bottom: 1 }).borderRadius(8).backgroundColor('#E53935')
                .scale({ x: 1.05, y: 1.05 }).animation({ duration: 700, iterations: -1, curve: Curve.EaseInOut })
            } else {
              Text(item.hot).fontSize(8).fontColor('#A1887F')
            }
          }.alignItems(HorizontalAlign.End)
        }.width('100%').padding(10).backgroundColor('#FFFFFF').borderRadius(12)
      }, (item: GoodsItem) => item.name)
    }.width('100%').padding(12)
  }

  // Tab5 车友会:年代话题 + 10 条藏车故事帖
  @Builder tab4() {
    Column({ space: 12 }) {
      Flex({ wrap: FlexWrap.Wrap }) {
        ForEach(this.topicChips, (t: string, i: number) => {
          Text('# ' + t).fontSize(11).fontColor(i % 2 === 0 ? '#8D2F2F' : '#3E5641')
            .padding({ left: 10, right: 10, top: 5, bottom: 5 }).borderRadius(14)
            .backgroundColor(i % 2 === 0 ? '#F6E4E4' : '#E4EDE6')
            .margin({ right: 8, bottom: 6 })
        }, (t: string) => t)
      }.width('100%')

      ForEach(this.clubList, (item: GoodsItem) => {
        Column({ space: 8 }) {
          Row({ space: 8 }) {
            Column() {
              Text(item.name.substring(0, 1)).fontSize(15).fontColor('#FFFFFF').fontWeight(FontWeight.Bold)
            }.width(36).height(36).borderRadius(18).backgroundColor('#3E5641')
            .justifyContent(FlexAlign.Center).alignItems(HorizontalAlign.Center)

            Column({ space: 2 }) {
              Text(item.name).fontSize(12).fontColor('#333333').fontWeight(FontWeight.Bold)
              Text(item.tag + ' 车主 · 声望 ' + item.score).fontSize(8).fontColor('#999999')
            }.alignItems(HorizontalAlign.Start).layoutWeight(1)

            Text('关注').fontSize(10).fontColor('#8D2F2F')
              .padding({ left: 10, right: 10, top: 3, bottom: 3 }).borderRadius(10).backgroundColor('#F6E4E4')
          }.alignItems(VerticalAlign.Center)

          Text(item.desc).fontSize(11).fontColor('#444444').maxLines(2).lineHeight(16)

          Row({ space: 6 }) {
            Column().layoutWeight(1).height(64).borderRadius(8).backgroundColor('#A1887F')
            Column().layoutWeight(1).height(64).borderRadius(8).backgroundColor('#C9B8A3')
            Column().layoutWeight(1).height(64).borderRadius(8).backgroundColor('#8D2F2F')
          }.width('100%')

          Row() {
            Text('阅读 ' + item.num + ' · ' + item.hot + '华帖').fontSize(9).fontColor('#999999')
            Column().layoutWeight(1)
            Row({ space: 4 }) {
              Text('👍').fontSize(12)
              Text(item.price + '').fontSize(11).fontColor('#8D2F2F').fontWeight(FontWeight.Bold)
                .scale({ x: 1.05, y: 1.05 }).animation({ duration: 700, iterations: -1, curve: Curve.EaseInOut })
            }.alignItems(VerticalAlign.Center)
          }.width('100%')
        }.width('100%').padding(12).backgroundColor('#FFFFFF').borderRadius(12)
      }, (item: GoodsItem) => item.name)
    }.width('100%').padding(12)
  }

  // Tab6 消息:12 条通知列表,未读红点带脉冲
  @Builder tab5() {
    Column({ space: 10 }) {
      Row() {
        Text('消息中心').fontSize(16).fontColor('#333333').fontWeight(FontWeight.Bold)
        Column().layoutWeight(1)
        Text('全部已读').fontSize(10).fontColor('#A1887F')
      }.width('100%').padding({ left: 2, right: 2 })

      ForEach(this.msgList, (item: GoodsItem) => {
        Row({ space: 10 }) {
          Column() {
            Text(item.name.substring(0, 1)).fontSize(14).fontColor('#FFFFFF').fontWeight(FontWeight.Bold)
          }.width(40).height(40).borderRadius(20)
          .backgroundColor(item.hot === '未' ? '#8D2F2F' : '#B8A98F')
          .justifyContent(FlexAlign.Center).alignItems(HorizontalAlign.Center)

          Column({ space: 3 }) {
            Row() {
              Text(item.name).fontSize(13).fontColor('#333333').fontWeight(FontWeight.Bold).maxLines(1)
              Column().layoutWeight(1)
              Text(item.tag).fontSize(8).fontColor('#BBBBBB')
            }.width('100%').alignItems(VerticalAlign.Center)

            Text(item.desc).fontSize(10).fontColor('#999999').maxLines(1)
          }.alignItems(HorizontalAlign.Start).layoutWeight(1)

          if (item.hot === '未') {
            Column().width(8).height(8).borderRadius(4).backgroundColor('#E53935')
              .scale({ x: 1.05, y: 1.05 }).animation({ duration: 700, iterations: -1, curve: Curve.EaseInOut })
          }
        }.width('100%').padding(12).backgroundColor('#FFFFFF').borderRadius(12)
        .onClick(() => { this.selectedItem = item; this.showDetailModal = true })
      }, (item: GoodsItem) => item.name)
    }.width('100%').padding(12)
  }

  // Tab7 我的:墨绿个人卡 + 三格统计 + 六行菜单
  @Builder tab6() {
    Column({ space: 12 }) {
      Row({ space: 12 }) {
        Column() {
          Text('藏').fontSize(20).fontColor('#FAF3E8').fontWeight(FontWeight.Bold)
        }.width(60).height(60).borderRadius(30).backgroundColor('#A1887F')
        .justifyContent(FlexAlign.Center).alignItems(HorizontalAlign.Center)

        Column({ space: 4 }) {
          Text('老陈的车库').fontSize(16).fontColor('#FFFFFF').fontWeight(FontWeight.Bold)
          Text('LV.8 资深经典车收藏家').fontSize(10).fontColor('#CFE0CF')
          Text('收藏 38 年 · 主修欧系与国产老车').fontSize(9).fontColor('#CFE0CF')
        }.alignItems(HorizontalAlign.Start).layoutWeight(1)

        Text('›').fontSize(18).fontColor('#CFE0CF')
      }.width('100%').padding(16).borderRadius(14).backgroundColor('#3E5641').alignItems(VerticalAlign.Center)

      Row() {
        Column({ space: 2 }) {
          Text('12').fontSize(16).fontColor('#8D2F2F').fontWeight(FontWeight.Bold)
          Text('我的藏车').fontSize(9).fontColor('#999999')
        }.alignItems(HorizontalAlign.Center).layoutWeight(1)

        Column().width(1).height(26).backgroundColor('#F0E6D8')

        Column({ space: 2 }) {
          Text('3').fontSize(16).fontColor('#8D2F2F').fontWeight(FontWeight.Bold)
          Text('修复订单').fontSize(9).fontColor('#999999')
        }.alignItems(HorizontalAlign.Center).layoutWeight(1)

        Column().width(1).height(26).backgroundColor('#F0E6D8')

        Column({ space: 2 }) {
          Text('5').fontSize(16).fontColor('#8D2F2F').fontWeight(FontWeight.Bold)
          Text('展会门票').fontSize(9).fontColor('#999999')
        }.alignItems(HorizontalAlign.Center).layoutWeight(1)
      }.width('100%').padding(14).backgroundColor('#FFFFFF').borderRadius(12)

      Column({ space: 8 }) {
        ForEach(this.menuList, (m: string, i: number) => {
          Row({ space: 10 }) {
            Text(i === 0 ? '🚗' : (i === 1 ? '🔧' : (i === 2 ? '🧩' : (i === 3 ? '📤' : (i === 4 ? '🎟' : '⚙'))))).fontSize(14)
            Text(m).fontSize(13).fontColor('#333333').layoutWeight(1)
            Text(i === 0 ? '12 台' : (i === 1 ? '进行中 3' : (i === 4 ? '未使用 5' : ''))).fontSize(10).fontColor('#999999')
            Text('›').fontSize(14).fontColor('#CCCCCC')
          }.width('100%').padding({ left: 14, right: 14, top: 13, bottom: 13 })
          .backgroundColor('#FFFFFF').borderRadius(12).alignItems(VerticalAlign.Center)
          .onClick(() => {
            if (i === 0) {
              this.currentTab = 0
            } else if (i === 1) {
              this.currentTab = 2
            } else if (i === 2) {
              this.chipA = 0; this.chipB = 0; this.stepNum = 1; this.showWantModal = true
            } else if (i === 3) {
              this.chipA = 0; this.chipB = 0; this.showAddModal = true
            } else if (i === 4) {
              this.currentTab = 0
            } else {
              this.currentTab = 6
            }
          })
        }, (m: string) => m)
      }.width('100%')
    }.width('100%').padding(12)
  }

  // 弹框一:发布藏车(底部弹出)
  @Builder addModal() {
    Column() {
      Column().layoutWeight(1)

      Column({ space: 14 }) {
        Row() {
          Column().width(4).height(16).borderRadius(2).backgroundColor('#8D2F2F')
          Text('发布经典车').fontSize(16).fontColor('#333333').fontWeight(FontWeight.Bold)
          Column().layoutWeight(1)
          Text('×').fontSize(18).fontColor('#999999').padding(4)
            .onClick(() => { this.showAddModal = false })
        }.width('100%').alignItems(VerticalAlign.Center)

        Text('出厂年代').fontSize(12).fontColor('#666666').width('100%')
        Flex({ wrap: FlexWrap.Wrap }) {
          ForEach(this.eraChips, (c: string, i: number) => {
            Text(c).fontSize(12).fontColor(this.chipA === i ? '#FFFFFF' : '#666666')
              .padding({ left: 14, right: 14, top: 6, bottom: 6 }).borderRadius(14)
              .backgroundColor(this.chipA === i ? '#8D2F2F' : '#F5EFE3')
              .margin({ right: 8, bottom: 6 })
              .onClick(() => { this.chipA = i })
          }, (c: string) => c)
        }.width('100%')

        Text('当前车况').fontSize(12).fontColor('#666666').width('100%')
        Flex({ wrap: FlexWrap.Wrap }) {
          ForEach(this.condChips, (c: string, i: number) => {
            Text(c).fontSize(12).fontColor(this.chipB === i ? '#FFFFFF' : '#666666')
              .padding({ left: 14, right: 14, top: 6, bottom: 6 }).borderRadius(14)
              .backgroundColor(this.chipB === i ? '#A1887F' : '#F5EFE3')
              .margin({ right: 8, bottom: 6 })
              .onClick(() => { this.chipB = i })
          }, (c: string) => c)
        }.width('100%')

        Text('车辆描述').fontSize(12).fontColor('#666666').width('100%')
        TextInput({ placeholder: '车况、里程、过户次数等', text: this.inputDesc })
          .fontSize(12).height(40).backgroundColor('#F5EFE3').borderRadius(8)
          .padding({ left: 10, right: 10 })
          .onChange((value: string) => { this.inputDesc = value })

        Text('立即发布').fontSize(14).fontColor('#FFFFFF').fontWeight(FontWeight.Bold)
          .width('100%').textAlign(TextAlign.Center)
          .padding({ top: 10, bottom: 10 }).borderRadius(20).backgroundColor('#8D2F2F')
          .onClick(() => { this.showAddModal = false })
      }.width('100%').padding(16).backgroundColor('#FFFFFF')
      .borderRadius({ topLeft: 16, topRight: 16 })
      .constraintSize({ maxHeight: '80%' })
    }.width('100%').height('100%').backgroundColor('rgba(0,0,0,0.5)')
    .onClick(() => { this.showAddModal = false })
  }

  // 弹框二:修复评估(底部弹出,报价带脉冲)
  @Builder fixModal() {
    Column() {
      Column().layoutWeight(1)

      Column({ space: 14 }) {
        Row() {
          Column().width(4).height(16).borderRadius(2).backgroundColor('#3E5641')
          Text('修复评估').fontSize(16).fontColor('#333333').fontWeight(FontWeight.Bold)
          Column().layoutWeight(1)
          Text('×').fontSize(18).fontColor('#999999').padding(4)
            .onClick(() => { this.showFixModal = false })
        }.width('100%').alignItems(VerticalAlign.Center)

        Text('修复项目').fontSize(12).fontColor('#666666').width('100%')
        Flex({ wrap: FlexWrap.Wrap }) {
          ForEach(this.fixItemChips, (c: string, i: number) => {
            Text(c).fontSize(12).fontColor(this.chipA === i ? '#FFFFFF' : '#666666')
              .padding({ left: 14, right: 14, top: 6, bottom: 6 }).borderRadius(14)
              .backgroundColor(this.chipA === i ? '#3E5641' : '#F5EFE3')
              .margin({ right: 8, bottom: 6 })
              .onClick(() => { this.chipA = i })
          }, (c: string) => c)
        }.width('100%')

        Text('期望工期').fontSize(12).fontColor('#666666').width('100%')
        Flex({ wrap: FlexWrap.Wrap }) {
          ForEach(this.fixDurChips, (c: string, i: number) => {
            Text(c).fontSize(12).fontColor(this.chipB === i ? '#FFFFFF' : '#666666')
              .padding({ left: 14, right: 14, top: 6, bottom: 6 }).borderRadius(14)
              .backgroundColor(this.chipB === i ? '#A1887F' : '#F5EFE3')
              .margin({ right: 8, bottom: 6 })
              .onClick(() => { this.chipB = i })
          }, (c: string) => c)
        }.width('100%')

        Column({ space: 6 }) {
          Row() {
            Text('预估报价').fontSize(12).fontColor('#666666')
            Column().layoutWeight(1)
            Text('¥' + this.priceText(this.fixQuote())).fontSize(22).fontColor('#E53935').fontWeight(FontWeight.Bold)
              .scale({ x: 1.05, y: 1.05 }).animation({ duration: 700, iterations: -1, curve: Curve.EaseInOut })
          }.width('100%').alignItems(VerticalAlign.Center)

          Text('报价随项目与工期浮动,最终以实车勘验为准').fontSize(9).fontColor('#999999').width('100%')
        }.width('100%').padding(12).borderRadius(10).backgroundColor('#F5EFE3')

        Text('提交评估').fontSize(14).fontColor('#FFFFFF').fontWeight(FontWeight.Bold)
          .width('100%').textAlign(TextAlign.Center)
          .padding({ top: 10, bottom: 10 }).borderRadius(20).backgroundColor('#3E5641')
          .onClick(() => { this.showFixModal = false })
      }.width('100%').padding(16).backgroundColor('#FFFFFF')
      .borderRadius({ topLeft: 16, topRight: 16 })
      .constraintSize({ maxHeight: '80%' })
    }.width('100%').height('100%').backgroundColor('rgba(0,0,0,0.5)')
    .onClick(() => { this.showFixModal = false })
  }

  // 弹框三:配件求购(底部弹出,含数量步进器)
  @Builder wantModal() {
    Column() {
      Column().layoutWeight(1)

      Column({ space: 14 }) {
        Row() {
          Column().width(4).height(16).borderRadius(2).backgroundColor('#A1887F')
          Text('配件求购').fontSize(16).fontColor('#333333').fontWeight(FontWeight.Bold)
          Column().layoutWeight(1)
          Text('×').fontSize(18).fontColor('#999999').padding(4)
            .onClick(() => { this.showWantModal = false })
        }.width('100%').alignItems(VerticalAlign.Center)

        Text('配件类型').fontSize(12).fontColor('#666666').width('100%')
        Flex({ wrap: FlexWrap.Wrap }) {
          ForEach(this.partTypeChips, (c: string, i: number) => {
            Text(c).fontSize(12).fontColor(this.chipA === i ? '#FFFFFF' : '#666666')
              .padding({ left: 14, right: 14, top: 6, bottom: 6 }).borderRadius(14)
              .backgroundColor(this.chipA === i ? '#8D2F2F' : '#F5EFE3')
              .margin({ right: 8, bottom: 6 })
              .onClick(() => { this.chipA = i })
          }, (c: string) => c)
        }.width('100%')

        Text('适配年代').fontSize(12).fontColor('#666666').width('100%')
        Flex({ wrap: FlexWrap.Wrap }) {
          ForEach(this.wantEraChips, (c: string, i: number) => {
            Text(c).fontSize(12).fontColor(this.chipB === i ? '#FFFFFF' : '#666666')
              .padding({ left: 14, right: 14, top: 6, bottom: 6 }).borderRadius(14)
              .backgroundColor(this.chipB === i ? '#A1887F' : '#F5EFE3')
              .margin({ right: 8, bottom: 6 })
              .onClick(() => { this.chipB = i })
          }, (c: string) => c)
        }.width('100%')

        Row() {
          Text('求购数量').fontSize(12).fontColor('#666666')
          Column().layoutWeight(1)
          Text('-').fontSize(14).fontColor(this.stepNum <= 1 ? '#CCCCCC' : '#8D2F2F')
            .width(30).height(30).borderRadius(15).textAlign(TextAlign.Center).backgroundColor('#F5EFE3')
            .onClick(() => { if (this.stepNum > 1) { this.stepNum = this.stepNum - 1 } })
          Text(this.stepNum + ' 件').fontSize(13).fontColor('#333333').fontWeight(FontWeight.Bold)
            .width(56).textAlign(TextAlign.Center)
          Text('+').fontSize(14).fontColor(this.stepNum >= 10 ? '#CCCCCC' : '#8D2F2F')
            .width(30).height(30).borderRadius(15).textAlign(TextAlign.Center).backgroundColor('#F5EFE3')
            .onClick(() => { if (this.stepNum < 10) { this.stepNum = this.stepNum + 1 } })
        }.width('100%').alignItems(VerticalAlign.Center)

        Text('发布求购').fontSize(14).fontColor('#FFFFFF').fontWeight(FontWeight.Bold)
          .width('100%').textAlign(TextAlign.Center)
          .padding({ top: 10, bottom: 10 }).borderRadius(20).backgroundColor('#A1887F')
          .onClick(() => { this.showWantModal = false })
      }.width('100%').padding(16).backgroundColor('#FFFFFF')
      .borderRadius({ topLeft: 16, topRight: 16 })
      .constraintSize({ maxHeight: '80%' })
    }.width('100%').height('100%').backgroundColor('rgba(0,0,0,0.5)')
    .onClick(() => { this.showWantModal = false })
  }

  // 弹框四:删除确认(居中警示小卡)
  @Builder deleteModal() {
    Column() {
      Column({ space: 14 }) {
        Column() {
          Text('⚠').fontSize(28).fontColor('#FFFFFF')
        }.width(56).height(56).borderRadius(28).backgroundColor('#E53935')
        .justifyContent(FlexAlign.Center).alignItems(HorizontalAlign.Center)

        Text('确认删除该藏车收藏?').fontSize(15).fontColor('#333333').fontWeight(FontWeight.Bold)
        Text('删除后相关展车预约将一并取消').fontSize(10).fontColor('#999999')

        Row({ space: 12 }) {
          Text('取消').fontSize(14).fontColor('#666666').textAlign(TextAlign.Center).layoutWeight(1)
            .padding({ top: 10, bottom: 10 }).borderRadius(20).backgroundColor('#F5EFE3')
            .onClick(() => { this.showDeleteModal = false })

          Text('删除').fontSize(14).fontColor('#FFFFFF').fontWeight(FontWeight.Bold)
            .textAlign(TextAlign.Center).layoutWeight(1)
            .padding({ top: 10, bottom: 10 }).borderRadius(20).backgroundColor('#E53935')
            .onClick(() => { this.showDeleteModal = false; this.showDetailModal = false })
        }.width('100%').alignItems(VerticalAlign.Center)
      }.width('72%').padding(20).borderRadius(12).backgroundColor('#FFFFFF')
      .alignItems(HorizontalAlign.Center)
    }.width('100%').height('100%').backgroundColor('rgba(0,0,0,0.5)')
    .justifyContent(FlexAlign.Center).alignItems(HorizontalAlign.Center)
    .onClick(() => { this.showDeleteModal = false })
  }

  // 弹框五:车辆详情(右侧滑出全高面板)
  @Builder detailModal() {
    Column() {
      Column({ space: 12 }) {
        Stack() {
          Column().width('100%').height(190).borderRadius(12)
            .linearGradient({ angle: 135, colors: [['#8D2F2F', 0], ['#5E1F1F', 1]] })

          Column({ space: 6 }) {
            Text('传世经典').fontSize(11).fontColor('#FAF3E8')
              .padding({ left: 10, right: 10, top: 3, bottom: 3 }).borderRadius(10)
              .border({ width: 1, color: '#A1887F' })
              .scale({ x: 1.05, y: 1.05 }).animation({ duration: 700, iterations: -1, curve: Curve.EaseInOut })
            Text(this.selName().substring(0, 1)).fontSize(52).fontColor('#FAF3E8').fontWeight(FontWeight.Bold)
          }.height(190).justifyContent(FlexAlign.Center)
        }.width('100%')

        Text(this.selName()).fontSize(17).fontColor('#333333').fontWeight(FontWeight.Bold).width('100%')
        Text(this.selDesc()).fontSize(10).fontColor('#999999').width('100%')

        Row() {
          Text('¥' + this.priceText(this.selPrice())).fontSize(24).fontColor('#E53935').fontWeight(FontWeight.Bold)
          Column().layoutWeight(1)
          Text(this.selTag() + ' · 热度 ' + this.selHot()).fontSize(10).fontColor('#A1887F')
        }.width('100%').alignItems(VerticalAlign.Bottom)

        Column({ space: 5 }) {
          Text('稀有度 ' + this.selScore() + '%').fontSize(10).fontColor('#666666').width('100%')
          Row() {
            Column().height(6).borderRadius(3).backgroundColor('#A1887F').width(this.selScore() + '%')
          }.width('100%').height(6).borderRadius(3).backgroundColor('#F0E6D8')
        }.width('100%')

        Text('历史档案').fontSize(12).fontColor('#666666').width('100%')
        Flex({ wrap: FlexWrap.Wrap }) {
          ForEach(this.historyChips, (c: string) => {
            Text(c).fontSize(10).fontColor('#3E5641')
              .padding({ left: 10, right: 10, top: 4, bottom: 4 }).borderRadius(10)
              .backgroundColor('#E4EDE6')
              .margin({ right: 8, bottom: 6 })
          }, (c: string) => c)
        }.width('100%')

        Column().layoutWeight(1)

        Text('移出收藏').fontSize(12).fontColor('#999999').width('100%').textAlign(TextAlign.Center)
          .padding({ top: 8, bottom: 8 }).borderRadius(18)
          .onClick(() => { this.showDeleteModal = true })

        Text('预约看车').fontSize(14).fontColor('#FFFFFF').fontWeight(FontWeight.Bold)
          .width('100%').textAlign(TextAlign.Center)
          .padding({ top: 10, bottom: 10 }).borderRadius(20).backgroundColor('#8D2F2F')
          .onClick(() => { this.showDetailModal = false })
      }.width('80%').height('100%').padding(14).backgroundColor('#FFFFFF')
    }.width('100%').height('100%').backgroundColor('rgba(0,0,0,0.5)')
    .justifyContent(FlexAlign.End).alignItems(HorizontalAlign.End)
    .onClick(() => { this.showDetailModal = false })
  }

  item0State(): string {
    return '本季度接单 ' + this.fixList.length + ' 项'
  }

  build() {
    Stack() {
      Column() {
        this.headerBuilder()
        Scroll() {
          Column() {
            if (this.currentTab === 0) {
              this.tab0()
            } else if (this.currentTab === 1) {
              this.tab1()
            } else if (this.currentTab === 2) {
              this.tab2()
            } else if (this.currentTab === 3) {
              this.tab3()
            } else if (this.currentTab === 4) {
              this.tab4()
            } else if (this.currentTab === 5) {
              this.tab5()
            } else {
              this.tab6()
            }
          }.width('100%')
        }.layoutWeight(1).width('100%')
        this.bottomBuilder()
      }.width('100%').height('100%')

      if (this.showAddModal) {
        this.addModal()
      }
      if (this.showFixModal) {
        this.fixModal()
      }
      if (this.showWantModal) {
        this.wantModal()
      }
      if (this.showDeleteModal) {
        this.deleteModal()
      }
      if (this.showDetailModal) {
        this.detailModal()
      }
    }.width('100%').height('100%')
  }
}


总结

在这里插入图片描述

本文深入解析了一款基于HarmonyOS ArkTS声明式UI框架构建的复古经典车馆应用页面的完整实现。该应用以复古红、黄铜金、米白和墨绿四色体系构建了浓郁的怀旧视觉基调,通过七大Tab页面(经典车展、老爷车市、修复工坊、配件集市、车友会、消息、我的)和五类弹窗(发布藏车、修复评估、配件求购、删除确认、车辆详情)实现了从经典车浏览到修复评估再到配件求购的完整业务链路。

在数据可视化方面,应用实现了三种柱状图——车龄分布图(使用maxNumOf归一化)、修复工期一览图和稀有度指数图(使用score/100*120直接百分比映射),通过linearGradient线性渐变实现了横幅卡片和详情弹窗头部的海报级视觉效果。在业务逻辑方面,fixQuote()方法通过"基础价+工期系数"的二元参数模型实现了修复报价的动态计算,priceText()方法将数值价格格式化为中文"万"单位,这两个方法的设计体现了状态驱动业务计算的核心思想。在交互细节方面,步进器通过stepNum <= 1stepNum >= 10的条件着色提供了操作边界反馈,消息列表通过hot字段值"未"/"已"驱动头像背景色和未读红点的条件渲染,配件列表通过index % 3循环取色实现了三色交替的视觉节奏。

从工程架构角度,该应用的设计体现了HarmonyOS ArkTS开发的多个关键实践:统一GoodsItem接口复用覆盖78条六类业务数据、@Builder方法封装实现七大Tab和五类弹窗的UI复用、Stack条件渲染实现弹窗层叠管理、stopPropagation精确控制事件冒泡、constraintSize({ maxHeight: '80%' })限制弹窗高度。这些技术实践为汽车后市场情怀类垂直应用和需要多维度数据展示、参数化报价计算、多类型弹窗交互的复杂业务场景提供了可借鉴的声明式UI实现方案。

Logo

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

更多推荐