在HarmonyOS 6.1.1生态蓬勃发展的今天,深色模式与霓虹风格正成为年轻用户的新宠。本文将深入剖析一款潮流纹身贴纸馆应用的技术实现,从深色主题设计到荧光动效实现,全方位展示HarmonyOS ArkTS API 24在潮流文化应用中的创新实践。

深紫黑背景下荧光青与电粉的激烈碰撞,赛博朋克美学与东方纹身文化的完美融合,这款纹身贴纸应用以前卫的视觉语言和丰富的交互体验,为Z世代用户打造了沉浸式的潮流文化消费场景。

本文将从深色主题系统、霓虹动画引擎、数据模型设计、组件架构实现、六大Tab功能解析等多个维度,系统拆解这款潮流纹身应用的技术内核,为HarmonyOS开发者提供深色模式应用的设计范式与开发参考。

引言

在这里插入图片描述

随着HarmonyOS 6.1.1的正式发布,ArkTS声明式UI框架进入了更加成熟的阶段,为各类风格的应用开发提供了坚实的技术底座。这款潮流纹身贴纸馆应用正是基于HarmonyOS ArkTS API 24构建的一款面向年轻用户的潮流文化应用,它以"潮流图案·荧光墨水"为核心理念,将赛博朋克美学与纹身文化完美结合。

应用整体采用"IW"(INK WORLD)前缀的命名规范,以深紫黑(#0F0A1A)为背景色,荧光青(#00FFFF)为主色调,电粉(#FF1493)为强调色,配合紫色辉光(#9D4EDD)和深色卡片(#1A1528),构建出极具冲击力的深色霓虹视觉体系。在黑色背景的衬托下,荧光色元素显得格外醒目,完美契合了纹身文化的前卫气质。

从业务架构来看,这是一款集纹身贴选购、图案设计、工具耗材、护理产品、线下门店、社区交流于一体的综合性潮流纹身平台。六大核心Tab页签——首页、纹身贴、工具、护理、图案、我的——构建了完整的用户旅程,从发现潮流到购买产品,从图案下载到线下体验,全方位满足纹身爱好者的需求。

技术实现方面,应用采用了典型的ArkTS声明式开发架构。底层是TypeScript接口定义与常量数据,中间层是纯函数工具库(包含6个动画函数和多个业务工具函数),上层是组件体系(主组件、首页组件、各分类Tab组件、个人中心组件)。深色主题下的动画效果设计是这款应用的一大亮点,墨水扩散、霓虹辉光、旋转光晕等特效在深色背景下呈现出极佳的视觉效果。

深色主题系统设计

在这里插入图片描述

主题接口与配色方案

interface IwTheme {
  bg: string
  primary: string
  accent: string
  card: string
  text: string
  sub: string
  line: string
  glow: string
  dark: string
}

const IW: IwTheme = {
  bg: '#0F0A1A',
  primary: '#00FFFF',
  accent: '#FF1493',
  card: '#1A1528',
  text: '#E8E0F0',
  sub: '#7A6B8A',
  line: '#2A2040',
  glow: '#9D4EDD',
  dark: '#0A0612'
}

深色主题的配色方案是这款应用最核心的视觉特征。背景色采用深紫黑(#0F0A1A),比纯黑更有层次感和神秘感;主色是高饱和度的荧光青(#00FFFF),在深色背景下极具穿透力;强调色是电粉色(#FF1493),与荧光青形成强烈的冷暖对比,视觉冲击力十足。

卡片背景使用深紫色(#1A1528),比背景色稍亮但仍保持深色基调,形成自然的层级区分。文字颜色使用淡紫色(#E8E0F0),次要文字使用灰紫色(#7A6B8A),在保证可读性的同时保持了整体色调的统一。分割线使用深紫色(#2A2040),几乎与背景融为一体,只提供微妙的边界提示。

深色主题设计并非简单地把背景变黑、文字变白。一个优秀的深色主题需要精心设计多层级的深色(背景、卡片、弹框等)、合适的文字对比度(避免纯白造成的眩光)、以及在深色下依然醒目的品牌色。这款应用的配色方案在这些方面都做得相当出色。

Tab导航配置

在这里插入图片描述

const IW_TABS: IwTab[] = [
  { key: 'home', label: '首页', icon: $r('app.media.layered_image') },
  { key: 'tattoo', label: '纹身贴', icon: $r('app.media.layered_image') },
  { key: 'tool', label: '工具', icon: $r('app.media.layered_image') },
  { key: 'care', label: '护理', icon: $r('app.media.layered_image') },
  { key: 'design', label: '图案', icon: $r('app.media.layered_image') },
  { key: 'mine', label: '我的', icon: $r('app.media.layered_image') }
]

六个Tab页签构成了应用的核心导航架构:首页负责内容发现和功能入口,纹身贴是核心商品品类,工具和护理是配套产品,图案是特色内容板块,我的是个人中心。这种"核心商品+配套产品+内容社区"的结构非常适合垂直领域电商应用。

数据模型与业务数据

纹身贴数据模型

在这里插入图片描述

interface IwTattoo {
  name: string
  style: string
  size: number
  color: string
  duration: number
  waterproof: number
  price: number
  stock: number
  sold: number
  tag: string
}

const IW_TATTOOS: IwTattoo[] = [
  { name: '盘龙·墨韵', style: '新传统', size: 25, color: '黑色', duration: 7, waterproof: 5, price: 168, stock: 30, sold: 456, tag: '热门' },
  { name: '玫瑰·荧光', style: '新传统', size: 15, color: '荧光', duration: 5, waterproof: 4, price: 128, stock: 25, sold: 378, tag: '热门' },
  { name: '几何·赛博', style: '几何', size: 12, color: '彩色', duration: 6, waterproof: 5, price: 98, stock: 35, sold: 512, tag: '潮流' },
  { name: '骷髅·暗黑', style: '暗黑', size: 20, color: '黑色', duration: 7, waterproof: 5, price: 148, stock: 20, sold: 334, tag: '暗黑' },
  { name: '曼陀罗·禅', style: '点刺', size: 18, color: '黑色', duration: 6, waterproof: 4, price: 138, stock: 28, sold: 289, tag: '禅意' },
  // ... 更多数据
]

纹身贴的数据模型设计非常专业,包含了风格、尺寸、颜色、持续时间、防水等级等产品核心属性。持续时间(duration)以天为单位,防水等级(waterproof)采用5分制评分,这些维度都是用户选购纹身贴时最关心的指标。

数据包含10款纹身贴产品,风格涵盖新传统、几何、暗黑、点刺、水彩、字母等多种流派,颜色有黑色、荧光、彩色、渐变等多种选择,价格从68元到228元不等,充分满足了不同用户的个性化需求。

垂直领域电商的数据模型设计需要深入理解行业特性。纹身贴的持续时间、防水等级这些属性,在外行看来可能无关紧要,但对于目标用户来说却是关键决策因素。专业的数据模型是产品专业性的基础。

图案设计数据

在这里插入图片描述

interface IwDesign {
  name: string
  category: string
  complexity: number
  downloads: number
  likes: number
  price: number
  tag: string
}

const IW_DESIGNS: IwDesign[] = [
  { name: '盘龙·升天', category: '传统', complexity: 5, downloads: 1280, likes: 892, price: 38, tag: '热门' },
  { name: '几何·漩涡', category: '几何', complexity: 3, downloads: 890, likes: 567, price: 18, tag: '潮流' },
  { name: '骷髅·花火', category: '暗黑', complexity: 4, downloads: 670, likes: 445, price: 28, tag: '暗黑' },
  // ... 更多数据
]

图案设计(IwDesign)是这款应用特有的数据类型,体现了内容社区的属性。每个图案包含分类、复杂度(5分制)、下载量、点赞数、价格等属性。这种UGC+PGC的内容模式能够有效提升用户粘性和平台活跃度。

霓虹动画引擎解析

在这里插入图片描述

六大动画函数

function iwInk(wave: number, i: number): number {
  let phase: number = (wave + i * 30) % 100
  return 0.3 + phase / 100 * 0.7
}

function iwGlow(wave: number, i: number): number {
  let v: number = (wave + i * 40) % 200
  return v < 100 ? 1.0 : 0.4
}

function iwSpin(wave: number): number {
  return (wave * 3) % 360
}

function iwDrip(wave: number, i: number): number {
  let base: number = (wave + i * 25) % 150
  return base - 50
}

function iwFloatY(wave: number, i: number): number {
  return Math.sin(wave / 35 + i) * 6
}

function iwBlink(wave: number, i: number): number {
  let v: number = (wave + i * 50) % 200
  return v < 100 ? 1.0 : 0.5
}

这款纹身应用拥有6个精心设计的动画函数,是四款应用中动画效果最丰富的之一。iwInk函数模拟墨水扩散效果,透明度从0.3渐变到1.0;iwGlow函数实现霓虹辉光的呼吸效果,在完全明亮和暗淡之间切换;iwSpin函数产生持续旋转效果,每帧旋转3度;iwDrip函数模拟墨水滴落的流动效果,返回垂直位移量。

iwFloatY函数实现上下浮动的正弦运动,iwBlink函数产生闪烁效果。这些动画函数在深色背景下呈现出极佳的视觉效果,荧光色的光影变化充满了赛博朋克的未来感。

深色主题下的动画设计有其独特的优势:发光效果、透明度变化、颜色渐变在黑色背景下都更加醒目和绚丽。这款应用充分利用了深色主题的视觉特性,通过精心设计的霓虹动画营造出强烈的潮流氛围。

业务工具函数

在这里插入图片描述

function iwFilterTattoos(tag: string): IwTattoo[] {
  let r: IwTattoo[] = []
  for (let i = 0; i < IW_TATTOOS.length; i++) {
    if (tag === '全部' || IW_TATTOOS[i].tag === tag) {
      r.push(IW_TATTOOS[i])
    }
  }
  return r
}

function iwSoldRank(): IwTattoo[] {
  let r: IwTattoo[] = IW_TATTOOS.slice()
  r.sort((a: IwTattoo, b: IwTattoo) => b.sold - a.sold)
  return r.slice(0, 5)
}

function iwSizeW(size: number): number {
  return Math.min(size / 30 * 100, 100)
}

function iwWaterproofW(w: number): number {
  return w / 5 * 100
}

function iwStatusColor(status: string): string {
  if (status === '已签收') {
    return IW.primary
  }
  if (status === '运输中') {
    return IW.accent
  }
  if (status === '已退换') {
    return '#888888'
  }
  return IW.sub
}

业务工具函数层包含筛选、排序、计算等多种功能。iwWaterproofW函数将防水等级(5分制)转换为百分比,是防水等级可视化的核心计算函数。iwSizeW函数将尺寸转换为百分比宽度,用于尺寸对比图表。

订单状态颜色函数中,"已签收"使用荧光青色(主色),"运输中"使用电粉色(强调色),"已退换"使用灰色。在深色背景下,这些高饱和度的颜色非常醒目,用户可以快速识别订单状态。

深色主题下的文字对比度需要特别注意。如果文字颜色太亮,长时间使用会造成视觉疲劳;如果太暗,又会影响可读性。这款应用使用淡紫色(#E8E0F0)作为主要文字颜色,在保证可读性的同时避免了纯白的刺眼感,是一个相当不错的选择。

主组件架构

头部品牌栏

        // 头部品牌栏
        Row() {
          Column() {
            Text('INK').fontSize(22).fontWeight(900).fontColor(IW.primary)
            Text('WORLD · 纹身潮流').fontSize(10).fontColor(IW.sub).letterSpacing(2)
          }
          .alignItems(HorizontalAlign.Start)
          Column().layoutWeight(1)
          Row() {
            Text('潮流图案').fontSize(12).fontColor(IW.sub)
            Column().width(2).height(12).backgroundColor(IW.line).margin({ left: 8, right: 8 })
            Text('荧光墨水').fontSize(10).fontColor(IW.accent).fontWeight(700)
          }
        }
        .width('100%').height(56).padding({ left: 16, right: 16 }).backgroundColor(IW.card)

头部品牌栏的设计充分体现了深色霓虹风格。"INK"大字使用荧光青色(主色调),在深紫色背景下格外醒目;"WORLD · 纹身潮流"小字使用次要文字颜色,形成层级对比。右侧Slogan"潮流图案 · 荧光墨水"中,"荧光墨水"使用电粉色强调,点明产品特色。

品牌栏是应用的"门面",其设计直接影响用户对品牌的第一印象。将品牌名用主色高亮显示,既能强化品牌记忆,又能在深色主题下形成强烈的视觉焦点。

首页四大功能弹框

      if (this.showHomeCustom) {
        Stack() {
          this.modalOverlay()
          Column() {
            Text('纹身定制').fontSize(18).fontWeight(700).fontColor(IW.primary).margin({ top: 20 })
            Text('专属定制你的纹身图案').fontSize(12).fontColor(IW.sub).margin({ top: 4 })
            Column() {
              Text('风格:').fontSize(13).fontColor(IW.text).fontWeight(600).margin({ bottom: 8 })
              Row() {
                Text('新传统').fontSize(12).fontColor(IW.dark).padding(8).borderRadius(8).backgroundColor(IW.primary)
                Text('几何').fontSize(12).fontColor(IW.text).padding(8).borderRadius(8).backgroundColor(IW.card).margin({ left: 8 })
                Text('暗黑').fontSize(12).fontColor(IW.text).padding(8).borderRadius(8).backgroundColor(IW.card).margin({ left: 8 })
                Text('水彩').fontSize(12).fontColor(IW.text).padding(8).borderRadius(8).backgroundColor(IW.card).margin({ left: 8 })
              }
              .width('100%')
            }
            // ... 尺寸选择、颜色选择
            Row() {
              Text('定制费:').fontSize(13).fontColor(IW.text).fontWeight(600)
              Text('¥80起').fontSize(18).fontWeight(800).fontColor(IW.accent)
              Column().layoutWeight(1)
              Text('立即定制').fontSize(13).fontColor(IW.dark).padding({ left: 20, right: 20, top: 8, bottom: 8 }).borderRadius(20).backgroundColor(IW.primary)
            }
            .width('100%').margin({ top: 20 })
          }
          .width('86%').backgroundColor(IW.card).borderRadius(16).padding(20)
          .constraintSize({ maxHeight: '80%' }).zIndex(1000)
        }
        .width('100%').height('100%')
      }

纹身定制弹框提供了风格、尺寸、颜色三个维度的定制选项。风格维度包括新传统、几何、暗黑、水彩四种主流纹身风格;尺寸维度有小号、中号、大号、特大四种选择;颜色维度则有黑色、荧光、彩色、渐变四种。"立即定制"按钮使用荧光青色背景+深色文字,在深色主题下非常醒目。

值得注意的是,深色主题下按钮的文字颜色使用了深色(IW.dark)而非白色,这是因为荧光色背景本身已经非常明亮,配上深色文字对比度更好,也更符合霓虹灯光的视觉效果。

深色主题下的按钮设计需要特别注意对比度和可读性。对于亮色背景的按钮,使用深色文字通常比白色文字效果更好;对于深色背景的按钮,则需要使用亮色文字或边框来保证可识别性。

应用整体流程图

home

tattoo

tool

care

design

mine

点击切换

应用入口 IwApp

深色主题系统初始化

渲染霓虹品牌头部

渲染搜索条

当前Tab切换

首页组件

纹身贴Tab

工具Tab

护理Tab

图案Tab

我的Tab

霓虹渐变Banner

荧光仪表盘

品类统计卡

功能宫格

热销榜单

潮流横滑

首页弹框层

纹身定制弹框

纹身课堂弹框

线下店铺弹框

纹身社区弹框

风格筛选Chips

双列网格卡片

尺寸对比图

防水等级柱状图

商品弹框层

详情弹框

新增弹框

编辑弹框

删除弹框

图案分类

复杂度可视化

下载/点赞数据

会员卡片

消费统计

月度消费图

订单列表

收藏列表

设置列表

底部Tab栏

纹身贴Tab深度解析

筛选系统与双列网格

          // 筛选 chips
          Scroll() {
            Row({ space: 8 }) {
              ForEach(['全部', '热门', '潮流', '暗黑', '禅意', '高端'], (t: string) => {
                Text(t).fontSize(12).fontColor(this.filterTag === t ? IW.dark : IW.text)
                  .padding({ left: 16, right: 16, top: 6, bottom: 6 })
                  .borderRadius(16)
                  .backgroundColor(this.filterTag === t ? IW.primary : IW.bg)
                  .onClick(() => {
                    this.filterTag = t
                    this.list = iwFilterTattoos(t)
                  })
              }, (t: string) => t)
            }
            .padding({ left: 12, right: 12 })
          }
          .scrollable(ScrollDirection.Horizontal)
          .scrollBar(BarState.Off)
          .width('100%')
          .height(36)

筛选Chips提供了"全部、热门、潮流、暗黑、禅意、高端"六个标签,涵盖了纹身文化的主要风格分类。选中状态使用荧光青背景+深色文字,未选中状态使用深黑背景+浅色文字。在深色主题下,荧光色的选中状态非常醒目,用户可以清晰地识别当前筛选条件。

筛选标签的命名应该贴合目标用户的文化语境。"热门、潮流、暗黑、禅意"这些词汇都是纹身爱好者熟悉的分类方式,能够有效降低用户的认知成本,提升筛选效率。

双列产品卡片

          // 双列网格
          Flex({ wrap: FlexWrap.Wrap, justifyContent: FlexAlign.SpaceBetween }) {
            ForEach(this.list, (t: IwTattoo, i: number) => {
              Column() {
                Stack() {
                  Column().width('100%').height(80).borderRadius(12)
                    .linearGradient({ angle: 135, colors: [[IW.glow, 0], [IW.primary, 1]] })
                  Column().width(36).height(36).borderRadius(18).backgroundColor('rgba(15,10,26,0.3)')
                    .opacity(iwGlow(this.wave, i))
                }
                .width('100%').height(80)
                Text(t.name).fontSize(13).fontWeight(700).fontColor(IW.text).margin({ top: 8 })
                Text(t.style + ' · ' + t.color).fontSize(10).fontColor(IW.sub).margin({ top: 2 })
                Row() {
                  Text(t.tag).fontSize(10).fontColor(IW.accent).fontWeight(600)
                  Column().layoutWeight(1)
                  Text(t.duration + '天').fontSize(10).fontColor(IW.sub)
                }
                .width('100%').margin({ top: 4 })
                Row() {
                  Text('¥').fontSize(10).fontColor(IW.sub)
                  Text(t.price.toString()).fontSize(14).fontColor(IW.accent).fontWeight(700)
                  Column().layoutWeight(1)
                  Text('防水' + t.waterproof.toString()).fontSize(10).fontColor(IW.sub)
                }
                .width('100%').margin({ top: 4 })
              }
              .width('48.5%')
              .padding(10)
              .backgroundColor(IW.card)
              .borderRadius(12)
              .margin({ bottom: 8 })
              .onClick(() => {
                this.selName = t.name
                this.showDetail = true
              })
            }, (t: IwTattoo) => t.name)
          }
          .width('100%').padding({ left: 12, right: 12 })

产品卡片设计延续了深色霓虹风格。卡片顶部的渐变预览图从紫色辉光过渡到荧光青,呈现出神秘而炫酷的视觉效果。中心的圆形光点通过iwGlow函数驱动呼吸动画,模拟霓虹灯光的闪烁效果。

卡片信息层次分明:产品名称使用主要文字颜色,风格和颜色使用次要文字颜色,标签使用电粉色强调,价格同样使用电粉色突出显示。持续时间和防水等级作为产品核心参数,以次要信息的形式展示在卡片上。

在深色主题下,产品图片/预览区域的设计尤为重要。由于真实图片在深色背景下可能显得突兀,使用渐变色块+装饰元素的方式来替代图片,既能保持视觉风格的统一性,又能减少图片资源的加载成本。

数据可视化图表

          // 防水等级对比
          Column() {
            Text('防水等级').fontSize(13).fontWeight(700).fontColor(IW.text).margin({ bottom: 12 })
            ForEach(this.list.slice(0, 5), (t: IwTattoo, i: number) => {
              Row() {
                Text(t.name.substring(0, 6)).fontSize(10).fontColor(IW.sub).width(60)
                Stack({ alignContent: Alignment.Start }) {
                  Column().width('100%').height(10).borderRadius(5).backgroundColor(IW.bg)
                  Column().width(iwWaterproofW(t.waterproof).toString() + '%').height(10).borderRadius(5).backgroundColor(IW.primary)
                }
                .layoutWeight(1)
                Text(t.waterproof.toString()).fontSize(10).fontColor(IW.text).fontWeight(600).width(20)
              }
              .width('100%').margin({ bottom: 6 })
            }, (t: IwTattoo) => t.name)
          }
          .width('100%').padding(16).backgroundColor(IW.card).margin({ top: 8 })

防水等级对比图是纹身贴品类特有的数据可视化。使用横向进度条展示各款纹身贴的防水等级(满分5分),进度条使用荧光青色,在深色背景下非常醒目。这种将产品核心参数可视化的做法,能够帮助用户快速对比和决策。

尺寸分布柱状图则以竖向柱形展示各款纹身贴的尺寸大小,柱形使用电粉色,与防水等级图形成颜色区分。两种不同类型的图表使用不同的颜色,既美观又有助于用户快速识别图表类型。

图案Tab与内容社区

图案设计数据展示

          // 图案列表
          Column() {
            Text('热门图案').fontSize(14).fontWeight(700).fontColor(IW.text).margin({ bottom: 12 })
            ForEach(this.designList, (d: IwDesign, i: number) => {
              Row() {
                Stack() {
                  Column().width(56).height(56).borderRadius(28)
                    .linearGradient({ angle: 135, colors: [[IW.accent, 0], [IW.glow, 1]] })
                  Column().width(40).height(40).borderRadius(20).backgroundColor('rgba(15,10,26,0.3)')
                    .rotate({ z: iwSpin(this.wave) })
                }
                .width(56).height(56)
                Column() {
                  Text(d.name).fontSize(14).fontWeight(700).fontColor(IW.text)
                  Text(d.category + ' · ' + d.complexity + '星难度').fontSize(10).fontColor(IW.sub).margin({ top: 2 })
                  Row() {
                    Text(d.tag).fontSize(10).fontColor(IW.primary).padding({ left: 6, right: 6, top: 2, bottom: 2 }).borderRadius(4).backgroundColor(IW.bg)
                    Column().layoutWeight(1)
                    Text(d.downloads + '下载').fontSize(10).fontColor(IW.sub)
                  }
                  .width('100%').margin({ top: 4 })
                }
                .alignItems(HorizontalAlign.Start).layoutWeight(1).padding({ left: 12 })
                Column() {
                  Text('¥' + d.price.toString()).fontSize(14).fontWeight(700).fontColor(IW.accent)
                  Text(d.likes + '赞').fontSize(10).fontColor(IW.sub).margin({ top: 2 })
                }
                .alignItems(HorizontalAlign.End)
              }
              .width('100%').padding(12).backgroundColor(IW.card).borderRadius(12).margin({ bottom: 8 })
              .onClick(() => {
                this.selName = d.name
                this.showDetail = true
              })
            }, (d: IwDesign) => d.name)
          }

图案Tab是这款应用的特色板块,融合了内容社区和付费下载的模式。每个图案展示项包含圆形预览图、图案名称、分类、难度、标签、下载量、价格和点赞数等信息。圆形预览图中心的装饰元素使用iwSpin函数驱动旋转动画,形成霓虹旋转的视觉效果。

内容社区是提升用户粘性的有效手段。通过提供图案设计下载、用户分享、点赞互动等功能,可以将单纯的购物App升级为社区平台,大幅提升用户的停留时长和复购率。

"我的"Tab与会员体系

会员卡与消费数据

          // 会员卡
          Stack() {
            Column().width('100%').height(120).borderRadius(16)
              .linearGradient({ angle: 135, colors: [[IW.dark, 0], [IW.glow, 1]] })
            Column() {
              Text('INK VIP').fontSize(22).fontWeight(900).fontColor('#E8E0F0').letterSpacing(2)
              Text('纹身潮流会员').fontSize(12).fontColor('rgba(232,224,240,0.7)').margin({ top: 4 })
              Row() {
                Text('积分').fontSize(11).fontColor('rgba(232,224,240,0.7)')
                Text('3,280').fontSize(20).fontWeight(800).fontColor('#E8E0F0').margin({ left: 8 })
              }
              .margin({ top: 12 })
            }
            .alignItems(HorizontalAlign.Center).margin({ top: 24 })
            Column().width(60).height(60).borderRadius(30).backgroundColor('rgba(0,255,255,0.2)')
              .opacity(iwGlow(this.wave, 0))
              .position({ x: 280, y: 16 })
          }
          .width('100%').height(120).padding({ left: 16, right: 16, top: 16 })

会员卡设计延续了深色霓虹风格,采用深紫黑到紫色辉光的渐变背景,配合"INK VIP"的英文标识,传递出潮流会员的酷感。右上角的荧光青色光晕使用iwGlow函数驱动呼吸效果,如同霓虹灯般闪烁。

月度消费柱状图使用荧光青到电粉的渐变柱形,在深色背景下格外醒目。订单列表中的状态颜色同样使用荧光青和电粉区分不同状态,保持了视觉风格的一致性。

技术点对比表格

技术维度 纹身潮流 (IW) 盆景艺术 (BN) 皮具工坊 (LT) 玻璃艺术 (VG)
主题模式 深色系 浅色暖调 浅色暖调 浅色系
背景色 深紫黑 #0F0A1A 米白 #F5F2E8 做旧米 #F5EDE0 淡紫 #F1EFF7
主色调 荧光青 #00FFFF 苔藓绿 #5B7C5A 马鞍棕 #8B4513 靛蓝 #4338CA
强调色 电粉 #FF1493 陶土棕 #B5651D 焦糖橙 #D2691E 琥珀金 #D97706
辉光色 紫色 #9D4EDD 浅绿 #8FAB7B 棕灰 #BCAAA4 浅紫 #7C6FF0
动画数量 6个 4个 6个 4个
特色动画 旋转/滴落/霓虹辉光 水墨晕染/摇摆 皮革光泽/表扣旋转 光线折射/彩色玻璃
商品品类 纹身贴/工具/护理/图案 松柏/杂木/山水/盆器 钱包/包袋/表带/护理 玻璃/作品/工具/课程
内容板块 图案设计下载 盆景展览拍卖 匠人作品定制 课程培训体系
目标用户 Z世代潮流青年 东方美学爱好者 手工皮具发烧友 艺术手工爱好者

安装DevEco Studio程序

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

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

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

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

在这里插入图片描述


完整代码:

// IW 前缀 | 深紫黑×荧光青×电粉 | 纹身潮流风 | 深色系 | 6 tab

// ============ 接口定义 ============
interface IwTheme {
  bg: string
  primary: string
  accent: string
  card: string
  text: string
  sub: string
  line: string
  glow: string
  dark: string
}

interface IwTab {
  key: string
  label: string
  icon: Resource
}

interface IwTattoo {
  name: string
  style: string
  size: number
  color: string
  duration: number
  waterproof: number
  price: number
  stock: number
  sold: number
  tag: string
}

interface IwTool {
  name: string
  type: string
  brand: string
  material: string
  use: string
  price: number
  stock: number
  sold: number
}

interface IwCare {
  name: string
  type: string
  volume: number
  use: string
  price: number
  stock: number
  sold: number
}

interface IwDesign {
  name: string
  category: string
  complexity: number
  downloads: number
  likes: number
  price: number
  tag: string
}

interface IwOrder {
  id: string
  item: string
  date: string
  status: string
  amount: number
}

interface IwCollect {
  name: string
  brand: string
  price: number
  tag: string
}

interface IwMonth {
  month: string
  amount: number
}

// ============ 主题常量 ============
const IW: IwTheme = {
  bg: '#0F0A1A',
  primary: '#00FFFF',
  accent: '#FF1493',
  card: '#1A1528',
  text: '#E8E0F0',
  sub: '#7A6B8A',
  line: '#2A2040',
  glow: '#9D4EDD',
  dark: '#0A0612'
}

const IW_TABS: IwTab[] = [
  { key: 'home', label: '首页', icon: $r('app.media.layered_image') },
  { key: 'tattoo', label: '纹身贴', icon: $r('app.media.layered_image') },
  { key: 'tool', label: '工具', icon: $r('app.media.layered_image') },
  { key: 'care', label: '护理', icon: $r('app.media.layered_image') },
  { key: 'design', label: '图案', icon: $r('app.media.layered_image') },
  { key: 'mine', label: '我的', icon: $r('app.media.layered_image') }
]

// ============ 数据:纹身贴 10 条 ============
const IW_TATTOOS: IwTattoo[] = [
  { name: '盘龙·墨韵', style: '新传统', size: 25, color: '黑色', duration: 7, waterproof: 5, price: 168, stock: 30, sold: 456, tag: '热门' },
  { name: '玫瑰·荧光', style: '新传统', size: 15, color: '荧光', duration: 5, waterproof: 4, price: 128, stock: 25, sold: 378, tag: '热门' },
  { name: '几何·赛博', style: '几何', size: 12, color: '彩色', duration: 6, waterproof: 5, price: 98, stock: 35, sold: 512, tag: '潮流' },
  { name: '骷髅·暗黑', style: '暗黑', size: 20, color: '黑色', duration: 7, waterproof: 5, price: 148, stock: 20, sold: 334, tag: '暗黑' },
  { name: '曼陀罗·禅', style: '点刺', size: 18, color: '黑色', duration: 6, waterproof: 4, price: 138, stock: 28, sold: 289, tag: '禅意' },
  { name: '闪电·电粉', style: '水彩', size: 10, color: '荧光', duration: 4, waterproof: 3, price: 88, stock: 40, sold: 623, tag: '潮流' },
  { name: '凤凰·重彩', style: '新传统', size: 28, color: '彩色', duration: 7, waterproof: 5, price: 188, stock: 15, sold: 267, tag: '高端' },
  { name: '字母·极简', style: '字母', size: 8, color: '黑色', duration: 5, waterproof: 4, price: 68, stock: 50, sold: 689, tag: '入门' },
  { name: '蝴蝶·渐变', style: '水彩', size: 14, color: '渐变', duration: 5, waterproof: 4, price: 108, stock: 32, sold: 445, tag: '潮流' },
  { name: '龙虎·对决', style: '新传统', size: 30, color: '彩色', duration: 7, waterproof: 5, price: 228, stock: 12, sold: 198, tag: '高端' }
]

// ============ 数据:工具 8 条 ============
const IW_TOOLS: IwTool[] = [
  { name: '转印纸-A4', type: '转印', brand: 'INKPRO', material: '碳粉纸', use: '图案转印', price: 38, stock: 60, sold: 456 },
  { name: '纹身贴膜', type: '贴膜', brand: 'INKPRO', material: 'PVC膜', use: '防水覆盖', price: 28, stock: 80, sold: 534 },
  { name: '刮板套装', type: '刮板', brand: 'TattooX', material: '亚克力', use: '贴压排气', price: 48, stock: 45, sold: 378 },
  { name: '喷水瓶', type: '喷雾', brand: 'INKPRO', material: '塑料', use: '湿润皮肤', price: 18, stock: 100, sold: 612 },
  { name: '纹身剪刀', type: '剪刀', brand: 'TattooX', material: '不锈钢', use: '裁剪图案', price: 58, stock: 40, sold: 289 },
  { name: '热转印机', type: '转印机', brand: 'INKPRO', material: '金属', use: '热转印', price: 488, stock: 10, sold: 128 },
  { name: '清洁棉片', type: '清洁', brand: 'TattooX', material: '无纺布', use: '清洁皮肤', price: 12, stock: 200, sold: 789 },
  { name: '定位贴纸', type: '定位', brand: 'INKPRO', material: '透明膜', use: '精准定位', price: 22, stock: 90, sold: 445 }
]

// ============ 数据:护理 6 条 ============
const IW_CARE: IwCare[] = [
  { name: '定影喷雾', type: '定影', volume: 100, use: '固定图案', price: 68, stock: 45, sold: 378 },
  { name: '防水涂层', type: '防护', volume: 50, use: '防水保护', price: 88, stock: 35, sold: 289 },
  { name: '清洁啫喱', type: '清洁', volume: 80, use: '温和清洁', price: 48, stock: 50, sold: 456 },
  { name: '保湿乳液', type: '保湿', volume: 120, use: '皮肤保湿', price: 58, stock: 40, sold: 334 },
  { name: '卸贴液', type: '卸除', volume: 60, use: '轻松卸除', price: 38, stock: 55, sold: 512 },
  { name: '亮彩喷雾', type: '亮彩', volume: 80, use: '增亮色彩', price: 78, stock: 30, sold: 267 }
]

// ============ 数据:图案 8 条 ============
const IW_DESIGNS: IwDesign[] = [
  { name: '盘龙·升天', category: '传统', complexity: 5, downloads: 1280, likes: 892, price: 38, tag: '热门' },
  { name: '几何·漩涡', category: '几何', complexity: 3, downloads: 890, likes: 567, price: 18, tag: '潮流' },
  { name: '骷髅·花火', category: '暗黑', complexity: 4, downloads: 670, likes: 445, price: 28, tag: '暗黑' },
  { name: '玫瑰·藤蔓', category: '花卉', complexity: 4, downloads: 780, likes: 623, price: 22, tag: '热门' },
  { name: '字母·哥特', category: '字母', complexity: 2, downloads: 560, likes: 378, price: 12, tag: '入门' },
  { name: '曼陀罗·星', category: '点刺', complexity: 5, downloads: 450, likes: 389, price: 35, tag: '禅意' },
  { name: '蝴蝶·幻彩', category: '水彩', complexity: 3, downloads: 620, likes: 512, price: 20, tag: '潮流' },
  { name: '龙虎·咆哮', category: '传统', complexity: 5, downloads: 890, likes: 745, price: 42, tag: '高端' }
]

// ============ 数据:订单 6 条 ============
const IW_ORDERS: IwOrder[] = [
  { id: 'IW20260815', item: '盘龙·墨韵纹身贴', date: '08-15', status: '已签收', amount: 168 },
  { id: 'IW20260810', item: '定影喷雾', date: '08-10', status: '已签收', amount: 68 },
  { id: 'IW20260802', item: '转印纸-A4', date: '08-02', status: '运输中', amount: 38 },
  { id: 'IW20260725', item: '闪电·电粉纹身贴', date: '07-25', status: '已签收', amount: 88 },
  { id: 'IW20260718', item: '热转印机', date: '07-18', status: '已签收', amount: 488 },
  { id: 'IW20260701', item: '几何·赛博纹身贴', date: '07-01', status: '已退换', amount: 98 }
]

// ============ 数据:收藏 6 条 ============
const IW_COLLECTS: IwCollect[] = [
  { name: '龙虎·对决', brand: 'INKPRO', price: 228, tag: '高端' },
  { name: '凤凰·重彩', brand: 'INKPRO', price: 188, tag: '高端' },
  { name: '盘龙·升天', brand: 'INKPRO', price: 38, tag: '热门' },
  { name: '热转印机', brand: 'INKPRO', price: 488, tag: '设备' },
  { name: '骷髅·暗黑', brand: 'INKPRO', price: 148, tag: '暗黑' },
  { name: '曼陀罗·星', brand: 'INKPRO', price: 35, tag: '禅意' }
]

// ============ 数据:月度消费 6 条 ============
const IW_MONTHS: IwMonth[] = [
  { month: '03月', amount: 168 },
  { month: '04月', amount: 288 },
  { month: '05月', amount: 428 },
  { month: '06月', amount: 356 },
  { month: '07月', amount: 574 },
  { month: '08月', amount: 236 }
]

// ============ 全局纯函数 ============
function iwInk(wave: number, i: number): number {
  let phase: number = (wave + i * 30) % 100
  return 0.3 + phase / 100 * 0.7
}

function iwGlow(wave: number, i: number): number {
  let v: number = (wave + i * 40) % 200
  return v < 100 ? 1.0 : 0.4
}

function iwSpin(wave: number): number {
  return (wave * 3) % 360
}

function iwDrip(wave: number, i: number): number {
  let base: number = (wave + i * 25) % 150
  return base - 50
}

function iwFloatY(wave: number, i: number): number {
  return Math.sin(wave / 35 + i) * 6
}

function iwBlink(wave: number, i: number): number {
  let v: number = (wave + i * 50) % 200
  return v < 100 ? 1.0 : 0.5
}

function iwFilterTattoos(tag: string): IwTattoo[] {
  let r: IwTattoo[] = []
  for (let i = 0; i < IW_TATTOOS.length; i++) {
    if (tag === '全部' || IW_TATTOOS[i].tag === tag) {
      r.push(IW_TATTOOS[i])
    }
  }
  return r
}

function iwSoldRank(): IwTattoo[] {
  let r: IwTattoo[] = IW_TATTOOS.slice()
  r.sort((a: IwTattoo, b: IwTattoo) => b.sold - a.sold)
  return r.slice(0, 5)
}

function iwSizeW(size: number): number {
  return Math.min(size / 30 * 100, 100)
}

function iwWaterproofW(w: number): number {
  return w / 5 * 100
}

function iwComplexityW(c: number): number {
  return c / 5 * 100
}

function iwDownloadW(d: number): number {
  return Math.min(d / 1280 * 100, 100)
}

function iwMonthH(amount: number): number {
  let max: number = 574
  return Math.max(amount / max * 120, 8)
}

function iwTopN(i: number): string {
  return ['1', '2', '3', '4', '5'][i] || ''
}

function iwStatusColor(status: string): string {
  if (status === '已签收') {
    return IW.primary
  }
  if (status === '运输中') {
    return IW.accent
  }
  if (status === '已退换') {
    return '#888888'
  }
  return IW.sub
}

function iwTattooByName(name: string): IwTattoo {
  let idx: number = 0
  for (let i = 0; i < IW_TATTOOS.length; i++) {
    if (IW_TATTOOS[i].name === name) {
      idx = i
    }
  }
  return IW_TATTOOS[idx]
}

function iwToolByName(name: string): IwTool {
  let idx: number = 0
  for (let i = 0; i < IW_TOOLS.length; i++) {
    if (IW_TOOLS[i].name === name) {
      idx = i
    }
  }
  return IW_TOOLS[idx]
}

function iwCareByName(name: string): IwCare {
  let idx: number = 0
  for (let i = 0; i < IW_CARE.length; i++) {
    if (IW_CARE[i].name === name) {
      idx = i
    }
  }
  return IW_CARE[idx]
}

function iwDesignByName(name: string): IwDesign {
  let idx: number = 0
  for (let i = 0; i < IW_DESIGNS.length; i++) {
    if (IW_DESIGNS[i].name === name) {
      idx = i
    }
  }
  return IW_DESIGNS[idx]
}

// ============ 主组件 ============
@Entry
@Component
struct IwApp {
  @State tab: string = 'home'
  @State showHomeCustom: boolean = false
  @State showHomeCourse: boolean = false
  @State showHomeShop: boolean = false
  @State showHomeCommunity: boolean = false

  @Builder modalOverlay() {
    Column() {
      Column().width('100%').height('100%').backgroundColor('rgba(10,6,18,0.75)')
    }
    .width('100%').height('100%').position({ x: 0, y: 0 }).zIndex(999)
    .onClick(() => {
      this.showHomeCustom = false
      this.showHomeCourse = false
      this.showHomeShop = false
      this.showHomeCommunity = false
    })
  }

  build() {
    Stack() {
      Column() {
        // 头部品牌栏
        Row() {
          Column() {
            Text('INK').fontSize(22).fontWeight(900).fontColor(IW.primary)
            Text('WORLD · 纹身潮流').fontSize(10).fontColor(IW.sub).letterSpacing(2)
          }
          .alignItems(HorizontalAlign.Start)
          Column().layoutWeight(1)
          Row() {
            Text('潮流图案').fontSize(12).fontColor(IW.sub)
            Column().width(2).height(12).backgroundColor(IW.line).margin({ left: 8, right: 8 })
            Text('荧光墨水').fontSize(10).fontColor(IW.accent).fontWeight(700)
          }
        }
        .width('100%').height(56).padding({ left: 16, right: 16 }).backgroundColor(IW.card)

        // 搜索条
        Row() {
          Row() {
            Text('🔍').fontSize(14).fontColor(IW.sub).margin({ left: 12, right: 8 })
            Text('搜索纹身贴 / 工具 / 图案...').fontSize(13).fontColor(IW.sub)
            Column().layoutWeight(1)
            Text().width(28).height(28).borderRadius(14).backgroundColor(IW.primary).onClick(() => {})
          }
          .width('100%').height(40).backgroundColor(IW.bg).borderRadius(20).padding({ left: 4, right: 4 })
        }
        .width('100%').padding({ left: 12, right: 12, top: 8, bottom: 8 })

        // tab 内容区
        Column() {
          if (this.tab === 'home') {
            IwHomeTab({
              onCustom: () => { this.showHomeCustom = true },
              onCourse: () => { this.showHomeCourse = true },
              onShop: () => { this.showHomeShop = true },
              onCommunity: () => { this.showHomeCommunity = true }
            })
          } else if (this.tab === 'tattoo') {
            IwTattooTab()
          } else if (this.tab === 'tool') {
            IwToolTab()
          } else if (this.tab === 'care') {
            IwCareTab()
          } else if (this.tab === 'design') {
            IwDesignTab()
          } else {
            IwMineTab()
          }
        }
        .layoutWeight(1)

        // 底部 tab 栏
        Row() {
          ForEach(IW_TABS, (t: IwTab) => {
            Column() {
              Text(t.icon).width(20).height(20).fontColor(this.tab === t.key ? IW.primary : IW.sub)
              Text(t.label).fontSize(10).fontColor(this.tab === t.key ? IW.primary : IW.sub).fontWeight(this.tab === t.key ? 700 : 400)
            }
            .layoutWeight(1)
            .padding({ top: 6, bottom: 6 })
            .onClick(() => {
              this.tab = t.key
            })
          }, (t: IwTab) => t.key)
        }
        .width('100%').height(52).backgroundColor(IW.card)
        .border({ width: { top: 1 }, color: IW.line })
      }
      .width('100%').height('100%').backgroundColor(IW.bg)

      // 首页弹框
      if (this.showHomeCustom) {
        Stack() {
          this.modalOverlay()
          Column() {
            Text('纹身定制').fontSize(18).fontWeight(700).fontColor(IW.primary).margin({ top: 20 })
            Text('专属定制你的纹身图案').fontSize(12).fontColor(IW.sub).margin({ top: 4 })
            Column() {
              Text('风格:').fontSize(13).fontColor(IW.text).fontWeight(600).margin({ bottom: 8 })
              Row() {
                Text('新传统').fontSize(12).fontColor(IW.dark).padding(8).borderRadius(8).backgroundColor(IW.primary)
                Text('几何').fontSize(12).fontColor(IW.text).padding(8).borderRadius(8).backgroundColor(IW.card).margin({ left: 8 })
                Text('暗黑').fontSize(12).fontColor(IW.text).padding(8).borderRadius(8).backgroundColor(IW.card).margin({ left: 8 })
                Text('水彩').fontSize(12).fontColor(IW.text).padding(8).borderRadius(8).backgroundColor(IW.card).margin({ left: 8 })
              }
              .width('100%')
            }
            .width('100%').margin({ top: 16 })
            Column() {
              Text('尺寸:').fontSize(13).fontColor(IW.text).fontWeight(600).margin({ bottom: 8 })
              Row() {
                Text('小号').fontSize(12).fontColor(IW.text).padding(8).borderRadius(8).backgroundColor(IW.card)
                Text('中号').fontSize(12).fontColor(IW.dark).padding(8).borderRadius(8).backgroundColor(IW.primary).margin({ left: 8 })
                Text('大号').fontSize(12).fontColor(IW.text).padding(8).borderRadius(8).backgroundColor(IW.card).margin({ left: 8 })
                Text('特大').fontSize(12).fontColor(IW.text).padding(8).borderRadius(8).backgroundColor(IW.card).margin({ left: 8 })
              }
              .width('100%')
            }
            .width('100%').margin({ top: 12 })
            Column() {
              Text('颜色:').fontSize(13).fontColor(IW.text).fontWeight(600).margin({ bottom: 8 })
              Row() {
                Text('黑色').fontSize(12).fontColor(IW.dark).padding(8).borderRadius(8).backgroundColor(IW.accent)
                Text('荧光').fontSize(12).fontColor(IW.text).padding(8).borderRadius(8).backgroundColor(IW.card).margin({ left: 8 })
                Text('彩色').fontSize(12).fontColor(IW.text).padding(8).borderRadius(8).backgroundColor(IW.card).margin({ left: 8 })
                Text('渐变').fontSize(12).fontColor(IW.text).padding(8).borderRadius(8).backgroundColor(IW.card).margin({ left: 8 })
              }
              .width('100%')
            }
            .width('100%').margin({ top: 12 })
            Row() {
              Text('定制费:').fontSize(13).fontColor(IW.text).fontWeight(600)
              Text('¥80起').fontSize(18).fontWeight(800).fontColor(IW.accent)
              Column().layoutWeight(1)
              Text('立即定制').fontSize(13).fontColor(IW.dark).padding({ left: 20, right: 20, top: 8, bottom: 8 }).borderRadius(20).backgroundColor(IW.primary)
            }
            .width('100%').margin({ top: 20 })
          }
          .width('86%').backgroundColor(IW.card).borderRadius(16).padding(20)
          .constraintSize({ maxHeight: '80%' }).zIndex(1000)
        }
        .width('100%').height('100%')
      }

      if (this.showHomeCourse) {
        Stack() {
          this.modalOverlay()
          Column() {
            Text('纹身课堂').fontSize(18).fontWeight(700).fontColor(IW.primary).margin({ top: 20 })
            Text('学习纹身贴使用技巧').fontSize(12).fontColor(IW.sub).margin({ top: 4 })
            Column() {
              Text('课程一:贴纸转印入门').fontSize(13).fontColor(IW.text).fontWeight(600).margin({ bottom: 4 })
              Text('讲师:墨老师 | 1小时 | ¥88').fontSize(11).fontColor(IW.sub)
            }
            .width('100%').padding(12).backgroundColor(IW.bg).borderRadius(12).margin({ top: 16 })
            Column() {
              Text('课程二:防水定影技巧').fontSize(13).fontColor(IW.text).fontWeight(600).margin({ bottom: 4 })
              Text('讲师:彩老师 | 1.5小时 | ¥128').fontSize(11).fontColor(IW.sub)
            }
            .width('100%').padding(12).backgroundColor(IW.bg).borderRadius(12).margin({ top: 8 })
            Column() {
              Text('课程三:图案设计基础').fontSize(13).fontColor(IW.text).fontWeight(600).margin({ bottom: 4 })
              Text('讲师:创老师 | 2小时 | ¥188').fontSize(11).fontColor(IW.sub)
            }
            .width('100%').padding(12).backgroundColor(IW.bg).borderRadius(12).margin({ top: 8 })
            Row() {
              Text().width(28).height(28).borderRadius(14).backgroundColor(IW.sub).onClick(() => { this.showHomeCourse = false })
              Column().layoutWeight(1)
              Text('预约全部').fontSize(13).fontColor(IW.dark).padding({ left: 20, right: 20, top: 8, bottom: 8 }).borderRadius(20).backgroundColor(IW.primary)
            }
            .width('100%').margin({ top: 20 })
          }
          .width('86%').backgroundColor(IW.card).borderRadius(16).padding(20)
          .constraintSize({ maxHeight: '80%' }).zIndex(1000)
        }
        .width('100%').height('100%')
      }

      if (this.showHomeShop) {
        Stack() {
          this.modalOverlay()
          Column() {
            Text('线下纹身店').fontSize(18).fontWeight(700).fontColor(IW.primary).margin({ top: 20 })
            Text('预约线下纹身店体验').fontSize(12).fontColor(IW.sub).margin({ top: 4 })
            Column() {
              Text('城市:').fontSize(13).fontColor(IW.text).fontWeight(600).margin({ bottom: 8 })
              Row() {
                Text('上海').fontSize(12).fontColor(IW.dark).padding(8).borderRadius(8).backgroundColor(IW.accent)
                Text('北京').fontSize(12).fontColor(IW.text).padding(8).borderRadius(8).backgroundColor(IW.card).margin({ left: 8 })
                Text('广州').fontSize(12).fontColor(IW.text).padding(8).borderRadius(8).backgroundColor(IW.card).margin({ left: 8 })
                Text('成都').fontSize(12).fontColor(IW.text).padding(8).borderRadius(8).backgroundColor(IW.card).margin({ left: 8 })
              }
              .width('100%')
            }
            .width('100%').margin({ top: 16 })
            Column() {
              Text('店铺:').fontSize(13).fontColor(IW.text).fontWeight(600).margin({ bottom: 8 })
              Row() {
                Text('INK STUDIO').fontSize(12).fontColor(IW.dark).padding(8).borderRadius(8).backgroundColor(IW.primary)
                Text('墨色工坊').fontSize(12).fontColor(IW.text).padding(8).borderRadius(8).backgroundColor(IW.card).margin({ left: 8 })
                Text('荧光社').fontSize(12).fontColor(IW.text).padding(8).borderRadius(8).backgroundColor(IW.card).margin({ left: 8 })
              }
              .width('100%')
            }
            .width('100%').margin({ top: 12 })
            Row() {
              Text('体验费:').fontSize(13).fontColor(IW.text).fontWeight(600)
              Text('¥288').fontSize(18).fontWeight(800).fontColor(IW.accent)
              Column().layoutWeight(1)
              Text('预约体验').fontSize(13).fontColor(IW.dark).padding({ left: 20, right: 20, top: 8, bottom: 8 }).borderRadius(20).backgroundColor(IW.primary)
            }
            .width('100%').margin({ top: 20 })
          }
          .width('86%').backgroundColor(IW.card).borderRadius(16).padding(20)
          .constraintSize({ maxHeight: '80%' }).zIndex(1000)
        }
        .width('100%').height('100%')
      }

      if (this.showHomeCommunity) {
        Stack() {
          this.modalOverlay()
          Column() {
            Text('纹身社区').fontSize(18).fontWeight(700).fontColor(IW.primary).margin({ top: 20 })
            Text('与纹身爱好者交流分享').fontSize(12).fontColor(IW.sub).margin({ top: 4 })
            Column() {
              Text('"新贴的盘龙墨韵,荧光效果太帅了!"').fontSize(13).fontColor(IW.text).margin({ bottom: 4 })
              Text('@墨客 | 2小时前').fontSize(11).fontColor(IW.sub)
            }
            .width('100%').padding(12).backgroundColor(IW.bg).borderRadius(12).margin({ top: 16 })
            Column() {
              Text('"第一次试贴几何赛博,操作很简单"').fontSize(13).fontColor(IW.text).margin({ bottom: 4 })
              Text('@几何控 | 5小时前').fontSize(11).fontColor(IW.sub)
            }
            .width('100%').padding(12).backgroundColor(IW.bg).borderRadius(12).margin({ top: 8 })
            Column() {
              Text('"定影喷雾+防水涂层,维持了一周没掉"').fontSize(13).fontColor(IW.text).margin({ bottom: 4 })
              Text('@防水党 | 1天前').fontSize(11).fontColor(IW.sub)
            }
            .width('100%').padding(12).backgroundColor(IW.bg).borderRadius(12).margin({ top: 8 })
            Row() {
              Text().width(28).height(28).borderRadius(14).backgroundColor(IW.sub).onClick(() => { this.showHomeCommunity = false })
              Column().layoutWeight(1)
              Text('加入社区').fontSize(13).fontColor(IW.dark).padding({ left: 20, right: 20, top: 8, bottom: 8 }).borderRadius(20).backgroundColor(IW.primary)
            }
            .width('100%').margin({ top: 20 })
          }
          .width('86%').backgroundColor(IW.card).borderRadius(16).padding(20)
          .constraintSize({ maxHeight: '80%' }).zIndex(1000)
        }
        .width('100%').height('100%')
      }
    }
    .width('100%').height('100%')
  }
}

// ============ Tab 1: 首页 ============
@Component
struct IwHomeTab {
  @State wave: number = 0
  @State tattooList: IwTattoo[] = []
  @State rankList: IwTattoo[] = []
  private timer: number = -1
  @State showDetail: boolean = false
  @State selName: string = ''
  onCustom: () => void = () => {}
  onCourse: () => void = () => {}
  onShop: () => void = () => {}
  onCommunity: () => void = () => {}

  aboutToAppear() {
    this.tattooList = IW_TATTOOS.slice(0, 4)
    this.rankList = iwSoldRank()
    this.timer = setInterval(() => {
      this.wave += 1
    }, 60)
  }

  aboutToDisappear() {
    if (this.timer !== -1) {
      clearInterval(this.timer)
    }
  }

  @Builder modalOverlay() {
    Column() {
      Column().width('100%').height('100%').backgroundColor('rgba(10,6,18,0.75)')
    }
    .width('100%').height('100%').position({ x: 0, y: 0 }).zIndex(999)
    .onClick(() => {
      this.showDetail = false
    })
  }

  build() {
    Stack() {
      Scroll() {
        Column() {
          // 墨水扩散 banner
          Stack() {
            Column().width('100%').height(120)
              .linearGradient({ angle: 135, colors: [[IW.dark, 0], [IW.glow, 1]] })
            Column() {
              Text('INK WORLD').fontSize(28).fontWeight(900).fontColor(IW.primary).letterSpacing(3)
              Text('荧光纹身 · 潮流贴纸').fontSize(12).fontColor('rgba(232,224,240,0.8)').margin({ top: 4 })
            }
            .alignItems(HorizontalAlign.Center).margin({ top: 20 })
            // 墨水扩散效果
            Row() {
              ForEach([0, 1, 2, 3, 4], (i: number) => {
                Column().width(30).height(30).borderRadius(15).backgroundColor('rgba(0,255,255,0.15)')
                  .scale({ x: iwInk(this.wave, i), y: iwInk(this.wave, i) })
                  .margin({ left: 6, right: 6 })
              }, (i: number) => i.toString())
            }
            .margin({ top: 56 })
          }
          .width('100%').height(120)

          // 纹身仪表盘
          Row() {
            Stack() {
              Column().width(100).height(100).borderRadius(50).border({ width: 4, color: IW.line })
              Column().width(80).height(80).borderRadius(40).backgroundColor(IW.card)
              Column() {
                Text('维持').fontSize(10).fontColor(IW.sub)
                Text('7天').fontSize(24).fontWeight(900).fontColor(IW.primary).margin({ top: 2 })
                Text('最长').fontSize(10).fontColor(IW.sub)
              }
              .alignItems(HorizontalAlign.Center)
            }
            .width(110).height(110)
            Column() {
              Text('明星产品').fontSize(11).fontColor(IW.sub)
              Text('闪电·电粉').fontSize(20).fontWeight(800).fontColor(IW.text).margin({ top: 4 })
              Text('水彩风 | 10cm | 荧光').fontSize(11).fontColor(IW.sub).margin({ top: 4 })
              Text('维持4天 | ¥88').fontSize(11).fontColor(IW.accent).fontWeight(600).margin({ top: 2 })
            }
            .alignItems(HorizontalAlign.Start).layoutWeight(1).padding({ left: 12 })
          }
          .width('100%').padding(16).backgroundColor(IW.card).margin({ top: 8 })

          // 4 格统计卡
          Row() {
            Column() {
              Text('120').fontSize(22).fontWeight(800).fontColor(IW.primary)
              Text('纹身贴').fontSize(11).fontColor(IW.sub).margin({ top: 2 })
            }
            .layoutWeight(1).alignItems(HorizontalAlign.Center).padding({ top: 12, bottom: 12 })
            Column().width(1).height(36).backgroundColor(IW.line)
            Column() {
              Text('68').fontSize(22).fontWeight(800).fontColor(IW.accent)
              Text('工具').fontSize(11).fontColor(IW.sub).margin({ top: 2 })
            }
            .layoutWeight(1).alignItems(HorizontalAlign.Center).padding({ top: 12, bottom: 12 })
            Column().width(1).height(36).backgroundColor(IW.line)
            Column() {
              Text('42').fontSize(22).fontWeight(800).fontColor(IW.primary)
              Text('护理').fontSize(11).fontColor(IW.sub).margin({ top: 2 })
            }
            .layoutWeight(1).alignItems(HorizontalAlign.Center).padding({ top: 12, bottom: 12 })
            Column().width(1).height(36).backgroundColor(IW.line)
            Column() {
              Text('88').fontSize(22).fontWeight(800).fontColor(IW.accent)
              Text('图案').fontSize(11).fontColor(IW.sub).margin({ top: 2 })
            }
            .layoutWeight(1).alignItems(HorizontalAlign.Center).padding({ top: 12, bottom: 12 })
          }
          .width('100%').backgroundColor(IW.card).margin({ top: 8 })

          // 功能宫格
          Column() {
            Text('快捷功能').fontSize(14).fontWeight(700).fontColor(IW.text).margin({ bottom: 12 })
            Row() {
              Column() {
                Column().width(44).height(44).borderRadius(22).backgroundColor(IW.primary)
                Text('定制').fontSize(11).fontColor(IW.text).margin({ top: 4 })
              }
              .layoutWeight(1).alignItems(HorizontalAlign.Center)
              .onClick(() => { this.onCustom() })
              Column() {
                Column().width(44).height(44).borderRadius(22).backgroundColor(IW.accent)
                Text('课堂').fontSize(11).fontColor(IW.text).margin({ top: 4 })
              }
              .layoutWeight(1).alignItems(HorizontalAlign.Center)
              .onClick(() => { this.onCourse() })
              Column() {
                Column().width(44).height(44).borderRadius(22).backgroundColor(IW.glow)
                Text('门店').fontSize(11).fontColor(IW.text).margin({ top: 4 })
              }
              .layoutWeight(1).alignItems(HorizontalAlign.Center)
              .onClick(() => { this.onShop() })
              Column() {
                Column().width(44).height(44).borderRadius(22).backgroundColor(IW.dark)
                Text('社区').fontSize(11).fontColor(IW.text).margin({ top: 4 })
              }
              .layoutWeight(1).alignItems(HorizontalAlign.Center)
              .onClick(() => { this.onCommunity() })
            }
            .width('100%')
          }
          .width('100%').padding(16).backgroundColor(IW.card).margin({ top: 8 })

          // 热销榜单
          Column() {
            Row() {
              Text('热销榜单').fontSize(14).fontWeight(700).fontColor(IW.text)
              Column().layoutWeight(1)
              Text('查看全部').fontSize(12).fontColor(IW.sub)
            }
            .width('100%').margin({ bottom: 12 })
            ForEach(this.rankList, (t: IwTattoo, i: number) => {
              Row() {
                Text(iwTopN(i)).fontSize(18).fontWeight(900).fontColor(i < 3 ? IW.accent : IW.sub).width(28)
                Column() {
                  Text(t.name).fontSize(14).fontWeight(600).fontColor(IW.text)
                  Text(t.style + ' · ' + t.color + ' · ' + t.size + 'cm').fontSize(11).fontColor(IW.sub).margin({ top: 2 })
                }
                .alignItems(HorizontalAlign.Start).layoutWeight(1)
                Column() {
                  Text('已售 ' + t.sold.toString()).fontSize(12).fontColor(IW.accent).fontWeight(700)
                  Text('库存 ' + t.stock.toString()).fontSize(10).fontColor(IW.sub).margin({ top: 2 })
                }
                .alignItems(HorizontalAlign.End)
              }
              .width('100%').padding({ top: 8, bottom: 8 })
              .border({ width: { bottom: 1 }, color: IW.line })
              .onClick(() => {
                this.selName = t.name
                this.showDetail = true
              })
            }, (t: IwTattoo) => t.name)
          }
          .width('100%').padding(16).backgroundColor(IW.card).margin({ top: 8 })

          // 联名横滑
          Column() {
            Text('限定联名').fontSize(14).fontWeight(700).fontColor(IW.text).margin({ bottom: 8 })
            Scroll() {
              Row({ space: 12 }) {
                ForEach(IW_TATTOOS.slice(5, 10), (t: IwTattoo) => {
                  Column() {
                    Column().width(140).height(80).borderRadius(12)
                      .linearGradient({ angle: 135, colors: [[IW.glow, 0], [IW.accent, 1]] })
                      .padding(12)
                    Text(t.name).fontSize(12).fontWeight(600).fontColor(IW.text).margin({ top: 6 })
                    Text(t.tag + ' · ' + t.style).fontSize(10).fontColor(IW.primary).margin({ top: 2 })
                  }
                  .width(140).alignItems(HorizontalAlign.Start)
                }, (t: IwTattoo) => t.name)
              }
              .padding({ left: 4, right: 4 })
            }
            .scrollable(ScrollDirection.Horizontal)
            .scrollBar(BarState.Off)
          }
          .width('100%').padding(16).backgroundColor(IW.card).margin({ top: 8, bottom: 8 })
        }
        .width('100%')
      }
      .scrollBar(BarState.Off)
      .layoutWeight(1)
      .width('100%')

      // 纹身详情弹框
      if (this.showDetail) {
        Stack() {
          this.modalOverlay()
          Column() {
            Text('纹身贴详情').fontSize(18).fontWeight(700).fontColor(IW.primary).margin({ top: 20 })
            Text(iwTattooByName(this.selName).name).fontSize(16).fontWeight(600).fontColor(IW.text).margin({ top: 8 })
            Text(iwTattooByName(this.selName).style + ' · ' + iwTattooByName(this.selName).color + ' · ' + iwTattooByName(this.selName).tag)
              .fontSize(12).fontColor(IW.sub).margin({ top: 4 })
            Column() {
              Text('尺寸').fontSize(12).fontColor(IW.sub).margin({ bottom: 4 })
              Stack({ alignContent: Alignment.Start }) {
                Column().width('100%').height(8).borderRadius(4).backgroundColor(IW.bg)
                Column().width(iwSizeW(iwTattooByName(this.selName).size).toString() + '%').height(8).borderRadius(4).backgroundColor(IW.primary)
              }
              Text(iwTattooByName(this.selName).size.toString() + ' cm').fontSize(12).fontColor(IW.text).fontWeight(600).margin({ top: 4 })
            }
            .width('100%').margin({ top: 16 })
            Column() {
              Text('防水等级').fontSize(12).fontColor(IW.sub).margin({ bottom: 4 })
              Stack({ alignContent: Alignment.Start }) {
                Column().width('100%').height(8).borderRadius(4).backgroundColor(IW.bg)
                Column().width(iwWaterproofW(iwTattooByName(this.selName).waterproof).toString() + '%').height(8).borderRadius(4).backgroundColor(IW.accent)
              }
              Text(iwTattooByName(this.selName).waterproof.toString() + '/5星').fontSize(12).fontColor(IW.text).fontWeight(600).margin({ top: 4 })
            }
            .width('100%').margin({ top: 12 })
            Row() {
              Column() { Text('价格').fontSize(11).fontColor(IW.sub); Text('¥' + iwTattooByName(this.selName).price.toString()).fontSize(14).fontWeight(700).fontColor(IW.accent) }
              .layoutWeight(1).alignItems(HorizontalAlign.Center)
              Column() { Text('维持').fontSize(11).fontColor(IW.sub); Text(iwTattooByName(this.selName).duration.toString() + '天').fontSize(14).fontWeight(700).fontColor(IW.text) }
              .layoutWeight(1).alignItems(HorizontalAlign.Center)
              Column() { Text('库存').fontSize(11).fontColor(IW.sub); Text(iwTattooByName(this.selName).stock.toString()).fontSize(14).fontWeight(700).fontColor(IW.text) }
              .layoutWeight(1).alignItems(HorizontalAlign.Center)
              Column() { Text('已售').fontSize(11).fontColor(IW.sub); Text(iwTattooByName(this.selName).sold.toString()).fontSize(14).fontWeight(700).fontColor(IW.accent) }
              .layoutWeight(1).alignItems(HorizontalAlign.Center)
            }
            .width('100%').padding(12).backgroundColor(IW.bg).borderRadius(12).margin({ top: 12 })
            Row() {
              Text().width(28).height(28).borderRadius(14).backgroundColor(IW.sub).onClick(() => { this.showDetail = false })
              Column().layoutWeight(1)
              Text('加入收藏').fontSize(13).fontColor(IW.dark).padding({ left: 20, right: 20, top: 8, bottom: 8 }).borderRadius(20).backgroundColor(IW.primary)
            }
            .width('100%').margin({ top: 16 })
          }
          .width('86%').backgroundColor(IW.card).borderRadius(16).padding(20)
          .constraintSize({ maxHeight: '80%' }).zIndex(1000)
        }
        .width('100%').height('100%')
      }
    }
    .width('100%').height('100%')
  }
}

// ============ Tab 2: 纹身贴 ============
@Component
struct IwTattooTab {
  @State wave: number = 0
  @State list: IwTattoo[] = []
  @State filterTag: string = '全部'
  private timer: number = -1
  @State showDetail: boolean = false
  @State showAdd: boolean = false
  @State showEdit: boolean = false
  @State showDelete: boolean = false
  @State selName: string = ''

  aboutToAppear() {
    this.list = iwFilterTattoos('全部')
    this.timer = setInterval(() => {
      this.wave += 1
    }, 60)
  }

  aboutToDisappear() {
    if (this.timer !== -1) {
      clearInterval(this.timer)
    }
  }

  @Builder modalOverlay() {
    Column() {
      Column().width('100%').height('100%').backgroundColor('rgba(10,6,18,0.75)')
    }
    .width('100%').height('100%').position({ x: 0, y: 0 }).zIndex(999)
    .onClick(() => {
      this.showDetail = false
      this.showAdd = false
      this.showEdit = false
      this.showDelete = false
    })
  }

  build() {
    Stack() {
      Scroll() {
        Column() {
          // 筛选 chips
          Scroll() {
            Row({ space: 8 }) {
              ForEach(['全部', '热门', '潮流', '暗黑', '禅意', '高端', '入门'], (t: string) => {
                Text(t).fontSize(12).fontColor(this.filterTag === t ? IW.dark : IW.text)
                  .padding({ left: 16, right: 16, top: 6, bottom: 6 })
                  .borderRadius(16)
                  .backgroundColor(this.filterTag === t ? IW.primary : IW.card)
                  .onClick(() => {
                    this.filterTag = t
                    this.list = iwFilterTattoos(t)
                  })
              }, (t: string) => t)
            }
            .padding({ left: 12, right: 12 })
          }
          .scrollable(ScrollDirection.Horizontal)
          .scrollBar(BarState.Off)
          .width('100%')
          .height(36)

          // 双列网格
          Flex({ wrap: FlexWrap.Wrap, justifyContent: FlexAlign.SpaceBetween }) {
            ForEach(this.list, (t: IwTattoo, i: number) => {
              Column() {
                Stack() {
                  Column().width('100%').height(70).borderRadius(12)
                    .linearGradient({ angle: 135, colors: [[IW.glow, 0], [IW.accent, 1]] })
                  Column().width(28).height(28).borderRadius(14).backgroundColor('rgba(0,255,255,0.25)')
                    .scale({ x: iwInk(this.wave, i), y: iwInk(this.wave, i) })
                }
                .width('100%').height(70)
                Text(t.name).fontSize(13).fontWeight(700).fontColor(IW.text).margin({ top: 8 })
                Text(t.style + ' · ' + t.color).fontSize(10).fontColor(IW.sub).margin({ top: 2 })
                Row() {
                  Text(t.tag).fontSize(10).fontColor(IW.primary).fontWeight(600)
                  Column().layoutWeight(1)
                  Text(t.size + 'cm').fontSize(10).fontColor(IW.sub)
                }
                .width('100%').margin({ top: 4 })
                Row() {
                  Text('¥').fontSize(10).fontColor(IW.sub)
                  Text(t.price.toString()).fontSize(14).fontColor(IW.accent).fontWeight(700)
                  Column().layoutWeight(1)
                  Text('库存 ' + t.stock.toString()).fontSize(10).fontColor(IW.sub)
                }
                .width('100%').margin({ top: 4 })
              }
              .width('48.5%')
              .padding(10)
              .backgroundColor(IW.card)
              .borderRadius(12)
              .margin({ bottom: 8 })
              .onClick(() => {
                this.selName = t.name
                this.showDetail = true
              })
            }, (t: IwTattoo) => t.name)
          }
          .width('100%').padding({ left: 12, right: 12 })

          // 尺寸对比
          Column() {
            Text('尺寸对比 (cm)').fontSize(13).fontWeight(700).fontColor(IW.text).margin({ bottom: 12 })
            ForEach(this.list.slice(0, 5), (t: IwTattoo, i: number) => {
              Row() {
                Text(t.name.substring(0, 6)).fontSize(10).fontColor(IW.sub).width(60)
                Stack({ alignContent: Alignment.Start }) {
                  Column().width('100%').height(10).borderRadius(5).backgroundColor(IW.bg)
                  Column().width(iwSizeW(t.size).toString() + '%').height(10).borderRadius(5).backgroundColor(IW.primary)
                }
                .layoutWeight(1)
                Text(t.size.toString()).fontSize(10).fontColor(IW.text).fontWeight(600).width(28)
              }
              .width('100%').margin({ bottom: 6 })
            }, (t: IwTattoo) => t.name)
          }
          .width('100%').padding(16).backgroundColor(IW.card).margin({ top: 8 })

          // 防水等级分布
          Column() {
            Text('防水等级分布').fontSize(13).fontWeight(700).fontColor(IW.text).margin({ bottom: 12 })
            Row({ space: 6 }) {
              ForEach(this.list.slice(0, 6), (t: IwTattoo, i: number) => {
                Column() {
                  Column().width(24).height(iwWaterproofW(t.waterproof)).borderRadius(4).backgroundColor(IW.accent)
                  Text(t.waterproof.toString()).fontSize(9).fontColor(IW.sub).margin({ top: 4 })
                }
                .alignItems(HorizontalAlign.Center)
              }, (t: IwTattoo) => t.name)
            }
            .width('100%').justifyContent(FlexAlign.SpaceAround)
          }
          .width('100%').padding(16).backgroundColor(IW.card).margin({ top: 8, bottom: 8 })
        }
        .width('100%')
      }
      .scrollBar(BarState.Off)
      .layoutWeight(1)
      .width('100%')

      // 详情弹框
      if (this.showDetail) {
        Stack() {
          this.modalOverlay()
          Column() {
            Text('纹身贴详情').fontSize(18).fontWeight(700).fontColor(IW.primary).margin({ top: 20 })
            Text(iwTattooByName(this.selName).name).fontSize(16).fontWeight(600).fontColor(IW.text).margin({ top: 8 })
            Text(iwTattooByName(this.selName).style + ' · ' + iwTattooByName(this.selName).color + ' · ' + iwTattooByName(this.selName).tag)
              .fontSize(12).fontColor(IW.sub).margin({ top: 4 })
            Column() {
              Text('尺寸').fontSize(12).fontColor(IW.sub).margin({ bottom: 4 })
              Stack({ alignContent: Alignment.Start }) {
                Column().width('100%').height(8).borderRadius(4).backgroundColor(IW.bg)
                Column().width(iwSizeW(iwTattooByName(this.selName).size).toString() + '%').height(8).borderRadius(4).backgroundColor(IW.primary)
              }
              Text(iwTattooByName(this.selName).size.toString() + ' cm').fontSize(12).fontColor(IW.text).fontWeight(600).margin({ top: 4 })
            }
            .width('100%').margin({ top: 16 })
            Column() {
              Text('防水等级').fontSize(12).fontColor(IW.sub).margin({ bottom: 4 })
              Stack({ alignContent: Alignment.Start }) {
                Column().width('100%').height(8).borderRadius(4).backgroundColor(IW.bg)
                Column().width(iwWaterproofW(iwTattooByName(this.selName).waterproof).toString() + '%').height(8).borderRadius(4).backgroundColor(IW.accent)
              }
              Text(iwTattooByName(this.selName).waterproof.toString() + '/5星').fontSize(12).fontColor(IW.text).fontWeight(600).margin({ top: 4 })
            }
            .width('100%').margin({ top: 12 })
            Row() {
              Column() { Text('价格').fontSize(11).fontColor(IW.sub); Text('¥' + iwTattooByName(this.selName).price.toString()).fontSize(14).fontWeight(700).fontColor(IW.accent) }
              .layoutWeight(1).alignItems(HorizontalAlign.Center)
              Column() { Text('维持').fontSize(11).fontColor(IW.sub); Text(iwTattooByName(this.selName).duration.toString() + '天').fontSize(14).fontWeight(700).fontColor(IW.text) }
              .layoutWeight(1).alignItems(HorizontalAlign.Center)
              Column() { Text('库存').fontSize(11).fontColor(IW.sub); Text(iwTattooByName(this.selName).stock.toString()).fontSize(14).fontWeight(700).fontColor(IW.text) }
              .layoutWeight(1).alignItems(HorizontalAlign.Center)
              Column() { Text('已售').fontSize(11).fontColor(IW.sub); Text(iwTattooByName(this.selName).sold.toString()).fontSize(14).fontWeight(700).fontColor(IW.accent) }
              .layoutWeight(1).alignItems(HorizontalAlign.Center)
            }
            .width('100%').padding(12).backgroundColor(IW.bg).borderRadius(12).margin({ top: 12 })
            Row() {
              Text().width(28).height(28).borderRadius(14).backgroundColor(IW.sub).onClick(() => { this.showDetail = false })
              Column().layoutWeight(1)
              Text('编辑').fontSize(12).fontColor(IW.dark).padding({ left: 14, right: 14, top: 8, bottom: 8 }).borderRadius(16).backgroundColor(IW.accent)
                .onClick(() => { this.showDetail = false; this.showEdit = true })
              Text('删除').fontSize(12).fontColor('#FFFFFF').padding({ left: 14, right: 14, top: 8, bottom: 8 }).borderRadius(16).backgroundColor('#CC3333')
                .margin({ left: 8 }).onClick(() => { this.showDetail = false; this.showDelete = true })
            }
            .width('100%').margin({ top: 16 })
          }
          .width('86%').backgroundColor(IW.card).borderRadius(16).padding(20)
          .constraintSize({ maxHeight: '80%' }).zIndex(1000)
        }
        .width('100%').height('100%')
      }

      // 新增弹框
      if (this.showAdd) {
        Stack() {
          this.modalOverlay()
          Column() {
            Text('新增纹身贴').fontSize(18).fontWeight(700).fontColor(IW.primary).margin({ top: 20 })
            Column() {
              Text('名称').fontSize(12).fontColor(IW.sub).margin({ bottom: 4 })
              Row() {
                Text('请输入纹身贴名称').fontSize(12).fontColor(IW.sub)
                Column().layoutWeight(1)
              }
              .width('100%').height(36).backgroundColor(IW.bg).borderRadius(8).padding({ left: 12, right: 12 })
            }
            .width('100%').margin({ top: 16 })
            Column() {
              Text('风格').fontSize(12).fontColor(IW.sub).margin({ bottom: 4 })
              Row() {
                Text('新传统').fontSize(12).fontColor(IW.dark).padding(8).borderRadius(8).backgroundColor(IW.primary)
                Text('几何').fontSize(12).fontColor(IW.text).padding(8).borderRadius(8).backgroundColor(IW.card).margin({ left: 8 })
                Text('暗黑').fontSize(12).fontColor(IW.text).padding(8).borderRadius(8).backgroundColor(IW.card).margin({ left: 8 })
                Text('水彩').fontSize(12).fontColor(IW.text).padding(8).borderRadius(8).backgroundColor(IW.card).margin({ left: 8 })
              }
            }
            .width('100%').margin({ top: 12 })
            Column() {
              Text('颜色').fontSize(12).fontColor(IW.sub).margin({ bottom: 4 })
              Row() {
                Text('黑色').fontSize(12).fontColor(IW.dark).padding(8).borderRadius(8).backgroundColor(IW.accent)
                Text('荧光').fontSize(12).fontColor(IW.text).padding(8).borderRadius(8).backgroundColor(IW.card).margin({ left: 8 })
                Text('彩色').fontSize(12).fontColor(IW.text).padding(8).borderRadius(8).backgroundColor(IW.card).margin({ left: 8 })
                Text('渐变').fontSize(12).fontColor(IW.text).padding(8).borderRadius(8).backgroundColor(IW.card).margin({ left: 8 })
              }
            }
            .width('100%').margin({ top: 12 })
            Row() {
              Text().width(28).height(28).borderRadius(14).backgroundColor(IW.sub).onClick(() => { this.showAdd = false })
              Column().layoutWeight(1)
              Text('确认新增').fontSize(13).fontColor(IW.dark).padding({ left: 20, right: 20, top: 8, bottom: 8 }).borderRadius(20).backgroundColor(IW.primary)
                .onClick(() => { this.showAdd = false })
            }
            .width('100%').margin({ top: 20 })
          }
          .width('86%').backgroundColor(IW.card).borderRadius(16).padding(20)
          .constraintSize({ maxHeight: '80%' }).zIndex(1000)
        }
        .width('100%').height('100%')
      }

      // 编辑弹框
      if (this.showEdit) {
        Stack() {
          this.modalOverlay()
          Column() {
            Text('编辑纹身贴').fontSize(18).fontWeight(700).fontColor(IW.primary).margin({ top: 20 })
            Text('当前:' + this.selName).fontSize(12).fontColor(IW.sub).margin({ top: 8 })
            Column() {
              Text('修改名称').fontSize(12).fontColor(IW.sub).margin({ bottom: 4 })
              Row() {
                Text(this.selName).fontSize(12).fontColor(IW.text)
                Column().layoutWeight(1)
              }
              .width('100%').height(36).backgroundColor(IW.bg).borderRadius(8).padding({ left: 12, right: 12 })
            }
            .width('100%').margin({ top: 16 })
            Column() {
              Text('修改风格').fontSize(12).fontColor(IW.sub).margin({ bottom: 4 })
              Row() {
                Text('新传统').fontSize(12).fontColor(IW.dark).padding(8).borderRadius(8).backgroundColor(IW.accent)
                Text('几何').fontSize(12).fontColor(IW.text).padding(8).borderRadius(8).backgroundColor(IW.card).margin({ left: 8 })
                Text('水彩').fontSize(12).fontColor(IW.text).padding(8).borderRadius(8).backgroundColor(IW.card).margin({ left: 8 })
              }
            }
            .width('100%').margin({ top: 12 })
            Row() {
              Text().width(28).height(28).borderRadius(14).backgroundColor(IW.sub).onClick(() => { this.showEdit = false })
              Column().layoutWeight(1)
              Text('保存修改').fontSize(13).fontColor(IW.dark).padding({ left: 20, right: 20, top: 8, bottom: 8 }).borderRadius(20).backgroundColor(IW.primary)
                .onClick(() => { this.showEdit = false })
            }
            .width('100%').margin({ top: 20 })
          }
          .width('86%').backgroundColor(IW.card).borderRadius(16).padding(20)
          .constraintSize({ maxHeight: '80%' }).zIndex(1000)
        }
        .width('100%').height('100%')
      }

      // 删除弹框
      if (this.showDelete) {
        Stack() {
          this.modalOverlay()
          Column() {
            Text('确认删除').fontSize(18).fontWeight(700).fontColor('#FF4466').margin({ top: 20 })
            Text('删除后不可恢复').fontSize(12).fontColor(IW.sub).margin({ top: 8 })
            Column() {
              Text('删除目标').fontSize(12).fontColor(IW.sub).margin({ bottom: 4 })
              Text(this.selName).fontSize(16).fontWeight(700).fontColor(IW.text)
            }
            .width('100%').padding(16).backgroundColor('rgba(255,20,147,0.1)').borderRadius(12)
            .border({ width: 1, color: 'rgba(255,20,147,0.3)' }).margin({ top: 16 })
            Row() {
              Text().width(28).height(28).borderRadius(14).backgroundColor(IW.sub).onClick(() => { this.showDelete = false })
              Column().layoutWeight(1)
              Text('取消').fontSize(13).fontColor(IW.text).padding({ left: 20, right: 20, top: 8, bottom: 8 }).borderRadius(20).backgroundColor(IW.card)
                .onClick(() => { this.showDelete = false })
              Text('确认删除').fontSize(13).fontColor('#FFFFFF').padding({ left: 20, right: 20, top: 8, bottom: 8 }).borderRadius(20).backgroundColor('#CC3333')
                .margin({ left: 8 }).onClick(() => { this.showDelete = false })
            }
            .width('100%').margin({ top: 20 })
          }
          .width('86%').backgroundColor(IW.card).borderRadius(16).padding(20)
          .constraintSize({ maxHeight: '80%' }).zIndex(1000)
        }
        .width('100%').height('100%')
      }
    }
    .width('100%').height('100%')
  }
}

// ============ Tab 3: 工具 ============
@Component
struct IwToolTab {
  @State wave: number = 0
  @State list: IwTool[] = []
  private timer: number = -1
  @State showDetail: boolean = false
  @State showAdd: boolean = false
  @State showEdit: boolean = false
  @State selName: string = ''

  aboutToAppear() {
    this.list = IW_TOOLS.slice()
    this.timer = setInterval(() => { this.wave += 1 }, 60)
  }
  aboutToDisappear() {
    if (this.timer !== -1) { clearInterval(this.timer) }
  }

  @Builder modalOverlay() {
    Column() {
      Column().width('100%').height('100%').backgroundColor('rgba(10,6,18,0.75)')
    }
    .width('100%').height('100%').position({ x: 0, y: 0 }).zIndex(999)
    .onClick(() => { this.showDetail = false; this.showAdd = false; this.showEdit = false })
  }

  build() {
    Stack() {
      Scroll() {
        Column() {
          Column() {
            Text('工具热销榜').fontSize(14).fontWeight(700).fontColor(IW.text).margin({ bottom: 12 })
            ForEach(this.list, (t: IwTool, i: number) => {
              Row() {
                Text(iwTopN(i)).fontSize(20).fontWeight(900).fontColor(i < 3 ? IW.accent : IW.sub).width(28)
                Column() {
                  Column().width(56).height(56).borderRadius(12).backgroundColor(IW.bg).border({ width: 1, color: IW.line })
                  Text(t.type).fontSize(10).fontColor(IW.primary).fontWeight(600).margin({ top: 2 })
                }
                .width(56).alignItems(HorizontalAlign.Center)
                Column() {
                  Text(t.name).fontSize(14).fontWeight(700).fontColor(IW.text)
                  Text(t.brand + ' · ' + t.material).fontSize(10).fontColor(IW.sub).margin({ top: 2 })
                  Row() {
                    Text(t.use).fontSize(10).fontColor(IW.primary).padding({ left: 6, right: 6, top: 2, bottom: 2 }).borderRadius(4).backgroundColor(IW.bg)
                    Column().layoutWeight(1)
                    Text('¥' + t.price.toString()).fontSize(10).fontColor(IW.accent).fontWeight(700)
                  }
                  .width('100%').margin({ top: 4 })
                  Row() {
                    Text('已售 ' + t.sold.toString()).fontSize(10).fontColor(IW.sub)
                    Column().layoutWeight(1)
                    Text('库存 ' + t.stock.toString()).fontSize(10).fontColor(IW.sub)
                  }
                  .width('100%').margin({ top: 4 })
                }
                .alignItems(HorizontalAlign.Start).layoutWeight(1).padding({ left: 12 })
              }
              .width('100%').padding(12).backgroundColor(IW.card).borderRadius(12).margin({ bottom: 8 })
              .onClick(() => { this.selName = t.name; this.showDetail = true })
            }, (t: IwTool) => t.name)
          }
          .width('100%').padding(16).backgroundColor(IW.bg)

          Column() {
            Text('工具类型分布').fontSize(13).fontWeight(700).fontColor(IW.text).margin({ bottom: 12 })
            Column() {
              Row() {
                Text('转印').fontSize(11).fontColor(IW.sub).width(56)
                Stack({ alignContent: Alignment.Start }) {
                  Column().width('100%').height(8).borderRadius(4).backgroundColor(IW.bg)
                  Column().width('13%').height(8).borderRadius(4).backgroundColor(IW.primary)
                }
                .layoutWeight(1)
                Text('13%').fontSize(11).fontColor(IW.text).fontWeight(600).width(32)
              }.margin({ bottom: 8 })
              Row() {
                Text('贴膜').fontSize(11).fontColor(IW.sub).width(56)
                Stack({ alignContent: Alignment.Start }) {
                  Column().width('100%').height(8).borderRadius(4).backgroundColor(IW.bg)
                  Column().width('13%').height(8).borderRadius(4).backgroundColor(IW.accent)
                }
                .layoutWeight(1)
                Text('13%').fontSize(11).fontColor(IW.text).fontWeight(600).width(32)
              }.margin({ bottom: 8 })
              Row() {
                Text('其他').fontSize(11).fontColor(IW.sub).width(56)
                Stack({ alignContent: Alignment.Start }) {
                  Column().width('100%').height(8).borderRadius(4).backgroundColor(IW.bg)
                  Column().width('74%').height(8).borderRadius(4).backgroundColor(IW.glow)
                }
                .layoutWeight(1)
                Text('74%').fontSize(11).fontColor(IW.text).fontWeight(600).width(32)
              }
            }
          }
          .width('100%').padding(16).backgroundColor(IW.card).margin({ top: 8, bottom: 8 })
        }
        .width('100%')
      }
      .scrollBar(BarState.Off).layoutWeight(1).width('100%')

      if (this.showDetail) {
        Stack() {
          this.modalOverlay()
          Column() {
            Text('工具详情').fontSize(18).fontWeight(700).fontColor(IW.primary).margin({ top: 20 })
            Text(iwToolByName(this.selName).name).fontSize(16).fontWeight(600).fontColor(IW.text).margin({ top: 8 })
            Text(iwToolByName(this.selName).brand + ' · ' + iwToolByName(this.selName).type + ' · ' + iwToolByName(this.selName).material)
              .fontSize(12).fontColor(IW.sub).margin({ top: 4 })
            Column() {
              Text('用途').fontSize(12).fontColor(IW.sub).margin({ bottom: 4 })
              Text(iwToolByName(this.selName).use).fontSize(14).fontWeight(700).fontColor(IW.text)
            }
            .width('100%').margin({ top: 16 })
            Row() {
              Column() { Text('价格').fontSize(11).fontColor(IW.sub); Text('¥' + iwToolByName(this.selName).price.toString()).fontSize(14).fontWeight(700).fontColor(IW.accent) }
              .layoutWeight(1).alignItems(HorizontalAlign.Center)
              Column() { Text('库存').fontSize(11).fontColor(IW.sub); Text(iwToolByName(this.selName).stock.toString()).fontSize(14).fontWeight(700).fontColor(IW.text) }
              .layoutWeight(1).alignItems(HorizontalAlign.Center)
              Column() { Text('已售').fontSize(11).fontColor(IW.sub); Text(iwToolByName(this.selName).sold.toString()).fontSize(14).fontWeight(700).fontColor(IW.accent) }
              .layoutWeight(1).alignItems(HorizontalAlign.Center)
            }
            .width('100%').padding(12).backgroundColor(IW.bg).borderRadius(12).margin({ top: 12 })
            Row() {
              Text().width(28).height(28).borderRadius(14).backgroundColor(IW.sub).onClick(() => { this.showDetail = false })
              Column().layoutWeight(1)
              Text('编辑').fontSize(12).fontColor(IW.dark).padding({ left: 14, right: 14, top: 8, bottom: 8 }).borderRadius(16).backgroundColor(IW.accent)
                .onClick(() => { this.showDetail = false; this.showEdit = true })
            }
            .width('100%').margin({ top: 16 })
          }
          .width('86%').backgroundColor(IW.card).borderRadius(16).padding(20).constraintSize({ maxHeight: '80%' }).zIndex(1000)
        }
        .width('100%').height('100%')
      }
      if (this.showAdd) {
        Stack() {
          this.modalOverlay()
          Column() {
            Text('新增工具').fontSize(18).fontWeight(700).fontColor(IW.primary).margin({ top: 20 })
            Column() {
              Text('名称').fontSize(12).fontColor(IW.sub).margin({ bottom: 4 })
              Row() {
                Text('请输入工具名称').fontSize(12).fontColor(IW.sub)
                Column().layoutWeight(1)
              }
              .width('100%').height(36).backgroundColor(IW.bg).borderRadius(8).padding({ left: 12, right: 12 })
            }
            .width('100%').margin({ top: 16 })
            Column() {
              Text('类型').fontSize(12).fontColor(IW.sub).margin({ bottom: 4 })
              Row() {
                Text('转印').fontSize(12).fontColor(IW.dark).padding(8).borderRadius(8).backgroundColor(IW.primary)
                Text('贴膜').fontSize(12).fontColor(IW.text).padding(8).borderRadius(8).backgroundColor(IW.card).margin({ left: 8 })
                Text('清洁').fontSize(12).fontColor(IW.text).padding(8).borderRadius(8).backgroundColor(IW.card).margin({ left: 8 })
                Text('刮板').fontSize(12).fontColor(IW.text).padding(8).borderRadius(8).backgroundColor(IW.card).margin({ left: 8 })
              }
            }
            .width('100%').margin({ top: 12 })
            Row() {
              Text().width(28).height(28).borderRadius(14).backgroundColor(IW.sub).onClick(() => { this.showAdd = false })
              Column().layoutWeight(1)
              Text('确认新增').fontSize(13).fontColor(IW.dark).padding({ left: 20, right: 20, top: 8, bottom: 8 }).borderRadius(20).backgroundColor(IW.primary)
                .onClick(() => { this.showAdd = false })
            }
            .width('100%').margin({ top: 20 })
          }
          .width('86%').backgroundColor(IW.card).borderRadius(16).padding(20).constraintSize({ maxHeight: '80%' }).zIndex(1000)
        }
        .width('100%').height('100%')
      }
      if (this.showEdit) {
        Stack() {
          this.modalOverlay()
          Column() {
            Text('编辑工具').fontSize(18).fontWeight(700).fontColor(IW.primary).margin({ top: 20 })
            Text('当前:' + this.selName).fontSize(12).fontColor(IW.sub).margin({ top: 8 })
            Column() {
              Text('修改名称').fontSize(12).fontColor(IW.sub).margin({ bottom: 4 })
              Row() {
                Text(this.selName).fontSize(12).fontColor(IW.text)
                Column().layoutWeight(1)
              }
              .width('100%').height(36).backgroundColor(IW.bg).borderRadius(8).padding({ left: 12, right: 12 })
            }
            .width('100%').margin({ top: 16 })
            Row() {
              Text().width(28).height(28).borderRadius(14).backgroundColor(IW.sub).onClick(() => { this.showEdit = false })
              Column().layoutWeight(1)
              Text('保存修改').fontSize(13).fontColor(IW.dark).padding({ left: 20, right: 20, top: 8, bottom: 8 }).borderRadius(20).backgroundColor(IW.primary)
                .onClick(() => { this.showEdit = false })
            }
            .width('100%').margin({ top: 20 })
          }
          .width('86%').backgroundColor(IW.card).borderRadius(16).padding(20).constraintSize({ maxHeight: '80%' }).zIndex(1000)
        }
        .width('100%').height('100%')
      }
    }
    .width('100%').height('100%')
  }
}

// ============ Tab 4: 护理 ============
@Component
struct IwCareTab {
  @State wave: number = 0
  @State list: IwCare[] = []
  private timer: number = -1
  @State showDetail: boolean = false
  @State showAdd: boolean = false
  @State showDelete: boolean = false
  @State selName: string = ''

  aboutToAppear() {
    this.list = IW_CARE.slice()
    this.timer = setInterval(() => { this.wave += 1 }, 60)
  }
  aboutToDisappear() {
    if (this.timer !== -1) { clearInterval(this.timer) }
  }

  @Builder modalOverlay() {
    Column() {
      Column().width('100%').height('100%').backgroundColor('rgba(10,6,18,0.75)')
    }
    .width('100%').height('100%').position({ x: 0, y: 0 }).zIndex(999)
    .onClick(() => { this.showDetail = false; this.showAdd = false; this.showDelete = false })
  }

  build() {
    Stack() {
      Scroll() {
        Column() {
          ForEach(this.list, (c: IwCare, i: number) => {
            Column() {
              Row() {
                Column() {
                  Text(c.name).fontSize(16).fontWeight(700).fontColor(IW.text)
                  Text(c.type + ' · ' + c.use).fontSize(11).fontColor(IW.sub).margin({ top: 2 })
                }
                .alignItems(HorizontalAlign.Start).layoutWeight(1)
                Text(c.type).fontSize(11).fontColor(IW.dark).padding({ left: 10, right: 10, top: 4, bottom: 4 })
                  .borderRadius(12).backgroundColor(IW.primary)
              }
              .width('100%')
              Column() {
                Row() {
                  Text('容量').fontSize(11).fontColor(IW.sub)
                  Column().layoutWeight(1)
                  Text(c.volume.toString() + 'ml').fontSize(11).fontColor(IW.text).fontWeight(600)
                }
                .width('100%').margin({ bottom: 4 })
                Stack({ alignContent: Alignment.Start }) {
                  Column().width('100%').height(6).borderRadius(3).backgroundColor(IW.bg)
                  Column().width(Math.min(c.volume / 120 * 100, 100).toString() + '%').height(6).borderRadius(3).backgroundColor(IW.glow)
                }
                .width('100%')
              }
              .width('100%').margin({ top: 10 })
              Row() {
                Column() { Text('价格').fontSize(10).fontColor(IW.sub); Text('¥' + c.price.toString()).fontSize(13).fontWeight(700).fontColor(IW.accent) }
                .layoutWeight(1).alignItems(HorizontalAlign.Center)
                Column().width(1).height(28).backgroundColor(IW.line)
                Column() { Text('库存').fontSize(10).fontColor(IW.sub); Text(c.stock.toString()).fontSize(13).fontWeight(700).fontColor(IW.text) }
                .layoutWeight(1).alignItems(HorizontalAlign.Center)
                Column().width(1).height(28).backgroundColor(IW.line)
                Column() { Text('已售').fontSize(10).fontColor(IW.sub); Text(c.sold.toString()).fontSize(13).fontWeight(700).fontColor(IW.accent) }
                .layoutWeight(1).alignItems(HorizontalAlign.Center)
              }
              .width('100%').padding({ top: 10, bottom: 10 }).backgroundColor(IW.bg).borderRadius(10).margin({ top: 10 })
              Row() {
                Text('查看详情 >').fontSize(11).fontColor(IW.primary)
                Column().layoutWeight(1)
              }
              .width('100%').margin({ top: 8 })
            }
            .width('100%').padding(14).backgroundColor(IW.card).borderRadius(14).margin({ left: 12, right: 12, bottom: 10 })
            .onClick(() => { this.selName = c.name; this.showDetail = true })
          }, (c: IwCare) => c.name)

          Column() {
            Text('护理类型分布').fontSize(13).fontWeight(700).fontColor(IW.text).margin({ bottom: 12 })
            Column() {
              Row() {
                Text('定影').fontSize(11).fontColor(IW.sub).width(56)
                Stack({ alignContent: Alignment.Start }) {
                  Column().width('100%').height(8).borderRadius(4).backgroundColor(IW.bg)
                  Column().width('17%').height(8).borderRadius(4).backgroundColor(IW.primary)
                }
                .layoutWeight(1)
                Text('17%').fontSize(11).fontColor(IW.text).fontWeight(600).width(32)
              }.margin({ bottom: 8 })
              Row() {
                Text('防护').fontSize(11).fontColor(IW.sub).width(56)
                Stack({ alignContent: Alignment.Start }) {
                  Column().width('100%').height(8).borderRadius(4).backgroundColor(IW.bg)
                  Column().width('17%').height(8).borderRadius(4).backgroundColor(IW.accent)
                }
                .layoutWeight(1)
                Text('17%').fontSize(11).fontColor(IW.text).fontWeight(600).width(32)
              }.margin({ bottom: 8 })
              Row() {
                Text('其他').fontSize(11).fontColor(IW.sub).width(56)
                Stack({ alignContent: Alignment.Start }) {
                  Column().width('100%').height(8).borderRadius(4).backgroundColor(IW.bg)
                  Column().width('66%').height(8).borderRadius(4).backgroundColor(IW.glow)
                }
                .layoutWeight(1)
                Text('66%').fontSize(11).fontColor(IW.text).fontWeight(600).width(32)
              }
            }
          }
          .width('100%').padding(16).backgroundColor(IW.card).margin({ top: 8, bottom: 8 })
        }
        .width('100%')
      }
      .scrollBar(BarState.Off).layoutWeight(1).width('100%')

      if (this.showDetail) {
        Stack() {
          this.modalOverlay()
          Column() {
            Tex


总结

在这里插入图片描述

这款潮流纹身贴纸馆应用充分展示了HarmonyOS ArkTS API 24在构建深色主题应用方面的强大能力。从霓虹配色方案到荧光动画效果,从潮流内容社区到完整电商功能,每一个细节都体现了对目标用户群体的深刻理解和对技术的精准把控。

深色主题的设计是这款应用最突出的特点。深紫黑背景、荧光青主色、电粉强调色的组合,既符合纹身文化的前卫气质,又在视觉上形成了强烈的冲击力。六大动画函数在深色背景下发挥出最佳效果,墨水扩散、霓虹辉光、旋转光晕等特效为应用增添了赛博朋克般的未来感。

应用的业务架构同样值得关注。纹身贴商品、工具耗材、护理产品、图案设计四大板块相互支撑,形成了"产品+内容+服务"的完整生态。线下店铺预约、纹身课堂、社区交流等功能则进一步丰富了用户体验,将单纯的购物App升级为潮流文化平台。

Logo

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

更多推荐