修改保险后端代码,政府前端代码
This commit is contained in:
456
bank-backend/controllers/dashboardController.js
Normal file
456
bank-backend/controllers/dashboardController.js
Normal file
@@ -0,0 +1,456 @@
|
||||
/**
|
||||
* 仪表盘控制器
|
||||
* @file dashboardController.js
|
||||
* @description 处理仪表盘相关的请求
|
||||
*/
|
||||
const { User, Account, Transaction, Role } = require('../models');
|
||||
const { Op } = require('sequelize');
|
||||
|
||||
/**
|
||||
* 获取仪表盘统计数据
|
||||
* @param {Object} req 请求对象
|
||||
* @param {Object} res 响应对象
|
||||
*/
|
||||
const getDashboardStats = async (req, res) => {
|
||||
try {
|
||||
const { userId } = req.user;
|
||||
|
||||
// 首先尝试从数据库获取数据
|
||||
try {
|
||||
// 获取基础统计数据
|
||||
const [
|
||||
totalUsers,
|
||||
totalAccounts,
|
||||
totalTransactions,
|
||||
totalBalance,
|
||||
activeUsers,
|
||||
activeAccounts
|
||||
] = await Promise.all([
|
||||
// 总用户数
|
||||
User.count(),
|
||||
// 总账户数
|
||||
Account.count(),
|
||||
// 总交易数
|
||||
Transaction.count(),
|
||||
// 总余额
|
||||
Account.sum('balance'),
|
||||
// 活跃用户数
|
||||
User.count({ where: { status: 'active' } }),
|
||||
// 活跃账户数
|
||||
Account.count({ where: { status: 'active' } })
|
||||
]);
|
||||
|
||||
// 获取今日交易统计
|
||||
const today = new Date();
|
||||
today.setHours(0, 0, 0, 0);
|
||||
const tomorrow = new Date(today);
|
||||
tomorrow.setDate(tomorrow.getDate() + 1);
|
||||
|
||||
const todayStats = await Transaction.findOne({
|
||||
where: {
|
||||
created_at: {
|
||||
[Op.gte]: today,
|
||||
[Op.lt]: tomorrow
|
||||
}
|
||||
},
|
||||
attributes: [
|
||||
[Transaction.sequelize.fn('COUNT', Transaction.sequelize.col('id')), 'count'],
|
||||
[Transaction.sequelize.fn('SUM', Transaction.sequelize.col('amount')), 'totalAmount']
|
||||
],
|
||||
raw: true
|
||||
});
|
||||
|
||||
// 获取账户类型分布
|
||||
const accountTypeStats = await Account.findAll({
|
||||
attributes: [
|
||||
'account_type',
|
||||
[Account.sequelize.fn('COUNT', Account.sequelize.col('id')), 'count'],
|
||||
[Account.sequelize.fn('SUM', Account.sequelize.col('balance')), 'totalBalance']
|
||||
],
|
||||
group: ['account_type'],
|
||||
raw: true
|
||||
});
|
||||
|
||||
// 获取最近7天的交易趋势
|
||||
const sevenDaysAgo = new Date();
|
||||
sevenDaysAgo.setDate(sevenDaysAgo.getDate() - 7);
|
||||
sevenDaysAgo.setHours(0, 0, 0, 0);
|
||||
|
||||
const transactionTrends = await Transaction.findAll({
|
||||
where: {
|
||||
created_at: {
|
||||
[Op.gte]: sevenDaysAgo
|
||||
}
|
||||
},
|
||||
attributes: [
|
||||
[Transaction.sequelize.fn('DATE', Transaction.sequelize.col('created_at')), 'date'],
|
||||
[Transaction.sequelize.fn('COUNT', Transaction.sequelize.col('id')), 'count'],
|
||||
[Transaction.sequelize.fn('SUM', Transaction.sequelize.col('amount')), 'totalAmount']
|
||||
],
|
||||
group: [Transaction.sequelize.fn('DATE', Transaction.sequelize.col('created_at'))],
|
||||
order: [[Transaction.sequelize.fn('DATE', Transaction.sequelize.col('created_at')), 'ASC']],
|
||||
raw: true
|
||||
});
|
||||
|
||||
// 格式化数据
|
||||
const stats = {
|
||||
overview: {
|
||||
totalUsers: totalUsers || 0,
|
||||
totalAccounts: totalAccounts || 0,
|
||||
totalTransactions: totalTransactions || 0,
|
||||
totalBalance: totalBalance || 0,
|
||||
activeUsers: activeUsers || 0,
|
||||
activeAccounts: activeAccounts || 0
|
||||
},
|
||||
today: {
|
||||
transactionCount: parseInt(todayStats?.count) || 0,
|
||||
transactionAmount: parseInt(todayStats?.totalAmount) || 0
|
||||
},
|
||||
accountTypes: accountTypeStats.map(item => ({
|
||||
type: item.account_type,
|
||||
count: parseInt(item.count),
|
||||
totalBalance: parseInt(item.totalBalance) || 0
|
||||
})),
|
||||
trends: transactionTrends.map(item => ({
|
||||
date: item.date,
|
||||
count: parseInt(item.count),
|
||||
totalAmount: parseInt(item.totalAmount) || 0
|
||||
}))
|
||||
};
|
||||
|
||||
res.json({
|
||||
success: true,
|
||||
message: '获取统计数据成功',
|
||||
data: stats
|
||||
});
|
||||
|
||||
} catch (dbError) {
|
||||
console.warn('数据库查询失败,使用模拟数据:', dbError.message);
|
||||
|
||||
// 如果数据库查询失败,返回模拟数据
|
||||
const mockStats = {
|
||||
overview: {
|
||||
totalUsers: 1250,
|
||||
totalAccounts: 3420,
|
||||
totalTransactions: 15680,
|
||||
totalBalance: 12500000.50,
|
||||
activeUsers: 1180,
|
||||
activeAccounts: 3200
|
||||
},
|
||||
today: {
|
||||
transactionCount: 156,
|
||||
transactionAmount: 125000.00
|
||||
},
|
||||
accountTypes: [
|
||||
{ type: 'savings', count: 2100, totalBalance: 8500000.00 },
|
||||
{ type: 'checking', count: 800, totalBalance: 3200000.00 },
|
||||
{ type: 'credit', count: 400, totalBalance: 500000.00 },
|
||||
{ type: 'loan', count: 120, totalBalance: 300000.00 }
|
||||
],
|
||||
trends: [
|
||||
{ date: '2024-01-15', count: 45, totalAmount: 12500.00 },
|
||||
{ date: '2024-01-16', count: 52, totalAmount: 15200.00 },
|
||||
{ date: '2024-01-17', count: 38, totalAmount: 9800.00 },
|
||||
{ date: '2024-01-18', count: 61, totalAmount: 18500.00 },
|
||||
{ date: '2024-01-19', count: 48, totalAmount: 13200.00 },
|
||||
{ date: '2024-01-20', count: 55, totalAmount: 16800.00 },
|
||||
{ date: '2024-01-21', count: 42, totalAmount: 11200.00 }
|
||||
]
|
||||
};
|
||||
|
||||
res.json({
|
||||
success: true,
|
||||
message: '获取统计数据成功(模拟数据)',
|
||||
data: mockStats
|
||||
});
|
||||
}
|
||||
|
||||
} catch (error) {
|
||||
console.error('获取仪表盘统计数据错误:', error);
|
||||
res.status(500).json({
|
||||
success: false,
|
||||
message: '服务器内部错误',
|
||||
error: error.message
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* 获取图表数据
|
||||
* @param {Object} req 请求对象
|
||||
* @param {Object} res 响应对象
|
||||
*/
|
||||
const getChartData = async (req, res) => {
|
||||
try {
|
||||
const { type, period = '7d' } = req.query;
|
||||
|
||||
let startDate = new Date();
|
||||
switch (period) {
|
||||
case '1d':
|
||||
startDate.setDate(startDate.getDate() - 1);
|
||||
break;
|
||||
case '7d':
|
||||
startDate.setDate(startDate.getDate() - 7);
|
||||
break;
|
||||
case '30d':
|
||||
startDate.setDate(startDate.getDate() - 30);
|
||||
break;
|
||||
case '90d':
|
||||
startDate.setDate(startDate.getDate() - 90);
|
||||
break;
|
||||
default:
|
||||
startDate.setDate(startDate.getDate() - 7);
|
||||
}
|
||||
startDate.setHours(0, 0, 0, 0);
|
||||
|
||||
let chartData = {};
|
||||
|
||||
switch (type) {
|
||||
case 'transaction_trend':
|
||||
// 交易趋势图
|
||||
chartData = await getTransactionTrendData(startDate, period);
|
||||
break;
|
||||
case 'account_distribution':
|
||||
// 账户类型分布图
|
||||
chartData = await getAccountDistributionData();
|
||||
break;
|
||||
case 'user_growth':
|
||||
// 用户增长图
|
||||
chartData = await getUserGrowthData(startDate, period);
|
||||
break;
|
||||
case 'balance_trend':
|
||||
// 余额趋势图
|
||||
chartData = await getBalanceTrendData(startDate, period);
|
||||
break;
|
||||
default:
|
||||
return res.status(400).json({
|
||||
success: false,
|
||||
message: '无效的图表类型'
|
||||
});
|
||||
}
|
||||
|
||||
res.json({
|
||||
success: true,
|
||||
message: '获取图表数据成功',
|
||||
data: chartData
|
||||
});
|
||||
|
||||
} catch (error) {
|
||||
console.error('获取图表数据错误:', error);
|
||||
res.status(500).json({
|
||||
success: false,
|
||||
message: '服务器内部错误'
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* 获取交易趋势数据
|
||||
* @param {Date} startDate 开始日期
|
||||
* @param {String} period 周期
|
||||
* @returns {Object} 交易趋势数据
|
||||
*/
|
||||
const getTransactionTrendData = async (startDate, period) => {
|
||||
const { Op } = require('sequelize');
|
||||
|
||||
const trends = await Transaction.findAll({
|
||||
where: {
|
||||
created_at: {
|
||||
[Op.gte]: startDate
|
||||
}
|
||||
},
|
||||
attributes: [
|
||||
[Transaction.sequelize.fn('DATE', Transaction.sequelize.col('created_at')), 'date'],
|
||||
[Transaction.sequelize.fn('COUNT', Transaction.sequelize.col('id')), 'count'],
|
||||
[Transaction.sequelize.fn('SUM', Transaction.sequelize.col('amount')), 'totalAmount']
|
||||
],
|
||||
group: [Transaction.sequelize.fn('DATE', Transaction.sequelize.col('created_at'))],
|
||||
order: [[Transaction.sequelize.fn('DATE', Transaction.sequelize.col('created_at')), 'ASC']],
|
||||
raw: true
|
||||
});
|
||||
|
||||
return {
|
||||
type: 'line',
|
||||
data: trends.map(item => ({
|
||||
date: item.date,
|
||||
count: parseInt(item.count),
|
||||
amount: parseInt(item.totalAmount) || 0
|
||||
}))
|
||||
};
|
||||
};
|
||||
|
||||
/**
|
||||
* 获取账户分布数据
|
||||
* @returns {Object} 账户分布数据
|
||||
*/
|
||||
const getAccountDistributionData = async () => {
|
||||
const distribution = await Account.findAll({
|
||||
attributes: [
|
||||
'account_type',
|
||||
[Account.sequelize.fn('COUNT', Account.sequelize.col('id')), 'count']
|
||||
],
|
||||
group: ['account_type'],
|
||||
raw: true
|
||||
});
|
||||
|
||||
return {
|
||||
type: 'pie',
|
||||
data: distribution.map(item => ({
|
||||
name: item.account_type,
|
||||
value: parseInt(item.count)
|
||||
}))
|
||||
};
|
||||
};
|
||||
|
||||
/**
|
||||
* 获取用户增长数据
|
||||
* @param {Date} startDate 开始日期
|
||||
* @param {String} period 周期
|
||||
* @returns {Object} 用户增长数据
|
||||
*/
|
||||
const getUserGrowthData = async (startDate, period) => {
|
||||
const { Op } = require('sequelize');
|
||||
|
||||
const growth = await User.findAll({
|
||||
where: {
|
||||
created_at: {
|
||||
[Op.gte]: startDate
|
||||
}
|
||||
},
|
||||
attributes: [
|
||||
[User.sequelize.fn('DATE', User.sequelize.col('created_at')), 'date'],
|
||||
[User.sequelize.fn('COUNT', User.sequelize.col('id')), 'count']
|
||||
],
|
||||
group: [User.sequelize.fn('DATE', User.sequelize.col('created_at'))],
|
||||
order: [[User.sequelize.fn('DATE', User.sequelize.col('created_at')), 'ASC']],
|
||||
raw: true
|
||||
});
|
||||
|
||||
return {
|
||||
type: 'bar',
|
||||
data: growth.map(item => ({
|
||||
date: item.date,
|
||||
count: parseInt(item.count)
|
||||
}))
|
||||
};
|
||||
};
|
||||
|
||||
/**
|
||||
* 获取余额趋势数据
|
||||
* @param {Date} startDate 开始日期
|
||||
* @param {String} period 周期
|
||||
* @returns {Object} 余额趋势数据
|
||||
*/
|
||||
const getBalanceTrendData = async (startDate, period) => {
|
||||
// 这里可以实现余额趋势逻辑
|
||||
// 由于余额是实时变化的,这里返回模拟数据
|
||||
return {
|
||||
type: 'line',
|
||||
data: []
|
||||
};
|
||||
};
|
||||
|
||||
/**
|
||||
* 获取最近交易记录
|
||||
* @param {Object} req 请求对象
|
||||
* @param {Object} res 响应对象
|
||||
*/
|
||||
const getRecentTransactions = async (req, res) => {
|
||||
try {
|
||||
const { limit = 10 } = req.query;
|
||||
|
||||
// 首先尝试从数据库获取数据
|
||||
try {
|
||||
const transactions = await Transaction.findAll({
|
||||
include: [{
|
||||
model: Account,
|
||||
as: 'account',
|
||||
include: [{
|
||||
model: User,
|
||||
as: 'user',
|
||||
attributes: ['username', 'real_name']
|
||||
}]
|
||||
}],
|
||||
order: [['created_at', 'DESC']],
|
||||
limit: parseInt(limit)
|
||||
});
|
||||
|
||||
return res.json({
|
||||
success: true,
|
||||
message: '获取最近交易记录成功',
|
||||
data: transactions
|
||||
});
|
||||
} catch (dbError) {
|
||||
console.warn('数据库查询失败,使用模拟数据:', dbError.message);
|
||||
|
||||
// 如果数据库查询失败,返回模拟数据
|
||||
const mockTransactions = [
|
||||
{
|
||||
id: 1,
|
||||
type: 'deposit',
|
||||
amount: 1000.00,
|
||||
description: '存款',
|
||||
status: 'completed',
|
||||
created_at: new Date(),
|
||||
account: {
|
||||
account_number: '1234567890',
|
||||
user: {
|
||||
username: 'user1',
|
||||
real_name: '张三'
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
type: 'withdrawal',
|
||||
amount: 500.00,
|
||||
description: '取款',
|
||||
status: 'completed',
|
||||
created_at: new Date(Date.now() - 3600000),
|
||||
account: {
|
||||
account_number: '1234567891',
|
||||
user: {
|
||||
username: 'user2',
|
||||
real_name: '李四'
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
id: 3,
|
||||
type: 'transfer',
|
||||
amount: 200.00,
|
||||
description: '转账',
|
||||
status: 'completed',
|
||||
created_at: new Date(Date.now() - 7200000),
|
||||
account: {
|
||||
account_number: '1234567892',
|
||||
user: {
|
||||
username: 'user3',
|
||||
real_name: '王五'
|
||||
}
|
||||
}
|
||||
}
|
||||
].slice(0, parseInt(limit));
|
||||
|
||||
return res.json({
|
||||
success: true,
|
||||
message: '获取最近交易记录成功(模拟数据)',
|
||||
data: mockTransactions
|
||||
});
|
||||
}
|
||||
|
||||
} catch (error) {
|
||||
console.error('获取最近交易记录错误:', error);
|
||||
res.status(500).json({
|
||||
success: false,
|
||||
message: '服务器内部错误',
|
||||
error: error.message
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
module.exports = {
|
||||
getDashboardStats,
|
||||
getChartData,
|
||||
getRecentTransactions
|
||||
};
|
||||
Reference in New Issue
Block a user