/** * 账户控制器 * @file accountController.js * @description 处理银行账户相关的请求 */ const { Account, User, Transaction } = require('../models'); const { validationResult } = require('express-validator'); const { Op } = require('sequelize'); /** * 创建账户 * @param {Object} req 请求对象 * @param {Object} res 响应对象 */ exports.createAccount = async (req, res) => { try { const errors = validationResult(req); if (!errors.isEmpty()) { return res.status(400).json({ success: false, message: '输入数据验证失败', errors: errors.array() }); } const { user_id, account_type, initial_balance = 0 } = req.body; // 检查用户是否存在 const user = await User.findByPk(user_id); if (!user) { return res.status(404).json({ success: false, message: '用户不存在' }); } // 生成账户号码 const accountNumber = await generateAccountNumber(); // 创建账户 const account = await Account.create({ account_number: accountNumber, user_id, account_type, balance: initial_balance * 100, // 转换为分 available_balance: initial_balance * 100, frozen_amount: 0 }); // 如果有初始余额,创建存款交易记录 if (initial_balance > 0) { await Transaction.create({ transaction_number: await generateTransactionNumber(), account_id: account.id, transaction_type: 'deposit', amount: initial_balance * 100, balance_before: 0, balance_after: initial_balance * 100, description: '开户存款', status: 'completed', processed_at: new Date() }); } res.status(201).json({ success: true, message: '账户创建成功', data: { ...account.getSafeInfo(), balance_formatted: account.getBalanceFormatted(), available_balance_formatted: account.getAvailableBalanceFormatted() } }); } catch (error) { console.error('创建账户错误:', error); res.status(500).json({ success: false, message: '服务器内部错误' }); } }; /** * 获取账户列表 * @param {Object} req 请求对象 * @param {Object} res 响应对象 */ exports.getAccounts = async (req, res) => { try { const page = parseInt(req.query.page) || 1; const limit = parseInt(req.query.limit) || 10; const offset = (page - 1) * limit; const { user_id, account_type, status } = req.query; const whereClause = {}; // 普通用户只能查看自己的账户 if (req.user.role.name !== 'admin') { whereClause.user_id = req.user.id; } else if (user_id) { whereClause.user_id = user_id; } if (account_type) { whereClause.account_type = account_type; } if (status) { whereClause.status = status; } const { count, rows } = await Account.findAndCountAll({ where: whereClause, include: [{ model: User, as: 'user', attributes: ['id', 'username', 'real_name', 'email'] }], limit, offset, order: [['created_at', 'DESC']] }); res.json({ success: true, data: { accounts: rows.map(account => ({ ...account.getSafeInfo(), balance_formatted: account.getBalanceFormatted(), available_balance_formatted: account.getAvailableBalanceFormatted(), frozen_amount_formatted: account.getFrozenAmountFormatted() })), pagination: { page, limit, total: count, pages: Math.ceil(count / limit) } } }); } catch (error) { console.error('获取账户列表错误:', error); console.error('错误堆栈:', error.stack); res.status(500).json({ success: false, message: '服务器内部错误', error: process.env.NODE_ENV === 'development' ? error.message : undefined }); } }; /** * 获取账户详情 * @param {Object} req 请求对象 * @param {Object} res 响应对象 */ exports.getAccountDetail = async (req, res) => { try { const { accountId } = req.params; const account = await Account.findByPk(accountId, { include: [{ model: User, as: 'user', attributes: ['id', 'username', 'real_name', 'email'] }] }); if (!account) { return res.status(404).json({ success: false, message: '账户不存在' }); } // 检查权限 if (req.user.role.name !== 'admin' && account.user_id !== req.user.id) { return res.status(403).json({ success: false, message: '无权访问该账户' }); } res.json({ success: true, data: { ...account.getSafeInfo(), balance_formatted: account.getBalanceFormatted(), available_balance_formatted: account.getAvailableBalanceFormatted(), frozen_amount_formatted: account.getFrozenAmountFormatted() } }); } catch (error) { console.error('获取账户详情错误:', error); res.status(500).json({ success: false, message: '服务器内部错误' }); } }; /** * 更新账户状态 * @param {Object} req 请求对象 * @param {Object} res 响应对象 */ exports.updateAccountStatus = async (req, res) => { try { const { accountId } = req.params; const { status } = req.body; const account = await Account.findByPk(accountId); if (!account) { return res.status(404).json({ success: false, message: '账户不存在' }); } await account.update({ status }); res.json({ success: true, message: '账户状态更新成功', data: account.getSafeInfo() }); } catch (error) { console.error('更新账户状态错误:', error); res.status(500).json({ success: false, message: '服务器内部错误' }); } }; /** * 存款 * @param {Object} req 请求对象 * @param {Object} res 响应对象 */ exports.deposit = async (req, res) => { try { const errors = validationResult(req); if (!errors.isEmpty()) { return res.status(400).json({ success: false, message: '输入数据验证失败', errors: errors.array() }); } const { accountId } = req.params; const { amount, description } = req.body; const account = await Account.findByPk(accountId); if (!account) { return res.status(404).json({ success: false, message: '账户不存在' }); } // 检查账户状态 if (!account.isActive()) { return res.status(400).json({ success: false, message: '账户状态异常,无法进行存款操作' }); } const amountInCents = Math.round(amount * 100); const balanceBefore = account.balance; const balanceAfter = balanceBefore + amountInCents; // 开始事务 const transaction = await sequelize.transaction(); try { // 更新账户余额 await account.update({ balance: balanceAfter, available_balance: account.available_balance + amountInCents }, { transaction }); // 创建交易记录 await Transaction.create({ transaction_number: await generateTransactionNumber(), account_id: account.id, transaction_type: 'deposit', amount: amountInCents, balance_before: balanceBefore, balance_after: balanceAfter, description: description || '存款', status: 'completed', processed_at: new Date() }, { transaction }); await transaction.commit(); res.json({ success: true, message: '存款成功', data: { amount: amount, balance_after: account.formatAmount(balanceAfter), transaction_number: await generateTransactionNumber() } }); } catch (error) { await transaction.rollback(); throw error; } } catch (error) { console.error('存款错误:', error); res.status(500).json({ success: false, message: '服务器内部错误' }); } }; /** * 取款 * @param {Object} req 请求对象 * @param {Object} res 响应对象 */ exports.withdraw = async (req, res) => { try { const errors = validationResult(req); if (!errors.isEmpty()) { return res.status(400).json({ success: false, message: '输入数据验证失败', errors: errors.array() }); } const { accountId } = req.params; const { amount, description } = req.body; const account = await Account.findByPk(accountId); if (!account) { return res.status(404).json({ success: false, message: '账户不存在' }); } // 检查账户状态 if (!account.isActive()) { return res.status(400).json({ success: false, message: '账户状态异常,无法进行取款操作' }); } const amountInCents = Math.round(amount * 100); // 检查余额是否充足 if (!account.hasSufficientBalance(amountInCents)) { return res.status(400).json({ success: false, message: '账户余额不足' }); } const balanceBefore = account.balance; const balanceAfter = balanceBefore - amountInCents; // 开始事务 const transaction = await sequelize.transaction(); try { // 更新账户余额 await account.update({ balance: balanceAfter, available_balance: account.available_balance - amountInCents }, { transaction }); // 创建交易记录 await Transaction.create({ transaction_number: await generateTransactionNumber(), account_id: account.id, transaction_type: 'withdrawal', amount: amountInCents, balance_before: balanceBefore, balance_after: balanceAfter, description: description || '取款', status: 'completed', processed_at: new Date() }, { transaction }); await transaction.commit(); res.json({ success: true, message: '取款成功', data: { amount: amount, balance_after: account.formatAmount(balanceAfter), transaction_number: await generateTransactionNumber() } }); } catch (error) { await transaction.rollback(); throw error; } } catch (error) { console.error('取款错误:', error); res.status(500).json({ success: false, message: '服务器内部错误' }); } }; /** * 生成账户号码 * @returns {String} 账户号码 */ async function generateAccountNumber() { const bankCode = process.env.BANK_CODE || '001'; const timestamp = Date.now().toString().slice(-8); const random = Math.floor(Math.random() * 10000).toString().padStart(4, '0'); return `${bankCode}${timestamp}${random}`; } /** * 生成交易流水号 * @returns {String} 交易流水号 */ async function generateTransactionNumber() { const timestamp = Date.now().toString(); const random = Math.floor(Math.random() * 10000).toString().padStart(4, '0'); return `TXN${timestamp}${random}`; }