Flutter 框架跨平台鸿蒙开发 - 旅行预算管家
旅行预算管家应用
欢迎加入开源鸿蒙跨平台社区:
https://openharmonycrossplatform.csdn.net
一、项目概述
运行效果图




1.1 应用简介
旅行预算管家是一款旅行探索类应用,为旅行者提供全程预算管理服务。支持预算规划、实时记账、多币种换算、支出分析四大核心功能,帮助用户在旅途中合理控制开支,避免超支尴尬。无论是短途周末游还是长途跨国旅行,都能轻松掌握财务状况。
应用以清新的青色为主色调,象征旅途的轻松与自由。涵盖预算概览、支出记录、支出分析、我的旅行四大模块。用户可以创建旅行计划、设定预算、记录每笔支出、查看分析报告,实现旅行财务的全方位管理。
1.2 核心功能
| 功能模块 | 功能描述 | 实现方式 |
|---|---|---|
| 预算规划 | 创建旅行并设定预算 | 表单输入 |
| 实时记账 | 快速记录每笔支出 | 分类记账 |
| 多币种 | 支持10种货币换算 | 汇率转换 |
| 支出分析 | 分类统计与可视化 | 饼图展示 |
| 进度追踪 | 预算使用进度监控 | 进度条 |
| 旅行管理 | 多次旅行统一管理 | 列表展示 |
1.3 货币类型定义
| 序号 | 货币名称 | 符号 | 代码 | 汇率(参考) |
|---|---|---|---|---|
| 1 | 人民币 | ¥ | CNY | 1.0 |
| 2 | 美元 | $ | USD | 0.14 |
| 3 | 欧元 | € | EUR | 0.13 |
| 4 | 日元 | ¥ | JPY | 21.0 |
| 5 | 韩元 | ₩ | KRW | 188.0 |
| 6 | 泰铢 | ฿ | THB | 4.9 |
| 7 | 港币 | HK$ | HKD | 1.09 |
| 8 | 新币 | S$ | SGD | 0.19 |
| 9 | 马币 | RM | MYR | 0.66 |
| 10 | 澳元 | A$ | AUD | 0.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 / Web | API 21+ |
1.7 项目结构
lib/
└── main_travel_budget.dart
├── TravelBudgetApp # 应用入口
├── Currency # 货币类型枚举
├── ExpenseCategory # 支出分类枚举
├── TripStatus # 旅行状态枚举
├── Trip # 旅行模型
├── Expense # 支出模型
├── BudgetAllocation # 预算分配模型
├── TravelBudgetHomePage # 主页面(底部导航)
├── _buildOverviewPage # 预算概览页
├── _buildExpensesPage # 支出记录页
├── _buildAnalysisPage # 支出分析页
├── _buildTripsPage # 我的旅行页
└── PieChartPainter # 饼图绘制器
二、系统架构
2.1 整体架构图
2.2 类图设计
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 支出分类分布
3.2 页面结构设计
3.2.1 主页面布局
3.2.2 预算概览页结构
3.2.3 支出记录页结构
3.2.4 支出分析页结构
3.3 货币换算逻辑
3.4 预算进度计算
四、UI设计规范
4.1 配色方案
应用以清新的青色为主色调,象征旅途的轻松与自由:
| 颜色类型 | 色值 | 用途 |
|---|---|---|
| 主色 | #00ACC1 (Cyan) | 导航、主题元素 |
| 辅助色 | #00838F | 支出记录页 |
| 第三色 | #006064 | 分析页面 |
| 强调色 | #00BCD4 | 进度条 |
| 背景色 | #006064 | 页面背景 |
| 卡片背景 | #00838F | 统计卡片 |
4.2 分类颜色规范
| 分类 | 色值 | 视觉效果 |
|---|---|---|
| 交通 | #2196F3 | 蓝色 |
| 住宿 | #9C27B0 | 紫色 |
| 餐饮 | #FF9800 | 橙色 |
| 购物 | #E91E63 | 粉色 |
| 娱乐 | #4CAF50 | 绿色 |
| 门票 | #00BCD4 | 青色 |
| 通讯 | #795548 | 棕色 |
| 医疗 | #F44336 | 红色 |
| 其他 | #607D8B | 灰蓝 |
4.3 字体规范
| 元素 | 字号 | 字重 | 颜色 |
|---|---|---|---|
| 页面标题 | 24px | Bold | 白色 |
| 预算金额 | 28px | Bold | 白色 |
| 支出名称 | 16px | Bold | #000000 |
| 分类标签 | 12px | Regular | 灰色 |
| 统计数字 | 20px | Bold | 白色 |
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 后续版本规划
7.2 功能扩展建议
7.2.1 实时汇率
汇率功能:
- 接入汇率API
- 自动更新汇率
- 离线汇率缓存
- 汇率趋势图
7.2.2 预算提醒
提醒功能:
- 超支预警
- 日预算提醒
- 分类预算限制
- 自定义提醒规则
7.2.3 多人分账
分账功能:
- 创建旅行群组
- 成员费用记录
- 自动分账计算
- 结算报表导出
八、注意事项
8.1 开发注意事项
-
汇率精度:货币换算需注意精度问题
-
数据持久化:支出数据需本地持久化存储
-
状态管理:旅行切换时需正确更新状态
-
图表绘制:CustomPainter需正确实现shouldRepaint
-
日期计算:跨日期计算需注意时区问题
8.2 常见问题
| 问题 | 原因 | 解决方案 |
|---|---|---|
| 汇率不准 | 使用固定汇率 | 接入实时API |
| 金额显示异常 | 精度丢失 | 使用Decimal |
| 饼图不显示 | 数据为空 | 添加空判断 |
| 进度超100% | 超支未处理 | 添加clamp |
| 日期计算错误 | 时区问题 | 统一时区 |
8.3 使用技巧
💰 旅行预算管理技巧 💰
预算规划建议
- 交通费用:预留20%弹性空间
- 住宿费用:提前预订享优惠
- 餐饮费用:按人均×天数计算
- 购物费用:设定上限避免冲动
记账习惯培养
- 每日睡前整理当日支出
- 大额支出及时记录
- 保留小票便于核对
- 分类准确便于分析
超支应对策略
- 调整后续行程预算
- 减少非必要支出
- 寻找免费替代活动
- 合理使用优惠券
九、运行说明
9.1 环境要求
| 环境 | 版本要求 |
|---|---|
| Flutter SDK | >= 3.0.0 |
| Dart SDK | >= 2.17.0 |
| 鸿蒙OS | API 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 设计规范,以清新的青色为主色调,象征旅途的轻松与自由。通过本应用,希望能够帮助旅行者轻松掌握财务状况,享受无忧旅程。
旅行预算管家——不超支的旅行
更多推荐


所有评论(0)