Files
nxxmdata/backend/server.js
2025-09-17 19:01:52 +08:00

285 lines
8.9 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

const express = require('express');
const http = require('http');
const cors = require('cors');
const dotenv = require('dotenv');
const multer = require('multer');
const swaggerUi = require('swagger-ui-express');
const swaggerSpec = require('./config/swagger');
const { sequelize } = require('./config/database-simple');
const webSocketManager = require('./utils/websocket');
const logger = require('./utils/logger');
const {
apiRateLimiter,
inputSanitizer,
sessionTimeoutCheck,
securityHeaders
} = require('./middleware/security');
const { autoOperationLogger } = require('./middleware/autoOperationLogger');
// 加载环境变量
dotenv.config();
// 创建Express应用和HTTP服务器
const app = express();
const server = http.createServer(app);
const PORT = process.env.PORT || 3001;
// 配置文件上传
const storage = multer.diskStorage({
destination: function (req, file, cb) {
cb(null, 'uploads/') // 上传文件保存目录
},
filename: function (req, file, cb) {
// 生成唯一文件名
const uniqueSuffix = Date.now() + '-' + Math.round(Math.random() * 1E9);
cb(null, file.fieldname + '-' + uniqueSuffix + '.' + file.originalname.split('.').pop());
}
});
const upload = multer({
storage: storage,
limits: {
fileSize: 10 * 1024 * 1024 // 限制文件大小为10MB
},
fileFilter: function (req, file, cb) {
// 只允许Excel文件
const allowedTypes = [
'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
'application/vnd.ms-excel'
];
if (allowedTypes.includes(file.mimetype)) {
cb(null, true);
} else {
cb(new Error('只允许上传Excel文件(.xlsx或.xls格式)'), false);
}
}
});
// 安全中间件
app.use(securityHeaders);
app.use(apiRateLimiter);
app.use(inputSanitizer);
app.use(sessionTimeoutCheck);
// 基础中间件
app.use(cors());
app.use(express.json({ charset: 'utf8' }));
app.use(express.urlencoded({ extended: true, charset: 'utf8' }));
// API统一中间件
const { apiMiddleware, errorHandler, notFoundHandler } = require('./middleware/apiMiddleware');
app.use('/api', apiMiddleware);
// 静态文件服务 - 提供前端构建文件
app.use(express.static(__dirname + '/dist'));
// 自动操作日志中间件在所有API路由之前
app.use('/api', autoOperationLogger);
// 设置响应头确保UTF-8编码仅对API请求
app.use('/api', (req, res, next) => {
res.setHeader('Content-Type', 'application/json; charset=utf-8');
next();
});
// Swagger 文档路由配置
const swaggerOptions = {
explorer: true,
swaggerOptions: {
docExpansion: 'list',
defaultModelsExpandDepth: 2,
defaultModelExpandDepth: 2,
displayRequestDuration: true,
filter: true,
showExtensions: true,
showCommonExtensions: true,
tryItOutEnabled: true,
persistAuthorization: true,
layout: 'BaseLayout',
deepLinking: true,
displayOperationId: false,
syntaxHighlight: {
activate: true,
theme: 'tomorrow-night'
}
},
customCss: `
.swagger-ui .topbar { background: linear-gradient(135deg, #1890ff 0%, #722ed1 100%); }
.swagger-ui .topbar .download-url-wrapper { display: none; }
.swagger-ui .info { margin: 20px 0; }
.swagger-ui .info .title { color: #1890ff; font-size: 2.5em; }
.swagger-ui .scheme-container { background: #f8f9fa; padding: 15px; border-radius: 8px; }
.swagger-ui .btn.authorize { background: #52c41a; border-color: #52c41a; }
.swagger-ui .btn.authorize:hover { background: #73d13d; border-color: #73d13d; }
.swagger-ui .opblock.opblock-post { border-color: #1890ff; background: rgba(24, 144, 255, 0.1); }
.swagger-ui .opblock.opblock-get { border-color: #52c41a; background: rgba(82, 196, 26, 0.1); }
.swagger-ui .opblock.opblock-put { border-color: #fa8c16; background: rgba(250, 140, 22, 0.1); }
.swagger-ui .opblock.opblock-delete { border-color: #f5222d; background: rgba(245, 34, 45, 0.1); }
.swagger-ui .parameters-col_description p { font-size: 13px; line-height: 1.4; }
.swagger-ui .response-col_description { font-size: 13px; }
.swagger-ui .model-box { background: #fafafa; border: 1px solid #d9d9d9; border-radius: 6px; }
.swagger-ui .model-title { color: #1890ff; font-weight: 600; }
.swagger-ui .prop-type { color: #722ed1; font-weight: 500; }
.swagger-ui .prop-format { color: #fa8c16; }
.swagger-ui .opblock-summary-description { font-size: 14px; color: #595959; }
`,
customSiteTitle: '宁夏智慧养殖监管平台 - API文档',
customfavIcon: '/favicon.ico'
};
app.use('/api-docs', swaggerUi.serve, swaggerUi.setup(swaggerSpec, swaggerOptions));
// 基础路由
app.get('/', (req, res) => {
res.json({
message: '宁夏智慧养殖监管平台API服务',
version: '1.0.0',
docs: '/api-docs'
});
});
// 数据库同步
sequelize.sync()
.then(() => {
console.log('数据库同步成功');
})
.catch(err => {
console.error('数据库同步失败:', err);
});
// 认证相关路由
app.use('/api/auth', require('./routes/auth'));
// 用户相关路由
app.use('/api/users', require('./routes/users'));
// 产品相关路由
app.use('/api/products', require('./routes/products'));
// 订单相关路由
app.use('/api/orders', require('./routes/orders'));
// 农场相关路由
app.use('/api/farms', require('./routes/farms'));
// 动物相关路由
app.use('/api/animals', require('./routes/animals'));
// 牛只档案相关路由基于iot_cattle表
app.use('/api/iot-cattle', require('./routes/iot-cattle'));
// 栏舍相关路由
app.use('/api/pens', require('./routes/pens'));
app.use('/api/cattle-pens', require('./routes/cattle-pens'));
app.use('/api/cattle-batches', require('./routes/cattle-batches'));
app.use('/api/cattle-transfer-records', require('./routes/cattle-transfer-records'));
app.use('/api/cattle-exit-records', require('./routes/cattle-exit-records'));
// 牛只基础数据路由
app.use('/api/cattle-user', require('./routes/cattle-user'));
app.use('/api/cattle-type', require('./routes/cattle-type'));
// 设备相关路由
app.use('/api/devices', require('./routes/devices'));
// 智能设备相关路由
app.use('/api/smart-devices', require('./routes/smart-devices'));
app.use('/api/iot-jbq-client', require('./routes/iot-jbq-client'));
// 智能预警相关路由
app.use('/api/smart-alerts', require('./routes/smart-alerts'));
// 电子围栏相关路由
app.use('/api/electronic-fence', require('./routes/electronic-fence'));
// 电子围栏坐标点相关路由
app.use('/api/electronic-fence-points', require('./routes/electronic-fence-points'));
// 预警相关路由
app.use('/api/alerts', require('./routes/alerts'));
// 统计数据相关路由
app.use('/api/stats', require('./routes/stats'));
// 百度地图API相关路由
app.use('/api/map', require('./routes/map'));
// 报表管理相关路由
app.use('/api/reports', require('./routes/reports'));
// 系统管理相关路由
app.use('/api/system', require('./routes/system'));
// 数据备份相关路由
app.use('/api/backup', require('./routes/backup'));
// 菜单管理相关路由
app.use('/api/menus', require('./routes/menus'));
// 角色权限管理相关路由
app.use('/api/role-permissions', require('./routes/role-permissions'));
// 表单日志相关路由
app.use('/api/form-logs', require('./routes/formLogs'));
// 操作日志相关路由
app.use('/api/operation-logs', require('./routes/operationLogs'));
// 绑定信息相关路由
app.use('/api/binding', require('./routes/binding'));
// API演示路由
app.use('/api/demo', require('./routes/api-demo'));
// 统一错误处理中间件
app.use(errorHandler);
// 404处理中间件
app.use(notFoundHandler);
// 前端路由 - 处理所有非API请求返回前端应用
app.get('*', (req, res) => {
// 如果是API请求跳过
if (req.path.startsWith('/api')) {
return res.status(404).json({
success: false,
message: 'API接口不存在'
});
}
// 返回前端应用
res.sendFile(__dirname + '/dist/index.html');
});
// 错误处理中间件
app.use((err, req, res, next) => {
console.error('服务器错误:', err);
res.status(500).json({
success: false,
message: '服务器错误'
});
});
// 初始化WebSocket
webSocketManager.init(server);
// 初始化实时数据推送服务
const realtimeService = require('./services/realtimeService');
// 启动服务器
server.listen(PORT, '0.0.0.0', () => {
console.log(`服务器运行在端口 ${PORT}`);
console.log(`服务器监听所有网络接口 (0.0.0.0:${PORT})`);
console.log(`API 文档地址: http://localhost:${PORT}/api-docs`);
console.log(`WebSocket 服务已启动`);
// 启动实时数据推送服务
realtimeService.start();
console.log(`实时数据推送服务已启动`);
logger.info(`宁夏智慧养殖监管平台服务器启动成功,端口: ${PORT}`);
});
// 导出app和webSocketManager供其他模块使用
module.exports = { app, webSocketManager };