前言

在移动互联网的下半场,单纯的工具型App已经难以满足用户日益增长的需求。用户不再满足于"查看信息",而是期望应用能够"理解意图、主动服务"。这一趋势在旅行领域尤为明显——用户希望有了一个模糊的出行想法之后,App能自动帮他们完成从目的地推荐、行程规划、酒店航班预订到每日穿搭建议的全流程服务。

本文将深入剖析一个基于HarmonyOS ArkTS框架打造的AI旅行规划助手项目,从技术架构、设计模式、状态管理、AI Agent设计、API集成等多个维度,全面解读如何构建一个"小而美"的端侧智能应用。项目虽小,但涵盖了现代移动应用开发中数据建模、组件化设计、响应式UI、HTTP通信、路由管理等核心技术点,是学习HarmonyOS应用开发的优秀实践案例。


一、项目概览与技术栈

1.1 项目定位

本项目是一个面向C端用户的旅行规划助手,核心理念是"一句话生成旅行计划"——用户只需用自然语言描述出行想法(如"我下个月想去暖和的地方看海,预算5000元"),系统自动完成:

  • 意图识别:分析用户身份(上班族/大学生/银发族/亲子家庭/情侣等)、出行目的、当前心情
  • 目的地推荐:基于用户画像智能匹配目的地
  • 行程生成:生成包含航班、酒店、每日活动的完整行程
  • 细节完善:提供景点详情、美食推荐、天气查询、穿搭建议、旅行贴士等

1.2 技术栈一览

技术层面 技术选型
开发语言 ArkTS(TypeScript超集)
运行平台 HarmonyOS 6.1.0 (API 23)
UI框架 ArkUI 声明式UI
构建工具 Hvigor
模块管理 Stage模式
HTTP通信 @ohos.net.http
路由管理 @ohos.router
日志系统 @kit.PerformanceAnalysisKit (hilog)
应用生命周期 @kit.AbilityKit (UIAbility)
窗口管理 @kit.ArkUI (window)

1.3 项目结构

huaweidemo/
├── AppScope/
│   └── app.json5                    # 应用全局配置
├── entry/
│   ├── build-profile.json5          # 模块构建配置
│   └── src/main/
│       ├── module.json5             # 模块配置(权限、Ability声明)
│       ├── ets/
│       │   ├── entryability/
│       │   │   └── EntryAbility.ets # 应用入口Ability
│       │   ├── pages/
│       │   │   ├── Index.ets        # 首页(输入+意图识别入口)
│       │   │   ├── IntentRecognition.ets  # 意图识别确认页
│       │   │   ├── ItineraryDetail.ets    # 行程详情页
│       │   │   └── EditPlan.ets     # 行程编辑页
│       │   ├── components/
│       │   │   ├── InputSection.ets         # 输入区域组件
│       │   │   ├── IntentDialog.ets         # 意图对话组件
│       │   │   ├── PickerModal.ets          # 通用选择弹窗
│       │   │   └── DestinationPickerModal.ets # 目的地选择弹窗
│       │   └── theme.ets            # 统一主题系统
│       ├── resources/
│       │   └── base/
│       │       ├── element/
│       │       │   ├── string.json  # 字符串资源(支持国际化)
│       │       │   └── color.json   # 颜色资源
│       │       └── profile/
│       │           └── main_pages.json  # 页面路由配置
│       └── rawfile/                 # 原始资源文件(图片等)
└── hvigorfile.ts                    # 根构建配置

1.4项目演示

可进行在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

二、核心技术架构设计

2.1 声明式UI与组件化设计

ArkUI采用声明式UI范式,开发者只需描述UI的"最终状态",框架自动处理状态变化时的UI更新。本项目充分利用了这一特性,通过@State@Prop@Link等装饰器实现了高效的组件间通信。

主页面状态管理

在[Index.ets](file:///d:/HP/project/huaweidemo/entry/src/main/ets/pages/Index.ets)中,主页面通过@State管理了多个关键状态:

@State userInput: string = '';           // 用户输入文本
@State isListening: boolean = false;     // 语音输入状态
@State currentStep: ResourceStr = '输入需求';  // 当前步骤提示
@State itinerary: Itinerary = new Itinerary(); // 行程数据
@State showDialog: boolean = false;      // 是否显示意图对话
@State showLoading: boolean = false;     // 是否显示加载动画
@State identifiedIdentity: ResourceStr = '';  // 识别的用户身份
@State identifiedPurpose: ResourceStr = '';   // 识别出行目的
@State identifiedMood: ResourceStr = '期待';  // 识别当前心情
@State bgStyle: string = '#F9FCFF';     // 动态背景色

这种设计将UI渲染与业务状态完全解耦。当任何一个@State变量发生变化时,ArkUI框架会自动触发相关UI组件的重新渲染,开发者无需手动操作DOM。

组件间通信模式

本项目采用了三种典型的组件通信模式:

  1. @Link 双向绑定:父组件将状态传递给子组件,子组件修改后父组件自动同步。例如InputSection组件通过@Link userInput: string接收用户输入:
// InputSection.ets
export struct InputSection {
  @Link userInput: string;          // 双向绑定,子组件修改会自动同步到父组件
  @Prop useTravelPreference: boolean = true; // 单向传递,只读
  onGeneratePlan: () => void = () => {};     // 回调函数传递
}
  1. @Prop 单向传递:父组件将数据传给子组件展示,子组件不可修改。例如IntentDialog通过@Prop接收意图识别结果:
export struct IntentDialog {
  @Prop identifiedIdentity: ResourceStr = '';
  @Prop identifiedPurpose: ResourceStr = '';
  @Prop identifiedMood: ResourceStr = '期待';
  @Prop destination: ResourceStr = '未选择';
}
  1. 回调函数:子组件通过回调函数将事件通知父组件,如PickerModalonSelect回调:
onSelect: (value: ResourceStr) => void = () => {};
onClose: () => void = () => {};

2.2 统一主题系统设计

在[theme.ets](file:///d:/HP/project/huaweidemo/entry/src/main/ets/theme.ets)中,项目定义了一套完整的Design Token系统,将颜色、字体、间距、圆角、阴影、动画等设计参数统一管理:

export class Theme {
  static readonly colors: Colors = {
    primary: '#91D5FF',       // 主题色
    primaryLight: '#BAE7FF',  // 浅主题色
    primaryDark: '#40A9FF',   // 深主题色
    secondary: '#6BD8D7',     // 辅助色
    accent: '#FFB86C',        // 强调色
    neutral: {                // 中性色阶(9级)
      neutral50: '#fafafa',
      // ... neutral100 ~ neutral900
    },
    background: { primary: '#FAFCFF', secondary: '#fff', modal: '#fff9f0' },
    text: { primary: '#333333', secondary: '#666666', hint: '#999999' },
    status: { success: '#4caf50', warning: '#ff9800', error: '#f44336', info: '#2196f3' },
    shadow: { light: 'rgba(0,0,0,0.05)', medium: 'rgba(0,0,0,0.1)', heavy: 'rgba(0,0,0,0.15)' }
  };

  static readonly typography: Typography = {
    heading1: { fontSize: 32, fontWeight: FontWeight.Bold, lineHeight: 40 },
    heading2: { fontSize: 24, fontWeight: FontWeight.Bold, lineHeight: 32 },
    heading3: { fontSize: 20, fontWeight: FontWeight.Medium, lineHeight: 28 },
    bodyLarge: { fontSize: 18, fontWeight: FontWeight.Medium, lineHeight: 26 },
    body: { fontSize: 16, fontWeight: FontWeight.Normal, lineHeight: 24 },
    bodySmall: { fontSize: 14, fontWeight: FontWeight.Normal, lineHeight: 20 },
    caption: { fontSize: 12, fontWeight: FontWeight.Normal, lineHeight: 16 }
  };

  static readonly spacing: Spacing = {
    xs: 4, sm: 8, md: 16, lg: 24, xl: 32, xxl: 48, xxxl: 64
  };

  static readonly borderRadius: BorderRadius = {
    none: 0, sm: 4, md: 8, lg: 16, xl: 24, xxl: 32, full: 9999
  };

  static readonly shadows: Shadows = {
    subtle: { radius: 4, color: 'rgba(0,0,0,0.05)', offsetX: 0, offsetY: 2 },
    medium: { radius: 8, color: 'rgba(0,0,0,0.1)', offsetX: 0, offsetY: 4 },
    strong: { radius: 16, color: 'rgba(0,0,0,0.15)', offsetX: 0, offsetY: 8 }
  };
}

设计亮点

  • 中性色阶:9级色阶(neutral50 ~ neutral900)覆盖了从背景到文字的所有灰度需求,避免在组件中硬编码颜色值
  • 语义化命名:使用primarysecondaryaccentstatus等语义化名称,而非bluegreen等具体颜色名,方便后续换肤
  • 静态常量:使用static readonly确保Theme在全局唯一且不可变,所有组件通过Theme.colors.primary引用,实现设计一致性
  • 类型安全:通过TypeScript的interface定义每种Token的结构,编译期即可发现引用错误

2.3 页面路由与导航设计

HarmonyOS的Stage模型使用@ohos.router进行页面导航。本项目共有4个页面,路由配置在main_pages.json中:

{"src": ["pages/Index", "pages/IntentRecognition", "pages/ItineraryDetail", "pages/EditPlan"]}

页面跳转流程:

Index(首页)
  └─→ IntentRecognition(意图识别确认)
        └─→ ItineraryDetail(行程详情)
              └─→ EditPlan(行程编辑)

路由参数传递设计采用了强类型接口

// Index.ets 中定义的路由参数接口
export interface IntentParams {
  need: string;          // 用户需求
  userInput: string;     // 用户原始输入
  aiResponse: string;    // AI响应文本
  destination: string;   // 选择的目的地
}

export interface TravelRouteParams {
  need: string;
  userIdentity: string;
  travelPurpose: string;
  travelMood?: string;
  userInput?: string;
  itinerary: string;     // JSON序列化的行程数据
}

这种设计的好处是:

  1. 编译期检查:使用TypeScript接口定义参数结构,避免运行时字段名拼写错误
  2. 自文档化:接口本身就是参数文档,开发者一眼就能知道需要传递哪些字段
  3. 可扩展性:通过可选字段(?)支持渐进式扩展

三、AI Agent设计模式

3.1 智能体架构

项目中最核心的设计是AI Agent模式(位于[Index.ets](file:///d:/HP/project/huaweidemo/entry/src/main/ets/pages/Index.ets#L893-L1059)中的AIAgent类)。它将自然语言理解、信息抽取、推荐生成、行程规划等能力封装为独立的智能体:

class AIAgent {
  // 1. 信息抽取层:从用户输入中提取结构化信息
  recognizeFlightInfo(userInput: string): FlightInfo | null { ... }
  recognizeHotelInfo(userInput: string): HotelInfo | null { ... }

  // 2. 意图理解层:理解用户意图并构建意图对象
  understandIntent(userInput, userIdentity, travelPurpose, flightInfo, hotelInfo): Intent { ... }

  // 3. 推荐引擎层:基于意图生成推荐
  getDestinationRecommendation(intent: Intent): Destination { ... }
  getFlightOptions(destination, intent): Array<Flight> { ... }
  getHotelOptions(destination, intent): Array<Hotel> { ... }
  getAttractions(destination): Array<Attraction> { ... }

  // 4. 规划生成层:生成每日行程
  generateDailyPlans(destination, intent, attractions): Array<DailyPlan> { ... }

  // 5. 总结生成层:生成自然语言总结
  async generateSummary(itinerary, destination, intent): Promise<string> { ... }

  // 6. 外部API调用层
  async fetchRealWeatherData(city: string): Promise<WeatherData | null> { ... }

  // 主入口:处理完整请求
  async processRequest(userInput, userIdentity, travelPurpose): Promise<PlanResult> {
    const flightInfo = this.recognizeFlightInfo(userInput);
    const hotelInfo = this.recognizeHotelInfo(userInput);
    const intent = this.understandIntent(userInput, userIdentity, travelPurpose, flightInfo, hotelInfo);
    const destination = this.getDestinationRecommendation(intent);
    const flights = flightInfo ? [this.convertFlightInfo(flightInfo)] : this.getFlightOptions(destination, intent);
    const hotels = hotelInfo ? [this.convertHotelInfo(hotelInfo)] : this.getHotelOptions(destination, intent);
    const attractions = this.getAttractions(destination);
    const dailyPlans = this.generateDailyPlans(destination, intent, attractions);
    const itinerary = this.buildItinerary(destination, intent, flights, hotels, dailyPlans);
    const summary = await this.generateSummary(itinerary, destination, intent);
    return { summary, itinerary };
  }
}

3.2 正则表达式信息抽取

recognizeFlightInforecognizeHotelInfo方法使用正则表达式从自然语言中提取结构化信息,这是端侧轻量级NLP的经典实践:

recognizeFlightInfo(userInput: string): FlightInfo | null {
  const flightPatterns = [
    /([A-Z]{2}\d{3,4})/,                    // 航班号:如 CA1234
    /(\d{4}-\d{2}-\d{2})/,                  // 日期:如 2024-12-20
    /(\d{1,2}:\d{2})(\d{1,2}:\d{2})/,     // 时间范围:如 08:00到11:30
    /(.+?)(.+?)/                         // 城市对:如 从北京到三亚
  ];
  // 通过正则匹配提取航班信息 ...
}

这种方案的优势在于:

  • 零依赖:不需要引入任何NLP库,完全在端侧执行
  • 低延迟:正则匹配在毫秒级完成
  • 可解释:规则清晰,便于调试和维护

3.3 基于用户画像的推荐引擎

项目的推荐引擎不再是一刀切的热门推荐,而是基于用户身份画像的精准匹配。在getSmartRecommendation方法中,系统根据用户身份、出行目的、当前心情三个维度构建推荐矩阵:

getSmartRecommendation(): string {
  const identity = this.identifiedIdentity.toString();
  const purpose = this.identifiedPurpose.toString();
  const mood = this.identifiedMood.toString();

  // 上班族 + 放松解压 → 大理
  if (identity.includes('上班族') && (purpose.includes('放松') || purpose.includes('解压'))) {
    return '大理';
  }
  // 大学生 + 极致性价比/穷游 → 桂林/厦门/西安/成都
  if (identity.includes('大学生') && (purpose.includes('性价比') || purpose.includes('穷游'))) {
    const budgetCities = ['桂林', '厦门', '西安', '成都'];
    return budgetCities[Math.floor(Math.random() * budgetCities.length)];
  }
  // 银发族 + 文化探索 → 北京/西安/杭州/成都
  if (identity.includes('银发') && (purpose.includes('文化') || purpose.includes('历史'))) {
    const culturalCities = ['北京', '西安', '杭州', '成都'];
    return culturalCities[Math.floor(Math.random() * culturalCities.length)];
  }
  // 亲子家庭 → 成都(熊猫)/三亚(海滩)/厦门(文艺)
  if (identity.includes('亲子') || identity.includes('家庭')) {
    const familyCities = ['成都', '三亚', '厦门', '桂林'];
    return familyCities[Math.floor(Math.random() * familyCities.length)];
  }
  // ...
}

推荐策略的设计哲学

用户画像 推荐偏好 设计依据
上班族 大理、三亚、厦门 慢节奏、放松解压、远离工作
大学生 桂林、西安、成都 性价比高、文化底蕴、社交属性
银发族 北京、杭州、桂林 文化景点、交通便利、节奏舒缓
亲子家庭 成都、三亚、桂林 熊猫乐园、海滩玩沙、自然风光
情侣 丽江、三亚、杭州 浪漫氛围、网红打卡、蜜月氛围

3.4 情感化交互设计

项目不仅关注功能实现,还精心设计了情感化交互。在getEmotionComfortMessage方法中,系统根据用户身份和心情生成个性化的安抚话术:

getEmotionComfortMessage(identity: string, mood: string, userInput: string): string {
  // 疲惫的上班族 - 治愈与逃离
  if (identity.includes('上班族') || mood === '疲惫' || userInput.includes('累')) {
    return '亲爱的,辛苦了。这次我们不赶时间,只赶日落。去海边发发呆吧,工作群的消息先放一放。';
  }
  // 热血的大学生 - 震撼与性价比
  if (identity.includes('大学生') || mood === '热血') {
    return '青春没有售价,硬座直达拉萨!趁年轻,去看看祖国的大好河山,这趟旅程绝对是你简历上最酷的一笔!';
  }
  // 银发族 - 悠闲与怀旧
  if (identity.includes('银发') || identity.includes('老年') || mood === '怀旧') {
    return '岁月静好,您值得一段悠闲的旅程。让我们慢慢走,看看祖国的大好河山,品味每一处风景的独特韵味。';
  }
  // ...
}

这种情感化设计让用户感受到App不是在"冷冰冰地处理任务",而是在"温暖地陪伴用户",是产品体验从"能用"到"好用"的关键一步。


四、数据模型与领域驱动设计

4.1 领域模型设计

项目定义了一套完整的领域模型,涵盖行程规划的各个实体:

// 核心聚合根:行程
class Itinerary {
  destination: string;        // 目的地
  startDate: string;          // 开始日期
  endDate: string;            // 结束日期
  budget: number;             // 预算
  flights: Array<Flight>;     // 航班列表
  hotels: Array<Hotel>;       // 酒店列表
  dailyPlans: Array<DailyPlan>; // 每日计划
  userIdentity: string;       // 用户身份
  travelPurpose: string;      // 出行目的
  travelMood: string;         // 出行心情
}

// 实体:航班
class Flight {
  airline: string;            // 航空公司
  flightNumber: string;       // 航班号
  departure: string;          // 出发城市
  arrival: string;            // 到达城市
  departureTime: string;      // 出发时间
  arrivalTime: string;        // 到达时间
  price: number;              // 价格
}

// 实体:酒店
class Hotel {
  name: string;               // 酒店名称
  address: string;            // 地址
  pricePerNight: number;      // 每晚价格
  rating: number;             // 评分
  amenities: Array<string>;   // 设施列表
}

// 实体:每日计划
class DailyPlan {
  day: number;                // 第几天
  activities: Array<string>;  // 活动列表
  meals: Array<string>;       // 餐饮列表
  transportation: string;     // 交通方式
  weather: string;            // 天气
  clothingAdvice: string;     // 穿搭建议
  routeInfo: RouteInfo;       // 路线信息
}

// 值对象:路线信息
class RouteInfo {
  startPoint: string;         // 起点
  endPoint: string;           // 终点
  distance: string;           // 距离
  duration: string;           // 耗时
  steps: Array<RouteStep>;    // 步骤
  mapLink: string;            // 地图链接
}

4.2 聚合根设计思路

Itinerary作为聚合根,包含了行程的全部信息。这种设计的优势在于:

  1. 数据一致性:对行程的修改都通过Itinerary聚合根进行,确保航班、酒店、每日计划之间的数据一致性
  2. 序列化便利JSON.stringify(itinerary)即可将整个行程序列化为JSON字符串,便于路由传递和持久化存储
  3. 版本管理:聚合根可以携带版本号,支持行程数据的版本控制和增量更新

4.3 编辑模式下的行程项模型

在[ItineraryDetail.ets](file:///d:/HP/project/huaweidemo/entry/src/main/ets/pages/ItineraryDetail.ets)和[EditPlan.ets](file:///d:/HP/project/huaweidemo/entry/src/main/ets/pages/EditPlan.ets)中,项目定义了更细粒度的行程项模型:

interface ItineraryItem {
  id: string;                              // 唯一标识
  type: 'attraction' | 'restaurant' | 'transportation' | 'hotel' | 'activity'; // 类型
  name: string;                            // 名称
  description: string;                     // 描述
  time: string;                            // 时间
  period: TimePeriod;                      // 时间段(早上/上午/中午/下午/晚上/夜间)
  location: string;                        // 位置
  cost: number;                            // 费用
  rating?: number;                         // 评分
  icon: string;                            // 图标
  attractionDetail?: AttractionDetail;     // 景点详情(景点专属)
  restaurantDetail?: RestaurantDetail;     // 餐厅详情(餐饮专属)
}

这里的TimePeriod类型定义非常精妙:

type TimePeriod = 'morning' | 'forenoon' | 'noon' | 'afternoon' | 'evening' | 'night';

将一天划分为6个时段,使得行程编排更加精细。每个行程项归属于特定时段,用户可以按时间顺序查看和调整行程安排。


五、HTTP API集成与外部数据源

5.1 天气API集成

项目通过@ohos.net.http模块调用第三方天气API,实时获取目的地天气数据:

async fetchWeatherData(city: string): Promise<void> {
  if (!city || city.trim() === '') return;
  this.isLoadingWeather = true;

  try {
    const apiKey = '6d997a997fbf';
    const url = `https://whyta.cn/api/tianqi?key=${apiKey}&city=${encodeURIComponent(city)}`;

    const httpRequest = http.createHttp();
    const response = await httpRequest.request(url, {
      method: http.RequestMethod.GET,
      header: { 'Content-Type': 'application/json' },
      connectTimeout: 60000,
      readTimeout: 60000
    });

    if (response.responseCode === 200) {
      this.weatherData = JSON.parse(response.result.toString()) as WeatherData;
    }
    httpRequest.destroy();
  } catch (error) {
    console.error('获取天气数据失败:', error);
  }
  this.isLoadingWeather = false;
}

关键设计点

  1. 资源释放:无论成功失败,都调用httpRequest.destroy()释放HTTP连接资源
  2. 超时设置:设置了60秒的连接超时和读取超时,避免网络不稳定时长时间挂起
  3. URL编码:使用encodeURIComponent对中文城市名进行URL编码
  4. 响应式状态:通过@State isLoadingWeather控制UI的加载状态显示

5.2 景点API集成

类似地,景点查询API也采用相同的设计模式:

async fetchScenicInfo(word: string): Promise<void> {
  const url = `https://whyta.cn/api/tx/scenic?key=${apiKey}&word=${encodeURIComponent(word)}`;
  // ... 相同的HTTP调用模式
}

API响应数据结构

interface ScenicResponse {
  code: number;
  msg: string;
  result: {
    list: Array<{
      name: string;
      content: string;
      province: string;
      city: string;
    }>;
  };
}

interface WeatherData {
  city: string;
  temperature: string;
  weather: string;
  winddir: string;
  windspeed: string;
  humidity: string;
  precip: string;
}

5.3 离线降级策略

项目在API调用失败时,设计了完善的离线降级策略。以景点详情为例,generateAttractionDetail方法为9个城市(大理、北京、上海、成都、西安、杭州、三亚、丽江、厦门、桂林)的数十个热门景点预置了离线数据:

generateAttractionDetail(name: string): AttractionDetail {
  const destination = this.itinerary.destination;

  // 大理景点
  if (destination.includes('大理') || destination.includes('云南')) {
    if (name === '洱海' || name.includes('洱海')) {
      return {
        needReservation: '无需预约',
        openTime: '全天开放(建议8:00-18:00)',
        ticketInfo: '环海公路免费,部分观景台收费10-20元',
        tips: ['租电动车约60元/天,记得戴头盔', '带防晒霜和墨镜,紫外线强', ...],
        suggestedDuration: '建议半日游(4-5小时),可分段进行',
        workerFriendlyTip: '不用早起看日出,下午去光线更好,适合悠闲骑行'
      };
    }
    // ... 更多景点
  }
  // 默认通用模板
  return {
    needReservation: '建议提前咨询或现场确认',
    openTime: '09:00-17:00',
    tips: ['穿舒适的鞋子', '注意天气变化', ...],
    suggestedDuration: '建议游玩1.5-2小时',
    workerFriendlyTip: '轻松游玩,不必赶时间,享受旅途'
  };
}

这种离线预置数据的策略确保了:

  • 无网络时仍能提供有价值的景点信息
  • 首屏加载速度极快,无需等待API响应
  • 在线API数据作为增强补充,而非必需依赖

六、动态UI与用户体验优化

6.1 时段感知的动态问候语

首页的问候语会根据当前时间动态变化,让用户感受到App的"生命力":

updateDynamicPrompt() {
  const now = new Date();
  const hour = now.getHours();
  const day = now.getDay();

  if (day === 1 && hour < 12) {
    this.dynamicPrompt = '新的一周辛苦了,想去哪里透透气?';
  } else if (day === 5 && hour >= 18) {
    this.dynamicPrompt = '周末到了,是去拥抱山海,还是去城市漫步?';
  } else if (hour < 12) {
    this.dynamicPrompt = '早上好!今天想计划一次怎样的旅行?';
  } else if (hour < 18) {
    this.dynamicPrompt = '下午好!工作之余,有没有想去的地方?';
  } else {
    this.dynamicPrompt = '晚上好!是时候规划一次放松身心的旅行了';
  }
}

设计亮点

  • 周末(周五晚上)触发特殊的"周末模式"问候语
  • 周一早晨触发"关怀模式"问候语,站在用户角度体谅疲惫
  • 不同时段使用不同的语气和内容,让每一次打开都有新鲜感

6.2 身份感知的加载提示

加载动画不仅是视觉上的等待反馈,还会根据用户身份展示不同的文案:

Text(
  this.userIdentity.includes('上班族') ? '正在为你寻找治愈角落...' :
  this.userIdentity.includes('大学生') ? '正在计算最优穷游路线...' :
  '正在为你规划完美旅程...'
)

6.3 可编辑的行程系统

[EditPlan.ets](file:///d:/HP/project/huaweidemo/entry/src/main/ets/pages/EditPlan.ets)实现了完整的行程编辑功能,支持:

  • 按天浏览:通过水平滚动的Tab切换不同天数的行程
  • 添加行程:支持添加景点、餐饮、交通、活动四种类型
  • 编辑行程:修改已有行程项的名称、时间、位置、费用
  • 删除行程:移除不需要的行程项
  • 数据持久化:通过AppStorage在页面间传递编辑后的数据
saveAndBack() {
  AppStorage.setOrCreate('updatedDayPlans', JSON.stringify(this.dayPlans));
  router.back();
}

这种设计让用户不仅能"接受AI生成的计划",还能"自由调整和定制",真正实现了人机协作的旅行规划。


七、国际化与资源管理

7.1 字符串资源化

项目将所有用户可见的文本提取到string.json资源文件中,支持多语言切换:

{
  "string": [
    { "name": "app_title", "value": "旅行规划助手" },
    { "name": "input_placeholder", "value": "告诉我你的旅行想法" },
    { "name": "morning_greeting", "value": "早上好!今天想计划一次怎样的旅行?" },
    { "name": "identity_office_worker", "value": "上班族" },
    { "name": "identity_college_student", "value": "大学生" },
    { "name": "purpose_relaxation", "value": "放松解压" },
    { "name": "purpose_budget_optimization", "value": "极致性价比" },
    { "name": "loading_office_worker", "value": "正在为你寻找治愈角落..." },
    { "name": "loading_college_student", "value": "正在计算最优穷游路线..." }
    // ... 共240+个字符串资源
  ]
}

在代码中通过$r('app.string.xxx')引用,支持参数化:

Text($r('app.string.identity_label', { identity: this.identifiedIdentity }))

7.2 页面路由配置化

页面列表通过main_pages.json集中管理,而非在代码中硬编码:

{"src": ["pages/Index", "pages/IntentRecognition", "pages/ItineraryDetail", "pages/EditPlan"]}

八、项目技术亮点总结

8.1 架构设计亮点

方面 实践 价值
组件化 4个页面 + 4个可复用组件 高内聚低耦合,组件可独立测试和复用
主题系统 静态Design Token类 全局样式一致性,一次修改全局生效
状态管理 @State/@Prop/@Link装饰器 声明式UI,数据驱动视图更新
路由设计 强类型接口参数传递 编译期检查,避免运行时参数错误
AI Agent 多层管道式处理架构 单一职责,可独立测试和替换各层

8.2 用户体验亮点

方面 实践 价值
情感化设计 时段问候语、身份感知提示、安抚话术 产品有温度,用户有共鸣
离线降级 预置9城数十景点离线数据 无网络也能用,首屏加载快
智能推荐 用户画像×目的×心情三维推荐 千人千面,推荐精准
可编辑行程 完整的增删改查功能 人机协作,用户有掌控感
多维关怀 穿搭建议、天气查询、贴心提醒 超出预期的服务体验

8.3 工程化亮点

方面 实践 价值
国际化 240+字符串资源化 多语言支持就绪
类型安全 全面使用TypeScript接口 编译期发现错误
资源管理 HTTP连接正确释放 避免内存泄漏
错误处理 try-catch + 降级策略 应用健壮性高
日志系统 hilog分级日志 便于调试和线上追踪

九、技术展望与改进方向

虽然本项目已经是一个功能完备的旅行规划助手,但仍有以下可扩展方向:

9.1 接入真实AI大模型

当前AI Agent采用规则匹配和模拟数据,未来可接入真实的大语言模型(如盘古大模型),实现真正意义上的自然语言理解和行程生成。接入方式可以通过HarmonyOS的AI Kit实现端侧推理,或通过HTTP API调用云端模型。

9.2 分布式能力扩展

HarmonyOS的核心优势在于分布式能力。本项目可扩展:

  • 多设备协同:手机规划行程,智能屏展示详情,手表推送行程提醒
  • 跨设备数据同步:通过分布式数据管理,在多个设备间同步行程数据
  • 碰一碰分享:通过NFC碰一碰,与同伴分享行程计划

9.3 地图与导航集成

当前行程中的路线信息(起点、终点、距离、耗时)仅为静态文本,可集成HarmonyOS的地图服务,实现:

  • 地图可视化展示行程路线
  • 实时导航到景点
  • 周边推荐(餐厅、酒店、加油站等)

9.4 社交化功能

  • 行程分享到社交平台
  • 好友协同编辑行程
  • 社区UGC攻略内容

十、总结

本文从项目架构、组件设计、AI Agent模式、数据模型、API集成、用户体验优化等多个维度,全面剖析了一个基于HarmonyOS ArkTS的AI旅行规划助手的技术实现。

这个项目虽小,但涵盖了现代移动应用开发的诸多核心实践:声明式UI与组件化设计、统一主题系统、强类型路由参数、管道式AI Agent架构、离线降级策略、情感化交互设计等。这些技术实践不仅适用于HarmonyOS开发,其设计思想同样可以迁移到Android(Jetpack Compose)、iOS(SwiftUI)、Flutter、React Native等跨平台框架中。

对于正在学习HarmonyOS应用开发的读者,本项目是一个极具参考价值的实践案例——它展示了一个"小而美"的应用如何从零开始,通过良好的架构设计和对细节的极致追求,打磨出兼具实用功能和情感温度的产品体验。


项目信息:本项目基于HarmonyOS 6.1.0 (API 23),使用ArkTS语言开发,采用Stage模型。项目地址见文首文件路径。

免责声明:本文中的AI Agent采用规则匹配和模拟数据实现,用于演示架构设计思路。生产环境建议接入真实的大语言模型API。# 基于HarmonyOS ArkTS的AI旅行规划助手:从零到一构建端侧智能应用

Logo

AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。

更多推荐