13 KiB
13 KiB
记账小助手 — 项目文档
项目概述
| 项目 | 说明 |
|---|---|
| 应用名称 | 记账小助手(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 通道 │
└──────────┴──────────────────┴───────────────────┘
数据流:
- 用户在记账页添加记录 →
ExpenseModel.addExpense()写入本地 Preferences - 同时异步调用
ApiService.submitBill()同步到远端服务器(失败则静默降级,仅保存本地) - 总览页通过
@Consume获取全量数据,按月筛选后计算分类汇总 - 设备页通过
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 状态,成功后显示 "✓ 添加成功" 浮层 Toast(1.8s 自动消失)
- 服务端同步:静默失败策略,服务器不可用时 Toast 提示但数据已保存在本地
4. 记录列表 — ExpenseRecords.ets
- 按日期分组:
yyyy-MM-dd为 key,每日显示日期标题 + 当日收支汇总 - 记录行:
- 左侧:分类颜色圆点 + 分类名 + AI 标签(蓝色胶囊)+ 备注
- 右侧:金额(消费红/收入绿)+ 格式化时间
MM-dd HH:mm
- 长按删除:触发确认对话框,确认后从本地存储删除
- 分类筛选:支持按分类过滤,顶部显示筛选标签 + 记录数量 + 返回按钮
- 空状态:无记录时显示 "📋 暂无消费记录"
5. 设备页 — DevicePage.ets
- 蓝牙状态栏:显示蓝牙开关状态(绿点/灰点),刷新按钮
- 已配对设备列表:
- 显示设备名称、连接状态(绿点/灰点)、上次同步时间、已同步条数
- 点击"连接"按钮模拟连接
- 点击"同步"按钮将选中数据通过蓝牙发送
- 同步设置:
- 发送消费记录(Toggle 开关)
- 发送收入记录(Toggle 开关)
- 手表应用设置:
- 手表端显示消费明细 / 收入明细 / 震动提醒(预留 UI)
- 同步结果:顶部显示同步进度/结果横幅
6. 蓝牙传输 — BluetoothTransfer.ets
这是一个模态弹窗组件,支持发送和接收两种模式:
发送流程:
- 选择记录(Checkbox 多选 + 全选)
- 搜索附近的蓝牙设备(12s 超时)
- 显示设备列表(设备名 + 地址 + 连接按钮)
- 连接设备并通过 SPP 传输选中的 JSON 数据
- 显示传输进度百分比
接收流程:
- 等待发送方连接(显示本机蓝牙名称)
- 自动接收数据(
__BT_EOF__标记结束) - 接收完成后显示记录数,提供"导入数据"按钮
- 导入将数据合并到本地存储
状态机: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
preferencesAPI,键值对存储在expense_store,key 为expenses - 数据迁移:
migrateItem()函数兼容旧版数据结构(如mash→amount、name→category、text/note→remark等字段映射) - 生成 ID:
Date.now().toString(36) + 计数器.toString(36) + 随机数
API 服务
服务器配置
- 配置文件存储在
app_configpreferences 中,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
技术方案
- 使用 SPP(Serial Port Profile) 基于 RFCOMM 通道传输
- UUID:
00001101-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) 架构:
- 用户操作直接写入本地 Preferences,操作体验不受网络影响
- 服务器同步为异步旁路流程,成功/失败均不影响本地数据完整性
- 蓝牙传输同样先将接收数据合并到本地存储,再触发 UI 刷新
- 总览页刷新按钮从本地存储重新读取,确保数据一致性
跨平台支持(ArkUI-X)
项目包含 .arkui-x/ 目录,配置了 Android 和 iOS 的原生工程:
- Android:Gradle 构建,包含
arkui_android_adapter.jar和相关.so库 - iOS:Xcode 工程(
app.xcodeproj),包含AppDelegate和LodefusiLodefusiAbilityViewController
这意味着同一套 ArkTS 代码可以编译为 HarmonyOS / Android / iOS 三端应用。
测试
| 测试类型 | 路径 | 说明 |
|---|---|---|
| 本地单元测试 | src/test/List.test.ets、LocalUnit.test.ets |
逻辑层测试 |
| 自动化测试 | src/ohosTest/ets/test/Ability.test.ets、List.test.ets |
设备上运行的 UI 测试 |
| Mock 配置 | src/mock/mock-config.json5 |
模拟数据配置 |