上传文件至「/」
This commit is contained in:
@@ -0,0 +1,297 @@
|
|||||||
|
# 记账小助手 — 项目文档
|
||||||
|
|
||||||
|
## 项目概述
|
||||||
|
|
||||||
|
| 项目 | 说明 |
|
||||||
|
|------|------|
|
||||||
|
| **应用名称** | 记账小助手(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 状态,成功后显示 "✓ 添加成功" 浮层 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`
|
||||||
|
|
||||||
|
这是一个模态弹窗组件,支持发送和接收两种模式:
|
||||||
|
|
||||||
|
**发送流程**:
|
||||||
|
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
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
interface ExpenseItem {
|
||||||
|
id: string; // 唯一标识(时间戳+计数器+随机数)
|
||||||
|
type: '消费' | '收入'; // 交易类型
|
||||||
|
category: string; // 分类名称(餐饮、工资等)
|
||||||
|
amount: number; // 金额
|
||||||
|
remark: string; // 备注
|
||||||
|
message: string; // AI 分类返回的建议消息
|
||||||
|
createTime: string; // ISO 时间字符串
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### 预设分类
|
||||||
|
|
||||||
|
| 类型 | 分类项 |
|
||||||
|
|------|--------|
|
||||||
|
| **消费** | 餐饮、医药、数码、还款、购物、交通、娱乐、住房、日用、服饰、教育、人情、其他 |
|
||||||
|
| **收入** | 工资、奖金、理财、兼职、报销、退款、红包、其他收入 |
|
||||||
|
|
||||||
|
每个分类有对应的颜色值,用于 UI 中的圆点和进度条等元素。
|
||||||
|
|
||||||
|
### 数据持久化
|
||||||
|
|
||||||
|
- **本地存储**:使用 HarmonyOS `preferences` API,键值对存储在 `expense_store`,key 为 `expenses`
|
||||||
|
- **数据迁移**:`migrateItem()` 函数兼容旧版数据结构(如 `mash` → `amount`、`name` → `category`、`text/note` → `remark` 等字段映射)
|
||||||
|
- **生成 ID**:`Date.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`
|
||||||
|
|
||||||
|
### 技术方案
|
||||||
|
|
||||||
|
- 使用 **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)** 架构:
|
||||||
|
|
||||||
|
1. 用户操作直接写入本地 Preferences,操作体验不受网络影响
|
||||||
|
2. 服务器同步为异步旁路流程,成功/失败均不影响本地数据完整性
|
||||||
|
3. 蓝牙传输同样先将接收数据合并到本地存储,再触发 UI 刷新
|
||||||
|
4. 总览页刷新按钮从本地存储重新读取,确保数据一致性
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 跨平台支持(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` | 模拟数据配置 |
|
||||||
Reference in New Issue
Block a user