更新政府端和银行端
This commit is contained in:
434
bank-backend/controllers/accountController.js
Normal file
434
bank-backend/controllers/accountController.js
Normal file
@@ -0,0 +1,434 @@
|
||||
/**
|
||||
* 账户控制器
|
||||
* @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);
|
||||
res.status(500).json({
|
||||
success: false,
|
||||
message: '服务器内部错误'
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* 获取账户详情
|
||||
* @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}`;
|
||||
}
|
||||
Reference in New Issue
Block a user