ATM系统JavaScript开发:转出功能收款方账号验证问题咨询
解决ATM系统转出功能的收款方验证及转账逻辑问题
看起来你已经搭好了不错的基础框架,但转出功能的核心逻辑有几个需要调整的地方:一是收款方的验证逻辑不需要密码(现实中ATM转账只需要确认收款账号存在即可),二是当前的交易设计把转出单独拆成了transferReg,这不符合实际流程——转账应该由转出方发起,验证自身身份后再验证收款方账号,同时完成双方账户的金额变动。
下面是调整后的完整代码,我会标注关键修改点:
<!DOCTYPE html> <html> <head> <title>Trial</title> </head> <body> <h1>$ Trial $</h1> <script type="text/javascript"> verify(); function Bank(bankName, bankCode){ this.bankName = bankName; this.bankCode = bankCode; this.accounts = []; this.registerAccount = function(accountInfo){ this.accounts.push({info: accountInfo, balance: 0}); } // 新增:银行内通过账号查找账户(无需密码) this.findAccountByCode = function(accountCode){ return this.accounts.reduce(function(acc, cur){ return cur.info.code === accountCode ? cur : acc; }, null); } } function ATM(initCurrency){ this.currency = initCurrency; this.banks = []; this.registerBank = function(bank){ this.banks.push(bank); } this.auth = function(authinfo){ return { authinfo: authinfo, operations:[], deposit: function(amount){ this.operations.push({type: 'deposit', amount: amount}); }, withdraw: function(amount){ this.operations.push({type: 'withdraw', amount: amount}); }, transferIn: function(amount){ this.operations.push({type: 'transfer-in', amount: amount}); }, // 关键修改:把转出功能整合到已授权的交易中,接收收款方信息 transferOut: function(receiverInfo, amount){ this.operations.push({ type: 'transfer-out', amount: amount, receiver: receiverInfo // 存储收款方信息用于后续验证 }); }, getBalance: function(){ this.operations.push({type: 'balance-view'}); }, } } // 新增:验证收款方账号(仅需银行代码和账号存在) this.findReceiverAccount = function(receiverInfo){ const bank = this.banks.reduce(function(acc, cur){ return cur.bankCode === receiverInfo.bankCode ? cur : acc; }, null); return bank ? bank.findAccountByCode(receiverInfo.code) : null; } this.currencyLeft = function() { return (this.currency); } this.commit = function(transaction){ // 先验证转出方身份 const senderAccount = this.findAccount(transaction.authinfo); if(!senderAccount){ return {status: 'FAILURE', reason: '转出方身份验证失败'} } let result = {status: 'SUCCESS'} const commitedOperations = [] for (let operation of transaction.operations){ commitedOperations.push(operation); switch (operation.type){ case 'deposit': senderAccount.balance += operation.amount; this.currency += operation.amount; break; case 'withdraw': senderAccount.balance -= operation.amount; this.currency -= operation.amount; break; case 'transfer-in': // 转入功能按原有逻辑:外部转入增加ATM现金 senderAccount.balance += operation.amount; this.currency += operation.amount; break; case 'transfer-out': // 关键修改:验证收款方账号是否存在 const receiverAccount = this.findReceiverAccount(operation.receiver); if(!receiverAccount){ result.status = 'FAILURE'; result.reason = '收款方账号不存在'; break; } // 检查转出方余额是否足够 if(senderAccount.balance < operation.amount){ result.status = 'FAILURE'; result.reason = '余额不足'; break; } // 完成转账:转出方减额,转入方加额,ATM现金不变(账户间转账不涉及现金) senderAccount.balance -= operation.amount; receiverAccount.balance += operation.amount; break; case 'balance-view': result.data = senderAccount.balance; break; } if(result.status === 'FAILURE'){ break; } } // 交易失败时的回滚逻辑 if(result.status === 'FAILURE'){ while(commitedOperations.length){ let undoOperation = commitedOperations.pop(); switch(undoOperation.type){ case 'deposit': senderAccount.balance -= undoOperation.amount; this.currency -= undoOperation.amount; break; case 'withdraw': senderAccount.balance += undoOperation.amount; this.currency += undoOperation.amount; break; case 'transfer-in': // 修复原有bug:把错误的amount.balance改为senderAccount.balance senderAccount.balance -= undoOperation.amount; this.currency -= undoOperation.amount; break; case 'transfer-out': const receiverAccount = this.findReceiverAccount(undoOperation.receiver); if(receiverAccount){ senderAccount.balance += undoOperation.amount; receiverAccount.balance -= undoOperation.amount; } break; case 'balance-view': delete result.data; break; } } } return result; } this.findAccount = function(authinfo){ var bank = this.banks.reduce(function(acc, cur){ return (cur.bankCode === authinfo.bankCode) ? cur : acc }, null); return bank ? bank.accounts.reduce(function(acc, cur){ return(cur.info.code === authinfo.code && cur.info.password === authinfo.password) ? cur : acc }, null) : null } } function verify(){ var bankName = 'Standard Chartered'; var bankCode = 52; var bank = new Bank(bankName, bankCode); // 注册转出方账号 const senderInfo = { name: 'John', code: 113322, password: 223333, } bank.registerAccount(senderInfo); // 新增:注册收款方测试账号 const receiverInfo = { name: 'Thomas', code: 1234567, password: '123456', } bank.registerAccount(receiverInfo); var initCurrency = 1000 var atm = new ATM(initCurrency); atm.registerBank(bank); // 原有基础功能测试用例 { let transaction = atm.auth({bankCode: 52, code: 113322, password: 223333}); transaction.getBalance(); let result = atm.commit(transaction); console.log(result.status === 'SUCCESS'); console.log(result.data === 0); } { let transaction = atm.auth({bankCode: 52, code: 113322, password: 223333}); transaction.deposit(5600); transaction.getBalance(); let result = atm.commit(transaction); console.log(result.status === 'SUCCESS'); console.log(result.data === 5600); } { let transaction = atm.auth({bankCode: 52, code: 113322, password: 223333}); transaction.withdraw(3000); transaction.getBalance(); let result = atm.commit(transaction); console.log(result.status === 'SUCCESS'); console.log(result.data === 2600); } { let transaction = atm.auth({bankCode: 52, code: 113322, password: 223333}); transaction.transferIn(2000); transaction.getBalance(); let result = atm.commit(transaction); console.log(result.status === 'SUCCESS'); console.log(result.data === 4600); } // 修改转账测试用例:使用正确的收款账号 { let transaction = atm.auth({bankCode: 52, code: 113322, password: 223333}); transaction.transferOut({bankCode: 52, code: 1234567}, 2000); transaction.getBalance(); let result = atm.commit(transaction); console.log(result.status === 'SUCCESS'); console.log(result.data === 2600); // 额外验证收款方余额是否正确增加 const receiverAccount = atm.findReceiverAccount({bankCode:52, code:1234567}); console.log(receiverAccount.balance === 2000); } console.log(atm.currencyLeft() === 3600); // 转账不影响ATM现金,数值保持不变 // 测试收款方账号不存在的失败场景 { let transaction = atm.auth({bankCode: 52, code: 113322, password: 223333}); transaction.transferOut({bankCode: 52, code: 987654}, 1000); transaction.getBalance(); let result = atm.commit(transaction); console.log(result.status === 'FAILURE'); console.log(result.reason === '收款方账号不存在'); } // 原有其他失败测试用例 { let transaction = atm.auth({bankCode: 52, code: 113322, password: 2233}); transaction.withdraw(3000); transaction.getBalance(); let result = atm.commit(transaction); console.log(result.status === 'FAILURE'); } { let transaction = atm.auth({bankCode: 52, code: 113322, password: 223333}); transaction.withdraw(1000); transaction.withdraw(1000); transaction.withdraw(1000); transaction.withdraw(1000); transaction.withdraw(1000); transaction.withdraw(1000); transaction.withdraw(1000); transaction.getBalance(); let result = atm.commit(transaction); console.log(result.status === 'FAILURE'); } { let transaction = atm.auth({bankCode: 52, code: 113322, password: 223333}); transaction.getBalance(); let result = atm.commit(transaction); console.log(result.status === 'SUCCESS'); console.log(result.data === 2600); } } </script> </body> </html>
关键修改说明:
收款方验证逻辑优化:
- 在
Bank类中新增findAccountByCode方法,仅通过账号查找账户,不需要验证密码(符合现实ATM转账的逻辑)。 - ATM类新增
findReceiverAccount方法,专门负责验证收款方的银行代码和账号是否真实存在。
- 在
转账功能流程重构:
- 移除了单独的
transferReg方法,将transferOut整合到已授权的交易对象中——转账必须由已验证身份的转出方发起,更贴近实际操作流程。 transferOut方法接收收款方的银行代码和账号信息,将这些信息存入操作记录,方便后续commit时进行验证和处理。
- 移除了单独的
转账交易核心处理:
- 在
commit处理transfer-out操作时,先验证收款账户是否存在,再检查转出方余额是否足够,最后同时修改转出方和转入方的余额(ATM现金不变,因为账户间转账不涉及现金存取)。
- 在
修复原有代码bug:
- 修正了回滚逻辑中
transfer-in操作的错误(原代码错误使用amount.balance,改为正确的senderAccount.balance)。 - 补充了收款账户的注册代码,确保转账测试用例可以正常运行。
- 修正了回滚逻辑中
这样调整后,转出功能的收款方验证逻辑就符合要求了,整个转账流程也更贴近实际的ATM操作逻辑。
内容的提问来源于stack exchange,提问作者Melody Mak
相关产品推荐
相关产品推荐

