海西蒙古族藏族自治州网站建设_网站建设公司_响应式网站_seo优化
2025/12/17 17:40:33 网站建设 项目流程

欢迎大家加入开源鸿蒙跨平台开发者社区,一起共建开源鸿蒙跨平台生态。

本文对应模块:pages.js中转账相关 JS 逻辑(如saveTransfer)、db.js中账户与交易的处理方式,以及这些逻辑如何在首页和账户管理页中体现账户余额变化。


1. 模块目标:保证“钱没变多,但账户余额正确变化”

转账与记收入/记支出最大的差异在于:

  • 总资产不变:只是在不同账户之间“搬家”;
  • 账户余额要同时变更:一个减,一个加;
  • 历史记录要可追踪:方便后续对账和分析。

本模块要梳理的是:从点击“保存转账”开始,到accountstransactions两张表被正确更新,以及首页仪表板和账户管理页面如何反映这些变化的全过程。


2. 转账入口:saveTransfer 的基本结构

pages.js中,转账业务的入口函数通常类似如下(示意):

// ==================== 保存转账 ====================asyncsaveTransfer(){constamountInput=document.getElementById('transfer-amount');constamount=parseFloat(amountInput?.value)||0;if(!amount||amount<=0){Toast.error('请输入有效的转账金额');return;}constfromSelect=document.getElementById('transfer-from');consttoSelect=document.getElementById('transfer-to');constfromAccountId=fromSelect?.value;consttoAccountId=toSelect?.value;if(!fromAccountId||!toAccountId||fromAccountId===toAccountId){Toast.error('请选择不同的转出账户和转入账户');return;}constdateInput=document.getElementById('transfer-date');constdate=dateInput?.value||newDate().toISOString().slice(0,10);constremarkInput=document.getElementById('transfer-remark');constremark=remarkInput?.value?.trim()||'';// 交给数据库层处理具体记录与余额联动awaitthis._performTransfer({amount,fromAccountId,toAccountId,date,remark,});Toast.success('转账成功');// 可选:刷新账户页面或仪表板// this.renderPage('accounts');}

这里saveTransfer的职责很清晰:

  • 从 UI 中获取金额、源账户、目标账户、日期和备注;
  • 做最基础的校验(金额有效、账户不为空且不相同);
  • 把业务参数打包交给内部_performTransfer方法处理;
  • 成功后给出提示,并根据需要刷新界面。

3. 内部转账实现:_performTransfer 如何更新数据

_performTransfer的典型实现思路是:

  1. 从数据库中取出源账户和目标账户信息;
  2. 校验源账户余额是否足以支付转账金额;
  3. transactions表中记录一条或两条转账记录;
  4. 更新accounts表中两个账户的余额;
  5. 保证整个过程要么全部成功,要么全部失败(理想情况下可以用事务语义模拟)。

示意代码如下(根据项目结构合理还原):

async_performTransfer({amount,fromAccountId,toAccountId,date,remark}){// 1. 获取账户信息constaccounts=awaitwindow.financeDB.getAccounts();constfromAccount=accounts.find(acc=>acc.id===fromAccountId);consttoAccount=accounts.find(acc=>acc.id===toAccountId);if(!fromAccount||!toAccount){Toast.error('账户信息异常,请重试');return;}if(fromAccount.balance<amount){Toast.error('转出账户余额不足');return;}// 2. 构造转账交易记录(你可以选择一条记录标记转出和转入,也可以两条记录)consttransferOut={type:'transfer-out',amount,accountId:fromAccountId,category:'TRANSFER',date,remark:remark||`转出到${toAccount.name}`,};consttransferIn={type:'transfer-in',amount,accountId:toAccountId,category:'TRANSFER',date,remark:remark||`${fromAccount.name}转入`,};// 3. 写入交易表awaitwindow.financeDB.addTransaction(transferOut);awaitwindow.financeDB.addTransaction(transferIn);// 4. 更新账户余额fromAccount.balance-=amount;toAccount.balance+=amount;awaitwindow.financeDB.updateAccount(fromAccount);awaitwindow.financeDB.updateAccount(toAccount);}

说明:具体项目中可能使用不同的type或分类标记转账,这里采用transfer-out/transfer-in只是为了强调“方向”,实际实现以你仓库里的字段为准。


4. db.js 视角:账户与交易的关系

db.js中,账户和交易分别由两张表承载:

// 账户表if(!db.objectStoreNames.contains('accounts')){constaccountStore=db.createObjectStore('accounts',{keyPath:'id'});accountStore.createIndex('type','type',{unique:false});accountStore.createIndex('createdAt','createdAt',{unique:false});}// 交易表if(!db.objectStoreNames.contains('transactions')){consttransStore=db.createObjectStore('transactions',{keyPath:'id'});transStore.createIndex('accountId','accountId',{unique:false});transStore.createIndex('type','type',{unique:false});transStore.createIndex('date','date',{unique:false});transStore.createIndex('category','category',{unique:false});}

以及对应的操作方法:

// 获取所有账户asyncgetAccounts(){returnthis.getAll('accounts');}// 更新账户asyncupdateAccount(account){account.updatedAt=newDate().toISOString();returnthis.update('accounts',account);}// 添加交易asyncaddTransaction(transaction){transaction.id=this.generateId();transaction.createdAt=newDate().toISOString();returnthis.add('transactions',transaction);}

从数据库角度看,转账只是两类操作的组合:

  • transactions表里写两条(或一条带方向信息的)记录;
  • 更新accounts表中两个账户的balance字段。

在首页仪表板和账户管理页面中,账户余额通常是通过对历史交易进行聚合计算得到的,或者在每次操作时直接维护余额字段。从你当前项目的结构来看,更偏向于在账户对象中直接维护一个balance字段,并在记账/转账时更新它。


5. 首页与账户管理页:如何反映转账结果

5.1 首页仪表板中的总资产

在首页模块中,总资产一般是通过汇总所有账户余额得到的:

constaccounts=awaitwindow.financeDB.getAccounts();consttotal=accounts.reduce((sum,acc)=>sum+acc.balance,0);

由于转账操作会同时更新两个账户的balance

  • 一个减amount
  • 一个加amount

所以总资产total在数学上保持不变,这也符合“转账不改变总资产”的业务定义。

5.2 账户管理页面中的每个账户余额

账户管理页面通常会列出所有账户及其余额:

asyncloadAccountsPage(){constaccounts=awaitwindow.financeDB.getAccounts();consttotal=accounts.reduce((sum,acc)=>sum+acc.balance,0);// 使用 accounts 渲染账户列表,每项显示名称、类型、余额等}

在执行了_performTransfer后:

  • fromAccount.balance已减去转账金额;
  • toAccount.balance已加上转账金额;
  • loadAccountsPage重新读取accounts时,就能看到最新的余额信息。

这就是“账户联动”的最直接体现:转账逻辑中的一次更新,被首页和账户管理页面同时感知到。


6. ArkTS 与转账:更多出现在数据导出导入场景

与记收入/记支出相同,转账业务本身完全可以在 Web + IndexedDB 层完成,而 ArkTS 更多出现在:

  • 数据导出

    • 用户希望备份所有账户信息和交易历史(包括转账记录);
    • JS 调用financeDB.exportData()导出当前数据库快照;
    • 通过cordova.exec('FileManager', 'exportData', [...])交给 ArkTS 插件写入文件。
  • 数据导入

    • 从备份恢复时,转账记录仍然是transactions表中的普通记录(可能 type 为 ‘transfer-out’/‘transfer-in’ 或类似标记);
    • ArkTS 插件负责从文件读取 JSON 字符串;
    • JS 调用financeDB.importData()将这些记录重新写回数据库。

在这两个场景中,ArkTS 不关心“这笔交易是转账还是普通支出”,它只负责把数据整体搬运进出。而转账的业务含义,主要体现在 JS 层对交易类型和账户余额的处理上。


7. 小结:转账业务逻辑模块的关键要点

综合来看,“转账业务逻辑与账户联动”模块的关键设计点可以归纳为:

  1. 入口函数清晰

    • 通过saveTransfer统一处理输入采集和基础校验;
    • 所有转账相关逻辑集中在_performTransfer,便于维护和测试。
  2. 账户与交易双表联动

    • 每次转账都会在transactions表中记录对应的交易信息;
    • 同时更新accounts表中源账户和目标账户的余额,保证数据一致性。
  3. 与首页仪表板、账户管理页自然联动

    • 首页总资产通过汇总账户余额得到,转账不会改变总额;
    • 账户管理页直接展示每个账户的balance,转账完成后只需重新加载数据即可反映变化。
  4. 与 ArkTS / FileManager 插件弱耦合

    • 转账业务完全在 Web + IndexedDB 侧完成;
    • ArkTS 只在数据导出/导入时参与,负责文件读写,不干预业务语义。
  5. 为后续对账与分析打基础

    • 通过在transactions表中记录带方向含义的转账记录(transfer-out/transfer-in),将来可以很方便地对某个账户的转入转出进行详细分析。

理解了这个模块后,你就能完整地串起:“用户点下转账按钮 → 两个账户余额变化 → 首页与账户管理页同步更新 → 将来导出这些数据做分析或备份”的整个链路。


ArkTS 侧与转账数据的协同

在导入导出场景中,转账记录和其他交易一样,由 ArkTS FileManager 插件负责落盘和恢复。下面是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';exportclassFileManagerPluginextendsCordovaPlugin{asyncexportData(callbackContext:CallbackContext,args:string[]):Promise<void>{try{// args[0]:前端通过 financeDB.exportData() 打包好的 JSON 字符串constjson=args[0];constcontext=getContext()ascommon.UIAbilityContext;constcacheDir:string=context.cacheDir;constfilePath:string=`${cacheDir}/finance-backup.json`;constfile=awaitfileIo.open(filePath,fileIo.OpenMode.WRITE_ONLY|fileIo.OpenMode.CREATE);awaitfileIo.write(file.fd,json);awaitfileIo.close(file.fd);constresult=PluginResult.createByString(MessageStatus.OK,filePath);callbackContext.sendPluginResult(result);}catch(error){constresult=PluginResult.createByString(MessageStatus.ERROR,(errorasError).message);callbackContext.sendPluginResult(result);}}}

在本模块的语境下,这段 ArkTS 代码意味着:

  • 所有包含转账在内的交易记录,都会先在 Web 层汇总为一个 JSON;
  • 通过cordova.exec('FileManager', 'exportData', [...])把这份 JSON 交给 ArkTS 插件;
  • 插件负责选择合适的存储位置写入文件,使得用户可以在设备之间迁移包括“转账历史”在内的全部账本数据。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询