消费热力图应用


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

一、项目概述

运行效果图
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

1.1 应用简介

消费热力图是一款个人财务管理可视化应用,通过直观的热力图展示用户的消费分布情况。应用将消费数据按时间维度和类别维度进行可视化呈现,让用户一目了然地了解自己的钱都花在了哪里。通过日历热力图、类别热力图、饼图、趋势图等多种可视化方式,帮助用户发现消费规律,优化支出结构。

应用以珊瑚红为主色调,营造温馨而不失警示感的视觉体验。涵盖概览统计、热力图展示、消费分析、明细记录四大模块,支持9种消费分类和多种时间粒度查看,通过智能洞察提供个性化的理财建议。

1.2 核心功能

功能模块 功能描述 实现方式
概览统计 月度消费总览 CustomScrollView
热力图 日消费热力展示 GridView网格
消费分析 饼图+趋势分析 CustomPainter
明细记录 消费记录列表 ListView
添加记录 新增消费记录 ModalBottomSheet
筛选功能 按类别筛选 FilterChip

1.3 消费分类系统

序号 类别名称 Emoji 颜色 典型消费
1 餐饮 🍔 #FF6B6B 早餐、午餐、晚餐、外卖
2 交通 🚗 #4ECDC4 地铁、公交、打车、加油
3 购物 🛍️ #45B7D1 日用品、服装、数码产品
4 娱乐 🎮 #96CEB4 电影、KTV、游戏、旅游
5 住房 🏠 #DDA0DD 房租、水电费、物业费
6 医疗 💊 #98D8C8 药品、体检、挂号
7 教育 📚 #F7DC6F 书籍、课程、培训
8 通讯 📱 #BB8FCE 话费、网费、会员
9 其他 📦 #85C1E9 红包、礼物、杂项

1.4 时间粒度

粒度 标签 描述
按日查看消费热力图
按周汇总消费数据
按月汇总消费数据

1.5 热力图等级

等级 颜色 消费强度
0 #E0E0E0 无消费
1 #FFE5E5 低消费
2 #FFB4B4 中低消费
3 #FF8E8E 中高消费
4 #FF6B6B 高消费

1.6 技术栈

技术领域 技术选型 版本要求
开发框架 Flutter >= 3.0.0
编程语言 Dart >= 2.17.0
设计规范 Material Design 3 -
图表绘制 CustomPainter -
动画控制 AnimationController -
日期格式化 intl -
目标平台 鸆蒙OS / Web API 21+

1.7 项目结构

lib/
└── main_spending_heatmap.dart
    ├── SpendingHeatmapApp      # 应用入口
    ├── SpendingCategory        # 消费分类枚举
    ├── TimeGranularity         # 时间粒度枚举
    ├── SpendingRecord          # 消费记录数据模型
    ├── DailySpending           # 日消费汇总模型
    ├── SpendingHeatmapHomePage # 主页面(底部导航)
    ├── _buildOverviewPage      # 概览页面
    ├── _buildHeatmapPage       # 热力图页面
    ├── _buildAnalysisPage      # 分析页面
    ├── _buildRecordsPage       # 明细页面
    ├── _AddRecordSheet         # 添加记录弹窗
    ├── PieChartPainter         # 饼图绘制器
    └── TrendChartPainter       # 趋势图绘制器

二、系统架构

2.1 整体架构图

Data Layer

Presentation Layer

主页面
SpendingHeatmapHomePage

概览页面

热力图页面

分析页面

明细页面

头部统计

快速统计

消费分布

最近记录

日历热力图

类别热力图

热力图图例

饼图分析

趋势图表

消费洞察

记录列表

筛选功能

SpendingRecord
消费记录

SpendingCategory
消费分类

DailySpending
日消费汇总

2.2 类图设计

has

aggregates

manages

computes

renders

renders

SpendingHeatmapApp

+Widget build()

«enumeration»

SpendingCategory

+String label

+String emoji

+Color color

+food()

+transport()

+shopping()

+entertainment()

+housing()

+health()

+education()

+communication()

+other()

«enumeration»

TimeGranularity

+String label

+String description

+daily()

+weekly()

+monthly()

SpendingRecord

+String id

+String title

+double amount

+SpendingCategory category

+DateTime date

+String? note

DailySpending

+DateTime date

+Map<SpendingCategory,double> categoryAmounts

+double total

+double getAmount()

SpendingHeatmapHomePage

-int _selectedIndex

-List<SpendingRecord> _records

-TimeGranularity _granularity

-DateTime _selectedMonth

-SpendingCategory? _selectedCategory

-AnimationController _pulseController

+Widget build()

-_getStatistics()

-_getDailySpendings()

-_addRecord()

PieChartPainter

+Map<SpendingCategory,double> categoryTotals

+double total

+void paint()

+bool shouldRepaint()

TrendChartPainter

+List<double> data

+double maxValue

+Color color

+void paint()

+bool shouldRepaint()

2.3 页面导航流程

概览

热力图

分析

明细

应用启动

概览页面

底部导航

月度统计

日历热力图

消费分析

消费明细

消费分布

最近记录

日历网格

点击日期

显示当日详情

饼图展示

趋势图表

消费洞察

记录列表

筛选记录

2.4 数据流向图

可视化组件 统计系统 界面 用户 可视化组件 统计系统 界面 用户 选择月份 获取月度数据 过滤当月记录 计算各类别总额 计算日均消费 返回统计数据 传递数据 绘制热力图 绘制饼图 绘制趋势图 返回渲染结果 展示可视化图表

三、核心模块设计

3.1 数据模型设计

3.1.1 消费分类枚举 (SpendingCategory)
enum SpendingCategory {
  food('餐饮', '🍔', Color(0xFFFF6B6B)),
  transport('交通', '🚗', Color(0xFF4ECDC4)),
  shopping('购物', '🛍️', Color(0xFF45B7D1)),
  entertainment('娱乐', '🎮', Color(0xFF96CEB4)),
  housing('住房', '🏠', Color(0xFFDDA0DD)),
  health('医疗', '💊', Color(0xFF98D8C8)),
  education('教育', '📚', Color(0xFFF7DC6F)),
  communication('通讯', '📱', Color(0xFFBB8FCE)),
  other('其他', '📦', Color(0xFF85C1E9));

  final String label;   // 类别名称
  final String emoji;   // 代表表情
  final Color color;    // 主题颜色
}
3.1.2 时间粒度枚举 (TimeGranularity)
enum TimeGranularity {
  daily('日', '按日查看'),
  weekly('周', '按周查看'),
  monthly('月', '按月查看');

  final String label;        // 粒度标签
  final String description;  // 描述文字
}
3.1.3 消费记录模型 (SpendingRecord)
class SpendingRecord {
  final String id;              // 唯一标识
  final String title;           // 消费名称
  final double amount;          // 消费金额
  final SpendingCategory category; // 消费类别
  final DateTime date;          // 消费日期
  final String? note;           // 备注信息
}
3.1.4 日消费汇总模型 (DailySpending)
class DailySpending {
  final DateTime date;                        // 日期
  final Map<SpendingCategory, double> categoryAmounts; // 各类别金额
  final double total;                         // 总金额

  double getAmount(SpendingCategory category) {
    return categoryAmounts[category] ?? 0;
  }
}
3.1.5 消费分类分布
30% 20% 15% 12% 10% 5% 4% 3% 1% 典型消费分类占比 餐饮 购物 交通 娱乐 住房 教育 医疗 通讯 其他

3.2 页面结构设计

3.2.1 主页面布局

SpendingHeatmapHomePage

IndexedStack

概览页面

热力图页面

分析页面

明细页面

FloatingActionButton

添加记录弹窗

NavigationBar

概览 Tab

热力图 Tab

分析 Tab

明细 Tab

3.2.2 概览页面结构

概览页面

SliverAppBar

月份选择器

快速统计

消费分布

最近记录

渐变背景

总消费金额

日均消费

消费笔数

最高消费类别

消费类别数

类别进度条

金额与百分比

3.2.3 热力图页面结构

热力图页面

月份选择器

日历热力图

热力图图例

类别热力图

星期标题行

日期网格

热力格子

点击显示详情

类别网格

类别卡片

Emoji+金额

3.2.4 分析页面结构

分析页面

月份选择器

饼图卡片

趋势图表

消费洞察

环形饼图

类别图例

折线图

填充区域

数据点

主要消费

日均消费

理财建议

3.3 统计计算流程

获取月度统计

过滤当月记录

计算总消费

计算各类别总额

计算日均消费

排序类别

返回统计结果

total: 总消费

avgDaily: 日均

categoryTotals: 类别总额

sortedCategories: 排序列表

recordCount: 记录数


四、UI设计规范

4.1 配色方案

应用以珊瑚红为主色调,营造温馨而不失警示感的视觉体验:

颜色类型 色值 用途
主色 #FF6B6B (Coral Red) 导航、强调元素
渐变浅 #FF8E8E 渐变过渡
渐变淡 #FFB4B4 渐变背景
背景白 #FFFFFF 卡片背景
文字灰 #9E9E9E 次要文字

4.2 类别配色

类别 色值 视觉效果
餐饮 #FF6B6B 温暖红色
交通 #4ECDC4 清新青色
购物 #45B7D1 明亮蓝色
娱乐 #96CEB4 自然绿色
住房 #DDA0DD 柔和紫色
医疗 #98D8C8 清淡绿色
教育 #F7DC6F 明亮黄色
通讯 #BB8FCE 优雅紫色
其他 #85C1E9 天空蓝色

4.3 热力图配色

等级 色值 消费强度
0 #E0E0E0 无消费
1 #FFE5E5 低 (<25%)
2 #FFB4B4 中低 (25-50%)
3 #FF8E8E 中高 (50-75%)
4 #FF6B6B 高 (>75%)

4.4 字体规范

元素 字号 字重 颜色
总消费金额 42px Bold #FFFFFF
页面标题 20px Bold #000000
类别名称 16px Bold #000000
金额数值 14px Bold 类别颜色
百分比 12px Regular #9E9E9E
日期 10px Medium 根据强度

4.5 组件规范

4.5.1 头部统计卡片
┌─────────────────────────────────────┐
│                                     │
│         本月消费                    │
│                                     │
│       ¥ 3,256.80                   │
│                                     │
│     日均消费 ¥108.56               │
│                                     │
└─────────────────────────────────────┘
4.5.2 快速统计卡片
┌──────────┐  ┌──────────┐  ┌──────────┐
│    📄    │  │    📈    │  │    📊    │
│    45    │  │   餐饮   │  │    6     │
│ 消费笔数 │  │ 最高消费 │  │ 消费类别 │
└──────────┘  └──────────┘  └──────────┘
4.5.3 消费分布条
🍔 餐饮        ████████████████████░░░░  ¥980  30.1%
🛍️ 购物        ████████████░░░░░░░░░░░░  ¥650  20.0%
🚗 交通        █████████░░░░░░░░░░░░░░░  ¥490  15.0%
🎮 娱乐        ████████░░░░░░░░░░░░░░░░  ¥390  12.0%
🏠 住房        ██████░░░░░░░░░░░░░░░░░░  ¥330  10.0%
4.5.4 日历热力图
┌─────────────────────────────────────┐
│  一   二   三   四   五   六   日   │
├─────────────────────────────────────┤
│      [1]  [2]  [3]  [4]  [5]  [6]  │
│  [7]  [8]  [9] [10] [11] [12] [13] │
│ [14] [15] [16] [17] [18] [19] [20] │
│ [21] [22] [23] [24] [25] [26] [27] │
│ [28] [29] [30] [31]                │
└─────────────────────────────────────┘
  低 □□□□□ 高
4.5.5 添加记录弹窗
┌─────────────────────────────────────┐
│  添加消费记录                       │
├─────────────────────────────────────┤
│  消费名称: [________________]       │
│  消费金额: [¥_______]               │
│                                     │
│  消费类别:                          │
│  [🍔餐饮] [🚗交通] [🛍️购物]        │
│  [🎮娱乐] [🏠住房] [💊医疗]        │
│  [📚教育] [📱通讯] [📦其他]        │
│                                     │
│  消费日期: 2024-01-15      [📅]    │
│                                     │
│  [        添加记录        ]         │
└─────────────────────────────────────┘

五、核心功能实现

5.1 统计计算实现

Map<String, dynamic> _getStatistics() {
  // 过滤当月记录
  final monthRecords = _records.where((r) =>
    r.date.year == _selectedMonth.year &&
    r.date.month == _selectedMonth.month
  ).toList();

  // 计算总消费
  final totalSpending = monthRecords.fold<double>(0, (sum, r) => sum + r.amount);
  
  // 计算各类别总额
  final categoryTotals = <SpendingCategory, double>{};
  for (var category in SpendingCategory.values) {
    categoryTotals[category] = monthRecords
        .where((r) => r.category == category)
        .fold<double>(0, (sum, r) => sum + r.amount);
  }

  // 计算日均消费
  final avgDaily = totalSpending / DateTime(_selectedMonth.year, _selectedMonth.month + 1, 0).day;

  // 排序类别
  final sortedCategories = categoryTotals.entries.toList()
    ..sort((a, b) => b.value.compareTo(a.value));

  return {
    'total': totalSpending,
    'avgDaily': avgDaily,
    'categoryTotals': categoryTotals,
    'sortedCategories': sortedCategories,
    'recordCount': monthRecords.length,
  };
}

5.2 热力图颜色计算

Color _getHeatmapColor(double intensity) {
  if (intensity == 0) return Colors.grey[200]!;
  if (intensity < 0.25) return const Color(0xFFFFE5E5);
  if (intensity < 0.5) return const Color(0xFFFFB4B4);
  if (intensity < 0.75) return const Color(0xFFFF8E8E);
  return const Color(0xFFFF6B6B);
}

5.3 饼图绘制实现

class PieChartPainter extends CustomPainter {
  final Map<SpendingCategory, double> categoryTotals;
  final double total;

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

    if (total == 0) return;

    double startAngle = -pi / 2;

    // 按金额排序
    final sortedEntries = categoryTotals.entries.toList()
      ..sort((a, b) => b.value.compareTo(a.value));

    // 绘制各扇区
    for (var entry in sortedEntries) {
      if (entry.value <= 0) continue;

      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, Paint()..color = Colors.white);

    // 绘制总金额文字
    final textPainter = TextPainter(
      text: TextSpan(
        text: ${total.toStringAsFixed(0)}',
        style: const TextStyle(fontSize: 16, fontWeight: FontWeight.bold),
      ),
      textDirection: TextDirection.ltr,
    );
    textPainter.layout();
    textPainter.paint(canvas, Offset(center.dx - textPainter.width / 2, center.dy - textPainter.height / 2));
  }
}

5.4 趋势图绘制实现

class TrendChartPainter extends CustomPainter {
  final List<double> data;
  final double maxValue;
  final Color color;

  
  void paint(Canvas canvas, Size size) {
    if (data.isEmpty) return;

    final paint = Paint()
      ..color = color
      ..strokeWidth = 2
      ..style = PaintingStyle.stroke;

    // 填充渐变
    final fillPaint = Paint()
      ..shader = LinearGradient(
        begin: Alignment.topCenter,
        end: Alignment.bottomCenter,
        colors: [color.withValues(alpha: 0.3), color.withValues(alpha: 0.05)],
      ).createShader(Rect.fromLTWH(0, 0, size.width, size.height))
      ..style = PaintingStyle.fill;

    final path = Path();
    final fillPath = Path();
    final stepX = size.width / (data.length - 1);

    for (int i = 0; i < data.length; i++) {
      final x = i * stepX;
      final y = size.height - (data[i] / maxValue) * size.height;

      if (i == 0) {
        path.moveTo(x, y);
        fillPath.moveTo(x, size.height);
        fillPath.lineTo(x, y);
      } else {
        path.lineTo(x, y);
        fillPath.lineTo(x, y);
      }
    }

    fillPath.lineTo(size.width, size.height);
    fillPath.close();

    canvas.drawPath(fillPath, fillPaint);
    canvas.drawPath(path, paint);

    // 绘制数据点
    for (int i = 0; i < data.length; i++) {
      final x = i * stepX;
      final y = size.height - (data[i] / maxValue) * size.height;
      canvas.drawCircle(Offset(x, y), 3, Paint()..color = color);
    }
  }
}

5.5 添加记录实现

void _addRecord() {
  showModalBottomSheet(
    context: context,
    isScrollControlled: true,
    shape: const RoundedRectangleBorder(
      borderRadius: BorderRadius.vertical(top: Radius.circular(24)),
    ),
    builder: (context) => _AddRecordSheet(
      onAdd: (record) {
        setState(() {
          _records.insert(0, record);
        });
      },
    ),
  );
}

六、可视化设计

6.1 日历热力图

无消费

<25%

25-50%

50-75%

>75%

获取当月天数

计算第一天星期

创建网格布局

填充空白格子

填充日期格子

计算消费强度

灰色背景

浅红背景

中红背景

深红背景

红色背景

显示日期数字

6.2 类别热力图

获取各类别总额

计算最大值

遍历所有类别

计算相对强度

生成渐变背景

显示类别信息

类别Emoji

类别名称

消费金额

点击查看详情

6.3 饼图分析

获取类别总额

按金额排序

计算各扇区角度

从12点方向开始

绘制扇区

还有类别?

累加角度

绘制中心圆

显示总金额

绘制图例

6.4 趋势图表

获取日消费数据

计算最大值

计算X轴步进

创建路径

遍历数据点

计算坐标位置

连线到路径

还有数据?

创建填充路径

绘制填充区域

绘制折线

绘制数据点


七、交互设计

7.1 添加记录流程

添加弹窗 主页面 用户 添加弹窗 主页面 用户 点击添加按钮 显示底部弹窗 展示表单 输入消费名称 输入消费金额 选择消费类别 选择消费日期 点击添加按钮 返回SpendingRecord 插入记录列表 更新界面显示

7.2 热力图交互

用户点击格子

关闭弹窗

查看热力图

点击日期

显示详情弹窗

显示当日消费总额
显示当日消费明细
按类别分组展示

7.3 筛选记录流程

选择类别

取消选择

点击筛选按钮

显示筛选弹窗

展示类别选项

选择类别

高亮选中项

清除筛选

更新记录列表

仅显示选中类别记录


八、扩展功能规划

8.1 后续版本规划

2024-01-07 2024-01-14 2024-01-21 2024-01-28 2024-02-04 2024-02-11 2024-02-18 2024-02-25 2024-03-03 2024-03-10 2024-03-17 概览统计功能 热力图可视化 消费分析功能 预算设置 超支提醒 数据导出 多账户管理 预算分析报告 云端同步 V1.0 基础版本 V1.1 增强版本 V1.2 进阶版本 消费热力图应用开发计划

8.2 功能扩展建议

8.2.1 预算管理

预算功能:

  • 设置月度总预算
  • 设置各类别预算
  • 预算进度条显示
  • 超支预警提醒
8.2.2 数据导出

导出功能:

  • 导出Excel报表
  • 导出PDF报告
  • 分享消费统计图
  • 数据备份恢复
8.2.3 智能分析

智能功能:

  • AI消费建议
  • 异常消费检测
  • 消费预测分析
  • 同比环比分析

九、注意事项

9.1 开发注意事项

  1. 金额精度:使用double类型,注意精度问题

  2. 日期过滤:比较日期时注意年月日匹配

  3. 动画释放:AnimationController需要在dispose时释放

  4. 空数据处理:统计数据为空时需要特殊处理

  5. 颜色强度:热力图强度计算需要归一化

9.2 常见问题

问题 原因 解决方案
热力图颜色不对 强度计算错误 检查maxValue是否正确
饼图不显示 总额为0 添加总额判断
趋势图变形 数据点过少 添加空数据处理
日期筛选失效 日期格式不一致 使用DateTime比较

9.3 设计理念

💰 设计理念 💰

每一笔消费都是生活的痕迹,
每一次支出都有它的意义。

通过热力图的可视化呈现,
让抽象的数字变成直观的色彩,
帮助用户发现消费规律,
优化支出结构,
实现财务自由的第一步。


十、运行说明

10.1 环境要求

环境 版本要求
Flutter SDK >= 3.0.0
Dart SDK >= 2.17.0
鸆蒙OS API 21+

10.2 运行命令

# 查看可用设备
flutter devices

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

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

# 运行到Edge浏览器
flutter run -d edge lib/main_spending_heatmap.dart

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

十一、总结

消费热力图应用通过概览统计、热力图展示、消费分析、明细记录四大模块,为用户提供了一个直观了解消费分布的可视化平台。应用支持9种消费分类和多种时间粒度查看,通过日历热力图、类别热力图、饼图、趋势图等多种可视化方式,帮助用户发现消费规律。

核心功能涵盖消费统计、热力图可视化、饼图分析、趋势图表、消费洞察五大模块。统计系统支持按月汇总消费数据,计算各类别占比;热力图系统通过颜色强度直观展示消费分布;分析系统提供饼图和趋势图两种可视化方式;洞察系统基于数据提供个性化理财建议。

应用采用Material Design 3设计规范,以珊瑚红为主色调,营造温馨而不失警示感的视觉体验。通过本应用,希望能够帮助用户了解自己的消费习惯,发现消费规律,优化支出结构,实现财务健康。

可视化你的钱都花在哪了

Logo

作为“人工智能6S店”的官方数字引擎,为AI开发者与企业提供一个覆盖软硬件全栈、一站式门户。

更多推荐