财务目标页面 UI 与进度展示 - Cordova与OpenHarmony混合开发实战
本文介绍了财务目标模块的设计与实现,包括页面结构、目标项UI渲染、数据库操作以及ArkTS侧的数据导出导入功能。该模块帮助用户设定可量化的财务目标(如存款、首付等),并通过进度条直观展示完成情况。系统采用IndexedDB存储目标数据,支持增删改查操作,同时与ArkTS插件配合实现数据备份功能,确保目标数据的安全性和跨平台一致性。整体设计延续了应用的前后分离架构,兼顾功能性和用户体验。

欢迎大家加入开源鸿蒙跨平台开发者社区,一起共建开源鸿蒙跨平台生态。
本文对应模块:
pages.js中“财务目标”页面的 HTML 模板与 UI 结构,以及与db.js中 goals 表的配合;同时会补充一段鸿蒙 ArkTS 代码,说明目标数据如何通过 FileManager 插件参与导出与导入。
1. 模块定位:从“记账”到“有目标地记账”
前面的模块更多关注日常收支、账户和预算,本模块要解决的是另一个问题:
不只是记录历史,而是给未来定一个可以量化的目标,并在页面中清楚地看到当前达成进度。
典型的财务目标示例:
- 存 5 万元作为应急金;
- 在一年内攒够首付;
- 在半年内还清某笔贷款。
在 UI 层面,我们需要一个页面:
- 列出所有目标;
- 展示当前进度(进度条或百分比);
- 提供新增/编辑目标的入口。
2. 页面整体结构:目标列表 + 进度概览
在 pages.js 中,“财务目标”页面的结构可以设计为:
// ==================== 财务目标页面 ====================
'goals': () => `
<div class="pc-page-container">
<div class="pc-page-header">
<h2>🎯 财务目标</h2>
<p>制定和跟踪你的长期财务目标</p>
</div>
<div class="pc-card">
<div class="pc-card-header">
<h3>目标列表</h3>
<button id="goal-add-btn" class="pc-button pc-button-primary">新增目标</button>
</div>
<div class="pc-card-body">
<div id="goals-list" class="pc-goals-list">
<!-- JS 动态渲染每个目标及其进度条 -->
</div>
</div>
</div>
</div>
`,
这里沿用了熟悉的 PC 布局骨架:
pc-page-container+pc-page-header作为页面的统一头部;- 用一张
pc-card承载“目标列表”; goal-add-btn是新增目标的主入口;goals-list容器承载每一个目标项的 UI 结构。
3. 单个目标项的 UI 结构
一个目标项至少需要展示:
- 目标名称;
- 目标金额;
- 当前已完成金额;
- 进度条和百分比;
- 操作按钮(编辑 / 删除)。
示例结构:
function renderGoalItem(goal) {
const ratio = goal.targetAmount > 0
? Math.min(goal.currentAmount / goal.targetAmount, 1)
: 0;
const percent = Math.round(ratio * 100);
return `
<div class="pc-goal-item" data-id="${goal.id}">
<div class="pc-goal-main">
<div class="pc-goal-title">${goal.name}</div>
<div class="pc-goal-amounts">
<span>目标:¥${goal.targetAmount.toFixed(2)}</span>
<span>当前:¥${goal.currentAmount.toFixed(2)}</span>
</div>
<div class="pc-goal-progress">
<div class="pc-goal-progress-bar">
<div
class="pc-goal-progress-inner"
style="width: ${percent}%;"
></div>
</div>
<span class="pc-goal-progress-text">${percent}%</span>
</div>
</div>
<div class="pc-goal-actions">
<button class="pc-button pc-button-sm" data-action="edit">编辑</button>
<button class="pc-button pc-button-sm pc-button-danger" data-action="delete">删除</button>
</div>
</div>
`;
}
通过 pc-goal-progress-inner 的宽度控制进度条长度,配合百分比文本,使用户一眼就能看到目标完成度。
4. 从数据库加载目标并渲染
在 db.js 中,我们可以有一个 goals 表,结构类似:
// 目标表
if (!db.objectStoreNames.contains('goals')) {
const goalStore = db.createObjectStore('goals', { keyPath: 'id' });
goalStore.createIndex('createdAt', 'createdAt', { unique: false });
}
async getGoals() {
return this.getAll('goals');
}
在 pages.js 中加载并渲染:
async loadGoalsPage() {
const container = document.getElementById('goals-list');
if (!container) return;
const goals = await window.financeDB.getGoals();
if (!goals || goals.length === 0) {
container.innerHTML = '<p class="pc-text-muted">暂时还没有任何财务目标,可以点击右上角“新增目标”创建一个。</p>';
return;
}
const html = goals.map(g => renderGoalItem(g)).join('');
container.innerHTML = html;
}
这段逻辑与前面交易列表、账户列表的加载方式是同一种思路:
- 从 IndexedDB 取出所有目标;
- 映射成 HTML 片段;
- 写入页面容器。
5. 新增和编辑目标:表单与保存逻辑
新增目标可以通过一个模态框或右侧表单来完成,这里展示一个简化的保存逻辑:
async saveGoal() {
const nameInput = document.getElementById('goal-name');
const targetInput = document.getElementById('goal-target');
const currentInput = document.getElementById('goal-current');
const name = nameInput?.value.trim();
const targetAmount = parseFloat(targetInput?.value || '0');
const currentAmount = parseFloat(currentInput?.value || '0');
if (!name) {
Toast.error('请输入目标名称');
return;
}
if (!targetAmount || targetAmount <= 0) {
Toast.error('请输入合理的目标金额');
return;
}
if (currentAmount < 0) {
Toast.error('当前金额不能为负数');
return;
}
const goal = {
name,
targetAmount,
currentAmount,
};
await window.financeDB.addGoal(goal);
Toast.success('目标已保存');
this.loadGoalsPage();
}
对应的数据库操作(示例):
async addGoal(goal) {
goal.id = this.generateId();
goal.createdAt = new Date().toISOString();
return this.add('goals', goal);
}
编辑目标则是在 UI 中找出对应 data-id,从 goals 表读取后填充表单,再通过 updateGoal 保存修改即可。
6. ArkTS 侧:财务目标数据的导出与导入
财务目标作为 goals 表的一部分,同样需要在导出/导入时被保留下来。导出调用链和前面预算模块类似:
- Web 层调用
financeDB.exportData(),返回包含goals在内的完整数据对象; - JS 使用
JSON.stringify序列化; - 通过
cordova.exec('FileManager', 'exportData', [json])把字符串交给 ArkTS 插件; - ArkTS 插件使用
fileIo将其写入备份文件。
下面是 FileManagerPlugin.ets 中的鸿蒙 ArkTS 片段(与前文保持一致风格):
import { CordovaPlugin, CallbackContext } from '@magongshou/harmony-cordova/Index';
import { PluginResult, MessageStatus } from '@magongshou/harmony-cordova/Index';
import { common } from '@kit.AbilityKit';
import { fileIo } from '@kit.CoreFileKit';
export class FileManagerPlugin extends CordovaPlugin {
async exportData(callbackContext: CallbackContext, args: string[]): Promise<void> {
try {
const json = args[0]; // 其中包含 goals 表以及其他所有表的数据
const context = getContext() as common.UIAbilityContext;
const cacheDir: string = context.cacheDir;
const filePath: string = `${cacheDir}/finance-backup.json`;
const file = await fileIo.open(filePath, fileIo.OpenMode.WRITE_ONLY | fileIo.OpenMode.CREATE);
await fileIo.write(file.fd, json);
await fileIo.close(file.fd);
const result = PluginResult.createByString(MessageStatus.OK, filePath);
callbackContext.sendPluginResult(result);
} catch (error) {
const result = PluginResult.createByString(MessageStatus.ERROR, (error as Error).message);
callbackContext.sendPluginResult(result);
}
}
}
从目标模块视角看:
- Web 层专注于目标的创建、进度计算和展示;
- ArkTS 插件专注于“把包含目标在内的全部数据安全写入文件”;
- 当在新设备上导入备份后,只要
goals表被正确恢复,目标页面 UI 就能重新渲染出所有目标及其进度。
7. 小结:财务目标页面 UI 的关键设计点
-
统一 PC 布局与组件风格:
- 继续复用
pc-page-container、pc-card等组件,让目标页面在整体视觉上与其他模块保持一致;
- 继续复用
-
进度条直观表达完成度:
- 通过
pc-goal-progress-inner的宽度和百分比文本,让用户一眼看懂“目标完成了多少”;
- 通过
-
与 goals 表结构紧密结合:
- 目标名称、目标金额、当前金额在 UI 与数据库之间一一映射,便于后续做统计或报表;
-
新增/编辑操作与列表展示解耦:
- 使用独立的表单负责新增/编辑,列表只负责展示和触发操作事件,代码结构更清晰;
-
与 ArkTS FileManager 插件协同:
- 目标数据作为整体数据库快照的一部分,由 ArkTS 插件负责导出/导入,保证在多设备之间迁移时不会丢失;
通过本模块,你的应用从“记录历史 + 管理当前”进一步扩展到了“规划未来”:用户不仅能看到资产现状,还能在目标页面上持续跟踪自己距离目标的差距和进展,这也是一个财务管理工具真正开始“有温度”的地方。
更多推荐


所有评论(0)