【江鸟中原】鸿蒙期末大作业——仿鲨鱼记账APP的记账软件
本项目是一个基于HarmonyOS的账单管理应用,是基于鸿蒙开发者社区中的记账本模版的二次创作,提供账单记录、分类管理、数据统计和可视化展示等功能。应用采用模块化架构,包含数据层、工具层和UI层,实现完整的财务管理流程。
项目概述
本项目是一个基于HarmonyOS的账单管理应用,是基于鸿蒙开发者社区中的记账本模版的二次创作,提供账单记录、分类管理、数据统计和可视化展示等功能。应用采用模块化架构,包含数据层、工具层和UI层,实现完整的财务管理流程。
一、架构设计
1.1 整体架构图

1.2 技术栈
- 开发框架: ArkTS/ArkUI
- 数据存储:
- 关系型数据库 (@ohos.data.relationalStore)
- 轻量级首选项 (@ohos.data.preferences)
- UI组件: ArkUI声明式UI
- 状态管理: @State、@Link、@Prop装饰器
- 模块化: Common模块共享代码
二、数据模型设计
2.1 核心数据实体
2.1.1 账单方向枚举 (BillDirection)
typescript
export enum BillDirection {
IN = 0, // 收入
OUT = 1 // 支出
}
2.1.2 账单信息接口 (BillInfo)
typescript
export interface BillInfo {
id?: number; // 唯一标识
type: BillType; // 账单类型
amount: number; // 金额
direction: BillDirection; // 收支方向
timestamp: number; // 时间戳
remark?: string; // 备注
image?: string; // 图片路径
}
2.1.3 账单类型接口 (BillType)
typescript
export interface BillType {
icon: Resource; // 图标资源
name: string; // 类型名称
}
2.2 数据库设计
2.2.1 BILL表结构
|
字段名 |
类型 |
说明 |
约束 |
|
ID |
INTEGER |
主键 |
PRIMARY KEY AUTOINCREMENT |
|
TYPE |
TEXT |
账单类型(JSON) |
NOT NULL |
|
AMOUNT |
REAL |
金额 |
NOT NULL |
|
DIRECTION |
INTEGER |
收支方向 |
NOT NULL |
|
TIMESTAMP |
INTEGER |
时间戳 |
NOT NULL |
|
REMARK |
TEXT |
备注 |
可选 |
|
IMAGE |
TEXT |
图片路径 |
可选 |
2.2.2 BILL_TYPE表结构
|
字段名 |
类型 |
说明 |
约束 |
|
ID |
INTEGER |
主键 |
PRIMARY KEY AUTOINCREMENT |
|
ICON |
TEXT |
图标资源(JSON) |
NOT NULL |
|
NAME |
TEXT |
类型名称 |
NOT NULL |
三、核心模块实现
3.1 数据库管理模块 (DBManager)
3.1.1 设计模式:单例模式
typescript
// 使用全局变量实现单例
public static getInstance(context: Context): DBManager {
if (globalThis.__dbManager__ == undefined)
globalThis.__dbManager__ = new DBManager(context??globalThis.context);
return globalThis.__dbManager__;
}
3.1.2 异步初始化处理
public constructor(context:Context) {
relationalStore.getRdbStore(...).then(store=> {
store.executeSql(...).then(() => {
this.storeInstance = store; // 异步设置
});
});
3.1.3 核心操作方法
typescript
// 1. 获取所有账单
public async getAllBillInfo(): Promise<BillInfo[]>
// 2. 添加账单
public async addBillInfo(data: BillInfo): Promise<number>
// 3. 搜索账单
public async searchBillInfo(keyword: string): Promise<BillInfo[]>
// 4. 按日期范围搜索
public async searchBillInfoByDateRange(start: Date, end: Date): Promise<BillInfo[]>
// 5. 账单分类管理
public async addBillInfoType(type: BillType): Promise<number>
public async getAllBillInfoType(): Promise<BillType[]>
3.2 工具类模块 (Utils)
3.2.1 账单信息工具类 (BillInfoUtils)
typescript
// 数据转换:ResultSet → BillInfo[]
public static createBillInfoArrayFromResultSet(set: relationalStore.ResultSet): BillInfo[]
// 数据筛选:按日期范围
public static filterByDate(src: BillInfo[], start: Date, end?: Date): BillInfo[]
// 数据聚合:按月/年分解
public static explodeMonthlyArray(src: BillInfo[], month: Date): BillInfo[][]
public static explodeYearlyArray(src: BillInfo[], year: Date): BillInfo[][]
// 财务计算
public static calculateTotalIncome(src: BillInfo[]): number // 总收入
public static calculateTotalOutBill(src: BillInfo[]): number // 总支出
public static calculateTotalLeft(src: BillInfo[]): number // 结余
3.2.2 其他工具类
- DateUtils: 日期相关工具(如获取月份天数)
- StringUtils: 字符串格式化(日期格式化)
- Logger: 统一日志管理
3.3 设置管理模块 (SettingManager)
typescript
// 使用Preferences进行轻量级数据存储
export class SettingManager {
private settingStore?: preferences.Preferences;
// 设置值
public set(k: string, v: SettingType)
// 获取值(带默认值)
public async get<T extends SettingType>(k: string, def: T)
}
四、UI层实现
4.1 页面结构设计
4.1.1 主页面 (Index.ets)
功能: 显示今日账单概览、提供快捷入口
typescript
@Entry
@Component
struct Index {
@State selectedDate: Date = new Date();
@State currentBillInfo: LocalBillInfo[] = [];
@State totalIncome: number = 0.00;
@State totalBalance: number = 0.00;
build() {
Column() {
// 1. 顶部标题栏
// 2. 收支概览组件 (BalanceViewer)
// 3. 底部导航组件 (PageEntries)
// 4. 账单列表组件 (BalanceList)
}
}
}
4.1.2 添加账单页面 (AddBalance.ets)
核心特性:
- 收入/支出选项卡切换
- 分类图标网格选择
- 自定义计算器键盘
- 日期选择器
交互流程:
text
选择分类 → 弹出输入面板 → 输入金额 → 添加备注 → 选择日期 → 保存
4.1.3 账单详情页 (BillInfoPage.ets)
功能: 按年度展示月度统计数据
text
┌─────────────────┐
│ 年份选择器 │
├─────────────────┤
│ 年度收支概览 │
├─────────────────┤
│ 月份 | 收入 | 支出 | 结余 │
│ 1月 | 5000 | 3000 | 2000 │
│ 2月 | 6000 | 4000 | 2000 │
└─────────────────┘
4.1.4 统计页面 (StatisticsPage.ets)
功能: 数据可视化展示
- 柱状图对比收入支出
- 总览数字卡片
- 手动刷新机制
- 具体如下图所示

4.2 可复用组件设计
4.2.1 收支概览组件 (BalanceViewer)
typescript
@Component
export struct BalanceViewer {
@Link selectedDate: Date;
@Link currentBillingInfo: string;
@Link totalIncome: number;
@Link totalBalance: number;
// 显示当前月份、总收入、总余额
}
4.2.2 账单列表组件 (BalanceList)
typescript
@Component
export struct BalanceList {
@Link currentBillInfo: LocalBillInfo[];
// 显示带图标的账单列表
// 支持空状态显示
}
4.2.3 底部导航组件 (PageEntries)
typescript
@Component
export struct PageEntries {
// 三按钮导航:账单、图表、记账
// 使用渐变色背景
}
4.2.4 柱状图组件 (BarChart)
typescript
@ComponentV2
export struct BarChart {
@Param income: number = 0; // 收入
@Param expense: number = 0; // 支出
@Param title: string = '收支对比';
// 自适应高度计算
private calculateHeight(value: number): number
}
五、关键实现细节
5.1 数据流管理
5.1.1 页面间数据传递
核心代码:
typescript
// 日期对象序列化/反序列化
router.pushUrl({
params: {
selectedDate: this.selectedDate.toISOString() // 转为字符串
}
});
// 接收端
const params = router.getParams() as ESObject;
this.activeDate = new Date(params['selectedDate'] as string);
功能体现:页面跳转时携带完整上下文,并且日期等复杂对象正确传递,也可保持用户体验连贯性
5.1.2 组件间数据同步
typescript
// 父子组件数据同步
@Link currentBillInfo: LocalBillInfo[];
@Link selectedDate: Date;
// 在父组件中使用
BalanceList({
currentBillInfo: $currentBillInfo, // 双向绑定
selectedDate: $selectedDate
})
5.2 错误处理与日志
5.2.1 统一错误处理
typescript
// 数据库操作错误处理
.catch((e:BusinessError) => {
Logger.err(TAG, "error while adding billing info", e, bucket);
ret(-1); // 返回错误标识
})
// 数据解析错误处理
try {
// 解析操作
} catch (e) {
Logger.err(TAG, "Failed to parse ResultSet", e);
return BillInfoUtils.createEmptyBillInfo(); // 返回空对象
}
5.2.2 日志分级
typescript
export class Logger {
static info(TAG: string, ...args: any[]) {
console.info("BILL", TAG, ...args);
}
static warn(TAG: string, ...args: any[]) {
console.warn("BILL", TAG, ...args);
}
static err(TAG: string, ...args: any[]) {
console.error("BILL", TAG, ...args);
}
}
5.3 数据处理
5.3.1 可视化图表
核心代码:
// 柱状图高度计算
private calculateHeight(value: number): number {
const maxValue = Math.max(this.income, this.expense);
if (maxValue === 0) return 0;
return (value / maxValue) * 120; // 最大高度120vp
}
// 财务状态判断
private getFinancialStatus(): string {
const balance = this.income - this.expense;
if (balance > 0) return '盈余';
if (balance < 0) return '赤字';
return '平衡';
}
功能体现:
-
StatisticsPage:收入/支出柱状对比图
-
自适应高度,数据越大柱子越高
-
颜色区分(收入绿、支出红)
-
财务状态自动判断
5.3.2 数据验证
核心代码:
// 提交前验证
if (this.balanceAmount == "0") {
return; // 金额为0不保存
}
if (this.remark == "") {
return; // 备注为空不保存
}
if (this.selectedTypeName == "") {
return; // 未选分类不保存
}
功能体现:
-
必填项验证,确保数据完整性
-
金额为0拦截,避免无意义记录
-
即时反馈,用户立即知道问题所在
六、项目配置与常量管理
6.1 统一常量管理
typescript
export class Constants {
// 字体大小
public static readonly FONT_SIZE_12 = '12fp';
public static readonly FONT_SIZE_14 = '14fp';
// 颜色定义
public static readonly THEME_COLOR = '#94B982';
public static readonly INCOME_COLOR = '#FF9800';
public static readonly EXPENSE_COLOR = '#4CAF50';
}
6.2 数据库配置
typescript
export const CommonConfiguration = {
SETTING_PREFERENCE_STORE_KEY: 'bill_setting',
DB_MANAGER: {
DB_FILE_NAME: 'BillApp.db',
SECURITY_LEVEL: relationalStore.SecurityLevel.S1,
SQL: {
INITIALIZE: "CREATE TABLE IF NOT EXISTS BILL (...)",
GET_ALL_BILLS: "SELECT * FROM BILL ORDER BY TIMESTAMP DESC;",
// ... 其他SQL语句
}
}
} as const;
6.3 预置分类数据
typescript
// 支出分类(18种)
export const defaultExpenseType: IBillType[] = [
{title: "餐饮", img: $r("app.media.eatIcon")},
{title: "购物", img: $r("app.media.shoppingIcon")},
// ... 其他分类
];
// 收入分类(5种)
export const defaultIncomeType: IBillType[] = [
{title: "工资", img: $r("app.media.salaryIcon")},
{title: "理财", img: $r("app.media.foundationIcon")},
// ... 其他分类
];
七、技术亮点
7.1 模块化架构设计
-
Common模块:数据库、工具类、数据模型,可复用
-
Entry模块:UI页面、组件、常量,专注展示
-
依赖清晰:Common不依赖Entry,可独立测试
更多推荐




所有评论(0)