Initial commit: 宁夏智慧养殖监管平台

This commit is contained in:
shenquanyi
2025-08-25 15:00:46 +08:00
commit ec72c6a8b5
177 changed files with 37263 additions and 0 deletions

View File

@@ -0,0 +1,270 @@
/**
* 数据库连接池配置
* @file database-pool.js
* @description 配置和管理Sequelize数据库连接池
*/
const { Sequelize } = require('sequelize');
const { EventEmitter } = require('events');
const logger = require('../utils/logger');
const ormConfig = require('./orm-config');
// 从环境变量获取数据库连接参数
const DB_DIALECT = process.env.DB_DIALECT || 'mysql';
const DB_STORAGE = process.env.DB_STORAGE || './database.sqlite';
const DB_NAME = process.env.DB_NAME || 'nxTest';
const DB_USER = process.env.DB_USER || 'root';
const DB_PASSWORD = process.env.DB_PASSWORD || 'Aiotagro@741';
const DB_HOST = process.env.DB_HOST || '129.211.213.226';
const DB_PORT = process.env.DB_PORT || 3306;
// 数据库连接池事件发射器
class DatabasePoolEmitter extends EventEmitter {}
const poolEvents = new DatabasePoolEmitter();
// 默认连接池配置
const DEFAULT_POOL_CONFIG = {
max: parseInt(process.env.DB_POOL_MAX || '10'), // 最大连接数
min: parseInt(process.env.DB_POOL_MIN || '2'), // 最小连接数
acquire: parseInt(process.env.DB_POOL_ACQUIRE || '30000'), // 获取连接超时时间(毫秒)
idle: parseInt(process.env.DB_POOL_IDLE || '10000'), // 连接空闲多久后释放(毫秒)
evict: parseInt(process.env.DB_POOL_EVICT || '1000'), // 多久检查一次空闲连接(毫秒)
};
// 创建Sequelize实例
let sequelize;
if (DB_DIALECT === 'sqlite') {
sequelize = new Sequelize({
dialect: 'sqlite',
storage: DB_STORAGE,
logging: (msg) => logger.debug(msg),
benchmark: process.env.NODE_ENV !== 'production',
pool: DEFAULT_POOL_CONFIG,
define: ormConfig.defaultModelOptions
});
} else {
sequelize = new Sequelize(DB_NAME, DB_USER, DB_PASSWORD, {
host: DB_HOST,
port: DB_PORT,
dialect: DB_DIALECT,
logging: (msg) => logger.debug(msg),
benchmark: process.env.NODE_ENV !== 'production',
pool: DEFAULT_POOL_CONFIG,
define: ormConfig.defaultModelOptions,
dialectOptions: {
charset: 'utf8mb4',
supportBigNumbers: true,
bigNumberStrings: true,
dateStrings: true,
multipleStatements: process.env.DB_MULTIPLE_STATEMENTS === 'true'
},
timezone: '+08:00'
});
}
// 监听连接池事件 - 使用Sequelize实例的hooks
sequelize.addHook('afterConnect', (connection, config) => {
logger.info(`数据库连接已建立`);
poolEvents.emit('connect', connection);
});
sequelize.addHook('beforeDisconnect', (connection) => {
logger.info(`数据库连接即将断开`);
poolEvents.emit('disconnect', connection);
});
// 注意acquire和release事件在新版Sequelize中需要通过其他方式监听
// 这里我们使用定时器来监控连接池状态
setInterval(() => {
if (sequelize.connectionManager && sequelize.connectionManager.pool) {
const pool = sequelize.connectionManager.pool;
poolEvents.emit('poolStatus', {
size: pool.size || 0,
available: pool.available || 0,
using: pool.using || 0,
waiting: pool.waiting || 0
});
}
}, 30000); // 每30秒检查一次连接池状态
// 测试数据库连接
async function testConnection() {
try {
await sequelize.authenticate();
logger.info('数据库连接测试成功');
poolEvents.emit('connectionSuccess');
return { success: true, message: '数据库连接测试成功' };
} catch (error) {
logger.error('数据库连接测试失败:', error);
poolEvents.emit('connectionError', error);
return { success: false, message: error.message };
}
}
// 获取连接池状态
async function getPoolStatus() {
try {
const pool = sequelize.connectionManager.pool;
if (!pool) {
return { error: '连接池未初始化' };
}
// 获取连接池统计信息
const status = {
all: pool.size, // 所有连接数
idle: pool.idleCount, // 空闲连接数
used: pool.size - pool.idleCount, // 使用中的连接数
waiting: pool.pending, // 等待连接的请求数
max: pool.options.max, // 最大连接数
min: pool.options.min, // 最小连接数
acquire: pool.options.acquire, // 获取连接超时时间
idle: pool.options.idle, // 空闲超时时间
created: new Date().toISOString(), // 状态创建时间
utilization: (pool.size > 0) ? ((pool.size - pool.idleCount) / pool.size) * 100 : 0 // 利用率
};
poolEvents.emit('poolStatus', status);
return status;
} catch (error) {
logger.error('获取连接池状态失败:', error);
return { error: error.message };
}
}
// 监控连接池
async function monitorPool(interval = 60000) {
try {
const status = await getPoolStatus();
logger.debug('连接池状态:', status);
// 检查连接池利用率
if (status.utilization > 80) {
logger.warn(`连接池利用率过高: ${status.utilization.toFixed(2)}%`);
poolEvents.emit('highUtilization', status);
}
// 检查等待连接的请求数
if (status.waiting > 5) {
logger.warn(`连接池等待请求过多: ${status.waiting}`);
poolEvents.emit('highWaiting', status);
}
return status;
} catch (error) {
logger.error('监控连接池失败:', error);
return { error: error.message };
}
}
// 关闭连接池
async function closePool() {
try {
await sequelize.close();
logger.info('数据库连接池已关闭');
poolEvents.emit('poolClosed');
return { success: true, message: '数据库连接池已关闭' };
} catch (error) {
logger.error('关闭数据库连接池失败:', error);
return { success: false, message: error.message };
}
}
// 重置连接池
async function resetPool() {
try {
await closePool();
// 重新初始化连接池
sequelize.connectionManager.initPools();
// 测试新的连接池
const testResult = await testConnection();
if (testResult.success) {
logger.info('数据库连接池已重置');
poolEvents.emit('poolReset');
return { success: true, message: '数据库连接池已重置' };
} else {
throw new Error(testResult.message);
}
} catch (error) {
logger.error('重置数据库连接池失败:', error);
poolEvents.emit('poolResetError', error);
return { success: false, message: error.message };
}
}
// 优化连接池配置
async function optimizePool(config = {}) {
try {
// 获取当前状态
const currentStatus = await getPoolStatus();
// 计算新的配置
const newConfig = {
max: config.max || Math.max(currentStatus.max, Math.ceil(currentStatus.used * 1.5)),
min: config.min || Math.min(currentStatus.min, Math.floor(currentStatus.used * 0.5)),
acquire: config.acquire || currentStatus.acquire,
idle: config.idle || currentStatus.idle
};
// 确保最小连接数不小于1
newConfig.min = Math.max(newConfig.min, 1);
// 确保最大连接数不小于最小连接数
newConfig.max = Math.max(newConfig.max, newConfig.min);
// 应用新配置
await closePool();
// 更新连接池配置
sequelize.options.pool = newConfig;
// 重新初始化连接池
sequelize.connectionManager.initPools();
// 测试新的连接池
const testResult = await testConnection();
if (testResult.success) {
logger.info('数据库连接池已优化:', newConfig);
poolEvents.emit('poolOptimized', newConfig);
return { success: true, message: '数据库连接池已优化', config: newConfig };
} else {
throw new Error(testResult.message);
}
} catch (error) {
logger.error('优化数据库连接池失败:', error);
poolEvents.emit('poolOptimizationError', error);
return { success: false, message: error.message };
}
}
// 获取数据库表列表
async function getTablesList() {
try {
const [results] = await sequelize.query(
`SELECT TABLE_NAME FROM information_schema.TABLES
WHERE TABLE_SCHEMA = ?
ORDER BY TABLE_NAME`,
{ replacements: [DB_NAME] }
);
return results.map(row => row.TABLE_NAME);
} catch (error) {
logger.error('获取数据库表列表失败:', error);
return [];
}
}
// 导出模块
module.exports = {
sequelize,
testConnection,
getPoolStatus,
monitorPool,
closePool,
resetPool,
optimizePool,
getTablesList,
events: poolEvents
};

View File

@@ -0,0 +1,46 @@
const { Sequelize } = require('sequelize');
require('dotenv').config();
// 从环境变量获取数据库配置
const DB_DIALECT = process.env.DB_DIALECT || 'mysql';
const DB_HOST = process.env.DB_HOST || '129.211.213.226';
const DB_PORT = process.env.DB_PORT || 3306;
const DB_NAME = process.env.DB_NAME || 'nxTest';
const DB_USER = process.env.DB_USER || 'root';
const DB_PASSWORD = process.env.DB_PASSWORD || 'Aiotagro@741';
// 创建Sequelize实例
const sequelize = new Sequelize(DB_NAME, DB_USER, DB_PASSWORD, {
host: DB_HOST,
port: DB_PORT,
dialect: DB_DIALECT,
logging: false,
pool: {
max: 5,
min: 0,
acquire: 30000,
idle: 10000
},
define: {
timestamps: true,
charset: 'utf8mb4'
},
timezone: '+08:00'
});
// 测试数据库连接
const testConnection = async () => {
try {
await sequelize.authenticate();
console.log('✅ 数据库连接成功');
return true;
} catch (err) {
console.error('❌ 数据库连接失败:', err.message);
return false;
}
};
module.exports = {
sequelize,
testConnection
};

View File

@@ -0,0 +1,68 @@
const { Sequelize } = require('sequelize');
// 从环境变量获取数据库配置
const dialect = process.env.DB_DIALECT || 'mysql';
const config = {
logging: false,
define: {
timestamps: true
}
};
// 根据数据库类型配置不同的选项
if (dialect === 'sqlite') {
config.storage = process.env.DB_STORAGE || './database.sqlite';
config.dialect = 'sqlite';
} else {
config.host = process.env.DB_HOST || '129.211.213.226';
config.port = process.env.DB_PORT || 3306;
config.dialect = 'mysql';
config.timezone = '+08:00';
config.define.charset = 'utf8mb4';
config.define.collate = 'utf8mb4_unicode_ci';
config.pool = {
max: 5,
min: 0,
acquire: 30000,
idle: 10000
};
}
let sequelize;
if (dialect === 'sqlite') {
sequelize = new Sequelize(config);
} else {
sequelize = new Sequelize(
process.env.DB_NAME || 'nxTest',
process.env.DB_USER || 'root',
process.env.DB_PASSWORD || 'Aiotagro@741',
config
);
}
// 测试数据库连接最多重试3次
const MAX_RETRIES = 3;
let retryCount = 0;
const testConnection = async () => {
try {
await sequelize.authenticate();
console.log('数据库连接成功');
} catch (err) {
console.error('数据库连接失败:', err);
if (retryCount < MAX_RETRIES) {
retryCount++;
console.log(`正在重试连接 (${retryCount}/${MAX_RETRIES})...`);
setTimeout(testConnection, 5000); // 5秒后重试
} else {
console.error('数据库连接失败,应用将使用模拟数据运行');
}
}
};
// 异步测试连接,不阻塞应用启动
testConnection().catch(() => {
console.log('数据库连接测试完成,应用继续启动');
});
module.exports = sequelize;

View File

@@ -0,0 +1,218 @@
/**
* 数据库连接监控工具
* @file db-monitor.js
* @description 实时监控数据库连接状态
*/
const { sequelize } = require('./database-pool');
const { QueryTypes } = require('sequelize');
const EventEmitter = require('events');
// 创建事件发射器
const dbEvents = new EventEmitter();
/**
* 检查数据库连接状态
* @returns {Promise<Object>} 连接状态信息
*/
async function checkConnectionStatus() {
try {
// 测试连接
await sequelize.authenticate();
// 获取连接信息
const processlist = await sequelize.query(
'SHOW PROCESSLIST',
{ type: QueryTypes.SELECT }
);
// 获取连接统计信息
const connectionStats = await sequelize.query(
'SELECT * FROM performance_schema.host_cache',
{ type: QueryTypes.SELECT }
).catch(() => []);
// 获取等待事件
const waitEvents = await sequelize.query(
'SELECT * FROM performance_schema.events_waits_current LIMIT 10',
{ type: QueryTypes.SELECT }
).catch(() => []);
// 返回状态信息
const status = {
connected: true,
connections: processlist.length,
connectionStats: connectionStats,
waitEvents: waitEvents,
timestamp: new Date()
};
// 触发状态更新事件
dbEvents.emit('status_update', status);
return status;
} catch (error) {
// 连接失败
const errorStatus = {
connected: false,
error: error.message,
timestamp: new Date()
};
// 触发错误事件
dbEvents.emit('connection_error', errorStatus);
return errorStatus;
}
}
/**
* 获取连接池状态
* @returns {Promise<Object>} 连接池状态
*/
async function getPoolStatus() {
try {
const pool = sequelize.connectionManager.pool;
if (!pool) {
return { error: '连接池未初始化' };
}
const status = {
total: pool.size,
available: pool.available,
borrowed: pool.borrowed,
pending: pool.pending,
max: pool.max,
min: pool.min,
idle: pool.idleTimeoutMillis,
acquire: pool.acquireTimeoutMillis
};
// 触发连接池状态更新事件
dbEvents.emit('pool_status_update', status);
return status;
} catch (error) {
console.error('获取连接池状态失败:', error);
return { error: error.message };
}
}
/**
* 识别慢查询
* @param {number} threshold 慢查询阈值(毫秒)
* @returns {Promise<Array>} 慢查询列表
*/
async function identifySlowQueries(threshold = 1000) {
try {
const slowQueries = await sequelize.query(
'SELECT * FROM information_schema.PROCESSLIST WHERE TIME > ?',
{
replacements: [threshold / 1000], // 转换为秒
type: QueryTypes.SELECT
}
);
if (slowQueries.length > 0) {
// 触发慢查询事件
dbEvents.emit('slow_queries_detected', slowQueries);
}
return slowQueries;
} catch (error) {
console.error('识别慢查询失败:', error);
return [];
}
}
/**
* 记录数据库错误
* @param {Error} error 错误对象
*/
function logDatabaseError(error) {
const errorLog = {
message: error.message,
stack: error.stack,
timestamp: new Date()
};
// 触发错误日志事件
dbEvents.emit('error_logged', errorLog);
console.error('数据库错误:', error);
}
/**
* 启动定期监控
* @param {number} interval 监控间隔(毫秒)
* @returns {Object} 监控器对象
*/
function startMonitoring(interval = 60000) {
// 创建监控器
const monitor = {
interval: null,
isRunning: false,
lastStatus: null,
start: function() {
if (this.isRunning) return;
this.isRunning = true;
this.interval = setInterval(async () => {
try {
// 检查连接状态
this.lastStatus = await checkConnectionStatus();
// 检查连接池状态
await getPoolStatus();
// 检查慢查询
await identifySlowQueries();
} catch (error) {
logDatabaseError(error);
}
}, interval);
dbEvents.emit('monitoring_started', { interval });
return this;
},
stop: function() {
if (!this.isRunning) return;
clearInterval(this.interval);
this.interval = null;
this.isRunning = false;
dbEvents.emit('monitoring_stopped');
return this;
},
getStatus: function() {
return {
isRunning: this.isRunning,
interval: interval,
lastStatus: this.lastStatus,
timestamp: new Date()
};
}
};
return monitor;
}
/**
* 监听数据库事件
* @param {string} event 事件名称
* @param {Function} listener 监听器函数
*/
function onDatabaseEvent(event, listener) {
dbEvents.on(event, listener);
}
module.exports = {
checkConnectionStatus,
getPoolStatus,
identifySlowQueries,
logDatabaseError,
startMonitoring,
onDatabaseEvent,
dbEvents
};

View File

@@ -0,0 +1,123 @@
/**
* ORM配置文件
* @file orm-config.js
* @description 提供统一的ORM配置和扩展功能
*/
const { Sequelize, DataTypes, Op } = require('sequelize');
const sequelize = require('./database-pool').sequelize;
const queryOptimizer = require('./query-optimizer');
/**
* 默认模型选项
*/
const defaultModelOptions = {
timestamps: true, // 默认添加 createdAt 和 updatedAt
paranoid: true, // 软删除(添加 deletedAt 而不是真正删除数据)
underscored: true, // 使用下划线命名法 (例如: created_at 而不是 createdAt)
freezeTableName: false, // 使用模型名称的复数形式作为表名
charset: 'utf8mb4', // 字符集
collate: 'utf8mb4_unicode_ci', // 排序规则
};
/**
* 创建模型时的默认字段
*/
const defaultFields = {
id: {
type: DataTypes.INTEGER,
primaryKey: true,
autoIncrement: true,
comment: '主键ID'
},
created_at: {
type: DataTypes.DATE,
defaultValue: Sequelize.literal('CURRENT_TIMESTAMP'),
comment: '创建时间'
},
updated_at: {
type: DataTypes.DATE,
defaultValue: Sequelize.literal('CURRENT_TIMESTAMP'),
onUpdate: Sequelize.literal('CURRENT_TIMESTAMP'),
comment: '更新时间'
},
deleted_at: {
type: DataTypes.DATE,
allowNull: true,
comment: '删除时间'
}
};
/**
* 扩展Sequelize模型功能
* @param {Object} modelClass Sequelize模型类
*/
function extendModel(modelClass) {
// 添加通用的查询方法
modelClass.findAllActive = function(options = {}) {
return this.findAll({
...options,
where: {
...options.where,
deleted_at: null
}
});
};
// 添加分页查询方法
modelClass.findAllPaginated = function({ page = 1, pageSize = 10, ...options } = {}) {
const offset = (page - 1) * pageSize;
return this.findAndCountAll({
...options,
limit: pageSize,
offset
}).then(result => ({
rows: result.rows,
total: result.count,
page,
pageSize,
totalPages: Math.ceil(result.count / pageSize)
}));
};
// 添加批量更新方法
modelClass.bulkUpdateById = async function(records, options = {}) {
if (!Array.isArray(records) || records.length === 0) {
return [];
}
const results = [];
for (const record of records) {
if (!record.id) continue;
const [affectedCount, affectedRows] = await this.update(record, {
where: { id: record.id },
returning: true,
...options
});
if (affectedCount > 0 && affectedRows.length > 0) {
results.push(affectedRows[0]);
}
}
return results;
};
}
/**
* 初始化ORM
* @returns {Object} Sequelize实例和工具函数
*/
function initORM() {
// 扩展Sequelize.Model
extendModel(Sequelize.Model);
return {
sequelize,
Sequelize,
DataTypes,
Op,
defaultModelOptions,
defaultFields,
queryOptimizer
};
}
module.exports = initORM();

View File

@@ -0,0 +1,122 @@
/**
* 性能监控配置
* @file performance-config.js
* @description 性能监控系统的配置和集成
*/
const { performanceMonitor, events: perfEvents } = require('../utils/performance-monitor');
const { apiPerformanceMonitor, apiErrorMonitor } = require('../middleware/performance-middleware');
const logger = require('../utils/logger');
/**
* 初始化性能监控系统
* @param {Object} app Express应用实例
* @param {Object} options 配置选项
* @param {boolean} options.autoStart 是否自动启动监控
* @param {number} options.interval 监控间隔(毫秒)
* @param {Object} options.thresholds 警报阈值
* @param {boolean} options.logToConsole 是否将性能日志输出到控制台
* @returns {Object} 性能监控实例
*/
function initPerformanceMonitoring(app, options = {}) {
const {
autoStart = true,
interval = 60000, // 默认1分钟
thresholds = {},
logToConsole = false
} = options;
// 设置警报阈值
if (Object.keys(thresholds).length > 0) {
performanceMonitor.setAlertThresholds(thresholds);
}
// 应用API性能监控中间件
app.use(apiPerformanceMonitor);
// 应用API错误监控中间件应在路由之后应用
app.use(apiErrorMonitor);
// 设置事件监听
setupEventListeners(logToConsole);
// 自动启动监控
if (autoStart) {
performanceMonitor.startMonitoring(interval);
logger.info(`性能监控系统已自动启动,监控间隔: ${interval}ms`);
}
return performanceMonitor;
}
/**
* 设置性能监控事件监听
* @param {boolean} logToConsole 是否将性能日志输出到控制台
*/
function setupEventListeners(logToConsole = false) {
// 监控启动事件
perfEvents.on('monitoringStarted', (data) => {
logger.info(`性能监控已启动,间隔: ${data.interval}ms`);
});
// 监控停止事件
perfEvents.on('monitoringStopped', () => {
logger.info('性能监控已停止');
});
// 数据库状态变化事件
perfEvents.on('databaseStatus', (status) => {
if (logToConsole) {
logger.info('数据库状态更新:', status);
}
});
// 数据库错误事件
perfEvents.on('databaseError', (error) => {
logger.error('数据库错误:', error);
});
// 慢查询事件
perfEvents.on('slowQuery', (query) => {
logger.warn(`检测到慢查询: ${query.duration}ms - ${query.query.substring(0, 100)}...`);
});
// API错误事件
perfEvents.on('apiError', (data) => {
logger.error(`API错误: ${data.method} ${data.path} - ${data.error}`);
});
// 慢API请求事件
perfEvents.on('slowApiRequest', (data) => {
logger.warn(`慢API请求: ${data.endpoint} - ${data.duration}ms (阈值: ${data.threshold}ms)`);
});
// 高CPU使用率事件
perfEvents.on('highCpuUsage', (data) => {
logger.warn(`高CPU使用率: ${data.usage}% (阈值: ${data.threshold}%)`);
});
// 高内存使用率事件
perfEvents.on('highMemoryUsage', (data) => {
logger.warn(`高内存使用率: ${data.usage}% (阈值: ${data.threshold}%)`);
});
// 高磁盘使用率事件
perfEvents.on('highDiskUsage', (data) => {
logger.warn(`高磁盘使用率: ${data.usage}% (阈值: ${data.threshold}%)`);
});
}
/**
* 获取性能监控路由
* @returns {Object} Express路由
*/
function getPerformanceRoutes() {
return require('../routes/performance-routes');
}
module.exports = {
initPerformanceMonitoring,
getPerformanceRoutes,
performanceMonitor,
perfEvents
};

View File

@@ -0,0 +1,246 @@
/**
* 数据库查询优化器
* @file query-optimizer.js
* @description 监控和优化SQL查询性能
*/
const { sequelize } = require('./database-pool');
const { QueryTypes } = require('sequelize');
/**
* 记录查询性能
* @param {string} query SQL查询语句
* @param {number} executionTime 执行时间(毫秒)
* @returns {Promise<void>}
*/
async function logQueryPerformance(query, executionTime) {
try {
// 简化查询语句(移除参数值)
const simplifiedQuery = query.replace(/('([^']*)'|"([^"]*)"|`([^`]*)`)/g, '?');
// 记录到性能日志表
await sequelize.query(
'INSERT INTO query_performance_logs (query, execution_time, timestamp) VALUES (?, ?, NOW())',
{
replacements: [simplifiedQuery, executionTime],
type: QueryTypes.INSERT
}
).catch(() => {
// 如果表不存在,创建表
return sequelize.query(
`CREATE TABLE IF NOT EXISTS query_performance_logs (
id INT AUTO_INCREMENT PRIMARY KEY,
query TEXT NOT NULL,
execution_time FLOAT NOT NULL,
timestamp DATETIME NOT NULL,
INDEX (timestamp),
INDEX (execution_time)
)`,
{ type: QueryTypes.RAW }
).then(() => {
// 重新尝试插入
return sequelize.query(
'INSERT INTO query_performance_logs (query, execution_time, timestamp) VALUES (?, ?, NOW())',
{
replacements: [simplifiedQuery, executionTime],
type: QueryTypes.INSERT
}
);
});
});
} catch (error) {
console.error('记录查询性能失败:', error);
}
}
/**
* 识别慢查询
* @param {number} threshold 慢查询阈值毫秒默认为500ms
* @returns {Promise<Array>} 慢查询列表
*/
async function identifySlowQueries(threshold = 500) {
try {
// 查询性能日志表中的慢查询
const slowQueries = await sequelize.query(
'SELECT query, AVG(execution_time) as avg_time, COUNT(*) as count, MAX(timestamp) as last_seen ' +
'FROM query_performance_logs ' +
'WHERE execution_time > ? ' +
'GROUP BY query ' +
'ORDER BY avg_time DESC',
{
replacements: [threshold],
type: QueryTypes.SELECT
}
).catch(() => {
// 如果表不存在,返回空数组
return [];
});
return slowQueries;
} catch (error) {
console.error('识别慢查询失败:', error);
return [];
}
}
/**
* 分析和优化表
* @param {string} tableName 表名
* @returns {Promise<Object>} 优化结果
*/
async function analyzeAndOptimizeTable(tableName) {
try {
// 分析表
await sequelize.query(`ANALYZE TABLE ${tableName}`, { type: QueryTypes.RAW });
// 优化表
const optimizeResult = await sequelize.query(`OPTIMIZE TABLE ${tableName}`, { type: QueryTypes.RAW });
return optimizeResult[0];
} catch (error) {
console.error(`分析和优化表 ${tableName} 失败:`, error);
return { error: error.message };
}
}
/**
* 获取表的索引信息
* @param {string} tableName 表名
* @returns {Promise<Array>} 索引信息
*/
async function getIndexInfo(tableName) {
try {
const indexInfo = await sequelize.query(
'SHOW INDEX FROM ??',
{
replacements: [tableName],
type: QueryTypes.SELECT
}
);
return indexInfo;
} catch (error) {
console.error(`获取表 ${tableName} 的索引信息失败:`, error);
return [];
}
}
/**
* 获取表信息
* @param {string} tableName 表名
* @returns {Promise<Object>} 表信息
*/
async function getTableInfo(tableName) {
try {
// 获取表状态
const tableStatus = await sequelize.query(
'SHOW TABLE STATUS LIKE ?',
{
replacements: [tableName],
type: QueryTypes.SELECT
}
);
// 获取表结构
const tableStructure = await sequelize.query(
'DESCRIBE ??',
{
replacements: [tableName],
type: QueryTypes.SELECT
}
);
return {
status: tableStatus[0] || {},
structure: tableStructure
};
} catch (error) {
console.error(`获取表 ${tableName} 信息失败:`, error);
return { error: error.message };
}
}
/**
* 解释查询计划
* @param {Object} query Sequelize查询对象
* @returns {Promise<Array>} 查询计划
*/
async function explainQuery(query) {
try {
// 获取SQL语句
const sql = query.getQueryString();
// 执行EXPLAIN
const explainResult = await sequelize.query(
`EXPLAIN ${sql}`,
{
type: QueryTypes.SELECT
}
);
return explainResult;
} catch (error) {
console.error('解释查询计划失败:', error);
return [];
}
}
/**
* 获取数据库状态
* @returns {Promise<Object>} 数据库状态
*/
async function getDatabaseStatus() {
try {
// 获取全局状态
const globalStatus = await sequelize.query(
'SHOW GLOBAL STATUS',
{ type: QueryTypes.SELECT }
);
// 转换为对象格式
const status = {};
globalStatus.forEach(item => {
if (item.Variable_name && item.Value) {
status[item.Variable_name] = item.Value;
}
});
// 提取关键指标
return {
connections: {
max_used: status.Max_used_connections,
current: status.Threads_connected,
running: status.Threads_running,
created: status.Threads_created,
cached: status.Threads_cached
},
queries: {
total: status.Questions,
slow: status.Slow_queries,
qps: status.Queries
},
buffer_pool: {
size: status.Innodb_buffer_pool_pages_total,
free: status.Innodb_buffer_pool_pages_free,
dirty: status.Innodb_buffer_pool_pages_dirty,
reads: status.Innodb_buffer_pool_reads,
read_requests: status.Innodb_buffer_pool_read_requests,
hit_rate: status.Innodb_buffer_pool_read_requests && status.Innodb_buffer_pool_reads
? (1 - parseInt(status.Innodb_buffer_pool_reads) / parseInt(status.Innodb_buffer_pool_read_requests)) * 100
: 0
}
};
} catch (error) {
console.error('获取数据库状态失败:', error);
return { error: error.message };
}
}
module.exports = {
logQueryPerformance,
identifySlowQueries,
analyzeAndOptimizeTable,
getIndexInfo,
getTableInfo,
explainQuery,
getDatabaseStatus
};

320
backend/config/swagger.js Normal file
View File

@@ -0,0 +1,320 @@
const swaggerJsdoc = require('swagger-jsdoc');
const options = {
definition: {
openapi: '3.0.0',
info: {
title: '宁夏智慧养殖监管平台 API',
version: '1.0.0',
description: '宁夏智慧养殖监管平台后端 API 文档',
},
servers: [
{
url: 'http://localhost:5350',
description: '开发服务器',
},
],
components: {
securitySchemes: {
bearerAuth: {
type: 'http',
scheme: 'bearer',
bearerFormat: 'JWT',
}
},
schemas: {
MapGeocode: {
type: 'object',
properties: {
address: {
type: 'string',
description: '地址'
},
result: {
type: 'object',
properties: {
location: {
type: 'object',
properties: {
lng: {
type: 'number',
description: '经度'
},
lat: {
type: 'number',
description: '纬度'
}
}
}
}
}
}
},
MapReverseGeocode: {
type: 'object',
properties: {
lat: {
type: 'number',
description: '纬度'
},
lng: {
type: 'number',
description: '经度'
},
result: {
type: 'object',
properties: {
formatted_address: {
type: 'string',
description: '结构化地址'
},
addressComponent: {
type: 'object',
description: '地址组成部分'
}
}
}
}
},
MapDirection: {
type: 'object',
properties: {
origin: {
type: 'string',
description: '起点坐标,格式:纬度,经度'
},
destination: {
type: 'string',
description: '终点坐标,格式:纬度,经度'
},
mode: {
type: 'string',
enum: ['driving', 'walking', 'riding', 'transit'],
description: '交通方式'
}
}
},
Farm: {
type: 'object',
properties: {
id: {
type: 'integer',
description: '养殖场ID'
},
name: {
type: 'string',
description: '养殖场名称'
},
type: {
type: 'string',
description: '养殖场类型'
},
location: {
type: 'object',
properties: {
latitude: {
type: 'number',
format: 'float',
description: '纬度'
},
longitude: {
type: 'number',
format: 'float',
description: '经度'
}
},
description: '地理位置'
},
address: {
type: 'string',
description: '详细地址'
},
contact: {
type: 'string',
description: '联系人'
},
phone: {
type: 'string',
description: '联系电话'
},
status: {
type: 'string',
enum: ['active', 'inactive', 'maintenance'],
description: '养殖场状态'
},
createdAt: {
type: 'string',
format: 'date-time',
description: '创建时间'
},
updatedAt: {
type: 'string',
format: 'date-time',
description: '更新时间'
}
}
},
Animal: {
type: 'object',
properties: {
id: {
type: 'integer',
description: '动物ID'
},
type: {
type: 'string',
description: '动物类型'
},
count: {
type: 'integer',
description: '数量'
},
farmId: {
type: 'integer',
description: '所属养殖场ID'
},
health_status: {
type: 'string',
enum: ['healthy', 'sick', 'quarantined'],
description: '健康状态'
},
last_check_time: {
type: 'string',
format: 'date-time',
description: '上次检查时间'
},
notes: {
type: 'string',
description: '备注'
},
createdAt: {
type: 'string',
format: 'date-time',
description: '创建时间'
},
updatedAt: {
type: 'string',
format: 'date-time',
description: '更新时间'
}
}
},
Device: {
type: 'object',
properties: {
id: {
type: 'integer',
description: '设备ID'
},
name: {
type: 'string',
description: '设备名称'
},
type: {
type: 'string',
description: '设备类型'
},
status: {
type: 'string',
enum: ['online', 'offline', 'maintenance'],
description: '设备状态'
},
farmId: {
type: 'integer',
description: '所属养殖场ID'
},
last_maintenance: {
type: 'string',
format: 'date-time',
description: '上次维护时间'
},
installation_date: {
type: 'string',
format: 'date-time',
description: '安装日期'
},
metrics: {
type: 'object',
description: '设备指标'
},
createdAt: {
type: 'string',
format: 'date-time',
description: '创建时间'
},
updatedAt: {
type: 'string',
format: 'date-time',
description: '更新时间'
}
}
},
Alert: {
type: 'object',
properties: {
id: {
type: 'integer',
description: '预警ID'
},
type: {
type: 'string',
description: '预警类型'
},
level: {
type: 'string',
enum: ['low', 'medium', 'high', 'critical'],
description: '预警级别'
},
message: {
type: 'string',
description: '预警消息'
},
status: {
type: 'string',
enum: ['active', 'acknowledged', 'resolved'],
description: '预警状态'
},
farmId: {
type: 'integer',
description: '所属养殖场ID'
},
deviceId: {
type: 'integer',
description: '关联设备ID'
},
resolved_at: {
type: 'string',
format: 'date-time',
description: '解决时间'
},
resolved_by: {
type: 'integer',
description: '解决人ID'
},
resolution_notes: {
type: 'string',
description: '解决备注'
},
createdAt: {
type: 'string',
format: 'date-time',
description: '创建时间'
},
updatedAt: {
type: 'string',
format: 'date-time',
description: '更新时间'
}
}
}
}
},
security: [{
bearerAuth: []
}]
},
apis: ['./routes/*.js'], // 指定包含 API 注释的文件路径
};
const specs = swaggerJsdoc(options);
module.exports = specs;