旅行预算管家应用


欢迎加入开源鸿蒙跨平台社区:
https://openharmonycrossplatform.csdn.net

一、项目概述

运行效果图

image-20260409192843947

image-20260409192850459

image-20260409192855842

image-20260409192900327

1.1 应用简介

旅行预算管家是一款旅行探索类应用,为旅行者提供全程预算管理服务。支持预算规划、实时记账、多币种换算、支出分析四大核心功能,帮助用户在旅途中合理控制开支,避免超支尴尬。无论是短途周末游还是长途跨国旅行,都能轻松掌握财务状况。

应用以清新的青色为主色调,象征旅途的轻松与自由。涵盖预算概览、支出记录、支出分析、我的旅行四大模块。用户可以创建旅行计划、设定预算、记录每笔支出、查看分析报告,实现旅行财务的全方位管理。

1.2 核心功能

功能模块功能描述实现方式
预算规划创建旅行并设定预算表单输入
实时记账快速记录每笔支出分类记账
多币种支持10种货币换算汇率转换
支出分析分类统计与可视化饼图展示
进度追踪预算使用进度监控进度条
旅行管理多次旅行统一管理列表展示

1.3 货币类型定义

序号货币名称符号代码汇率(参考)
1人民币¥CNY1.0
2美元$USD0.14
3欧元EUR0.13
4日元¥JPY21.0
5韩元KRW188.0
6泰铢฿THB4.9
7港币HK$HKD1.09
8新币S$SGD0.19
9马币RMMYR0.66
10澳元A$AUD0.21

1.4 支出分类定义

序号分类名称Emoji颜色代码描述
1交通🚗#2196F3机票、车票等
2住宿🏨#9C27B0酒店、民宿
3餐饮🍜#FF9800餐厅、小吃
4购物🛍️#E91E63纪念品、特产
5娱乐🎢#4CAF50游乐、表演
6门票🎫#00BCD4景点门票
7通讯📱#795548电话卡、WiFi
8医疗💊#F44336药品、就医
9其他📦#607D8B其他支出

1.5 旅行状态定义

序号状态名称Emoji颜色代码描述
1计划中📋#9E9E9E尚未出发
2进行中✈️#4CAF50正在旅行
3已完成#2196F3旅行结束
4已取消#F44336取消计划

1.6 技术栈

技术领域技术选型版本要求
开发框架Flutter>= 3.0.0
编程语言Dart>= 2.17.0
设计规范Material Design 3-
自定义绘制CustomPainter-
图表展示饼图绘制-
目标平台鸿蒙OS / WebAPI 21+

1.7 项目结构

lib/
└── main_travel_budget.dart
    ├── TravelBudgetApp              # 应用入口
    ├── Currency                     # 货币类型枚举
    ├── ExpenseCategory              # 支出分类枚举
    ├── TripStatus                   # 旅行状态枚举
    ├── Trip                         # 旅行模型
    ├── Expense                      # 支出模型
    ├── BudgetAllocation             # 预算分配模型
    ├── TravelBudgetHomePage         # 主页面(底部导航)
    ├── _buildOverviewPage           # 预算概览页
    ├── _buildExpensesPage           # 支出记录页
    ├── _buildAnalysisPage           # 支出分析页
    ├── _buildTripsPage              # 我的旅行页
    └── PieChartPainter              # 饼图绘制器

二、系统架构

2.1 整体架构图

Data Layer

Business Layer

Presentation Layer

主页面
TravelBudgetHomePage

预算概览

支出记录

支出分析

我的旅行

预算进度

今日支出

统计卡片

日期分组

支出列表

添加支出

饼图展示

分类明细

旅行列表

创建旅行

货币转换器
CurrencyConverter

支出计算器
ExpenseCalculator

图表绘制器
ChartPainter

Trip
旅行模型

Expense
支出模型

Currency
货币枚举

ExpenseCategory
支出分类

2.2 类图设计

uses

has

uses

has

belongs to

TravelBudgetApp

+Widget build()

«enumeration»

Currency

+String label

+String symbol

+String code

+double rate

+toCny(amount)

+fromCny(amount)

+cny()

+usd()

+eur()

+jpy()

+krw()

+thb()

«enumeration»

ExpenseCategory

+String label

+String icon

+Color color

+transport()

+accommodation()

+food()

+shopping()

+entertainment()

+tickets()

«enumeration»

TripStatus

+String label

+String icon

+Color color

+planning()

+ongoing()

+completed()

+cancelled()

Trip

+String id

+String name

+String destination

+DateTime startDate

+DateTime endDate

+double budget

+Currency currency

+TripStatus status

+int days

+int daysRemaining

Expense

+String id

+String tripId

+String title

+double amount

+Currency currency

+ExpenseCategory category

+DateTime date

+double amountInCny

2.3 页面导航流程

概览

记录

分析

旅行

应用启动

预算概览

底部导航

查看预算进度

支出列表

饼图分析

旅行列表

添加支出

填写支出信息

保存支出

创建旅行

填写旅行信息

保存旅行

查看分类明细

2.4 记账流程

概览页支出管理记账弹窗用户概览页支出管理记账弹窗用户点击记一笔显示表单输入支出名称输入金额选择货币选择分类创建支出记录计算人民币金额更新统计数据显示更新后的进度

三、核心模块设计

3.1 数据模型设计

3.1.1 货币类型枚举 (Currency)
enum Currency {
  cny('人民币', '¥', 'CNY', 1.0),
  usd('美元', '\$', 'USD', 0.14),
  eur('欧元', '€', 'EUR', 0.13),
  jpy('日元', '¥', 'JPY', 21.0),
  krw('韩元', '₩', 'KRW', 188.0),
  thb('泰铢', '฿', 'THB', 4.9),
  hkd('港币', 'HK\$', 'HKD', 1.09),
  sgd('新币', 'S\$', 'SGD', 0.19),
  myr('马币', 'RM', 'MYR', 0.66),
  aud('澳元', 'A\$', 'AUD', 0.21);

  final String label;
  final String symbol;
  final String code;
  final double rate;

  double toCny(double amount) => amount / rate;
  double fromCny(double amount) => amount * rate;
}
3.1.2 支出分类枚举 (ExpenseCategory)
enum ExpenseCategory {
  transport('交通', '🚗', Color(0xFF2196F3)),
  accommodation('住宿', '🏨', Color(0xFF9C27B0)),
  food('餐饮', '🍜', Color(0xFFFF9800)),
  shopping('购物', '🛍️', Color(0xFFE91E63)),
  entertainment('娱乐', '🎢', Color(0xFF4CAF50)),
  tickets('门票', '🎫', Color(0xFF00BCD4)),
  communication('通讯', '📱', Color(0xFF795548)),
  medical('医疗', '💊', Color(0xFFF44336)),
  other('其他', '📦', Color(0xFF607D8B));

  final String label;
  final String icon;
  final Color color;
}
3.1.3 旅行模型 (Trip)
class Trip {
  final String id;              // 旅行ID
  final String name;            // 旅行名称
  final String destination;     // 目的地
  final DateTime startDate;     // 开始日期
  final DateTime endDate;       // 结束日期
  final double budget;          // 预算金额
  final Currency currency;      // 预算货币
  final TripStatus status;      // 旅行状态
  final String? coverImage;     // 封面图片
  final DateTime createdAt;     // 创建时间

  int get days => endDate.difference(startDate).inDays + 1;
  int get daysRemaining => endDate.difference(DateTime.now()).inDays;
}
3.1.4 支出模型 (Expense)
class Expense {
  final String id;              // 支出ID
  final String tripId;          // 所属旅行ID
  final String title;           // 支出名称
  final double amount;          // 金额
  final Currency currency;      // 货币类型
  final ExpenseCategory category; // 支出分类
  final DateTime date;          // 支出日期
  final String? notes;          // 备注
  final String? receipt;        // 小票图片

  double get amountInCny => currency.toCny(amount);
}
3.1.5 支出分类分布
30%25%20%15%5%5%支出分类分布示例交通住宿餐饮购物门票其他

3.2 页面结构设计

3.2.1 主页面布局

TravelBudgetHomePage

IndexedStack

预算概览页

支出记录页

支出分析页

我的旅行页

NavigationBar

概览 Tab

记录 Tab

分析 Tab

旅行 Tab

3.2.2 预算概览页结构

预算概览页

预算进度卡

统计卡片组

今日支出

总预算显示

进度条

已支出/剩余

行程天数

目的地

日均预算

预计支出

今日支出列表

空状态提示

3.2.3 支出记录页结构

支出记录页

统计头部

日期分组列表

日期组

日期标题

当日合计

支出项列表

支出项

分类图标

支出名称

金额显示

3.2.4 支出分析页结构

支出分析页

统计头部

饼图区域

分类明细列表

饼图绘制

中心总金额

分类项

分类图标

进度条

金额/百分比

3.3 货币换算逻辑

CNY

其他

获取支出金额

货币类型

直接使用

获取汇率

计算人民币金额

amount / rate

累加统计

更新预算进度

更新分类统计

3.4 预算进度计算

获取旅行预算

转换为人民币

获取总支出

计算进度百分比

percentage = spent / budget

是否超支

显示红色警告

显示正常进度

计算剩余金额

更新UI显示


四、UI设计规范

4.1 配色方案

应用以清新的青色为主色调,象征旅途的轻松与自由:

颜色类型色值用途
主色#00ACC1 (Cyan)导航、主题元素
辅助色#00838F支出记录页
第三色#006064分析页面
强调色#00BCD4进度条
背景色#006064页面背景
卡片背景#00838F统计卡片

4.2 分类颜色规范

分类色值视觉效果
交通#2196F3蓝色
住宿#9C27B0紫色
餐饮#FF9800橙色
购物#E91E63粉色
娱乐#4CAF50绿色
门票#00BCD4青色
通讯#795548棕色
医疗#F44336红色
其他#607D8B灰蓝

4.3 字体规范

元素字号字重颜色
页面标题24pxBold白色
预算金额28pxBold白色
支出名称16pxBold#000000
分类标签12pxRegular灰色
统计数字20pxBold白色

4.4 组件规范

4.4.1 预算进度卡片
┌─────────────────────────────────────┐
│  总预算                    进行中   │
│  ¥15000                             │
│  ████████████░░░░░░░░  65%          │
│  已支出 ¥9750      剩余 ¥5250       │
└─────────────────────────────────────┘
4.4.2 统计卡片组
┌─────────────────────────────────────┐
│  📅 行程天数    📍 目的地           │
│     7天           东京              │
├─────────────────────────────────────┤
│  💰 日均预算    📊 预计支出         │
│    ¥2143          ¥6429             │
└─────────────────────────────────────┘
4.4.3 支出项卡片
┌─────────────────────────────────────┐
│  🍜 餐饮                            │
│      拉面                ¥1200      │
│                          ≈¥57      │
└─────────────────────────────────────┘
4.4.4 分类明细项
┌─────────────────────────────────────┐
│  🏨 住宿                            │
│      ████████████░░░░░░░░           │
│                   ¥4500    30.0%    │
└─────────────────────────────────────┘
4.4.5 旅行卡片
┌─────────────────────────────────────┐
│  日本东京之旅              进行中   │
│  📍 日本东京                        │
│  📅 3/15 - 3/21  ⏱️ 7天             │
│  预算: ¥15000      已用: 65%        │
│  ████████████░░░░░░░░               │
└─────────────────────────────────────┘

五、核心功能实现

5.1 货币换算实现

enum Currency {
  cny('人民币', '¥', 'CNY', 1.0),
  jpy('日元', '¥', 'JPY', 21.0),
  // ...

  final double rate;

  // 换算为人民币
  double toCny(double amount) => amount / rate;
  
  // 从人民币换算
  double fromCny(double amount) => amount * rate;
}

汇率换算公式:

AmountCNY=AmountforeignRateforeign Amount_{CNY} = \frac{Amount_{foreign}}{Rate_{foreign}} AmountCNY=RateforeignAmountforeign

5.2 支出统计实现

double _getTotalExpenses(String tripId) {
  return _expenses
    .where((e) => e.tripId == tripId)
    .fold(0.0, (sum, e) => sum + e.amountInCny);
}

Map<ExpenseCategory, double> _getExpensesByCategory(String tripId) {
  Map<ExpenseCategory, double> result = {};
  for (var expense in _expenses.where((e) => e.tripId == tripId)) {
    result[expense.category] = 
      (result[expense.category] ?? 0) + expense.amountInCny;
  }
  return result;
}

5.3 饼图绘制实现

class PieChartPainter extends CustomPainter {
  final Map<ExpenseCategory, double> data;
  final double total;

  
  void paint(Canvas canvas, Size size) {
    final center = Offset(size.width / 2, size.height / 2);
    final radius = size.width < size.height 
      ? size.width / 2 - 20 
      : size.height / 2 - 20;

    double startAngle = -pi / 2;

    for (var entry in data.entries) {
      final sweepAngle = (entry.value / total) * 2 * pi;
      
      final paint = Paint()
        ..color = entry.key.color
        ..style = PaintingStyle.fill;

      canvas.drawArc(
        Rect.fromCircle(center: center, radius: radius),
        startAngle,
        sweepAngle,
        true,
        paint,
      );

      startAngle += sweepAngle;
    }

    // 绘制中心圆
    canvas.drawCircle(center, radius * 0.5, innerPaint);
  }
}

5.4 预算进度计算

预算使用百分比计算:

Percentage=TotalSpentTotalBudget×100% Percentage = \frac{TotalSpent}{TotalBudget} \times 100\% Percentage=TotalBudgetTotalSpent×100%

日均预算计算:

DailyBudget=TotalBudgetTripDays DailyBudget = \frac{TotalBudget}{TripDays} DailyBudget=TripDaysTotalBudget

预计支出计算:

ExpectedSpent=DailyBudget×DaysPassed ExpectedSpent = DailyBudget \times DaysPassed ExpectedSpent=DailyBudget×DaysPassed

5.5 添加支出实现

void _addExpense() {
  if (_selectedTrip == null) return;

  showDialog(
    context: context,
    builder: (context) => AlertDialog(
      title: const Row(
        children: [
          Icon(Icons.add_circle, color: Colors.cyanAccent),
          SizedBox(width: 8),
          Text('添加支出'),
        ],
      ),
      content: Column(
        mainAxisSize: MainAxisSize.min,
        children: [
          TextField(decoration: InputDecoration(hintText: '支出名称')),
          Row(
            children: [
              Expanded(child: TextField(keyboardType: TextInputType.number)),
              DropdownButtonFormField<Currency>(...),
            ],
          ),
          DropdownButtonFormField<ExpenseCategory>(...),
        ],
      ),
    ),
  );
}

六、交互设计

6.1 记账流程

数据层记账弹窗主页用户数据层记账弹窗主页用户点击记一笔显示表单填写支出信息保存支出更新统计显示更新

6.2 旅行切换流程

点击旅行

创建旅行

打开我的旅行

显示旅行列表

用户操作

选中旅行

跳转概览页

显示该旅行数据

显示创建表单

填写信息

保存旅行

6.3 分析查看流程

自动加载

滚动查看

按金额排序

分析页

饼图展示

分类明细

排序显示


七、扩展功能规划

7.1 后续版本规划

2024-01-072024-01-142024-01-212024-01-282024-02-042024-02-112024-02-182024-02-252024-03-032024-03-102024-03-172024-03-242024-03-312024-04-07基础UI框架 预算管理 多币种支持 实时汇率 预算提醒 导出报表 多人分账 云端同步 AI智能建议 V1.0 基础版本V1.1 增强版本V1.2 进阶版本旅行预算管家应用开发计划

7.2 功能扩展建议

7.2.1 实时汇率

汇率功能:

  • 接入汇率API
  • 自动更新汇率
  • 离线汇率缓存
  • 汇率趋势图
7.2.2 预算提醒

提醒功能:

  • 超支预警
  • 日预算提醒
  • 分类预算限制
  • 自定义提醒规则
7.2.3 多人分账

分账功能:

  • 创建旅行群组
  • 成员费用记录
  • 自动分账计算
  • 结算报表导出

八、注意事项

8.1 开发注意事项

  1. 汇率精度:货币换算需注意精度问题

  2. 数据持久化:支出数据需本地持久化存储

  3. 状态管理:旅行切换时需正确更新状态

  4. 图表绘制:CustomPainter需正确实现shouldRepaint

  5. 日期计算:跨日期计算需注意时区问题

8.2 常见问题

问题原因解决方案
汇率不准使用固定汇率接入实时API
金额显示异常精度丢失使用Decimal
饼图不显示数据为空添加空判断
进度超100%超支未处理添加clamp
日期计算错误时区问题统一时区

8.3 使用技巧

💰 旅行预算管理技巧 💰

预算规划建议

  • 交通费用:预留20%弹性空间
  • 住宿费用:提前预订享优惠
  • 餐饮费用:按人均×天数计算
  • 购物费用:设定上限避免冲动

记账习惯培养

  • 每日睡前整理当日支出
  • 大额支出及时记录
  • 保留小票便于核对
  • 分类准确便于分析

超支应对策略

  • 调整后续行程预算
  • 减少非必要支出
  • 寻找免费替代活动
  • 合理使用优惠券

九、运行说明

9.1 环境要求

环境版本要求
Flutter SDK>= 3.0.0
Dart SDK>= 2.17.0
鸿蒙OSAPI 21+
Web浏览器Chrome 90+

9.2 运行命令

# 查看可用设备
flutter devices

# 运行到Web服务器
flutter run -d web-server -t lib/main_travel_budget.dart --web-port 8140

# 运行到鸿蒙设备
flutter run -d 127.0.0.1:5555 lib/main_travel_budget.dart

# 代码分析
flutter analyze lib/main_travel_budget.dart

十、总结

旅行预算管家应用通过预算概览、支出记录、支出分析、我的旅行四大模块,为旅行者提供了一个便捷的预算管理平台。应用支持10种货币换算、9种支出分类、4种旅行状态,帮助用户在旅途中合理控制开支,避免超支尴尬。

核心功能涵盖预算规划、实时记账、多币种换算、支出分析四大模块。预算规划支持创建旅行并设定预算上限;实时记账支持快速记录每笔支出并自动换算;多币种换算支持10种常用货币;支出分析通过饼图直观展示消费分布。

应用采用 Material Design 3 设计规范,以清新的青色为主色调,象征旅途的轻松与自由。通过本应用,希望能够帮助旅行者轻松掌握财务状况,享受无忧旅程。

旅行预算管家——不超支的旅行


Logo

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

更多推荐