Files
HarmonyOS--shenqian/PROJECT_DOCUMENTATION.md
2026-07-13 03:54:20 +00:00

13 KiB
Raw Permalink Blame History

记账小助手 — 项目文档

项目概述

项目 说明
应用名称 记账小助手(keeping_accounts
平台 HarmonyOS (API 6.1 / Stage 模式)
Bundle Name com.example.keeping_accounts
版本 1.0.0 (versionCode: 1000000)
开发框架 ArkTS + ArkUI 声明式 UI
构建工具 Hvigor
目标设备 手机 (phone) + 手表(通过蓝牙同步)
跨平台 支持 Android / iOS(通过 ArkUI-X

目录结构

keeping_accounts/
├── AppScope/                          # 应用全局配置
│   ├── app.json5                      # Bundle 名称、图标、版本号
│   └── resources/                     # 全局资源(图标、背景、字符串)
├── build-profile.json5                # 签名配置、SDK 版本、模块列表
├── hvigorfile.ts                      # Hvigor 构建入口
├── code-linter.json5                  # 代码检查规则
├── lodefusi/                          # 主模块(entry
│   ├── build-profile.json5            # 模块构建配置
│   ├── oh-package.json5               # 模块依赖声明
│   ├── hvigorfile.ts                  # 模块构建脚本
│   ├── obfuscation-rules.txt          # 代码混淆规则
│   ├── src/
│   │   ├── main/
│   │   │   ├── module.json5           # 模块清单(权限、Ability、页面路由)
│   │   │   ├── ets/
│   │   │   │   ├── pages/
│   │   │   │   │   └── Index.ets          # 主页面(启动页 + Tab 导航)
│   │   │   │   ├── lodefusiability/
│   │   │   │   │   └── LodefusiAbility.ets # UIAbility 入口
│   │   │   │   ├── components/
│   │   │   │   │   ├── Overview.ets        # 总览页面(月度统计)
│   │   │   │   │   ├── AddExpense.ets      # 记账页面(手动 + AI)
│   │   │   │   │   ├── ExpenseRecords.ets  # 记录列表(按日期分组)
│   │   │   │   │   ├── Device.ets          # 设备页面(蓝牙手表同步)
│   │   │   │   │   └── BluetoothTransfer.ets # 蓝牙传输模态页
│   │   │   │   └── model/
│   │   │   │       ├── ExpenseModel.ets     # 数据模型 + 本地持久化
│   │   │   │       ├── ApiService.ets       # HTTP API 服务
│   │   │   │       ├── ApiConfig.ets        # 服务器地址配置
│   │   │   │       └── BluetoothService.ets  # 蓝牙 SPP 传输服务
│   │   │   └── resources/                # 模块资源(颜色、字符串、图标)
│   │   ├── mock/                         # Mock 数据配置
│   │   ├── ohosTest/                     # 自动化测试
│   │   └── test/                         # 本地单元测试
│   └── ...
└── .arkui-x/                          # ArkUI-X 跨平台配置(Android/iOS
    ├── android/                        # Android 工程
    └── ios/                            # iOS 工程

架构设计

┌─────────────────────────────────────────────────┐
│                  Index.ets (主入口)                │
│         启动页 → Tab 导航 (总览/记账/设备)           │
├──────────┬──────────────────┬───────────────────┤
│ Overview │   AddExpense     │    DevicePage      │
│ 月度统计  │  手动记账+AI分类  │  蓝牙设备管理+同步   │
├──────────┴──────────────────┴───────────────────┤
│              ExpenseRecords (记录列表)             │
│         按日期分组、分类筛选、长按删除               │
├─────────────────────────────────────────────────┤
│              BluetoothTransfer (蓝牙传输)          │
│          发送选择 → 搜索设备 → 连接 → 传输          │
├──────────┬──────────────────┬───────────────────┤
│ExpenseModel│   ApiService   │ BluetoothService  │
│ 本地存储   │  HTTP 同步     │  SPP 串口蓝牙      │
│Preferences│  /api/bills    │  RFCOMM 通道       │
└──────────┴──────────────────┴───────────────────┘

数据流

  1. 用户在记账页添加记录 → ExpenseModel.addExpense() 写入本地 Preferences
  2. 同时异步调用 ApiService.submitBill() 同步到远端服务器(失败则静默降级,仅保存本地)
  3. 总览页通过 @Consume 获取全量数据,按月筛选后计算分类汇总
  4. 设备页通过 BluetoothService.connectAndSend() 将选中数据以 JSON 形式 SPP 传输给手表

模块详解

1. 主入口 — Index.ets

  • 启动页:显示深蓝渐变背景 + "¥" 图标 + "这个月你省钱了吗?" slogan,带有淡入动画(1s+ 2.2s 后淡出
  • 主界面:3 个 Tab 页切换(底部导航栏),每个 Tab 有自定义图标:
    • 总览(环形图标)
    • 记账("+" 图标)
    • 设备(手表图标)
  • 页面级别的 @Provide expenses 将消费数据共享给所有子组件

2. 总览页 — Overview.ets

  • 环形进度卡片:总收入(绿)、总支出(红)、结余(蓝),显示当月合计金额
  • 消费分类网格:按金额降序排列,每个分类显示颜色圆点、金额、线性进度条
  • 收入来源网格:同理展示收入分类
  • 空状态:当月无记录时显示 "💰 本月暂无记录"
  • 刷新按钮:从本地存储重新加载数据

3. 记账页 — AddExpense.ets

  • 类型切换:消费(红色主题)/ 收入(绿色主题),切换时重置分类选择
  • 金额输入:仅允许数字和小数点,自动过滤非法字符,显示 "¥" 前缀
  • 分类选择
    • 手动模式:4 列 Grid 展示分类色块,选中项高亮 + 阴影
    • AI 智能分类模式(仅消费类型可用):
      • 用户输入消费内容描述,开启 Toggle 开关
      • 调用 /api/transfer 接口进行 AI 分类
      • 显示加载动画 "AI 正在识别..."
      • 识别结果以蓝色标签展示,自动填充分类
      • 分类完成后自动调用 /api/bills 同步到服务器
  • 备注输入:选填文本,AI 模式下替代为描述输入框
  • 提交按钮:带 loading 状态,成功后显示 "✓ 添加成功" 浮层 Toast1.8s 自动消失)
  • 服务端同步:静默失败策略,服务器不可用时 Toast 提示但数据已保存在本地

4. 记录列表 — ExpenseRecords.ets

  • 按日期分组yyyy-MM-dd 为 key,每日显示日期标题 + 当日收支汇总
  • 记录行
    • 左侧:分类颜色圆点 + 分类名 + AI 标签(蓝色胶囊)+ 备注
    • 右侧:金额(消费红/收入绿)+ 格式化时间 MM-dd HH:mm
  • 长按删除:触发确认对话框,确认后从本地存储删除
  • 分类筛选:支持按分类过滤,顶部显示筛选标签 + 记录数量 + 返回按钮
  • 空状态:无记录时显示 "📋 暂无消费记录"

5. 设备页 — DevicePage.ets

  • 蓝牙状态栏:显示蓝牙开关状态(绿点/灰点),刷新按钮
  • 已配对设备列表
    • 显示设备名称、连接状态(绿点/灰点)、上次同步时间、已同步条数
    • 点击"连接"按钮模拟连接
    • 点击"同步"按钮将选中数据通过蓝牙发送
  • 同步设置
    • 发送消费记录(Toggle 开关)
    • 发送收入记录(Toggle 开关)
  • 手表应用设置
    • 手表端显示消费明细 / 收入明细 / 震动提醒(预留 UI)
  • 同步结果:顶部显示同步进度/结果横幅

6. 蓝牙传输 — BluetoothTransfer.ets

这是一个模态弹窗组件,支持发送和接收两种模式:

发送流程

  1. 选择记录(Checkbox 多选 + 全选)
  2. 搜索附近的蓝牙设备(12s 超时)
  3. 显示设备列表(设备名 + 地址 + 连接按钮)
  4. 连接设备并通过 SPP 传输选中的 JSON 数据
  5. 显示传输进度百分比

接收流程

  1. 等待发送方连接(显示本机蓝牙名称)
  2. 自动接收数据(__BT_EOF__ 标记结束)
  3. 接收完成后显示记录数,提供"导入数据"按钮
  4. 导入将数据合并到本地存储

状态机IDLE → SELECTING → SCANNING → CONNECTING → TRANSFERRING → COMPLETE / ERROR (接收时:IDLE → WAITING → TRANSFERRING → COMPLETE / ERROR


数据模型

ExpenseItem

interface ExpenseItem {
  id: string;           // 唯一标识(时间戳+计数器+随机数)
  type: '消费' | '收入'; // 交易类型
  category: string;     // 分类名称(餐饮、工资等)
  amount: number;       // 金额
  remark: string;       // 备注
  message: string;      // AI 分类返回的建议消息
  createTime: string;   // ISO 时间字符串
}

预设分类

类型 分类项
消费 餐饮、医药、数码、还款、购物、交通、娱乐、住房、日用、服饰、教育、人情、其他
收入 工资、奖金、理财、兼职、报销、退款、红包、其他收入

每个分类有对应的颜色值,用于 UI 中的圆点和进度条等元素。

数据持久化

  • 本地存储:使用 HarmonyOS preferences API,键值对存储在 expense_storekey 为 expenses
  • 数据迁移migrateItem() 函数兼容旧版数据结构(如 mashamountnamecategorytext/noteremark 等字段映射)
  • 生成 IDDate.now().toString(36) + 计数器.toString(36) + 随机数

API 服务

服务器配置

  • 配置文件存储在 app_config preferences 中,key 为 server_url
  • 默认地址:http://192.168.1.1:9255

接口列表

接口 方法 路径 说明
提交账单 POST /api/bills 将消费/收入记录同步到服务器
AI 分类 POST /api/transfer 根据消费描述自动推荐分类
查询账单 GET /api/bills?type=&category= 按类型和分类筛选查询

错误处理

  • 网络不可用、超时(连接 5s / 读取 10s)、服务端异常均返回 { code: -1, msg: '...' }
  • 调用方采用静默降级策略,不影响本地数据保存

蓝牙服务 — BluetoothService

技术方案

  • 使用 SPPSerial Port Profile 基于 RFCOMM 通道传输
  • UUID00001101-0000-1000-8000-00805F9B34FB
  • 数据格式:JSON 字符串 + __BT_EOF__ 结束标记
  • 分块传输:每块 512 字节

主要功能

方法 说明
isBluetoothEnabled() 检查蓝牙是否开启
enableBluetooth() 打开蓝牙
waitForBluetoothOn(timeoutMs) 等待蓝牙开启(监听 stateChange 事件)
getLocalDeviceName() 获取本机蓝牙名称
getPairedDevices() 获取已配对设备列表
startDiscovery(cb) 搜索附近蓝牙设备
stopDiscovery() 停止搜索
startServer(onResult, onProgress) 启动 SPP 服务端监听(接收模式)
connectAndSend(deviceId, data, onResult, onProgress) 连接设备并发送数据
stopServer() / cancelTransfer() / destroy() 终止/清理资源

UTF-8 编解码

  • 内建 strToBytes()bytesToStr() 实现 UTF-8 编解码(支持中文),不依赖外部库

权限列表

权限 用途
ohos.permission.INTERNET HTTP API 通信
ohos.permission.USE_BLUETOOTH 蓝牙数据传输
ohos.permission.DISCOVER_BLUETOOTH 搜索附近蓝牙设备

离线策略

整体采用 本地优先(Local-First 架构:

  1. 用户操作直接写入本地 Preferences,操作体验不受网络影响
  2. 服务器同步为异步旁路流程,成功/失败均不影响本地数据完整性
  3. 蓝牙传输同样先将接收数据合并到本地存储,再触发 UI 刷新
  4. 总览页刷新按钮从本地存储重新读取,确保数据一致性

跨平台支持(ArkUI-X

项目包含 .arkui-x/ 目录,配置了 Android 和 iOS 的原生工程:

  • AndroidGradle 构建,包含 arkui_android_adapter.jar 和相关 .so
  • iOSXcode 工程(app.xcodeproj),包含 AppDelegateLodefusiLodefusiAbilityViewController

这意味着同一套 ArkTS 代码可以编译为 HarmonyOS / Android / iOS 三端应用。


测试

测试类型 路径 说明
本地单元测试 src/test/List.test.etsLocalUnit.test.ets 逻辑层测试
自动化测试 src/ohosTest/ets/test/Ability.test.etsList.test.ets 设备上运行的 UI 测试
Mock 配置 src/mock/mock-config.json5 模拟数据配置