像素不灭情怀永续:基于HarmonyOS ArkTS API 24声明式开发的像素游戏厅,从粒子漂浮动效到稀有度四级分级的复古游戏二手交易全栈实战解析

从FC红白机到Switch OLED,从绝版卡带到攻略秘籍,从以物换物到收藏图鉴——本文以一套完整的ArkTS像素游戏厅应用为例,深度解析HarmonyOS ArkTS API 24在复古游戏二手交易场景下的双Tab嵌套架构、14粒子漂浮动效、稀有度四级分级、游戏详情绿黄渐变头、以物换物交换帖等核心技术实现。

一、引言

复古游戏收藏是近年来越来越火热的文化现象。从FC红白机到GameBoy,从PS1到Switch,每一台老主机、每一张绝版卡带都承载着一代人的童年回忆。然而复古游戏二手交易长期依赖闲鱼、贴吧等泛平台,缺乏针对游戏收藏的专业化功能——稀有度评级、版本区分、以物换物、收藏图鉴等核心需求无法得到满足。

本应用(像素游戏厅)以"像素绿+复古灰"复古像素风为视觉基调,打造集集市交易、换卡交换、收藏图鉴、个人中心四大模块于一体的复古游戏二手交易与收藏社区。18款游戏/主机覆盖FC/GBA/PS1/Switch/Steam Deck等全世代,8条换卡交换帖覆盖以物换物场景,5套攻略教程覆盖速通/收集/对战/硬件维修,9款外设配件覆盖收藏周边,6套图鉴收藏记录收藏进度,3条圈友点评提供真实评价。

本文将从架构设计、色彩系统、数据模型、四大Tab页面、弹框体系、核心技术特性等维度,完整解析这套应用的ArkTS实现。

二、整体架构

本应用采用单组件双Tab嵌套架构——@Entry @Component struct Index作为唯一入口组件,通过@State currentBottomTab控制四大底部Tab(集市/换卡/图鉴/我的),集市Tab内部再通过@State currentTopTab控制六大顶部分类Tab(全部/主机/掌机/卡带/游戏/外设),形成双层Tab嵌套。

架构层次:

  • 入口层:Index,负责双层Tab切换、头部、底部导航、粒子动效、弹框管理
  • 页面层:4个底部Tab对应的Builder方法(bazaarContent/swapContent/collectionContent/mineContent),集市Tab内含6个顶部Tab对应的Builder方法(cityContent/retiredContent/mocContent/figContent/techContent/streetContent)
  • 数据层:8个全局const数组(18游戏+8换卡帖+5攻略教程+9外设配件+6图鉴收藏+3点评+2图表数据+2弹框选项)+1个配色常量PALETTE
  • 工具函数层:10+全局纯函数(catColor/catLabel/rarityLabel/rarityColor/tradeBarHeight/rateColor/6个分类筛选函数/swapBadge)
  • 弹框层:4种弹框(发布出售/发起交换/下架删除/游戏详情),均通过@State布尔值控制显隐

单组件架构的优势在于状态集中管理、数据共享方便、弹框统一调度,适合中等复杂度的应用。双层Tab嵌套是本应用的架构特色——集市作为主品类,内部再按主机/掌机/卡带/游戏/外设细分,用户可以快速切换品类浏览。

三、色彩系统:像素绿+复古灰复古像素风

复古游戏的视觉语言应该是"怀旧、像素、活力、有街机感"。本应用采用像素绿+复古灰配色:

主色体系:

  • #00A25B 像素绿:主高亮色、Tab选中态、按钮、标签、渐变——代表活力与复古
  • #4A4A4A 复古灰:辅助色、头部渐变终点、深色卡片——代表沉稳与怀旧
  • #2B2B2B 深灰:主文字色、深色卡片背景、弹框头部——代表厚重
  • #E8483C 复古红:价格、删除按钮、热门标签、稀有度最高级——代表警示与珍贵
  • #FFD400 像素黄:Tab指示条、Banner渐变、标签、统计数字——代表活力与街机
  • #FF8A00 像素橙:稀有度第二级、求购标签、统计数字——代表温暖
  • #8A8A8A 烟灰:辅助文字、未选中Tab、说明文字——代表素雅

浅色背景层次:

  • #F2F5F2 浅绿白:应用根背景
  • #FFFFFF 纯白:卡片背景、弹框背景
  • #DFF2E7 浅绿:标签背景、选中态背景、进度条背景
  • #FFF8DC 浅黄:高亮卡片背景、提示背景
  • #FFEBEE 浅红:想换物品背景
  • #F2F2F2 浅灰:高亮卡片背景
  • #E5E5E5 灰:分割线、进度条背景

渐变设计:

  • 头部:linearGradient angle 135 从#00A25B到#4A4A4A——像素绿到复古灰的怀旧渐变
  • 像素游戏节Banner:linearGradient angle 120 从#FFD400到#FFB300——像素黄到深黄的活力渐变
  • 初代神机大卡:linearGradient angle 160 从#00A25B到#2B2B2B——像素绿到深灰的深邃渐变
  • 游戏详情头部:linearGradient angle 135 从#FFD400到#A8E6CF——像素黄到浅绿的明快渐变
  • 发布出售弹框头部:linearGradient angle 120 从#00A25B到#2B2B2B——与头部一致的怀旧渐变
  • 我的页会员卡:linearGradient angle 120 从#00A25B到#2B2B2B——与头部一致

像素绿+复古灰的配色通过浅绿白根背景+纯白卡片+浅绿/浅黄高亮背景营造复古空间感,像素绿#00A25B作为唯一主高亮色贯穿全应用,像素黄#FFD400作为Tab指示条和Banner色,复古红#E8483C作为价格和删除操作色,确保视觉一致性和复古像素韵味。

四、数据模型

应用定义了7个接口,覆盖复古游戏交易全链路:

  • GameItem游戏/主机(id/name/eng/cat/price/rarity/year/rating/starStr/seller/tag/desc/want/sales/emoji/version)——18款,含中英文名称、分类、稀有度0-100、发行年份、版本(日版/GBA/OLED等)、想换物品等游戏特色字段
  • SwapItem换卡帖(id/user/avatar/offer/want/time/likes/content/place)——8条交换帖,含我提供/我想换/地点/点赞数
  • GuideItem攻略教程(id/name/type/pages/author/likes/downloads/emoji/steps)——5套教程,含步骤数组
  • AccessoryItem外设配件(id/name/series/price/condition/seller/emoji/desc)——9款配件
  • CollectionItem图鉴收藏(id/name/series/owned/total/rate/emoji)——6套图鉴,含已收/总数/进度百分比
  • GameReview点评(id/user/setName/starStr/content)——3条点评
  • ColorPalette配色(bg/card/green/gray/deep/red/yellow/sub/line)——9色配色常量

rarity稀有度字段是游戏藏品的特色设计——0-100数值,通过rarityLabel函数映射为四级(传世级≥95/稀有级≥80/紧俏级≥60/流通级<60),通过rarityColor函数映射为四色(复古红/像素橙/蓝/像素绿),在稀有度柱状图和游戏详情中直接渲染。version版本字段区分日版/GBA/OLED/国行等不同版本,want想换物品字段支持以物换物场景。

五、Tab0 集市交易(双Tab嵌套)

集市页是应用的核心,采用底部Tab+顶部Tab双层嵌套架构。顶部6个分类Tab(全部/主机/掌机/卡带/游戏/外设),每个Tab有独立的布局风格:

全部Tab:Banner+双列瀑布

  • 像素黄渐变Banner:像素游戏节第2季+怀旧专场3天限时+初代神机/绝版卡带标签
  • 全城新上架:双列瀑布布局,左列2件(FC手柄/街机摇杆),右列1件(世嘉MD,浅灰高亮背景),每件含emoji/中文名/英文名/描述/价格/标签

主机Tab:横滑大卡+稀有度柱状图+捡漏榜

  • 初代神机专区:3件横滑大卡(FC红白机/GameBoy初代/超级玛丽初代),像素绿渐变背景160宽,含emoji/名称/英文+年份/价格+稀有度标签
  • 稀有度排行:3根柱状图(92/80/98),第三根超级玛丽用复古红高亮,底部说明"超级玛丽初代以98分稀有度登顶,市面流通不足百套"
  • 今日捡漏榜:3件排行列表,第1名复古红数字,含排名/emoji/名称+稀有度+想换/价格

掌机Tab:攻略时间轴

  • 5套攻略教程时间轴布局(魂斗罗速通指南/塞尔达全收集攻略/宝可梦对战教学/街机游戏合集视频/GBA维修翻新指南),左侧emoji+像素黄竖线连接,右侧卡片含名称/下载数/作者+类型+页数/步骤列表(带序号圆点)/点赞+攻略可下载

卡带Tab:三列格子+交换行情

  • 外设配件三列网格(9款配件,31%宽度),每件含emoji/名称/系列/价格
  • 配件交换行情:偶数ID配件的交换列表,含emoji/名称+品相/描述/价格(像素绿)

游戏Tab:对决卡+侧栏统计

  • 跨世代对决:Switch OLED VS Steam Deck,两张像素绿渐变对决卡中间VS标识
  • 左侧3件游戏列表(Switch OLED/PS5光驱版/Steam Deck),右侧3格统计(12本周游戏成交像素绿/3.2万游戏总交易额像素橙/86%好评率像素绿)

外设Tab:标签云+紧凑列表

  • 收藏标签云:6套图鉴(任天堂主机/掌机系列/FC卡带/GBA游戏/索尼PS系列/格斗游戏),浅绿背景chip
  • 3件紧凑列表(马里奥赛车64/口袋妖怪绿宝石/最终幻想7),第2件浅绿高亮背景,含稀有度彩色标签
  • 底部提示:集齐任天堂全系列可召唤隐藏彩蛋

双层Tab嵌套让用户可以在集市主Tab内快速切换6大品类,每个品类有独立的视觉布局和数据展示方式,避免单一布局的单调感。

六、Tab1 换卡交换

换卡页是复古游戏交易的特色功能——以物换物。由两个层次构成:

1. 统计条+发交换按钮:四格统计(156在交换中像素绿/42今日成交像素橙/98%面交好评像素绿)+右侧发交换按钮(像素橙底,触发发起交换弹框)。

2. 换卡帖列表:8条交换帖卡片,每帖含:

  • 头部:头像emoji+用户名+热度标签(🔥热门≥50/👍热度≥30/🌱新帖<30,通过swapBadge函数动态生成)+时间+地点+右侧⋯菜单(触发下架删除弹框)
  • 交换区:我提供(浅绿背景)⇄ 我想换(浅红背景),左右对称布局
  • 内容:帖文描述
  • 底部:📍地点标签+❤️点赞数

换卡页解决了复古游戏交易中"以物换物"的核心需求——玩家可以用自己的闲置卡带/主机交换心仪的宝贝,通过地点标签支持线下面交,通过热度标签筛选热门交换帖。

七、Tab2 收藏图鉴

图鉴页是收藏进度管理功能。由三个层次构成:

1. 标题+登记按钮:我的游戏图鉴标题+记录每一台心头好的收藏进度+右侧✚登记按钮(像素绿底,触发发布出售弹框复用)。

2. 图鉴进度列表:6套图鉴(任天堂主机/掌机系列/FC卡带/GBA游戏/索尼PS系列/格斗游戏),每套含:

  • 头部:emoji+名称+英文系列名+已收X/总数+右侧进度百分比(通过rateColor函数动态着色:≥55像素绿/≥40像素黄/<40复古红)
  • 进度条:双色进度条(已收部分rateColor色+未收部分浅灰),宽度通过百分比动态计算

3. 图鉴成就墙:4个成就标签(🎖️游戏主机收集狂/🏆卡带原封大亨/💿爆款收藏者/🖱️外设百事通),不同颜色背景。

图鉴页让玩家可以系统化管理自己的收藏进度,通过进度条和百分比直观看到每套图鉴的完成度,通过成就墙增加收藏的趣味性和成就感。

八、Tab3 个人中心

我的页是玩家个人信息管理。由三个层次构成:

1. 会员信息卡:像素绿渐变背景(与头部一致),含👾头像+游戏收藏家阿乐+LV.9骨灰级玩家·信用分986+右侧>箭头+三格统计(38在售游戏像素黄/12求购中像素黄/¥8.6万累计成交额像素黄)。

2. 我的求购清单:3件求购游戏(马里奥赛车64/世嘉MD/街机摇杆),每件含emoji/名称+预算+想换/右侧出价中标签(像素橙底)。

3. 常去面交点:5个地点列表(光谷广场站/江汉路站/洪山广场站/楚河汉街站/线上互换),每个含不同emoji(🚇/🏬/🚌/🏪/📦)+地点名+右侧站点说明。

我的页通过求购清单和常去面交点两个特色功能,将复古游戏交易的线下场景融入个人中心,让玩家可以管理自己的求购需求和常去的线下交易地点。

九、弹框体系

本应用有4种弹框,均通过@State布尔值控制显隐,zIndex通过Stack层叠实现:

1. 发布出售弹框(新增):88%宽76%高,像素绿渐变头部(🎮发布出售+闲置回血神作不愁卖),滚动内容含:要出售的游戏(8款游戏chip选择,选中像素绿底白字)+成色说明(5档chip:全新未拆/仅拆盒/9成新/8成新/有缺件,选中像素橙底白字)+出售价格(−/¥价格/+步进器,步进10元,价格>2000显示"高价好物建议包邮"否则"实惠价更容易出手")+宝贝描述(TextInput输入)+取消/上架出售双按钮。

2. 发起交换弹框(新增):88%宽72%高,像素黄纯色头部(🤝发起交换+用闲置换心头好玩家互助),滚动内容含:我提供(5款游戏chip选择,选中深灰底白字)+我想换可多选(5款游戏chip,选中复古红底白字带✓)+面交地点(5个地点chip,选中像素绿底白字)+安全提示(💡交换双方可自行协商补差价,面交请选择人流密集的公共场所,注意安全)+再想想/发布交换帖双按钮。

3. 下架删除弹框:72%宽居中,🗑️图标+下架这款游戏?+说明文字(下架后买家将无法搜索到这条信息,收藏和留言会一并清空,可重新上架)+留着(像素绿底浅绿背景)/确认下架(复古红底白字)双按钮。

4. 游戏详情弹框:88%宽78%高,像素黄到浅绿渐变头部(emoji+中文名+英文名+标签+稀有度标签),滚动内容含:四格数据(售价复古红/版本像素绿/稀有度动态色/发行年份像素橙)+宝贝描述(描述文字+卖家+星级评分)+卖家想换(🤝+想换物品,浅红背景)+圈友点评(3条点评卡片)+留言问问(像素绿底浅绿背景)/立即购买(复古红底白字)双按钮。

所有弹框均通过Stack层叠+半透明黑色背景(99000000)+居中布局实现,点击背景区域关闭弹框。

十、核心技术特性

1. 双Tab嵌套架构:底部4Tab+集市Tab内部顶部6Tab,通过两个@State(currentBottomTab/currentTopTab)独立控制,if-else链分发到对应的Builder方法,实现双层分类浏览。

2. 14粒子漂浮动效:aboutToAppear生命周期中buildParticles生成14个粒子(🎮/👾/💿/📼/🕹️五种emoji随机,大小12-22px,速度0.6-2.0,透明度0.2-0.6),setInterval每80ms调用driftParticles更新x坐标(超出360重置为-20),通过position绝对定位漂浮在页面上,营造复古街机氛围。aboutToDisappear中clearInterval清理定时器避免内存泄漏。

3. 稀有度四级分级:rarity字段0-100数值,通过rarityLabel映射为四级标签(传世级≥95/稀有级≥80/紧俏级≥60/流通级<60),通过rarityColor映射为四色(复古红/像素橙/蓝/像素绿),在柱状图、游戏详情、紧凑列表中统一渲染,数据驱动UI。

4. 像素绿渐变头部设计:头部、初代神机大卡、发布出售弹框头部、我的页会员卡均使用像素绿#00A25B到复古灰#4A4A4A/深灰#2B2B2B的linearGradient渐变,像素黄#FFD400文字和标签在深色背景上形成强烈对比,营造复古街机感。

5. 以物换物交换帖:换卡页每条帖子采用我提供(浅绿背景)⇄我想换(浅红背景)的对称布局,通过swapBadge函数根据点赞数动态生成热度标签(🔥热门/👍热度/🌱新帖),支持线下面交,解决复古游戏交易中的以物换物需求。

6. 全局纯函数工具集:10+全局纯函数(catColor/catLabel/rarityLabel/rarityColor/tradeBarHeight/rateColor/6个分类筛选函数/swapBadge),将数据到UI的映射逻辑抽离为纯函数,便于复用和维护,符合函数式编程思想。

7. 分类筛选函数:6个函数(retiredSets/mocSets/figSets/techSets/streetSets/classicSets)通过数组切片返回对应分类的3件游戏,cityLeft/cityRight返回全部Tab的双列数据,hotSets返回热门游戏,数据筛选逻辑清晰。

8. 详情数据取值方法:13个detailXxx方法(detailName/detailEng/detailEmoji/detailPrice/detailVersion/detailRarity/detailYear/detailSeller/detailTag/detailStar/detailRating/detailDesc/detailWant)通过遍历GAMES数组查找selectedGameId对应的游戏字段,在详情弹框中调用,避免在Builder中写复杂的查找逻辑。

9. 步进器价格输入:发布出售弹框的价格采用−/¥价格/+步进器设计,步进10元,通过@State sellPrice控制,价格>2000时动态显示"高价好物建议包邮"提示,交互友好。

10. Stack层叠弹框管理:4种弹框通过Stack层叠+@State布尔值控制,半透明黑色背景99000000,点击背景关闭,弹框内容居中,zIndex自动由Stack层叠顺序决定,无需手动管理zIndex。

十一、同类对比

维度 通用二手游戏App 本应用(像素游戏厅)
主题 浅色/红色为主 像素绿+复古灰复古像素风
架构 单Tab或简单分类 双Tab嵌套(底部4+顶部6)
动效 无或简单 14个粒子漂浮动效
稀有度 无或简单星级 0-100数值+四级分级+四色映射
以物换物 无或简单留言 交换帖+我提供⇄我想换对称布局
攻略教程 无或外部链接 5套时间轴布局教程+步骤列表
收藏图鉴 无或简单收藏 6套图鉴+进度条+成就墙
求购清单 3件求购+预算+想换+出价中
常去面交点 5个地点+站点说明
弹框 2-3种 4种(发布出售/发起交换/下架/详情)

十二、完整代码结构总览

1302.ets
├── 数据结构(7个interface)
├── 静态配置(PALETTE配色 + 2个Tab配置 + 2个弹框选项 + 2个图表数据)
├── 静态数据(8个数组:18游戏+8换卡帖+5攻略教程+9外设配件+6图鉴+3点评)
├── 全局纯函数(10+个:catColor/catLabel/rarityLabel/rarityColor/rateColor/6分类筛选/swapBadge)
├── Index入口组件(@Entry @Component)
│   ├── 状态(currentBottomTab/currentTopTab/selectedGameId/4个弹框显隐/出售表单/交换表单/particles粒子)
│   ├── 生命周期(aboutToAppear生成粒子+启动定时器/aboutToDisappear清理定时器)
│   ├── 粒子方法(buildParticles/driftParticles)
│   ├── 详情取值方法(13个detailXxx)
│   ├── 头部Builder
│   ├── 顶部Tab Builder
│   ├── 6个顶部Tab内容Builder(city/retired/moc/fig/tech/street)
│   ├── 集市首页Builder(bazaarContent)
│   ├── 换卡页Builder(swapContent)
│   ├── 图鉴页Builder(collectionContent)
│   ├── 我的页Builder(mineContent)
│   ├── 底部Tab Builder
│   ├── 4种弹框Builder(sellModal/swapModal/deleteModal/detailModal)
│   ├── 交换多选辅助方法(pickedWant/toggleWant)
│   └── build主布局(Stack层叠+Column内容+粒子+4弹框)

十三、开发环境搭建

13.1 环境要求

DevEco Studio 5.0+(支持HarmonyOS ArkTS API 24)、HarmonyOS SDK API 24、Node.js 18+、至少8GB内存。

13.2 安装DevEco Studio

从华为开发者官网下载最新版本,运行安装包,选择安装路径,勾选创建桌面快捷方式,点击安装。

13.3 配置SDK

首次启动后进入File > Settings > HarmonyOS SDK,勾选API 24及以上版本,点击Apply等待下载完成。

13.4 创建项目

选择Create Project > Empty Ability,配置项目名称、包名、保存路径,选择Compile SDK为API 24,点击Finish。

13.5 运行应用

将1302.ets代码替换到entry/src/main/ets/pages/Index.ets,连接HarmonyOS设备或启动模拟器,点击运行按钮预览。

13.6 预览调试

DevEco Studio提供实时预览功能,编辑器右侧打开Previewer面板,支持多设备尺寸预览、深色模式切换、组件树inspect等调试能力。

十四、总结展望

本文完整解析了基于HarmonyOS ArkTS API 24的像素游戏厅应用,从像素绿+复古灰复古配色系统、双Tab嵌套架构、游戏藏品数据模型(含稀有度0-100/版本/想换物品等特色字段)、集市交易六大品类独立布局(全部双列瀑布/主机横滑大卡+稀有度柱状图+捡漏榜/掌机攻略时间轴/卡带三列网格/游戏对决卡+侧栏统计/外设标签云+紧凑列表)、换卡以物换物交换帖、收藏图鉴进度条、个人中心求购清单+常去面交点,到4种弹框体系、14粒子漂浮动效、稀有度四级分级、像素绿渐变头部、全局纯函数工具集、详情数据取值方法,展现了ArkTS在复古游戏二手交易场景下的完整工程实践。

核心价值:

  1. 像素绿+复古灰复古配色:6处linearGradient渐变营造怀旧街机的复古韵味
  2. 双Tab嵌套架构:底部4Tab+顶部6Tab,双层分类浏览体验
  3. 14粒子漂浮动效:setInterval驱动emoji粒子漂浮,aboutToDisappear清理定时器
  4. 稀有度四级分级:0-100数值→四级标签→四色映射,数据驱动UI
  5. 以物换物交换帖:我提供⇄我想换对称布局+热度标签动态生成+线下面交
  6. 收藏图鉴进度管理:6套图鉴+双色进度条+成就墙,收藏系统化
  7. 全局纯函数工具集:10+纯函数抽离数据到UI映射逻辑,代码可维护

未来可扩展:

  • 接入真实游戏数据库,自动识别游戏版本和稀有度,替代手动评级
  • 粒子动效接入设备陀螺仪,随手机倾斜方向漂移,增强沉浸感
  • 稀有度接入真实拍卖数据和市场行情,动态更新稀有度评分
  • 以物换物接入智能匹配算法,根据游戏品类和价值推荐交换对象
  • 图鉴接入NFC扫码登记,扫描游戏卡带NFC标签自动添加到图鉴
  • 接入直播开箱功能,玩家可以直播展示藏品请圈友在线鉴定
  • 求购清单接入推送通知,有匹配游戏时自动提醒玩家

像素游戏厅,让每一张老卡带都找到懂它的玩家,让像素不灭、情怀永续。


附录:完整源码

// ============================================================
// 1302.ets - 像素游戏厅
// 场景:复古游戏机/卡带/掌机/外设的二手交易与收藏社区(像素风)
// 风格:像素绿 #00A25B + 复古灰 #4A4A4A 复古像素风
// 底部Tab:集市 / 换卡 / 图鉴 / 我的
// 顶部Tab:全部 / 主机 / 掌机 / 卡带 / 游戏 / 外设
// 弹框:发布出售(新增) / 发起交换(新增) / 下架(删除) / 游戏详情(详情)
// ============================================================

// ---------------- 配色 ----------------
interface ColorPalette {
  bg: string;
  card: string;
  green: string;
  gray: string;
  deep: string;
  red: string;
  yellow: string;
  sub: string;
  line: string;
}

const PALETTE: ColorPalette = {
  bg: '#F2F5F2',
  card: '#FFFFFF',
  green: '#00A25B',
  gray: '#4A4A4A',
  deep: '#2B2B2B',
  red: '#E8483C',
  yellow: '#FFD400',
  sub: '#8A8A8A',
  line: '#E5E5E5'
};

// ---------------- 通用结构 ----------------
interface TabItem { label: string; icon: string; }
interface ParticleItem { x: number; emoji: string; size: number; speed: number; opacity: number; }

// ---------------- 游戏条目 ----------------
interface GameItem {
  id: number; name: string; eng: string; cat: string; price: number;
  rarity: number; year: number; rating: number; starStr: string; seller: string;
  tag: string; desc: string; want: string; sales: number; emoji: string; version: string;
}

// ---------------- 交换帖 ----------------
interface SwapItem {
  id: number; user: string; avatar: string; offer: string; want: string;
  time: string; likes: number; content: string; place: string;
}

// ---------------- 攻略/教程 ----------------
interface GuideItem {
  id: number; name: string; type: string; pages: number; author: string;
  likes: number; downloads: number; emoji: string; steps: string[];
}

// ---------------- 外设/配件 ----------------
interface AccessoryItem {
  id: number; name: string; series: string; price: number; condition: string;
  seller: string; emoji: string; desc: string;
}

// ---------------- 图鉴收藏 ----------------
interface CollectionItem {
  id: number; name: string; series: string; owned: number; total: number; rate: number; emoji: string;
}

// ---------------- 点评 ----------------
interface GameReview {
  id: number; user: string; setName: string; starStr: string; content: string;
}

// ---------------- Tab 配置 ----------------
const BOTTOM_TABS: TabItem[] = [
  { label: '集市', icon: '🏪' }, { label: '换卡', icon: '🤝' }, { label: '图鉴', icon: '📖' }, { label: '我的', icon: '👾' }
];

const TOP_TABS: TabItem[] = [
  { label: '全部', icon: '🧿' }, { label: '主机', icon: '🕹️' }, { label: '掌机', icon: '🎮' },
  { label: '卡带', icon: '📼' }, { label: '游戏', icon: '💿' }, { label: '外设', icon: '🖱️' }
];

// ---------------- 游戏数据(18款写死) ----------------
const GAMES: GameItem[] = [
  { id: 1, name: 'FC红白机', eng: 'Famicom', cat: 'retired', price: 2800, rarity: 92, year: 1983, rating: 5.0, starStr: '⭐⭐⭐⭐⭐', seller: '老玩家怀旧屋', tag: '初代神机', desc: '原装日版红白机,成色极佳,手柄按键手感完美,红白机玩家的终极信仰。', want: '换 SFC超任', sales: 2, emoji: '🕹️', version: '日版' },
  { id: 2, name: 'GameBoy 初代', eng: 'GameBoy DMG', cat: 'retired', price: 1200, rarity: 80, year: 1989, rating: 4.8, starStr: '⭐⭐⭐⭐✨', seller: '掌机博物馆', tag: '像素神机', desc: '带原装屏幕偏绿滤镜效果,外壳无裂痕,声音正常,童年的回忆。', want: '换 口袋妖怪卡带', sales: 5, emoji: '🎮', version: '灰机' },
  { id: 3, name: '超级玛丽 初代', eng: 'Super Mario Bros', cat: 'retired', price: 3500, rarity: 98, year: 1985, rating: 5.0, starStr: '⭐⭐⭐⭐⭐', seller: '任天堂铁粉', tag: '原封未拆', desc: '最经典的FC游戏卡带,原封未拆,极具收藏价值,游戏卡带界的劳斯莱斯。', want: '换 塞尔达传说', sales: 1, emoji: '🍄', version: '日版卡带' },
  { id: 4, name: '魂斗罗 秘籍教程', eng: 'Contra Cheat', cat: 'moc', price: 29, rarity: 30, year: 2025, rating: 4.9, starStr: '⭐⭐⭐⭐⭐', seller: '速通大神', tag: '上上下下', desc: '所有魂斗罗系列的通关秘籍与速通教程电子版,含隐藏关卡解密。', want: '可换任意游戏', sales: 156, emoji: '💥', version: '电子版' },
  { id: 5, name: '塞尔达传说 缩小帽', eng: 'Minish Cap GBA', cat: 'moc', price: 1500, rarity: 85, year: 2004, rating: 4.9, starStr: '⭐⭐⭐⭐⭐', seller: 'GBA死忠粉', tag: 'GBA神作', desc: 'GBA平台满分神作,卡带存档正常,盒说全,成色极好。', want: '换 黄金太阳', sales: 8, emoji: '⚔️', version: 'GBA' },
  { id: 6, name: 'PS1 游戏机', eng: 'Sony PS1', cat: 'moc', price: 800, rarity: 55, year: 1994, rating: 4.7, starStr: '⭐⭐⭐⭐', seller: '索尼老玩家', tag: '经典主机', desc: '初代PS1,1000型,读盘流畅,送2个原装手柄。', want: '换 PS2', sales: 10, emoji: '💿', version: '日版' },
  { id: 7, name: '宝可梦 金', eng: 'Pokemon Gold', cat: 'fig', price: 600, rarity: 65, year: 1999, rating: 4.8, starStr: '⭐⭐⭐⭐✨', seller: '口袋妖怪博士', tag: '电池存档', desc: '经典GBC卡带,最新换过电池,存档无问题,可传精灵!', want: '换 宝可梦银', sales: 12, emoji: '⚡', version: 'GBC' },
  { id: 8, name: '街霸2 卡带', eng: 'Street Fighter II', cat: 'fig', price: 900, rarity: 70, year: 1992, rating: 4.8, starStr: '⭐⭐⭐⭐✨', seller: '街机厅老板', tag: '超任16位', desc: 'SFC平台经典卡带,格斗游戏的鼻祖,卡带工艺绝佳,无划痕。', want: '换 拳皇94', sales: 6, emoji: '🥊', version: 'SFC' },
  { id: 9, name: 'GBA 游戏机', eng: 'GameBoy Advance', cat: 'fig', price: 650, rarity: 45, year: 2001, rating: 4.6, starStr: '⭐⭐⭐⭐', seller: '掌机铺子', tag: '高亮屏改', desc: '已改装高亮屏幕,带原装充电电池仓,吃灰中,出给喜欢的人。', want: '换 SP版', sales: 15, emoji: '🎮', version: '紫色版' },
  { id: 10, name: 'Switch OLED', eng: 'Nintendo Switch OLED', cat: 'tech', price: 1800, rarity: 40, year: 2021, rating: 4.9, starStr: '⭐⭐⭐⭐⭐', seller: '煮蛋机玩家', tag: '日版全新', desc: '日版OLED,全新未拆,附带原装底座和手柄,可面交。', want: '换 Steam Deck', sales: 22, emoji: '🎮', version: 'OLED' },
  { id: 11, name: 'PS5 光驱版', eng: 'Sony PS5 Disc', cat: 'tech', price: 3200, rarity: 35, year: 2020, rating: 4.9, starStr: '⭐⭐⭐⭐⭐', seller: '次世代主机', tag: '国行现货', desc: '国行全新未拆,保修期长,带原装手柄,性价比极高。', want: '换 XSX', sales: 8, emoji: '🎮', version: '国行' },
  { id: 12, name: 'Steam Deck', eng: 'Valve Steam Deck', cat: 'tech', price: 2800, rarity: 40, year: 2022, rating: 4.7, starStr: '⭐⭐⭐⭐', seller: '掌机破解师', tag: '二手9成新', desc: '64G版,已加装1T固态,贴了钢化膜,成色完美,仅用过几次。', want: '换 笔记本', sales: 14, emoji: '🕹️', version: '美版' },
  { id: 13, name: '马里奥赛车64', eng: 'Mario Kart 64', cat: 'street', price: 450, rarity: 50, year: 1996, rating: 4.8, starStr: '⭐⭐⭐⭐✨', seller: 'N64玩家', tag: '合家欢', desc: 'N64经典卡带,很适合朋友聚会一起玩,原装卡带,读档顺畅。', want: '换 马里奥医生', sales: 18, emoji: '🏎️', version: 'N64' },
  { id: 14, name: '口袋妖怪 绿宝石', eng: 'Pokemon Emerald', cat: 'street', price: 800, rarity: 75, year: 2004, rating: 4.9, starStr: '⭐⭐⭐⭐⭐', seller: '隐藏神兽猎人', tag: '完美存档', desc: 'GBA神作,包含全神兽捕捉存档,可打对战塔,极其珍稀。', want: '换 火红叶绿', sales: 7, emoji: '💚', version: 'GBA' },
  { id: 15, name: '最终幻想7', eng: 'Final Fantasy VII', cat: 'street', price: 1200, rarity: 72, year: 1997, rating: 4.9, starStr: '⭐⭐⭐⭐⭐', seller: 'RPG爱好者', tag: 'PS1神作', desc: '初代PS1的爆款,包含原版3张CD,剧情震撼,堪称里程碑。', want: '换 生化危机', sales: 5, emoji: '🍃', version: 'PS1' },
  { id: 16, name: '世嘉MD 游戏机', eng: 'Sega Mega Drive', cat: 'classic', price: 1000, rarity: 68, year: 1988, rating: 4.7, starStr: '⭐⭐⭐⭐', seller: '世嘉粉丝', tag: '16位音质', desc: '日版初代MD,音质非常棒,附带2个原装手柄和电源。', want: '换 世嘉土星', sales: 4, emoji: '🦔', version: '日版' },
  { id: 17, name: 'FC手柄 一把', eng: 'FC Controller', cat: 'classic', price: 300, rarity: 55, year: 1983, rating: 4.6, starStr: '⭐⭐⭐⭐', seller: '配件交换站', tag: '原装手感', desc: '原装FC手柄,按键微动反应灵敏,适合收藏和替换原手柄。', want: '换 外设', sales: 11, emoji: '🎮', version: '原装' },
  { id: 18, name: '街机摇杆', eng: 'Arcade Stick', cat: 'classic', price: 500, rarity: 48, year: 1995, rating: 4.8, starStr: '⭐⭐⭐⭐✨', seller: '格斗老哥', tag: '三和摇杆', desc: '三和摇杆件,街机厅手感,适用于PC和PS,格斗游戏必备神器。', want: '换 手柄', sales: 9, emoji: '🕹️', version: 'USB' }
];

// ---------------- 交换帖数据(8条写死) ----------------
const SWAPS: SwapItem[] = [
  { id: 1, user: '卡带搬运工', avatar: '📼', offer: 'GBA卡带', want: 'NDS卡带', time: '今天 13:20', likes: 46, content: 'GBA游戏卡带换NDS卡带,可平换,面交地铁站,诚心换。', place: '光谷广场站' },
  { id: 2, user: '怀旧老玩家', avatar: '🕹️', offer: 'FC红白机', want: 'SFC超任', time: '今天 11:05', likes: 38, content: 'FC换SFC,都是老机器,成色好,可补差价,互换补差价。', place: '江汉路站' },
  { id: 3, user: '掌机收藏家', avatar: '🎮', offer: 'GBA一台', want: 'GBA SP一台', time: '昨天 18:42', likes: 61, content: 'GBA换SP,都是老掌机,补差价换,成色很新,送保护壳。', place: '洪山广场站' },
  { id: 4, user: '怀旧理论家', avatar: '💡', offer: '游戏攻略手册', want: '任意游戏卡带', time: '昨天 15:30', likes: 29, content: '攻略秘籍电子版免费换,换取任意有缘的实体卡带,学生党优先。', place: '线上交换' },
  { id: 5, user: '主机拆迁户', avatar: '🖱️', offer: 'PS1主机', want: 'PS2主机', time: '前天 20:15', likes: 22, content: 'PS1换PS2,可补差价,老机换老机,附送2个手柄。', place: '楚河汉街站' },
  { id: 6, user: '口袋妖怪大师', avatar: '⚡', offer: '宝可梦金', want: '宝可梦银', time: '前天 09:50', likes: 41, content: '金换银,都是GBC卡带,互换吧,凑成一对。', place: '线上互换' },
  { id: 7, user: '速通玩家阿严', avatar: '💥', offer: '街霸2卡带', want: '拳皇94', time: '3天前 22:08', likes: 55, content: '老格斗换老格斗,情怀无价,可补差价,面交即可。', place: '武昌火车站' },
  { id: 8, user: '学生党小周', avatar: '🎒', offer: '掌机保护壳', want: '任意游戏', time: '4天前 14:26', likes: 17, content: '全新掌机保护壳换任意游戏,学生党不容易,大家帮帮忙。', place: '线上交换' }
];

// ---------------- 攻略/教程数据(5条写死) ----------------
const GUIDES: GuideItem[] = [
  { id: 1, name: '魂斗罗速通指南', type: '秘籍', pages: 12, author: '速通大神', likes: 342, downloads: 2100, emoji: '💥', steps: ['上上下下左右BA讲解 1-3页', '隐藏跳跃点技巧 4-8页', '无伤通关秘诀 9-12页'] },
  { id: 2, name: '塞尔达全收集攻略', type: 'RPG', pages: 88, author: '海拉鲁勇士', likes: 276, downloads: 1580, emoji: '⚔️', steps: ['地图探索技巧 1-20页', '迷宫解密指南 21-60页', '终极装备获取 61-88页'] },
  { id: 3, name: '宝可梦对战教学', type: '对战', pages: 45, author: '神奇宝贝联盟', likes: 415, downloads: 3300, emoji: '⚡', steps: ['属性克制表 1-10页', '性格与努力值 11-26页', '经典配招指南 27-45页'] },
  { id: 4, name: '街机游戏合集视频', type: '视频', pages: 30, author: '老街机厅', likes: 198, downloads: 1260, emoji: '🕹️', steps: ['街霸高手对战视频 1-10页', '拳皇连招教学 11-20页', '经典游戏合集试玩 21-30页'] },
  { id: 5, name: 'GBA维修翻新指南', type: '硬件', pages: 56, author: '掌机修理匠', likes: 233, downloads: 1420, emoji: '🔧', steps: ['拆机注意事项 1-10页', '屏幕更换方法 11-30页', '外壳按键翻新 31-56页'] }
];

// ---------------- 外设/配件数据(9条写死) ----------------
const ACCESSORIES: AccessoryItem[] = [
  { id: 1, name: 'GBA保护壳', series: '透明', price: 30, condition: '全新', seller: '掌机配件铺', emoji: '🛡️', desc: '防摔耐磨,不影响手感' },
  { id: 2, name: 'FC副手柄', series: '原装', price: 100, condition: '8成新', seller: '老玩家仓库', emoji: '🎮', desc: '原装手柄,按键灵敏无粘连' },
  { id: 3, name: 'HDMI转换线', series: '通用', price: 80, condition: '9成新', seller: '电视玩家', emoji: '🔌', desc: '适用于老主机转接电视' },
  { id: 4, name: '卡带防尘收纳盒', series: '大容量', price: 40, condition: '全新', seller: '收纳达人', emoji: '📦', desc: '抽屉式设计,防尘防潮' },
  { id: 5, name: '高亮屏幕改装件', series: 'GBA', price: 200, condition: '全新', seller: '硬件极客', emoji: '💡', desc: '无损安装,点亮老机的灵魂' },
  { id: 6, name: '摇杆替换胶垫', series: '街机', price: 15, condition: '全新', seller: '街机配件', emoji: '🕹️', desc: '提升摇杆回弹手感' },
  { id: 7, name: '主机专用电源适配器', series: 'PS1', price: 60, condition: '9成新', seller: '电源贩子', emoji: '🔋', desc: '稳定电压,保护主机主板' },
  { id: 8, name: '复古游戏电视', series: 'CRT', price: 500, condition: '7成新', seller: '旧货市场', emoji: '📺', desc: '经典显像管电视,还原老游戏画质' },
  { id: 9, name: '游戏卡带电池套装', series: '纽扣', price: 25, condition: '全新', seller: '维修大佬', emoji: '🔩', desc: '适用GBC/GB卡带换存档电池' }
];

// ---------------- 图鉴收藏数据(6条写死) ----------------
const COLLECTIONS: CollectionItem[] = [
  { id: 1, name: '任天堂主机', series: 'Nintendo', owned: 5, total: 12, rate: 42, emoji: '🍄' },
  { id: 2, name: '掌机系列', series: 'Handheld', owned: 6, total: 14, rate: 43, emoji: '🎮' },
  { id: 3, name: 'FC卡带', series: 'Famicom', owned: 20, total: 50, rate: 40, emoji: '📼' },
  { id: 4, name: 'GBA游戏', series: 'GameBoy', owned: 8, total: 20, rate: 40, emoji: '🔋' },
  { id: 5, name: '索尼PS系列', series: 'PlayStation', owned: 3, total: 10, rate: 30, emoji: '💿' },
  { id: 6, name: '格斗游戏', series: 'Fighting', owned: 4, total: 8, rate: 50, emoji: '🥊' }
];

// ---------------- 点评数据(3条写死) ----------------
const GAME_REVIEWS: GameReview[] = [
  { id: 1, user: 'FC评测员', setName: 'FC红白机', starStr: '⭐⭐⭐⭐⭐', content: '当年最神的主机,按键反弹力极好,色彩鲜艳,童年的回忆,收藏必备!' },
  { id: 2, user: '掌机技术控', setName: 'GBA保护壳', starStr: '⭐⭐⭐⭐✨', content: '材质很好,透光性极佳,套上去完全不臃肿,瞬间提升质感,推荐。' },
  { id: 3, user: '速通玩家', setName: '魂斗罗秘籍', starStr: '⭐⭐⭐⭐⭐', content: '解析得非常透彻,不仅有手法技巧,还能看懂底层逻辑,让新手也能速通!' }
];

// ---------------- 全城周交易量图表数据 ----------------
const TRADE_LABELS: string[] = ['周一', '周二', '周三', '周四', '周五', '周六', '周日'];
const TRADE_BARS: number[] = [76, 54, 62, 48, 112, 176, 158];

// ---------------- 弹框选项 ----------------
const CONDITION_OPTIONS: string[] = ['全新未拆', '仅拆盒', '9成新', '8成新', '有缺件'];
const PLACES: string[] = ['光谷广场站', '江汉路站', '洪山广场站', '楚河汉街站', '线上互换'];

// ---------------- 全局纯函数 ----------------
function catColor(cat: string): string {
  if (cat === 'retired') return '#E8483C';
  if (cat === 'moc') return '#7C4DFF';
  if (cat === 'fig') return '#00A25B';
  if (cat === 'tech') return '#E86A5B';
  if (cat === 'street') return '#1E88E5';
  return '#4A4A4A';
}

function catLabel(cat: string): string {
  if (cat === 'retired') return '初代神机';
  if (cat === 'moc') return '攻略秘籍';
  if (cat === 'fig') return '卡带交易';
  if (cat === 'tech') return '次世代';
  if (cat === 'street') return '经典收藏';
  return '怀旧配件';
}

function rarityLabel(r: number): string {
  if (r >= 95) return '传世级';
  if (r >= 80) return '稀有级';
  if (r >= 60) return '紧俏级';
  return '流通级';
}

function rarityColor(r: number): string {
  if (r >= 95) return '#E8483C';
  if (r >= 80) return '#FF8A00';
  if (r >= 60) return '#1E88E5';
  return '#00A25B';
}

function tradeBarHeight(v: number): string {
  return Math.round(v / 176 * 96).toString() + 'vp';
}

function rateColor(r: number): string {
  if (r >= 55) return '#00A25B';
  if (r >= 40) return '#FFD400';
  return '#E8483C';
}

function retiredSets(): GameItem[] { return [GAMES[0], GAMES[1], GAMES[2]]; }
function mocSets(): GameItem[] { return [GAMES[3], GAMES[4], GAMES[5]]; }
function figSets(): GameItem[] { return [GAMES[6], GAMES[7], GAMES[8]]; }
function techSets(): GameItem[] { return [GAMES[9], GAMES[10], GAMES[11]]; }
function streetSets(): GameItem[] { return [GAMES[12], GAMES[13], GAMES[14]]; }
function classicSets(): GameItem[] { return [GAMES[15], GAMES[16], GAMES[17]]; }
function cityLeft(): GameItem[] { return [GAMES[16], GAMES[17]]; }
function cityRight(): GameItem[] { return [GAMES[15]]; }
function hotSets(): GameItem[] { return [GAMES[3], GAMES[5], GAMES[16], GAMES[17], GAMES[9]]; }

function swapBadge(likes: number): string {
  if (likes >= 50) return '🔥热门';
  if (likes >= 30) return '👍热度';
  return '🌱新帖';
}

// ============================================================
// 主页面
// ============================================================
@Entry
@Component
struct Index {
  @State currentBottomTab: number = 0;
  @State currentTopTab: number = 0;
  @State selectedGameId: number = 1;
  @State showSellModal: boolean = false;
  @State showSwapModal: boolean = false;
  @State showDeleteModal: boolean = false;
  @State showDetailModal: boolean = false;
  @State sellGameIdx: number = 0;
  @State sellCondIdx: number = 2;
  @State sellPrice: number = 100;
  @State sellWords: string = '';
  @State swapOfferIdx: number = 0;
  @State swapWantIdx: number = 1;
  @State swapPlaceIdx: number = 0;
  @State particles: ParticleItem[] = [];
  private timerId: number = -1;

  aboutToAppear(): void {
    this.buildParticles();
    this.timerId = setInterval(() => { this.driftParticles(); }, 80);
  }

  aboutToDisappear(): void {
    if (this.timerId !== -1) { clearInterval(this.timerId); this.timerId = -1; }
  }

  buildParticles(): void {
    const emojis: string[] = ['🎮', '👾', '💿', '📼', '🕹️'];
    const list: ParticleItem[] = [];
    for (let i = 0; i < 14; i++) {
      list.push({ x: Math.random() * 340, emoji: emojis[i % emojis.length], size: 12 + Math.random() * 10, speed: 0.6 + Math.random() * 1.4, opacity: 0.2 + Math.random() * 0.4 });
    }
    this.particles = list;
  }

  driftParticles(): void {
    for (let i = 0; i < this.particles.length; i++) {
      this.particles[i].x += this.particles[i].speed;
      if (this.particles[i].x > 360) { this.particles[i].x = -20; }
    }
    this.particles = this.particles.slice();
  }

  // 详情弹框数据取值
  detailName(): string { for (let i = 0; i < GAMES.length; i++) if (GAMES[i].id === this.selectedGameId) return GAMES[i].name; return ''; }
  detailEng(): string { for (let i = 0; i < GAMES.length; i++) if (GAMES[i].id === this.selectedGameId) return GAMES[i].eng; return ''; }
  detailEmoji(): string { for (let i = 0; i < GAMES.length; i++) if (GAMES[i].id === this.selectedGameId) return GAMES[i].emoji; return '🎮'; }
  detailPrice(): string { for (let i = 0; i < GAMES.length; i++) if (GAMES[i].id === this.selectedGameId) return '¥' + GAMES[i].price.toString(); return ''; }
  detailVersion(): string { for (let i = 0; i < GAMES.length; i++) if (GAMES[i].id === this.selectedGameId) return GAMES[i].version; return ''; }
  detailRarity(): string { for (let i = 0; i < GAMES.length; i++) if (GAMES[i].id === this.selectedGameId) return GAMES[i].rarity.toString(); return ''; }
  detailYear(): string { for (let i = 0; i < GAMES.length; i++) if (GAMES[i].id === this.selectedGameId) return GAMES[i].year.toString(); return ''; }
  detailSeller(): string { for (let i = 0; i < GAMES.length; i++) if (GAMES[i].id === this.selectedGameId) return GAMES[i].seller; return ''; }
  detailTag(): string { for (let i = 0; i < GAMES.length; i++) if (GAMES[i].id === this.selectedGameId) return GAMES[i].tag; return ''; }
  detailStar(): string { for (let i = 0; i < GAMES.length; i++) if (GAMES[i].id === this.selectedGameId) return GAMES[i].starStr; return ''; }
  detailRating(): string { for (let i = 0; i < GAMES.length; i++) if (GAMES[i].id === this.selectedGameId) return GAMES[i].rating.toFixed(1) + '分'; return ''; }
  detailDesc(): string { for (let i = 0; i < GAMES.length; i++) if (GAMES[i].id === this.selectedGameId) return GAMES[i].desc; return ''; }
  detailWant(): string { for (let i = 0; i < GAMES.length; i++) if (GAMES[i].id === this.selectedGameId) return GAMES[i].want; return ''; }

  // ---------------- 头部 ----------------
  @Builder
  headerBuilder() {
    Column() {
      Row() {
        Column() {
          Text('👾 像素游戏厅').fontSize(22).fontWeight(FontWeight.Bold).fontColor('#FFFFFF')
          Text('回血 · 换机 · 换卡带').fontSize(11).fontColor('#A8E6CF').margin({ top: 3 })
        }.alignItems(HorizontalAlign.Start).layoutWeight(1)
        Row({ space: 14 }) {
          Text('🔎').fontSize(20)
          Text('📦').fontSize(20)
          Column() {
            Text('🎒').fontSize(20)
            Text('3').fontSize(9).fontColor('#00A25B').backgroundColor('#FFFFFF').borderRadius(6).padding({ left: 4, right: 4 }).margin({ top: -6 })
          }.alignItems(HorizontalAlign.End)
        }
      }.width('100%').padding({ left: 16, right: 16, top: 14, bottom: 10 })

      Row({ space: 8 }) {
        Text('🔍 搜索:红白机 / 卡带 / 攻略').fontSize(12).fontColor('#B8DFC8').layoutWeight(1)
        Text('🧰 我的求购').fontSize(11).fontColor('#00A25B').backgroundColor('#FFFFFF').borderRadius(10).padding({ left: 10, right: 10, top: 4, bottom: 4 })
      }.width('100%').padding({ left: 16, right: 16, bottom: 12 })
    }
    .linearGradient({ angle: 135, colors: [['#00A25B', 0], ['#4A4A4A', 1]] })
    .borderRadius({ bottomLeft: 18, bottomRight: 18 })
  }

  // ---------------- 顶部Tab ----------------
  @Builder
  topTabsBuilder() {
    Row() {
      ForEach(TOP_TABS, (t: TabItem, idx: number) => {
        Column() {
          Text(t.icon).fontSize(17)
          Text(t.label).fontSize(12).fontColor(this.currentTopTab === idx ? '#00A25B' : '#8A8A8A').fontWeight(this.currentTopTab === idx ? FontWeight.Bold : FontWeight.Normal).margin({ top: 2 })
          if (this.currentTopTab === idx) {
            Divider().width(16).strokeWidth(3).color('#FFD400').borderRadius(2).margin({ top: 4 })
          } else {
            Divider().width(16).strokeWidth(3).color('#F2F5F2').borderRadius(2).margin({ top: 4 })
          }
        }.layoutWeight(1).alignItems(HorizontalAlign.Center).padding({ top: 10, bottom: 6 }).onClick(() => { this.currentTopTab = idx; })
      }, (t: TabItem, idx: number) => 'top' + idx.toString() + t.label)
    }.width('100%').backgroundColor('#FFFFFF').borderRadius(14).margin({ top: 10 })
  }

  // ---------------- 全部Tab:banner + 双列瀑布 ----------------
  @Builder
  cityContent() {
    Column({ space: 12 }) {
      Column() {
        Text('👾 像素游戏节 · 第2季').fontSize(18).fontWeight(FontWeight.Bold).fontColor('#2B2B2B')
        Text('怀旧专场 3天限时 · 卖家免服务费').fontSize(12).fontColor('#5B6B7F').margin({ top: 6 })
        Row({ space: 10 }) {
          Text('🏆 初代神机').fontSize(11).fontColor('#2B2B2B').backgroundColor('#FFFFFF').borderRadius(12).padding({ left: 10, right: 10, top: 4, bottom: 4 })
          Text('📼 绝版卡带').fontSize(11).fontColor('#2B2B2B').backgroundColor('#FFFFFF').borderRadius(12).padding({ left: 10, right: 10, top: 4, bottom: 4 })
        }.margin({ top: 10 })
      }.width('100%').padding(18).alignItems(HorizontalAlign.Start).linearGradient({ angle: 120, colors: [['#FFD400', 0], ['#FFB300', 1]] }).borderRadius(16)

      Text('✨ 全城新上架').fontSize(15).fontWeight(FontWeight.Bold).fontColor('#2B2B2B').width('100%')

      Row({ space: 10 }) {
        Column({ space: 10 }) {
          ForEach(cityLeft(), (t: GameItem) => {
            Column() {
              Text(t.emoji).fontSize(34).margin({ top: 16 })
              Text(t.name).fontSize(14).fontWeight(FontWeight.Bold).fontColor('#2B2B2B').margin({ top: 8 })
              Text(t.eng).fontSize(9).fontColor('#8A8A8A').margin({ top: 2 })
              Text(t.desc).fontSize(11).fontColor('#8A8A8A').margin({ top: 8 }).maxLines(3).textOverflow({ overflow: TextOverflow.Ellipsis })
              Row({ space: 6 }) {
                Text('¥' + t.price.toString()).fontSize(15).fontWeight(FontWeight.Bold).fontColor('#E8483C')
                Text(t.tag).fontSize(9).fontColor('#00A25B').backgroundColor('#DFF2E7').borderRadius(8).padding({ left: 6, right: 6, top: 2, bottom: 2 })
              }.margin({ top: 10, bottom: 14 })
            }.width('100%').backgroundColor('#FFFFFF').borderRadius(14).alignItems(HorizontalAlign.Start).padding({ left: 14, right: 14 })
            .onClick(() => { this.selectedGameId = t.id; this.showDetailModal = true; })
          }, (t: GameItem) => 'cl' + t.id.toString())
        }.layoutWeight(1)

        Column({ space: 10 }) {
          ForEach(cityRight(), (t: GameItem) => {
            Column() {
              Text(t.emoji).fontSize(34).margin({ top: 24 })
              Text(t.name).fontSize(14).fontWeight(FontWeight.Bold).fontColor('#2B2B2B').margin({ top: 8 })
              Text(t.eng).fontSize(9).fontColor('#8A8A8A').margin({ top: 2 })
              Text(t.desc).fontSize(11).fontColor('#8A8A8A').margin({ top: 10 }).maxLines(4).textOverflow({ overflow: TextOverflow.Ellipsis })
              Row({ space: 6 }) {
                Text('¥' + t.price.toString()).fontSize(15).fontWeight(FontWeight.Bold).fontColor('#E8483C')
                Text(t.starStr).fontSize(10)
              }.margin({ top: 12, bottom: 20 })
            }.width('100%').backgroundColor('#F2F2F2').borderRadius(14).alignItems(HorizontalAlign.Start).padding({ left: 14, right: 14 })
            .onClick(() => { this.selectedGameId = t.id; this.showDetailModal = true; })
          }, (t: GameItem) => 'cr' + t.id.toString())
        }.layoutWeight(1)
      }.width('100%').alignItems(VerticalAlign.Top)
    }.width('100%').padding({ left: 14, right: 14, top: 10, bottom: 16 })
  }

  // ---------------- 主机Tab:横滑大卡 + 稀有度柱状图 + 捡漏榜 ----------------
  @Builder
  retiredContent() {
    Column({ space: 14 }) {
      Text('🏆 初代神机专区').fontSize(15).fontWeight(FontWeight.Bold).fontColor('#2B2B2B').width('100%')
      Scroll() {
        Row({ space: 12 }) {
          ForEach(retiredSets(), (t: GameItem) => {
            Column() {
              Text(t.emoji).fontSize(40).margin({ top: 18 })
              Text(t.name).fontSize(15).fontWeight(FontWeight.Bold).fontColor('#FFFFFF').margin({ top: 8 })
              Text(t.eng + ' · ' + t.year.toString() + '年').fontSize(9).fontColor('#B8DFC8').margin({ top: 4 })
              Row({ space: 6 }) {
                Text('¥' + t.price.toString()).fontSize(16).fontWeight(FontWeight.Bold).fontColor('#FFD400')
                Text(rarityLabel(t.rarity)).fontSize(10).fontColor('#2B2B2B').backgroundColor('#FFD400').borderRadius(8).padding({ left: 6, right: 6, top: 2, bottom: 2 })
              }.margin({ top: 10, bottom: 18 })
            }.width(160).linearGradient({ angle: 160, colors: [['#00A25B', 0], ['#2B2B2B', 1]] }).borderRadius(16).alignItems(HorizontalAlign.Center)
            .onClick(() => { this.selectedGameId = t.id; this.showDetailModal = true; })
          }, (t: GameItem) => 'rt' + t.id.toString())
        }.padding({ left: 14, right: 14 })
      }.scrollable(ScrollDirection.Horizontal).scrollBar(BarState.Off).width('100%')

      Column() {
        Text('📈 稀有度排行').fontSize(13).fontWeight(FontWeight.Bold).fontColor('#2B2B2B').width('100%')
        Row({ space: 6 }) {
          ForEach(retiredSets(), (t: GameItem, i: number) => {
            Column({ space: 5 }) {
              Text(t.rarity.toString()).fontSize(9).fontColor('#00A25B')
              Column().width(34).height((t.rarity).toString() + 'vp').backgroundColor(i === 2 ? '#E8483C' : '#00A25B').borderRadius({ topLeft: 5, topRight: 5 })
              Text(t.year.toString() + '年').fontSize(9).fontColor('#8A8A8A')
            }.alignItems(HorizontalAlign.Center).layoutWeight(1)
          }, (t: GameItem, i: number) => 'rb' + i.toString() + t.id.toString())
        }.width('100%').justifyContent(FlexAlign.Center).alignItems(VerticalAlign.Bottom).padding({ top: 12 })
        Text('超级玛丽初代以98分稀有度登顶,市面流通不足百套').fontSize(10).fontColor('#8A8A8A').margin({ top: 8 })
      }.width('100%').backgroundColor('#FFFFFF').borderRadius(14).padding(14).margin({ left: 14, right: 14 })

      Column() {
        Text('🕵️ 今日捡漏榜').fontSize(14).fontWeight(FontWeight.Bold).fontColor('#2B2B2B').width('100%').margin({ bottom: 8 })
        ForEach(retiredSets(), (t: GameItem, i: number) => {
          Row({ space: 10 }) {
            Text((i + 1).toString()).fontSize(14).fontWeight(FontWeight.Bold).fontColor(i === 0 ? '#E8483C' : '#8A8A8A').width(20)
            Text(t.emoji).fontSize(18)
            Column() {
              Text(t.name).fontSize(13).fontWeight(FontWeight.Bold).fontColor('#2B2B2B')
              Text(rarityLabel(t.rarity) + ' · ' + t.want).fontSize(10).fontColor('#8A8A8A').margin({ top: 2 })
            }.alignItems(HorizontalAlign.Start).layoutWeight(1)
            Text('¥' + t.price.toString()).fontSize(13).fontWeight(FontWeight.Bold).fontColor('#E8483C')
          }.width('100%').padding({ top: 8, bottom: 8 }).onClick(() => { this.selectedGameId = t.id; this.showDetailModal = true; })
        }, (t: GameItem, i: number) => 'pck' + i.toString() + t.id.toString())
      }.width('100%').backgroundColor('#FFFFFF').borderRadius(14).padding(14).margin({ left: 14, right: 14, bottom: 16 })
    }.width('100%').alignItems(HorizontalAlign.Start).padding({ top: 10 })
  }

  // ---------------- 掌机Tab:攻略时间轴 ----------------
  @Builder
  mocContent() {
    Column({ space: 0 }) {
      Text('📖 游戏攻略 · 通关秘籍').fontSize(15).fontWeight(FontWeight.Bold).fontColor('#2B2B2B').width('100%').margin({ top: 10, bottom: 12 })
      ForEach(GUIDES, (m: GuideItem, i: number) => {
        Row({ space: 12 }) {
          Column({ space: 4 }) {
            Text(m.emoji).fontSize(20)
            if (i < GUIDES.length - 1) {
              Column().width(2).layoutWeight(1).backgroundColor('#FFD400').margin({ top: 4 })
            }
          }.width(40).alignItems(HorizontalAlign.Center)
          Column({ space: 6 }) {
            Row({ space: 8 }) {
              Text(m.name).fontSize(14).fontWeight(FontWeight.Bold).fontColor('#2B2B2B').layoutWeight(1)
              Text('⬇ ' + m.downloads.toString()).fontSize(10).fontColor('#00A25B')
            }.width('100%')
            Text('by ' + m.author + ' · ' + m.type + ' · ' + m.pages.toString() + '页').fontSize(10).fontColor('#8A8A8A')
            Column({ space: 5 }) {
              ForEach(m.steps, (s: string, si: number) => {
                Row({ space: 8 }) {
                  Text((si + 1).toString()).fontSize(9).fontWeight(FontWeight.Bold).fontColor('#2B2B2B').backgroundColor('#F2F5F2').borderRadius(9).width(18).height(18).textAlign(TextAlign.Center)
                  Text(s).fontSize(10).fontColor('#4A5A6E').layoutWeight(1)
                }.width('100%')
              }, (s: string, si: number) => 'ms' + si.toString() + m.id.toString())
            }.width('100%').backgroundColor('#F2F5F2').borderRadius(10).padding(10)
            Row({ space: 8 }) {
              Text('❤️ ' + m.likes.toString()).fontSize(10).fontColor('#E8483C')
              Text(m.emoji + ' 攻略可下载').fontSize(10).fontColor('#00A25B').layoutWeight(1).textAlign(TextAlign.End)
            }.width('100%')
          }.layoutWeight(1).backgroundColor(i === 1 ? '#FFF8DC' : '#FFFFFF').borderRadius(14).padding(12).margin({ bottom: 14 })
        }.width('100%').alignItems(VerticalAlign.Top)
      }, (m: GuideItem, i: number) => 'moc' + i.toString() + m.id.toString())
    }.width('100%').padding({ left: 14, right: 14, bottom: 16 })
  }

  // ---------------- 卡带Tab:三列格子 + 交换建议 ----------------
  @Builder
  figContent() {
    Column({ space: 14 }) {
      Text('📼 卡带交易 · 存取记忆').fontSize(15).fontWeight(FontWeight.Bold).fontColor('#2B2B2B').width('100%')
      Flex({ wrap: FlexWrap.Wrap, justifyContent: FlexAlign.SpaceBetween }) {
        ForEach(ACCESSORIES, (f: AccessoryItem) => {
          Column() {
            Text(f.emoji).fontSize(26).margin({ top: 12 })
            Text(f.name).fontSize(11).fontWeight(FontWeight.Bold).fontColor('#2B2B2B').margin({ top: 6 }).maxLines(1)
            Text(f.series).fontSize(8).fontColor('#8A8A8A').margin({ top: 2 })
            Text('¥' + f.price.toString()).fontSize(13).fontWeight(FontWeight.Bold).fontColor('#E8483C').margin({ top: 4, bottom: 12 })
          }.width('31%').backgroundColor('#FFFFFF').borderRadius(12).alignItems(HorizontalAlign.Center).margin({ bottom: 8 })
          .onClick(() => { this.selectedGameId = 7 + f.id % 3; this.showDetailModal = true; })
        }, (f: AccessoryItem) => 'fg' + f.id.toString())
      }.width('100%')

      Column() {
        Text('🤝 配件交换行情').fontSize(14).fontWeight(FontWeight.Bold).fontColor('#2B2B2B').width('100%').margin({ bottom: 6 })
        ForEach(ACCESSORIES, (f: AccessoryItem) => {
          if (f.id % 2 === 0) {
            Row({ space: 10 }) {
              Text(f.emoji).fontSize(20)
              Column({ space: 2 }) {
                Text(f.name + ' · ' + f.condition).fontSize(12).fontWeight(FontWeight.Bold).fontColor('#2B2B2B')
                Text(f.desc).fontSize(10).fontColor('#8A8A8A')
              }.alignItems(HorizontalAlign.Start).layoutWeight(1)
              Text('¥' + f.price.toString()).fontSize(12).fontWeight(FontWeight.Bold).fontColor('#00A25B')
            }.width('100%').padding({ top: 8, bottom: 8 })
          }
        }, (f: AccessoryItem) => 'fgx' + f.id.toString())
      }.width('100%').backgroundColor('#FFFFFF').borderRadius(14).padding(14)
    }.width('100%').padding({ left: 14, right: 14, top: 10, bottom: 16 })
  }

  // ---------------- 游戏Tab:对决卡 + 侧栏统计 ----------------
  @Builder
  techContent() {
    Column({ space: 14 }) {
      Text('💿 游戏对决 · 跨世代').fontSize(15).fontWeight(FontWeight.Bold).fontColor('#2B2B2B').width('100%')
      Row({ space: 10 }) {
        Column() {
          Text('🎮').fontSize(34).margin({ top: 14 })
          Text('Switch OLED').fontSize(13).fontWeight(FontWeight.Bold).fontColor('#FFFFFF').margin({ top: 6 })
          Text('2021年 · 现价¥1800').fontSize(10).fontColor('#B8DFC8').margin({ top: 4, bottom: 14 })
        }.layoutWeight(1).linearGradient({ angle: 150, colors: [['#00A25B', 0], ['#2B2B2B', 1]] }).borderRadius(14).alignItems(HorizontalAlign.Center)
        Column() {
          Text('VS').fontSize(18).fontWeight(FontWeight.Bold).fontColor('#00A25B')
          Text('本周').fontSize(9).fontColor('#8A8A8A')
        }.alignItems(HorizontalAlign.Center)
        Column() {
          Text('🕹️').fontSize(34).margin({ top: 14 })
          Text('Steam Deck').fontSize(13).fontWeight(FontWeight.Bold).fontColor('#FFFFFF').margin({ top: 6 })
          Text('2022年 · 现价¥2800').fontSize(10).fontColor('#B8DFC8').margin({ top: 4, bottom: 14 })
        }.layoutWeight(1).linearGradient({ angle: 150, colors: [['#8A8A8A', 0], ['#2B2B2B', 1]] }).borderRadius(14).alignItems(HorizontalAlign.Center)
      }.width('100%')

      Row({ space: 10 }) {
        Column({ space: 10 }) {
          ForEach(techSets(), (t: GameItem) => {
            Row({ space: 10 }) {
              Text(t.emoji).fontSize(22)
              Column({ space: 2 }) {
                Text(t.name).fontSize(12).fontWeight(FontWeight.Bold).fontColor('#2B2B2B')
                Text(t.tag + ' · ' + t.version).fontSize(10).fontColor('#8A8A8A')
              }.alignItems(HorizontalAlign.Start).layoutWeight(1)
              Text('¥' + t.price.toString()).fontSize(12).fontWeight(FontWeight.Bold).fontColor('#E8483C')
            }.width('100%').backgroundColor('#FFFFFF').borderRadius(12).padding(12).onClick(() => { this.selectedGameId = t.id; this.showDetailModal = true; })
          }, (t: GameItem) => 'tc' + t.id.toString())
        }.layoutWeight(1)
        Column({ space: 10 }) {
          Column({ space: 4 }) {
            Text('12').fontSize(18).fontWeight(FontWeight.Bold).fontColor('#00A25B')
            Text('本周游戏成交').fontSize(9).fontColor('#8A8A8A')
          }.width('100%').backgroundColor('#DFF2E7').borderRadius(12).padding({ top: 10, bottom: 10 }).alignItems(HorizontalAlign.Center)
          Column({ space: 4 }) {
            Text('3.2万').fontSize(18).fontWeight(FontWeight.Bold).fontColor('#FF8A00')
            Text('游戏总交易额').fontSize(9).fontColor('#8A8A8A')
          }.width('100%').backgroundColor('#FFF8DC').borderRadius(12).padding({ top: 10, bottom: 10 }).alignItems(HorizontalAlign.Center)
          Column({ space: 4 }) {
            Text('86%').fontSize(18).fontWeight(FontWeight.Bold).fontColor('#00A25B')
            Text('好评率').fontSize(9).fontColor('#8A8A8A')
          }.width('100%').backgroundColor('#FFFFFF').borderRadius(12).padding({ top: 10, bottom: 10 }).alignItems(HorizontalAlign.Center)
        }.width(86)
      }.width('100%').alignItems(VerticalAlign.Top)
    }.width('100%').padding({ left: 14, right: 14, top: 10, bottom: 16 })
  }

  // ---------------- 外设Tab:标签云 + 紧凑列表 ----------------
  @Builder
  streetContent() {
    Column({ space: 14 }) {
      Text('🖱️ 外设收藏 · 手感加分').fontSize(15).fontWeight(FontWeight.Bold).fontColor('#2B2B2B').width('100%')
      Flex({ wrap: FlexWrap.Wrap, justifyContent: FlexAlign.Start }) {
        ForEach(COLLECTIONS, (c: CollectionItem) => {
          Text(c.emoji + ' ' + c.name + ' ' + c.owned.toString() + '/' + c.total.toString()).fontSize(11).fontColor('#2B2B2B').backgroundColor('#DFF2E7').borderRadius(12).padding({ left: 10, right: 10, top: 6, bottom: 6 }).margin(4)
        }, (c: CollectionItem) => 'ccoll' + c.id.toString())
      }.width('100%')

      ForEach(streetSets(), (t: GameItem) => {
        Row({ space: 12 }) {
          Text(t.emoji).fontSize(24)
          Column({ space: 2 }) {
            Row({ space: 6 }) {
              Text(t.name).fontSize(13).fontWeight(FontWeight.Bold).fontColor('#2B2B2B')
              Text(rarityLabel(t.rarity)).fontSize(8).fontColor('#FFFFFF').backgroundColor(rarityColor(t.rarity)).borderRadius(6).padding({ left: 5, right: 5, top: 1, bottom: 1 })
            }
            Text(t.desc).fontSize(10).fontColor('#8A8A8A').maxLines(1).textOverflow({ overflow: TextOverflow.Ellipsis })
          }.alignItems(HorizontalAlign.Start).layoutWeight(1)
          Text('¥' + t.price.toString()).fontSize(13).fontWeight(FontWeight.Bold).fontColor('#E8483C')
        }.width('100%').backgroundColor(t.id === 15 ? '#DFF2E7' : '#FFFFFF').borderRadius(12).padding(12).onClick(() => { this.selectedGameId = t.id; this.showDetailModal = true; })
      }, (t: GameItem) => 'st' + t.id.toString())

      Text('💬 集齐任天堂全系列可召唤隐藏彩蛋:红白机+GameBoy+Switch').fontSize(10).fontColor('#8A8A8A').width('100%')
    }.width('100%').padding({ left: 14, right: 14, top: 10, bottom: 16 })
  }

  // ---------------- 集市首页 ----------------
  @Builder
  bazaarContent() {
    Column() {
      this.topTabsBuilder()
      if (this.currentTopTab === 0) { this.cityContent() }
      else if (this.currentTopTab === 1) { this.retiredContent() }
      else if (this.currentTopTab === 2) { this.mocContent() }
      else if (this.currentTopTab === 3) { this.figContent() }
      else if (this.currentTopTab === 4) { this.techContent() }
      else { this.streetContent() }
    }.width('100%')
  }

  // ---------------- 换卡页 ----------------
  @Builder
  swapContent() {
    Column({ space: 12 }) {
      Row({ space: 0 }) {
        Column({ space: 4 }) { Text('156').fontSize(20).fontWeight(FontWeight.Bold).fontColor('#00A25B'); Text('在交换中').fontSize(10).fontColor('#8A8A8A') }.layoutWeight(1).alignItems(HorizontalAlign.Center)
        Column({ space: 4 }) { Text('42').fontSize(20).fontWeight(FontWeight.Bold).fontColor('#FF8A00'); Text('今日成交').fontSize(10).fontColor('#8A8A8A') }.layoutWeight(1).alignItems(HorizontalAlign.Center)
        Column({ space: 4 }) { Text('98%').fontSize(20).fontWeight(FontWeight.Bold).fontColor('#00A25B'); Text('面交好评').fontSize(10).fontColor('#8A8A8A') }.layoutWeight(1).alignItems(HorizontalAlign.Center)
        Column({ space: 6 }) { Text('🤝 发交换').fontSize(12).fontColor('#FFFFFF').backgroundColor('#FF8A00').borderRadius(14).padding({ left: 12, right: 12, top: 6, bottom: 6 }).onClick(() => { this.showSwapModal = true; }) }.alignItems(HorizontalAlign.Center)
      }.width('100%').backgroundColor('#FFFFFF').borderRadius(14).padding({ top: 14, bottom: 14 })

      ForEach(SWAPS, (s: SwapItem) => {
        Column({ space: 8 }) {
          Row({ space: 10 }) {
            Text(s.avatar).fontSize(26)
            Column({ space: 2 }) {
              Row({ space: 6 }) {
                Text(s.user).fontSize(13).fontWeight(FontWeight.Bold).fontColor('#2B2B2B')
                Text(swapBadge(s.likes)).fontSize(8).fontColor('#FF8A00').backgroundColor('#FFF8DC').borderRadius(6).padding({ left: 5, right: 5, top: 1, bottom: 1 })
              }
              Text(s.time + ' · ' + s.place).fontSize(9).fontColor('#8A8A8A')
            }.alignItems(HorizontalAlign.Start).layoutWeight(1)
            Text('⋯').fontSize(16).fontColor('#8A8A8A').onClick(() => { this.showDeleteModal = true; })
          }.width('100%')

          Row({ space: 10 }) {
            Column({ space: 4 }) { Text('我提供').fontSize(9).fontColor('#00A25B'); Text(s.offer).fontSize(11).fontWeight(FontWeight.Bold).fontColor('#2B2B2B') }.layoutWeight(1).backgroundColor('#DFF2E7').borderRadius(10).padding(8).alignItems(HorizontalAlign.Center)
            Text('⇄').fontSize(14).fontColor('#FFD400')
            Column({ space: 4 }) { Text('我想换').fontSize(9).fontColor('#E8483C'); Text(s.want).fontSize(11).fontWeight(FontWeight.Bold).fontColor('#2B2B2B') }.layoutWeight(1).backgroundColor('#FFEBEE').borderRadius(10).padding(8).alignItems(HorizontalAlign.Center)
          }.width('100%')

          Text(s.content).fontSize(11).fontColor('#4A5A6E').lineHeight(16).width('100%')
          Row({ space: 8 }) {
            Text('📍 ' + s.place).fontSize(10).fontColor('#00A25B').backgroundColor('#F2F5F2').borderRadius(10).padding({ left: 8, right: 8, top: 4, bottom: 4 })
            Text('❤️ ' + s.likes.toString()).fontSize(10).fontColor('#E8483C').layoutWeight(1).textAlign(TextAlign.End)
          }.width('100%')
        }.width('100%').backgroundColor('#FFFFFF').borderRadius(14).padding(14)
      }, (s: SwapItem) => 'sw' + s.id.toString())
    }.width('100%').padding({ left: 14, right: 14, top: 10, bottom: 16 })
  }

  // ---------------- 图鉴页 ----------------
  @Builder
  collectionContent() {
    Column({ space: 12 }) {
      Row({ space: 10 }) {
        Column({ space: 4 }) {
          Text('📖 我的游戏图鉴').fontSize(16).fontWeight(FontWeight.Bold).fontColor('#2B2B2B')
          Text('记录每一台心头好的收藏进度').fontSize(10).fontColor('#8A8A8A')
        }.alignItems(HorizontalAlign.Start).layoutWeight(1)
        Text('✚ 登记').fontSize(12).fontColor('#FFFFFF').backgroundColor('#00A25B').borderRadius(14).padding({ left: 14, right: 14, top: 7, bottom: 7 }).onClick(() => { this.showSellModal = true; })
      }.width('100%').margin({ top: 10 })

      ForEach(COLLECTIONS, (c: CollectionItem) => {
        Column({ space: 8 }) {
          Row({ space: 10 }) {
            Text(c.emoji).fontSize(28)
            Column({ space: 3 }) {
              Text(c.name).fontSize(14).fontWeight(FontWeight.Bold).fontColor('#2B2B2B')
              Text(c.series + ' · 已收 ' + c.owned.toString() + '/' + c.total.toString()).fontSize(10).fontColor('#8A8A8A')
            }.alignItems(HorizontalAlign.Start).layoutWeight(1)
            Text(c.rate.toString() + '%').fontSize(15).fontWeight(FontWeight.Bold).fontColor(rateColor(c.rate))
          }.width('100%')
          Row({ space: 0 }) {
            Column().width(c.rate.toString() + '%').height(6).backgroundColor(rateColor(c.rate)).borderRadius(3)
            Column().width((100 - c.rate).toString() + '%').height(6).backgroundColor('#E5E5E5').borderRadius(3)
          }.width('100%')
        }.width('100%').backgroundColor(c.id === 5 ? '#FFF8DC' : '#FFFFFF').borderRadius(14).padding(14)
      }, (c: CollectionItem) => 'coll' + c.id.toString())

      Column() {
        Text('🏅 图鉴成就墙').fontSize(14).fontWeight(FontWeight.Bold).fontColor('#2B2B2B').width('100%').margin({ bottom: 8 })
        Flex({ wrap: FlexWrap.Wrap }) {
          Text('🎖️ 游戏主机收集狂').fontSize(10).fontColor('#00A25B').backgroundColor('#DFF2E7').borderRadius(10).padding({ left: 8, right: 8, top: 5, bottom: 5 }).margin(4)
          Text('🏆 卡带原封大亨').fontSize(10).fontColor('#E8483C').backgroundColor('#FFEBEE').borderRadius(10).padding({ left: 8, right: 8, top: 5, bottom: 5 }).margin(4)
          Text('💿 爆款收藏者').fontSize(10).fontColor('#FF8A00').backgroundColor('#FFF8DC').borderRadius(10).padding({ left: 8, right: 8, top: 5, bottom: 5 }).margin(4)
          Text('🖱️ 外设百事通').fontSize(10).fontColor('#1E88E5').backgroundColor('#E8F0FE').borderRadius(10).padding({ left: 8, right: 8, top: 5, bottom: 5 }).margin(4)
        }.width('100%')
      }.width('100%').backgroundColor('#FFFFFF').borderRadius(14).padding(14)
    }.width('100%').padding({ left: 14, right: 14, bottom: 16 })
  }

  // ---------------- 我的页 ----------------
  @Builder
  mineContent() {
    Column({ space: 14 }) {
      Column() {
        Row({ space: 12 }) {
          Text('👾').fontSize(40)
          Column({ space: 4 }) {
            Text('游戏收藏家阿乐').fontSize(16).fontWeight(FontWeight.Bold).fontColor('#FFFFFF')
            Text('LV.9 骨灰级玩家 · 信用分 986').fontSize(10).fontColor('#B8DFC8')
          }.alignItems(HorizontalAlign.Start).layoutWeight(1)
          Text('>').fontSize(18).fontColor('#B8DFC8')
        }.width('100%')
        Row({ space: 0 }) {
          Column({ space: 3 }) { Text('38').fontSize(16).fontWeight(FontWeight.Bold).fontColor('#FFD400'); Text('在售游戏').fontSize(9).fontColor('#B8DFC8') }.layoutWeight(1).alignItems(HorizontalAlign.Center)
          Column({ space: 3 }) { Text('12').fontSize(16).fontWeight(FontWeight.Bold).fontColor('#FFD400'); Text('求购中').fontSize(9).fontColor('#B8DFC8') }.layoutWeight(1).alignItems(HorizontalAlign.Center)
          Column({ space: 3 }) { Text('¥8.6万').fontSize(16).fontWeight(FontWeight.Bold).fontColor('#FFD400'); Text('累计成交额').fontSize(9).fontColor('#B8DFC8') }.layoutWeight(1).alignItems(HorizontalAlign.Center)
        }.width('100%').margin({ top: 16 })
      }.width('100%').padding(18).linearGradient({ angle: 120, colors: [['#00A25B', 0], ['#2B2B2B', 1]] }).borderRadius(16).margin({ top: 10 })

      Column() {
        Text('🔨 我的求购清单').fontSize(14).fontWeight(FontWeight.Bold).fontColor('#2B2B2B').width('100%').margin({ bottom: 6 })
        ForEach(GAMES, (t: GameItem) => {
          if (t.id === 13 || t.id === 16 || t.id === 18) {
            Row({ space: 10 }) {
              Text(t.emoji).fontSize(20)
              Column({ space: 2 }) {
                Text(t.name).fontSize(12).fontWeight(FontWeight.Bold).fontColor('#2B2B2B')
                Text('预算 ¥' + t.price.toString() + ' 内 · ' + t.want).fontSize(9).fontColor('#8A8A8A')
              }.alignItems(HorizontalAlign.Start).layoutWeight(1)
              Text('出价中').fontSize(10).fontColor('#FF8A00').backgroundColor('#FFF8DC').borderRadius(10).padding({ left: 8, right: 8, top: 3, bottom: 3 })
            }.width('100%').padding({ top: 9, bottom: 9 })
          }
        }, (t: GameItem) => 'wish' + t.id.toString())
      }.width('100%').backgroundColor('#FFFFFF').borderRadius(14).padding(14)

      Column() {
        Text('📍 常去面交点').fontSize(14).fontWeight(FontWeight.Bold).fontColor('#2B2B2B').width('100%').margin({ bottom: 6 })
        ForEach(PLACES, (p: string, i: number) => {
          Row({ space: 10 }) {
            Text(['🚇', '🏬', '🚌', '🏪', '📦'][i]).fontSize(16)
            Text(p).fontSize(12).fontWeight(FontWeight.Bold).fontColor('#2B2B2B').layoutWeight(1)
            Text(['光谷站台', '江汉路天桥', '洪山转盘', '楚河入口', '顺丰网点'][i]).fontSize(9).fontColor('#8A8A8A')
          }.width('100%').padding({ top: 9, bottom: 9 })
        }, (p: string, i: number) => 'pl' + i.toString() + p)
      }.width('100%').backgroundColor('#FFFFFF').borderRadius(14).padding(14)
    }.width('100%').padding({ left: 14, right: 14, bottom: 16 })
  }

  // ---------------- 底部Tab ----------------
  @Builder
  bottomTabsBuilder() {
    Row() {
      ForEach(BOTTOM_TABS, (t: TabItem, idx: number) => {
        Column({ space: 3 }) {
          Text(t.icon).fontSize(20)
          Text(t.label).fontSize(10).fontColor(this.currentBottomTab === idx ? '#00A25B' : '#8A8A8A').fontWeight(this.currentBottomTab === idx ? FontWeight.Bold : FontWeight.Normal)
        }.layoutWeight(1).alignItems(HorizontalAlign.Center).padding({ top: 8, bottom: 8 }).onClick(() => { this.currentBottomTab = idx; })
      }, (t: TabItem, idx: number) => 'bt' + idx.toString() + t.label)
    }.width('100%').backgroundColor('#FFFFFF').borderRadius({ topLeft: 18, topRight: 18 })
  }

  // ---------------- 弹框1:发布出售(新增·绿渐变头) ----------------
  @Builder
  sellModalBuilder() {
    Column() {
      Column() {
        Text('🎮 发布出售').fontSize(17).fontWeight(FontWeight.Bold).fontColor('#FFFFFF').margin({ top: 16 })
        Text('闲置回血,神作不愁卖').fontSize(11).fontColor('#B8DFC8').margin({ top: 4, bottom: 16 })
      }.width('100%').linearGradient({ angle: 120, colors: [['#00A25B', 0], ['#2B2B2B', 1]] }).borderRadius({ topLeft: 18, topRight: 18 })

      Scroll() {
        Column({ space: 14 }) {
          Column({ space: 8 }) {
            Text('要出售的游戏').fontSize(12).fontWeight(FontWeight.Bold).fontColor('#2B2B2B').width('100%')
            Flex({ wrap: FlexWrap.Wrap }) {
              ForEach(GAMES, (t: GameItem, i: number) => {
                if (i < 8) {
                  Text(t.emoji + ' ' + t.name).fontSize(10).fontColor(this.sellGameIdx === i ? '#FFFFFF' : '#2B2B2B').backgroundColor(this.sellGameIdx === i ? '#00A25B' : '#DFF2E7').borderRadius(12).padding({ left: 9, right: 9, top: 5, bottom: 5 }).margin(4).onClick(() => { this.sellGameIdx = i; })
                }
              }, (t: GameItem, i: number) => 'st' + i.toString() + t.id.toString())
            }.width('100%')
          }.width('100%').alignItems(HorizontalAlign.Start)

          Column({ space: 8 }) {
            Text('成色说明').fontSize(12).fontWeight(FontWeight.Bold).fontColor('#2B2B2B').width('100%')
            Flex({ wrap: FlexWrap.Wrap }) {
              ForEach(CONDITION_OPTIONS, (c: string, i: number) => {
                Text(c).fontSize(10).fontColor(this.sellCondIdx === i ? '#FFFFFF' : '#FF8A00').backgroundColor(this.sellCondIdx === i ? '#FF8A00' : '#FFF8DC').borderRadius(12).padding({ left: 10, right: 10, top: 5, bottom: 5 }).margin(4).onClick(() => { this.sellCondIdx = i; })
              }, (c: string, i: number) => 'sd' + i.toString() + c)
            }.width('100%')
          }.width('100%').alignItems(HorizontalAlign.Start)

          Row({ space: 12 }) {
            Text('出售价格').fontSize(12).fontWeight(FontWeight.Bold).fontColor('#2B2B2B')
            Row({ space: 0 }) {
              Text('−').fontSize(16).fontColor('#00A25B').backgroundColor('#DFF2E7').borderRadius({ topLeft: 10, bottomLeft: 10 }).width(34).height(30).textAlign(TextAlign.Center).onClick(() => { if (this.sellPrice > 10) { this.sellPrice -= 10; } })
              Text('¥' + this.sellPrice.toString()).fontSize(13).fontWeight(FontWeight.Bold).fontColor('#2B2B2B').backgroundColor('#FFFFFF').height(30).textAlign(TextAlign.Center).padding({ left: 14, right: 14 })
              Text('+').fontSize(16).fontColor('#FFFFFF').backgroundColor('#00A25B').borderRadius({ topRight: 10, bottomRight: 10 }).width(34).height(30).textAlign(TextAlign.Center).onClick(() => { if (this.sellPrice < 9999) { this.sellPrice += 10; } })
            }.borderRadius(10)
            Text(this.sellPrice > 2000 ? '💰 高价好物建议包邮' : '实惠价更容易出手').fontSize(9).fontColor(this.sellPrice > 2000 ? '#E8483C' : '#8A8A8A').layoutWeight(1).textAlign(TextAlign.End)
          }.width('100%')

          Column({ space: 8 }) {
            Text('宝贝描述').fontSize(12).fontWeight(FontWeight.Bold).fontColor('#2B2B2B').width('100%')
            TextInput({ placeholder: '成色、缺件、配件情况如实描述…', text: this.sellWords }).fontSize(12).fontColor('#2B2B2B').backgroundColor('#F2F5F2').borderRadius(10).height(40).padding({ left: 12, right: 12 }).onChange((v: string) => { this.sellWords = v; })
          }.width('100%').alignItems(HorizontalAlign.Start)

          Row({ space: 12 }) {
            Text('取消').fontSize(13).fontColor('#8A8A8A').backgroundColor('#F2F5F2').borderRadius(20).layoutWeight(1).height(42).textAlign(TextAlign.Center).onClick(() => { this.showSellModal = false; })
            Text('上架出售').fontSize(13).fontWeight(FontWeight.Bold).fontColor('#FFFFFF').backgroundColor('#00A25B').borderRadius(20).layoutWeight(1).height(42).textAlign(TextAlign.Center).onClick(() => { this.showSellModal = false; })
          }.width('100%').margin({ top: 4, bottom: 18 })
        }.width('100%').padding({ left: 16, right: 16, top: 16 })
      }.scrollBar(BarState.Off).layoutWeight(1).align(Alignment.Top)
    }.width('88%').height('76%').backgroundColor('#FFFFFF').borderRadius(18).clip(true)
  }

  // ---------------- 弹框2:发起交换(新增·黄头) ----------------
  @Builder
  swapModalBuilder() {
    Column() {
      Column() {
        Row({ space: 8 }) { Text('🤝').fontSize(22); Text('发起交换').fontSize(17).fontWeight(FontWeight.Bold).fontColor('#2B2B2B') }.margin({ top: 16 })
        Text('用闲置换心头好,玩家互助').fontSize(11).fontColor('#5B6B7F').margin({ top: 4, bottom: 14 })
      }.width('100%').backgroundColor('#FFD400').borderRadius({ topLeft: 18, topRight: 18 })

      Scroll() {
        Column({ space: 14 }) {
          Column({ space: 8 }) {
            Text('我提供').fontSize(12).fontWeight(FontWeight.Bold).fontColor('#2B2B2B').width('100%')
            Flex({ wrap: FlexWrap.Wrap }) {
              ForEach(GAMES, (t: GameItem, i: number) => {
                if (i % 3 === 0 && i < 15) {
                  Text(t.emoji + ' ' + t.name).fontSize(10).fontColor(this.swapOfferIdx === i ? '#FFFFFF' : '#2B2B2B').backgroundColor(this.swapOfferIdx === i ? '#2B2B2B' : '#F2F5F2').borderRadius(12).padding({ left: 9, right: 9, top: 5, bottom: 5 }).margin(4).onClick(() => { this.swapOfferIdx = i; })
                }
              }, (t: GameItem, i: number) => 'wo' + i.toString() + t.id.toString())
            }.width('100%')
          }.width('100%').alignItems(HorizontalAlign.Start)

          Column({ space: 8 }) {
            Text('我想换(可多选)').fontSize(12).fontWeight(FontWeight.Bold).fontColor('#2B2B2B').width('100%')
            Flex({ wrap: FlexWrap.Wrap }) {
              ForEach(GAMES, (t: GameItem, i: number) => {
                if (i % 3 === 2 && i < 15) {
                  Text((this.pickedWant(i) ? '✓ ' : '') + t.emoji + ' ' + t.name).fontSize(10).fontColor(this.pickedWant(i) ? '#FFFFFF' : '#E8483C').backgroundColor(this.pickedWant(i) ? '#E8483C' : '#FFEBEE').borderRadius(12).padding({ left: 9, right: 9, top: 5, bottom: 5 }).margin(4).onClick(() => { this.toggleWant(i); })
                }
              }, (t: GameItem, i: number) => 'ww' + i.toString() + t.id.toString())
            }.width('100%')
          }.width('100%').alignItems(HorizontalAlign.Start)

          Column({ space: 8 }) {
            Text('面交地点').fontSize(12).fontWeight(FontWeight.Bold).fontColor('#2B2B2B').width('100%')
            Flex({ wrap: FlexWrap.Wrap }) {
              ForEach(PLACES, (p: string, i: number) => {
                Text(p).fontSize(10).fontColor(this.swapPlaceIdx === i ? '#FFFFFF' : '#00A25B').backgroundColor(this.swapPlaceIdx === i ? '#00A25B' : '#DFF2E7').borderRadius(12).padding({ left: 10, right: 10, top: 5, bottom: 5 }).margin(4).onClick(() => { this.swapPlaceIdx = i; })
              }, (p: string, i: number) => 'wp' + i.toString() + p)
            }.width('100%')
          }.width('100%').alignItems(HorizontalAlign.Start)

          Row({ space: 8 }) {
            Text('💡').fontSize(14)
            Text('交换双方可自行协商补差价,面交请选择人流密集的公共场所,注意安全。').fontSize(10).fontColor('#8A8A8A').lineHeight(15).layoutWeight(1)
          }.width('100%').backgroundColor('#FFF8DC').borderRadius(10).padding(10)

          Row({ space: 12 }) {
            Text('再想想').fontSize(13).fontColor('#8A8A8A').backgroundColor('#F2F5F2').borderRadius(20).layoutWeight(1).height(42).textAlign(TextAlign.Center).onClick(() => { this.showSwapModal = false; })
            Text('发布交换帖').fontSize(13).fontWeight(FontWeight.Bold).fontColor('#2B2B2B').backgroundColor('#FFD400').borderRadius(20).layoutWeight(1).height(42).textAlign(TextAlign.Center).onClick(() => { this.showSwapModal = false; })
          }.width('100%').margin({ top: 4, bottom: 18 })
        }.width('100%').padding({ left: 16, right: 16, top: 16 })
      }.scrollBar(BarState.Off).layoutWeight(1).align(Alignment.Top)
    }.width('88%').height('72%').backgroundColor('#FFFFFF').borderRadius(18).clip(true)
  }

  // ---------------- 弹框3:下架/删除 ----------------
  @Builder
  deleteModalBuilder() {
    Column({ space: 14 }) {
      Text('🗑️').fontSize(36)
      Text('下架这款游戏?').fontSize(16).fontWeight(FontWeight.Bold).fontColor('#2B2B2B')
      Text('下架后买家将无法搜索到这条信息,\n收藏和留言会一并清空,可重新上架。').fontSize(11).fontColor('#8A8A8A').textAlign(TextAlign.Center).lineHeight(17)
      Row({ space: 12 }) {
        Text('留着').fontSize(13).fontColor('#00A25B').backgroundColor('#DFF2E7').borderRadius(20).layoutWeight(1).height(40).textAlign(TextAlign.Center).onClick(() => { this.showDeleteModal = false; })
        Text('确认下架').fontSize(13).fontWeight(FontWeight.Bold).fontColor('#FFFFFF').backgroundColor('#E8483C').borderRadius(20).layoutWeight(1).height(40).textAlign(TextAlign.Center).onClick(() => { this.showDeleteModal = false; })
      }.width('100%').margin({ top: 6 })
    }.width('72%').backgroundColor('#FFFFFF').borderRadius(18).padding({ left: 20, right: 20, top: 24, bottom: 22 }).alignItems(HorizontalAlign.Center)
  }

  // ---------------- 弹框4:游戏详情(绿黄渐变头) ----------------
  @Builder
  detailModalBuilder() {
    Column() {
      Column() {
        Text(this.detailEmoji()).fontSize(40).margin({ top: 18 })
        Text(this.detailName()).fontSize(18).fontWeight(FontWeight.Bold).fontColor('#2B2B2B').margin({ top: 8 })
        Text(this.detailEng()).fontSize(10).fontColor('#5B6B7F').margin({ top: 2 })
        Row({ space: 8 }) {
          Text(this.detailTag()).fontSize(9).fontColor('#FFFFFF').backgroundColor('#00A25B').borderRadius(8).padding({ left: 7, right: 7, top: 2, bottom: 2 })
          Text(rarityLabel(Number(this.detailRarity()))).fontSize(9).fontColor('#2B2B2B').backgroundColor('#FFD400').borderRadius(8).padding({ left: 7, right: 7, top: 2, bottom: 2 })
        }.margin({ top: 10, bottom: 18 })
      }.width('100%').linearGradient({ angle: 135, colors: [['#FFD400', 0], ['#A8E6CF', 1]] }).borderRadius({ topLeft: 18, topRight: 18 }).alignItems(HorizontalAlign.Center)

      Scroll() {
        Column({ space: 14 }) {
          Row({ space: 0 }) {
            Column({ space: 4 }) { Text(this.detailPrice()).fontSize(17).fontWeight(FontWeight.Bold).fontColor('#E8483C'); Text('售价').fontSize(9).fontColor('#8A8A8A') }.layoutWeight(1).alignItems(HorizontalAlign.Center)
            Column({ space: 4 }) { Text(this.detailVersion()).fontSize(17).fontWeight(FontWeight.Bold).fontColor('#00A25B'); Text('版本').fontSize(9).fontColor('#8A8A8A') }.layoutWeight(1).alignItems(HorizontalAlign.Center)
            Column({ space: 4 }) { Text(this.detailRarity()).fontSize(17).fontWeight(FontWeight.Bold).fontColor(rarityColor(Number(this.detailRarity()))); Text('稀有度').fontSize(9).fontColor('#8A8A8A') }.layoutWeight(1).alignItems(HorizontalAlign.Center)
            Column({ space: 4 }) { Text(this.detailYear()).fontSize(17).fontWeight(FontWeight.Bold).fontColor('#FF8A00'); Text('发行年份').fontSize(9).fontColor('#8A8A8A') }.layoutWeight(1).alignItems(HorizontalAlign.Center)
          }.width('100%').backgroundColor('#F2F5F2').borderRadius(12).padding({ top: 12, bottom: 12 })

          Column({ space: 8 }) {
            Text('🧾 宝贝描述').fontSize(12).fontWeight(FontWeight.Bold).fontColor('#2B2B2B').width('100%')
            Text(this.detailDesc()).fontSize(11).fontColor('#4A5A6E').lineHeight(18)
            Row({ space: 8 }) {
              Text('👤 ' + this.detailSeller()).fontSize(10).fontColor('#00A25B')
              Text(this.detailStar() + ' ' + this.detailRating()).fontSize(10).fontColor('#FF8A00').layoutWeight(1).textAlign(TextAlign.End)
            }.width('100%')
          }.width('100%').alignItems(HorizontalAlign.Start)

          Row({ space: 8 }) {
            Text('🤝').fontSize(14)
            Text('卖家想换:' + this.detailWant()).fontSize(11).fontColor('#E8483C').layoutWeight(1)
          }.width('100%').backgroundColor('#FFEBEE').borderRadius(10).padding(10)

          Column({ space: 10 }) {
            Text('💬 圈友点评').fontSize(12).fontWeight(FontWeight.Bold).fontColor('#2B2B2B').width('100%')
            ForEach(GAME_REVIEWS, (r: GameReview) => {
              Column({ space: 5 }) {
                Row({ space: 8 }) { Text('👤').fontSize(14); Text(r.user).fontSize(11).fontWeight(FontWeight.Bold).fontColor('#2B2B2B'); Text(r.starStr).fontSize(9).layoutWeight(1).textAlign(TextAlign.End) }.width('100%')
                Text(r.content).fontSize(10).fontColor('#8A8A8A').lineHeight(15)
              }.width('100%').backgroundColor('#F2F5F2').borderRadius(10).padding(10)
            }, (r: GameReview) => 'rv' + r.id.toString())
          }.width('100%').alignItems(HorizontalAlign.Start)

          Row({ space: 12 }) {
            Text('💬 留言问问').fontSize(13).fontColor('#00A25B').backgroundColor('#DFF2E7').borderRadius(20).layoutWeight(1).height(42).textAlign(TextAlign.Center).onClick(() => { this.showDetailModal = false; })
            Text('🛒 立即购买').fontSize(13).fontWeight(FontWeight.Bold).fontColor('#FFFFFF').backgroundColor('#E8483C').borderRadius(20).layoutWeight(1).height(42).textAlign(TextAlign.Center).onClick(() => { this.showDetailModal = false; })
          }.width('100%').margin({ top: 2, bottom: 18 })
        }.width('100%').padding({ left: 16, right: 16, top: 14 })
      }.scrollBar(BarState.Off).layoutWeight(1).align(Alignment.Top)
    }.width('88%').height('78%').backgroundColor('#FFFFFF').borderRadius(18).clip(true)
  }

  // 交换多选辅助
  pickedWant(i: number): boolean { return (i % 2) === 0; }
  toggleWant(i: number): void { this.swapWantIdx = i; }

  // ---------------- 主布局 ----------------
  build() {
    Stack() {
      Column() {
        this.headerBuilder()
        Scroll() {
          Column() {
            if (this.currentBottomTab === 0) { this.bazaarContent() }
            else if (this.currentBottomTab === 1) { this.swapContent() }
            else if (this.currentBottomTab === 2) { this.collectionContent() }
            else { this.mineContent() }
          }.width('100%')
        }.layoutWeight(1).scrollBar(BarState.Off).align(Alignment.Top)
        this.bottomTabsBuilder()
      }.width('100%').height('100%')

      ForEach(this.particles, (p: ParticleItem, i: number) => {
        Text(p.emoji).fontSize(p.size).opacity(p.opacity).position({ x: p.x, y: 80 + (i % 5) * 118 })
      }, (p: ParticleItem, i: number) => 'pt' + i.toString())

      if (this.showDetailModal) {
        Column() { this.detailModalBuilder() }.width('100%').height('100%').backgroundColor('99000000').justifyContent(FlexAlign.Center).onClick(() => { this.showDetailModal = false; })
      }
      if (this.showSellModal) {
        Column() { this.sellModalBuilder() }.width('100%').height('100%').backgroundColor('99000000').justifyContent(FlexAlign.Center).onClick(() => { this.showSellModal = false; })
      }
      if (this.showSwapModal) {
        Column() { this.swapModalBuilder() }.width('100%').height('100%').backgroundColor('99000000').justifyContent(FlexAlign.Center).onClick(() => { this.showSwapModal = false; })
      }
      if (this.showDeleteModal) {
        Column() { this.deleteModalBuilder() }.width('100%').height('100%').backgroundColor('99000000').justifyContent(FlexAlign.Center).onClick(() => { this.showDeleteModal = false; })
      }
    }.width('100%').height('100%').backgroundColor(PALETTE.bg)
  }
}
TabsBuilder()
      }.width('100%').height('100%')

      ForEach(this.particles, (p: ParticleItem, i: number) => {
        Text(p.emoji).fontSize(p.size).opacity(p.opacity).position({ x: p.x, y: 80 + (i % 5) * 118 })
      }, (p: ParticleItem, i: number) => 'pt' + i.toString())

      if (this.showDetailModal) {
        Column() { this.detailModalBuilder() }.width('100%').height('100%').backgroundColor('99000000').justifyContent(FlexAlign.Center).onClick(() => { this.showDetailModal = false; })
      }
      if (this.showSellModal) {
        Column() { this.sellModalBuilder() }.width('100%').height('100%').backgroundColor('99000000').justifyContent(FlexAlign.Center).onClick(() => { this.showSellModal = false; })
      }
      if (this.showSwapModal) {
        Column() { this.swapModalBuilder() }.width('100%').height('100%').backgroundColor('99000000').justifyContent(FlexAlign.Center).onClick(() => { this.showSwapModal = false; })
      }
      if (this.showDeleteModal) {
        Column() { this.deleteModalBuilder() }.width('100%').height('100%').backgroundColor('99000000').justifyContent(FlexAlign.Center).onClick(() => { this.showDeleteModal = false; })
      }
    }.width('100%').height('100%').backgroundColor(PALETTE.bg)
  }
}
Logo

讨论HarmonyOS开发技术,专注于API与组件、DevEco Studio、测试、元服务和应用上架分发等。

更多推荐