Files
xlxumu/backend/api/server.js
2025-09-04 01:39:31 +08:00

291 lines
7.8 KiB
JavaScript

const express = require('express');
const cors = require('cors');
const helmet = require('helmet');
const dotenv = require('dotenv');
const rateLimit = require('express-rate-limit');
const mysql = require('mysql2/promise');
const path = require('path');
// 导入路由模块
const authModule = require('./routes/auth');
const usersModule = require('./routes/users');
const cattleModule = require('./routes/cattle');
const financeModule = require('./routes/finance');
const tradingModule = require('./routes/trading');
const governmentModule = require('./routes/government');
const mallModule = require('./routes/mall');
// 加载环境变量
dotenv.config();
// 数据库连接配置
const dbConfig = {
host: process.env.DB_HOST,
port: process.env.DB_PORT,
user: process.env.DB_USER,
password: process.env.DB_PASSWORD,
database: process.env.DB_NAME,
charset: process.env.DB_CHARSET || 'utf8mb4',
connectionLimit: 10,
acquireTimeout: 60000,
timeout: 60000
};
// 创建数据库连接池
const pool = mysql.createPool(dbConfig);
// 测试数据库连接
async function testDatabaseConnection() {
try {
const connection = await pool.getConnection();
console.log('✅ 数据库连接成功');
console.log(`📍 连接到: ${process.env.DB_HOST}:${process.env.DB_PORT}/${process.env.DB_NAME}`);
connection.release();
return true;
} catch (error) {
console.error('❌ 数据库连接失败:', error.message);
console.log('⚠️ 服务将继续运行,但数据库功能不可用');
return false;
}
}
// 启动时测试数据库连接(不阻塞服务启动)
testDatabaseConnection();
// 创建Express应用
const app = express();
const PORT = process.env.PORT || 8888;
// 设置路由模块的数据库连接
authModule.setPool(pool);
usersModule.setMiddleware(authModule.authenticateToken, authModule.checkPermission, pool);
cattleModule.setMiddleware(authModule.authenticateToken, authModule.checkPermission, pool);
financeModule.setMiddleware(authModule.authenticateToken, authModule.checkPermission, pool);
tradingModule.setMiddleware(authModule.authenticateToken, authModule.checkPermission, pool);
governmentModule.setMiddleware(authModule.authenticateToken, authModule.checkPermission, pool);
mallModule.setMiddleware(authModule.authenticateToken, authModule.checkPermission, pool);
// 中间件
app.use(helmet()); // 安全头部
app.use(cors()); // 跨域支持
app.use(express.json({ limit: '10mb' })); // JSON解析
app.use(express.urlencoded({ extended: true, limit: '10mb' })); // URL编码解析
// 速率限制
const limiter = rateLimit({
windowMs: 15 * 60 * 1000, // 15分钟
max: 100, // 限制每个IP 15分钟内最多100个请求
message: '请求过于频繁,请稍后再试'
});
app.use(limiter);
// 基础路由
app.get('/', (req, res) => {
res.json({
message: '欢迎使用锡林郭勒盟地区智慧养殖产业平台API服务',
version: '1.0.0',
timestamp: new Date().toISOString()
});
});
app.get('/health', async (req, res) => {
try {
// 测试数据库连接
const connection = await pool.getConnection();
const [rows] = await connection.execute('SELECT 1 as test');
connection.release();
res.json({
status: 'OK',
timestamp: new Date().toISOString(),
database: 'Connected',
environment: process.env.NODE_ENV,
version: '1.0.0'
});
} catch (error) {
res.status(500).json({
status: 'ERROR',
timestamp: new Date().toISOString(),
database: 'Disconnected',
error: error.message
});
}
});
// API路由
app.use('/api/v1/auth', authModule.router);
app.use('/api/v1/users', usersModule.router);
app.use('/api/v1/cattle', cattleModule.router);
app.use('/api/v1/finance', financeModule.router);
app.use('/api/v1/trading', tradingModule.router);
app.use('/api/v1/government', governmentModule.router);
app.use('/api/v1/mall', mallModule.router);
// 数据库查询接口
app.get('/api/v1/database/tables', async (req, res) => {
try {
const [tables] = await pool.execute(
'SELECT TABLE_NAME, TABLE_COMMENT FROM information_schema.TABLES WHERE TABLE_SCHEMA = ?',
[process.env.DB_NAME]
);
res.json({
success: true,
data: {
database: process.env.DB_NAME,
tables: tables,
count: tables.length
},
timestamp: new Date().toISOString()
});
} catch (error) {
res.status(500).json({
success: false,
error: error.message,
timestamp: new Date().toISOString()
});
}
});
// 数据库连接状态接口
app.get('/api/v1/database/status', async (req, res) => {
try {
const [statusResult] = await pool.execute('SHOW STATUS LIKE "Threads_connected"');
const [versionResult] = await pool.execute('SELECT VERSION() as version');
res.json({
success: true,
data: {
connected: true,
version: versionResult[0].version,
threads_connected: statusResult[0].Value,
database: process.env.DB_NAME,
host: process.env.DB_HOST,
port: process.env.DB_PORT
},
timestamp: new Date().toISOString()
});
} catch (error) {
res.status(500).json({
success: false,
error: error.message,
timestamp: new Date().toISOString()
});
}
});
app.get('/api/v1/dashboard/map/regions', (req, res) => {
// 模拟锡林郭勒盟各区域数据
const regions = [
{
id: 'xlg',
name: '锡林浩特市',
coordinates: [116.093, 43.946],
cattle_count: 25600,
farm_count: 120,
output_value: 650000000
},
{
id: 'dwq',
name: '东乌旗',
coordinates: [116.980, 45.514],
cattle_count: 18500,
farm_count: 95,
output_value: 480000000
},
{
id: 'xwq',
name: '西乌旗',
coordinates: [117.615, 44.587],
cattle_count: 21200,
farm_count: 108,
output_value: 520000000
},
{
id: 'abg',
name: '阿巴嘎旗',
coordinates: [114.971, 44.022],
cattle_count: 16800,
farm_count: 86,
output_value: 420000000
},
{
id: 'snz',
name: '苏尼特左旗',
coordinates: [113.653, 43.859],
cattle_count: 12400,
farm_count: 65,
output_value: 310000000
}
];
res.json({ regions });
});
app.get('/api/v1/dashboard/map/region/:regionId', (req, res) => {
const { regionId } = req.params;
// 模拟各区域详细数据
const regionDetails = {
'xlg': {
region: {
id: 'xlg',
name: '锡林浩特市',
coordinates: [116.093, 43.946],
cattle_count: 25600,
farm_count: 120,
output_value: 650000000,
trend: 'up'
},
farms: [
{
id: 'FARM001',
name: '锡林浩特市第一牧场',
coordinates: [116.120, 43.950],
cattle_count: 2450,
output_value: 62000000
},
{
id: 'FARM002',
name: '锡林浩特市第二牧场',
coordinates: [116.080, 43.930],
cattle_count: 2100,
output_value: 53000000
}
]
},
'dwq': {
region: {
id: 'dwq',
name: '东乌旗',
coordinates: [116.980, 45.514],
cattle_count: 18500,
farm_count: 95,
output_value: 480000000,
trend: 'up'
},
farms: [
{
id: 'FARM003',
name: '东乌旗牧场A',
coordinates: [116.990, 45.520],
cattle_count: 1950,
output_value: 49000000
}
]
}
};
const detail = regionDetails[regionId];
if (detail) {
res.json(detail);
} else {
res.status(404).json({ error: '区域未找到' });
}
});
// 启动服务器
app.listen(PORT, () => {
console.log(`API服务器正在端口 ${PORT} 上运行`);
});
module.exports = app;