AI租房避坑清单 —— 基于HarmonyOS原生AI应用的全流程开发实践

摘要:本文以"AI租房避坑清单"应用的完整开发过程为蓝本,深入剖析在 HarmonyOS 平台上使用 ArkTS/ArkUI 进行原生 AI 应用开发的全流程技术实践。文章严格遵循 Align(对齐)、Architect(架构)、Atomize(原子化)、Approve(审批)、Automate(自动化)、Assess(评估)六阶段方法论,从需求分析、架构设计、代码实现到部署运维逐层递进,完整呈现了一个面向租房场景的智能避坑指南应用的诞生全过程。文中包含大量可运行的 ArkTS 代码示例、ArkUI 声明式 UI 的最佳实践以及 HarmonyOS 开发中常见问题的解决方案。本文适合 HarmonyOS 应用开发者、ArkTS 初学者以及移动端 AI 应用产品经理阅读参考。


在这里插入图片描述

1. 对齐阶段(Align)

对齐阶段的目标是将模糊的原始需求转化为精确的、可执行的规范文档。这一阶段的核心产出是需求确认文档和验收标准,是整个开发流程的基石。

1.1 项目上下文分析

1.1.1 技术栈全景

"AI租房避坑清单"应用构建在 HarmonyOS 生态之上,其核心技术栈如下:

技术维度 选型方案 版本/规格
操作系统 HarmonyOS API 6.0.1 (21)
开发语言 ArkTS(静态类型方言) Stage Mode
UI框架 ArkUI(声明式UI框架) 组件化 + @State 驱动
开发工具 DevEco Studio 最新稳定版
构建系统 Hvigor oh-package.json5 配置
路由方案 @kit.ArkUI router 页面级跳转
数据模型 纯 ArkTS 类定义 零外部依赖
资源管理 $r 资源引用 + rawfile 国际化就绪

从项目根目录的 build-profile.json5 可以看到,目标 SDK 版本为 6.0.1(21),采用 stageMode 运行模式。oh-package.json5 中无任何第三方依赖,这是 HarmonyOS 原生开发的重要特点——所有能力均来自系统 Kit,开发者无需引入外部库即可完成完整的应用开发。

1.1.2 项目目录结构

"AI租房避坑清单"应用在项目中的完整路径如下:

entry/src/main/ets/apps/AI租房避坑清单/
├── AI租房避坑清单Page.ets       # 视图层(View)
├── AI租房避坑清单Model.ets      # 数据模型层(Model)
└── AI租房避坑清单Service.ets    # 业务逻辑层(Service/ViewModel)

此外,该应用还涉及以下配置文件的修改:

entry/src/main/resources/base/profile/main_pages.json   # 路由注册
entry/src/main/resources/rawfile/apps/apps.json          # 应用列表配置
1.1.3 架构模式分析

整个项目采用 MVVM(Model-View-ViewModel) 架构范式,在 ArkTS 的语法约束下做了适应性调整。这种架构的核心优势在于关注点分离——UI 代码只负责渲染和交互,业务逻辑集中在 Service 层,数据模型独立定义,三者各司其职。

在 ArkTS 环境下,MVVM 的落地方式有其特殊性:

  • Model 层AI租房避坑清单Data 类,承载所有数据结构。在 ArkTS 中,类声明引入的是一种新类型而非值,因此天然适合作为数据模型。所有字段必须在类声明中立即初始化,不支持在构造函数中动态声明字段。
  • View 层AI租房避坑清单Page 结构体,使用 @Component 装饰器标记为 UI 组件,通过 @State 装饰器声明响应式状态变量,驱动 UI 自动刷新。
  • Service 层AI租房避坑清单Service 类,封装核心业务逻辑,包括数据生成和处理,属于 ViewModel 的变体实现。

1.2 需求理解与确认

1.2.1 原始需求

"AI租房避坑清单"的原始需求可以概括为:用户输入租房相关的关键信息(城市、预算、租房类型),应用基于这些信息生成一份全面的租房避坑清单,包含实地看房检查项、合同要点、区域建议、费用清单、入住建议和退租策略等多个维度的内容,帮助用户在租房过程中规避常见陷阱。

1.2.2 用户输入规格

应用需要采集的用户输入包含三个核心字段:

字段 含义 示例值 输入组件
城市 租房所在城市 北京、上海、深圳 TextInput
预算 月租金预算范围 3000、5000-8000 TextInput
租房类型 房屋类型 整租、合租、公寓、城中村 TextInput
1.2.3 AI输出规格

应用生成的避坑清单包含 7 个数据维度:

输出字段 类型 说明
viewing_checklist string[] 实地看房检查清单
category string 房源分类
items string[] 具体检查项目
red_flags string[] 危险信号/警示项
contract_points string[] 合同审查要点
point string 核心关注点
why string 为什么重要
negotiable string 是否可协商
area_advice string[] 区域选择建议
area string 推荐区域
pros string 优点
cons string 缺点
avg_price string 均价范围
cost_checklist string[] 费用清单(含隐藏费用)
move_in_tips string[] 入住建议
exit_strategy string 退租注意事项
1.2.4 边界确认
维度 边界定义
输入范围 城市、预算、租房类型三个文本字段
输出范围 7个类别共16个维度的避坑信息
设备范围 仅支持手机(phone)设备类型
交互方式 文本输入 + 按钮触发 + 结果展示
网络依赖 当前版本无网络依赖(Mock数据演示)
数据持久化 无需持久化,结果仅当次展示
用户群体 租房人群、房产中介、房东
1.2.5 目标用户群体分析
  1. 首次租房者:刚毕业的大学生或工作调动者,对租房流程不熟悉,容易踩坑,需要全面的检查清单作为参考。
  2. 频繁换租者:因工作或生活需要频繁换房的人群,需要一个标准化的避坑检查流程,提高效率。
  3. 房产中介:专业中介可以将此工具作为服务客户的辅助手段,帮助客户做出更明智的决策。
  4. 房东:房东可以通过此清单了解租客的关注点,有针对性地改善房屋条件,提高出租率。

1.3 关键决策记录

决策1:数据类型选择——Record<string, Object> 替代 any

问题:ArkTS 不支持 anyunknown 类型,也不支持索引签名 { [key: string]: string },如何管理动态表单数据?

分析:在传统 TypeScript 中,表单数据通常使用 any 或索引签名类型来管理。但 ArkTS 明确禁止了这两种方式。在 ArkTS 的语法约束下,动态表单数据的管理需要另寻出路。

决策:使用 Record<string, Object> 类型替代 anyRecord 是 ArkTS 中少数支持的泛型工具类型之一(Partial、Required、Readonly 和 Record 是例外),它允许在编译时已知的键值对映射。对于 Object 类型的值,在 Service 层通过 String() 方法进行显式类型转换。这种方案在类型安全性和灵活性之间取得了平衡。

// 使用 Record<string, Object> 管理动态表单数据
@State inputData: Record<string, Object> = {}

// 采集用户输入
TextInput({ placeholder: '请输入城市' })
  .onChange((val: string) => {
    this.inputData['城市'] = val
  })

// Service 层使用时显式转换
let cityVal: string = String(inputData['城市'] || '')
决策2:结果数据模型使用可空类型

问题:ArkTS 不支持 undefined 作为初始值,如何表示"尚未生成结果"的状态?

分析:在 ArkTS 中,所有类字段必须在声明时初始化,不能在构造函数中动态声明。这意味着不能简单地使用 undefined 来表示"数据尚未生成"的状态。

决策:使用 T | null 联合类型,将初始值设为 null。在 UI 中通过 if (this.resultData !== null) 进行类型收窄。这种模式在 ArkTS 中被广泛使用,是模拟可选值的标准做法。

@State resultData: AI租房避坑清单Data | null = null

// 在 UI 中使用
if (this.showResult && this.resultData !== null) {
  // 安全访问 resultData 的字段
  Text(this.resultData.category)
}
决策3:UI 布局策略——Scroll 容器承载长内容

问题:避坑清单的输出结果可能包含大量文本和列表项,如何保证所有内容在屏幕内可滚动查看?

分析:应用需要在有限屏幕空间内展示大量信息,包括输入表单、生成按钮和完整的输出结果。如果所有内容都平铺在页面上,必然超出屏幕高度。

决策:将整个内容区域包裹在 Scroll 组件中,实现垂直滚动。输入区域和输出区域在 Column 容器中垂直排列,输出区域在点击生成按钮后动态渲染,所有内容自然地在 Scroll 中滚动。

Scroll() {
  Column() {
    // 输入表单区域
    Column() { /* 输入控件 */ }
    
    // 生成按钮
    Button('生成避坑清单')
    
    // 结果展示区域(条件渲染)
    if (this.showResult && this.resultData !== null) {
      Column() { /* 结果展示 */ }
    }
  }
}
.layoutWeight(1)

2. 架构阶段(Architect)

架构阶段的目标是从共识文档出发,设计出系统的整体架构、分层方案和模块间接口规范。这一阶段的核心产出是详细的设计文档。

2.1 整体架构设计

"AI租房避坑清单"应用的整体架构采用经典的三层 MVVM 模式,各层职责清晰、耦合度低:

┌─────────────────────────────────────────────────────────┐
│                    View 层 (Page.ets)                     │
│  @Entry @Component                                       │
│  - @State inputData: Record<string, Object>              │
│  - @State resultData: AI租房避坑清单Data | null           │
│  - @State showResult: boolean                            │
│  - build() 构建 UI 树                                    │
│  - 用户交互事件处理                                       │
├─────────────────────────────────────────────────────────┤
│                  Service 层 (Service.ets)                  │
│  AI租房避坑清单Service                                     │
│  - generateData(input): AI租房避坑清单Data                  │
│  - 调用 AI 模型/Mock 数据生成逻辑                          │
├─────────────────────────────────────────────────────────┤
│                  Model 层 (Model.ets)                      │
│  AI租房避坑清单Data                                        │
│  - 16 个字段定义全量输出结构                               │
│  - 构造函数初始化所有字段                                   │
└─────────────────────────────────────────────────────────┘
2.1.1 各层职责边界

Model 层(数据模型)

Model 层是整个应用的数据基石。AI租房避坑清单Data 类定义了应用输出的全部数据结构,共包含 16 个字段,涵盖了看房检查、合同审查、区域建议、费用清单、入住建议和退租策略等所有维度。

Model 层的设计要点包括:

  1. 所有字段必须立即初始化:在 ArkTS 中,类字段声明时必须赋值,构造函数中只能重新赋值,不能声明新字段。
  2. 使用数组类型存储列表数据:对于多值数据(如检查项列表、费用清单等),使用 string[] 类型。
  3. 使用字符串类型存储标量数据:对于单值数据(如区域名称、优点、缺点等),使用 string 类型。

Service 层(业务逻辑)

Service 层是 View 和 Model 之间的桥梁,负责封装核心业务逻辑。AI租房避坑清单Service 类接收原始输入,执行数据生成逻辑,返回结构化的数据模型实例。

Service 层的设计考虑:

  1. 无状态设计:Service 实例不持有状态,每次调用 generateData 都返回新的数据实例,避免副作用。
  2. 输入验证:在生成数据前对输入进行合法性检查,确保关键字段非空。
  3. 可扩展接口:当前版本使用 Mock 数据,后续可无缝替换为真实 AI 模型调用。

View 层(UI 视图)

View 层是用户与应用交互的界面,使用 ArkUI 的声明式 UI 语法构建。AI租房避坑清单Page 组件通过 @State 装饰器声明响应式状态变量,当状态变化时,UI 自动重新渲染。

View 层的设计要点:

  1. 状态驱动:所有 UI 变化都由 @State 变量驱动,符合 ArkUI 的声明式范式。
  2. 条件渲染:使用 if 语句控制结果区域的显示/隐藏,未生成结果时不占用屏幕空间。
  3. 列表渲染:使用 ForEach 循环渲染数组类型的数据,每个列表项以 符号开头。

2.2 数据流设计

应用的数据流遵循"单向数据流"原则,从用户输入到 UI 渲染的完整路径如下:

用户输入 → @State inputData 更新 → 
点击按钮 → Service.generateData() → 
返回 AI租房避坑清单Data 实例 → 
@State resultData 赋值 → 
@State showResult 设为 true →
ArkUI 自动触发 UI 重渲染 →
结果展示在页面中

这种单向数据流的设计优势在于:

  1. 可预测性:数据变化的方向是单一的,不会出现双向绑定导致的循环更新问题。
  2. 可调试性:每个数据变化点都是明确的,便于定位问题。
  3. 性能优化:ArkUI 的响应式系统只更新变化的部分,无需手动操作 DOM。

2.3 路由与集成设计

"AI租房避坑清单"应用作为主应用的一个子模块,需要通过路由注册和列表配置集成到主应用的导航体系中。

2.3.1 路由注册

main_pages.json 中注册页面路由:

{
  "src": [
    "pages/Index",
    "apps/AI租房避坑清单/AI租房避坑清单Page"
  ]
}
2.3.2 应用列表配置

apps.json 中添加应用配置,包含图标、标题、颜色主题和页面路由信息:

{
  "icon": "🏡",
  "title": "AI租房避坑清单",
  "subtitle": "租房避坑",
  "color": "#3B82F6",
  "bg": "#EFF6FF",
  "border": "#BFDBFE",
  "page": "apps/AI租房避坑清单/AI租房避坑清单Page",
  "cat": "工作效率"
}
2.3.3 页面跳转实现

在主页 Index.ets 中,通过 router.pushUrl 实现页面跳转:

.onClick(() => {
  router.pushUrl({ url: app.pageUrl })
})

在应用页面中,通过 router.back() 实现返回:

Text('← 返回')
  .onClick(() => {
    router.back()
  })

2.4 ArkTS 语法约束下的设计考量

在架构设计阶段,必须充分考虑 ArkTS 的语法约束,这些约束直接影响代码的实现方式。

2.4.1 类的声明与使用

在 ArkTS 中,类声明引入的是一种新类型,而不是一个值。这意味着:

  • 不能将类赋值给变量let Cls = MyClass 这种写法是不允许的。
  • 不能将类用作对象:不能在类上定义静态属性之外的其他属性。
  • 所有字段必须在声明时初始化:不支持在构造函数中声明新字段。
// 正确的做法:所有字段在声明时初始化
export class AI租房避坑清单Data {
  viewing_checklist: string[] = []
  category: string = ''
  items: string[] = []
  // ... 其他字段

  constructor() {
    // 构造函数中重新赋值,而非声明新字段
    this.viewing_checklist = []
    this.category = ''
    // ...
  }
}
2.4.2 状态变量的类型约束

@State 装饰器用于声明组件的内部状态,当状态变化时,UI 自动更新。在 ArkTS 中,@State 变量的类型必须明确指定,不能使用 any

// 正确的做法:明确指定类型
@State inputData: Record<string, Object> = {}
@State resultData: AI租房避坑清单Data | null = null
@State showResult: boolean = false
2.4.3 条件渲染与类型收窄

在 ArkTS 中,条件渲染使用 if 语句。当变量类型为联合类型(如 T | null)时,需要在条件判断中进行类型收窄。

// 类型收窄:在 if 块内,resultData 的类型被收窄为 AI租房避坑清单Data
if (this.showResult && this.resultData !== null) {
  Text(this.resultData.category)  // 安全访问
}

3. 原子化阶段(Atomize)

原子化阶段的目标是将架构设计阶段产出的系统方案分解为更小的、可独立执行和验证的原子任务。这种分解方式有助于并行开发、降低复杂度、提高交付质量。

3.1 任务分解

"AI租房避坑清单"应用的开发任务可以分解为以下 7 个原子任务:

任务 T1:定义数据模型(Model)

任务描述:创建 AI租房避坑清单Data 类,定义全部 16 个输出字段。

验收标准

  • 类中定义所有必需的字段,每个字段都有明确的类型
  • 所有字段在声明时已初始化
  • 构造函数中重新初始化所有字段

预估工时:0.5 小时

任务 T2:实现业务逻辑层(Service)

任务描述:创建 AI租房避坑清单Service 类,实现 generateData 方法,接收用户输入并返回结构化的数据。

验收标准

  • 方法签名清晰,输入为 Record<string, Object>,输出为 AI租房避坑清单Data
  • 当前版本使用 Mock 数据,后续可扩展为真实 AI 调用
  • 输入为空时提供默认值

预估工时:1 小时

任务 T3:构建页面骨架(Page - 基础结构)

任务描述:创建 AI租房避坑清单Page 组件,搭建页面的基本骨架,包括顶部导航栏、标题区域和 Scroll 容器。

验收标准

  • 页面包含顶部返回按钮和标题
  • 使用 Scroll 容器包裹可滚动内容区域
  • 页面背景色和布局符合设计规范

预估工时:0.5 小时

任务 T4:实现输入表单(Page - 输入区域)

任务描述:在页面中实现用户输入表单,包含城市、预算、租房类型三个输入字段和生成按钮。

验收标准

  • 三个 TextInput 组件正确绑定到 inputData 状态
  • 生成按钮样式醒目,点击触发数据生成
  • 表单布局清晰,标签和输入框对齐

预估工时:1 小时

任务 T5:实现结果展示(Page - 输出区域)

任务描述:实现避坑清单的结果展示区域,使用条件渲染控制显示/隐藏,使用 ForEach 渲染列表数据。

验收标准

  • 生成结果后自动显示结果区域
  • 每个数据维度都有对应的标题和内容展示
  • 列表数据使用 符号逐条展示
  • 标量数据使用标签 + 值的方式展示

预估工时:1.5 小时

任务 T6:注册路由和配置

任务描述:在 main_pages.json 中注册页面路由,在 apps.json 中添加应用列表配置。

验收标准

  • 路由路径正确,页面可正常跳转
  • 应用列表配置完整,包含图标、标题、主题色等
  • 返回功能正常

预估工时:0.5 小时

任务 T7:集成测试与验证

任务描述:验证应用从主页跳转到详情页、输入数据、生成结果、返回主页的完整流程。

验收标准

  • 所有页面跳转无异常
  • 输入表单正常采集数据
  • 生成结果正确展示
  • 返回功能正常
  • 无编译错误和运行时异常

预估工时:1 小时

3.2 任务依赖图

T1 (Model) ──→ T2 (Service) ──→ T5 (结果展示)
                                      ↑
T3 (页面骨架) ──→ T4 (输入表单) ────┘
                                      ↓
                                  T6 (路由配置) ──→ T7 (集成测试)

T1 和 T3 可以并行开发,T2 依赖 T1,T4 依赖 T3,T5 依赖 T2 和 T4,T6 依赖 T5,T7 依赖 T6。

3.3 代码实现详解

3.3.1 T1:Model 层实现

Model 层是数据定义的核心,AI租房避坑清单Data 类的完整代码如下:

// AI租房避坑清单Model.ets
export class AI租房避坑清单Data {
  viewing_checklist: string[] = []
  category: string = ''
  items: string[] = []
  red_flags: string[] = []
  contract_points: string[] = []
  point: string = ''
  why: string = ''
  negotiable: string = ''
  area_advice: string[] = []
  area: string = ''
  pros: string = ''
  cons: string = ''
  avg_price: string = ''
  cost_checklist: string[] = []
  move_in_tips: string[] = []
  exit_strategy: string = ''

  constructor() {
    this.viewing_checklist = []
    this.category = ''
    this.items = []
    this.red_flags = []
    this.contract_points = []
    this.point = ''
    this.why = ''
    this.negotiable = ''
    this.area_advice = []
    this.area = ''
    this.pros = ''
    this.cons = ''
    this.avg_price = ''
    this.cost_checklist = []
    this.move_in_tips = []
    this.exit_strategy = ''
  }
}

设计要点

  1. 数组类型字段viewing_checklistitemsred_flagscontract_pointsarea_advicecost_checklistmove_in_tips 使用 string[] 类型,用于存储多值数据。
  2. 字符串类型字段categorypointwhynegotiableareaprosconsavg_priceexit_strategy 使用 string 类型,用于存储单值数据。
  3. 双重初始化:在声明时和构造函数中分别初始化,确保字段在任何情况下都有确定的初始值。
3.3.2 T2:Service 层实现

Service 层封装了数据生成的核心逻辑。当前版本使用 Mock 数据,后续可扩展为调用真实 AI 模型。

// AI租房避坑清单Service.ets
import { AI租房避坑清单Data } from './AI租房避坑清单Model'

export class AI租房避坑清单Service {
  private model: AI租房避坑清单Data

  constructor() {
    this.model = new AI租房避坑清单Data()
  }

  // 生成AI租房避坑清单数据
  generateData(input: Record<string, Object>): AI租房避坑清单Data {
    let result: AI租房避坑清单Data = new AI租房避坑清单Data()
    
    // 提取用户输入,提供默认值
    let cityVal: string = String(input['城市'] || '')
    let budgetVal: string = String(input['预算'] || '')
    let typeVal: string = String(input['租房类型'] || '')
    
    // Mock 数据生成逻辑
    result.viewing_checklist = [
      '检查墙面是否有渗水、发霉痕迹',
      '测试水压和排水是否正常',
      '检查门窗密封性和开关是否顺畅',
      '确认空调、热水器等家电能否正常使用',
      '检查电路和插座是否完好',
      '观察周边环境和噪音情况',
      '确认网络覆盖和信号质量',
      '检查消防设施是否完备'
    ]
    
    result.items = [
      '房屋整体结构检查',
      '水电设施测试',
      '家具家电检查',
      '环境卫生评估',
      '安全设施确认'
    ]
    
    result.red_flags = [
      '⚠️ 墙面有明显裂缝或渗水痕迹',
      '⚠️ 电路老化,插座松动',
      '⚠️ 房屋存在甲醛超标嫌疑(新装修)',
      '⚠️ 周边环境嘈杂,有施工噪音'
    ]
    
    result.contract_points = [
      '明确押金退还条件和期限',
      '确认物业费、取暖费等由谁承担',
      '明确维修责任划分',
      '确认是否可以转租',
      '核实房东身份和房产证'
    ]
    
    result.cost_checklist = [
      '月租金:' + budgetVal + '元/月',
      '押金:通常为1-2个月租金',
      '中介费:通常为半个月到1个月租金',
      '物业费:确认是否包含在租金内',
      '水电燃气费:确认单价和缴费方式',
      '网络费:确认是否包含',
      '取暖费/空调费:季节性费用'
    ]
    
    result.move_in_tips = [
      '入住前拍照留存房屋现状证据',
      '更换门锁或确认密码锁安全',
      '确认所有家电操作方式',
      '了解垃圾投放和分类要求',
      '熟悉周边超市、医院、公交站位置'
    ]
    
    result.exit_strategy = '退租需提前30天书面通知房东;' +
      '退租时房屋需恢复原状(正常磨损除外);' +
      '押金退还一般在退租后15个工作日内完成;' +
      '建议退租前与房东共同检查房屋并签字确认。'
    
    return result
  }
}

设计要点

  1. 输入提取:使用 String(input['城市'] || '') 提取用户输入,通过 || '' 提供默认值,避免 undefined 被转换为 "undefined" 字符串。
  2. Mock 数据:根据真实租房场景设计了完整的检查清单和避坑建议,即使在没有 AI 模型的情况下也能提供有价值的参考信息。
  3. 可扩展性generateData 方法的输入输出接口已经固定,后续只需替换内部实现即可接入真实 AI 模型。
3.3.3 T3-T5:Page 层实现

Page 层是应用的 UI 部分,包含顶部导航栏、输入表单和结果展示三个主要区域。

// AI租房避坑清单Page.ets
import { AI租房避坑清单Data } from './AI租房避坑清单Model'
import { AI租房避坑清单Service } from './AI租房避坑清单Service'
import { router } from '@kit.ArkUI'

@Entry
@Component
struct AI租房避坑清单Page {
  @State inputData: Record<string, Object> = {}
  @State resultData: AI租房避坑清单Data | null = null
  @State showResult: boolean = false
  private service: AI租房避坑清单Service = new AI租房避坑清单Service()

  build() {
    Column() {
      // 顶部导航栏
      Row() {
        Text('← 返回')
          .fontSize(13)
          .fontColor('#1A1A1A')
          .onClick(() => {
            router.back()
          })
        Blank()
        Column() {
          Text('🏠 AI租房避坑清单')
            .fontSize(17)
            .fontWeight(FontWeight.Bold)
            .fontColor('#1A1A1A')
          Text('RENTAL CHECKLIST · 避坑指南')
            .fontSize(9)
            .fontColor('#6B7280')
            .margin({ top: 2 })
        }
        Blank()
        Text('🏠')
          .fontSize(22)
      }
      .width('100%')
      .padding({ left: 20, right: 20, top: 16, bottom: 14 })
      .backgroundColor('#F3F4F6')

      // 可滚动内容区域
      Scroll() {
        Column() {
          // 输入表单区域
          this.buildInputForm()
          
          // 生成按钮
          this.buildGenerateButton()
          
          // 结果展示区域
          this.buildResultSection()
        }
        .width('100%')
        .padding({ left: 18, right: 18, bottom: 40 })
      }
      .layoutWeight(1)
    }
    .width('100%')
    .height('100%')
    .backgroundColor('#F3F4F6')
  }

  // 输入表单区域
  @Builder
  buildInputForm() {
    Column() {
      Text('🏠 城市')
        .fontSize(11)
        .fontColor('#1A1A1A')
        .margin({ top: 6, bottom: 3 })
      TextInput({ placeholder: '请输入城市' })
        .fontSize(13)
        .height(40)
        .backgroundColor('#FFFFFF')
        .border({ width: 1, color: '#9CA3AF' })
        .padding({ left: 12, right: 12 })
        .onChange((val: string) => {
          this.inputData['城市'] = val
        })

      Text('🏠 预算')
        .fontSize(11)
        .fontColor('#1A1A1A')
        .margin({ top: 6, bottom: 3 })
      TextInput({ placeholder: '请输入预算(如:3000)' })
        .fontSize(13)
        .height(40)
        .backgroundColor('#FFFFFF')
        .border({ width: 1, color: '#9CA3AF' })
        .padding({ left: 12, right: 12 })
        .onChange((val: string) => {
          this.inputData['预算'] = val
        })

      Text('🏠 租房类型')
        .fontSize(11)
        .fontColor('#1A1A1A')
        .margin({ top: 6, bottom: 3 })
      TextInput({ placeholder: '请输入租房类型(整租/合租/公寓)' })
        .fontSize(13)
        .height(40)
        .backgroundColor('#FFFFFF')
        .border({ width: 1, color: '#9CA3AF' })
        .padding({ left: 12, right: 12 })
        .onChange((val: string) => {
          this.inputData['租房类型'] = val
        })
    }
    .width('100%')
    .padding(18)
    .backgroundColor('#FFFFFF')
    .border({ width: 1, color: '#D1D5DB' })
    .margin({ top: 6 })
  }

  // 生成按钮
  @Builder
  buildGenerateButton() {
    Button('🏠 生成避坑清单')
      .width('100%')
      .height(50)
      .backgroundColor('#1F2937')
      .borderRadius(0)
      .fontColor('#FFFFFF')
      .fontSize(16)
      .fontWeight(FontWeight.Bold)
      .margin({ top: 18, bottom: 14 })
      .onClick(() => {
        this.resultData = this.service.generateData(this.inputData)
        this.showResult = true
      })
  }

  // 结果展示区域
  @Builder
  buildResultSection() {
    if (this.showResult && this.resultData !== null) {
      Column() {
        Text('🏠 租房避坑清单')
          .fontSize(15)
          .fontWeight(FontWeight.Bold)
          .fontColor('#1A1A1A')
          .margin({ bottom: 12 })

        //
Logo

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

更多推荐