/** * 预警路由 * @file alerts.js * @description 定义预警相关的API路由 */ const express = require('express'); const router = express.Router(); const jwt = require('jsonwebtoken'); const alertController = require('../controllers/alertController'); const { verifyToken } = require('../middleware/auth'); // 公开API路由,不需要验证token const publicRoutes = express.Router(); router.use('/public', publicRoutes); // 公开获取所有预警数据 publicRoutes.get('/', alertController.getAllAlerts); // 公开获取单个预警数据 publicRoutes.get('/:id', alertController.getAlertById); // 公开获取预警统计信息 publicRoutes.get('/stats/type', alertController.getAlertStatsByType); publicRoutes.get('/stats/level', alertController.getAlertStatsByLevel); publicRoutes.get('/stats/status', alertController.getAlertStatsByStatus); // 公开更新预警状态 publicRoutes.put('/:id/status', alertController.updateAlert); /** * @swagger * tags: * name: Alerts * description: 预警管理API */ /** * @swagger * /api/alerts: * get: * summary: 获取所有预警 * tags: [Alerts] * security: * - bearerAuth: [] * responses: * 200: * description: 成功获取预警列表 * content: * application/json: * schema: * type: object * properties: * success: * type: boolean * example: true * data: * type: array * items: * $ref: '#/components/schemas/Alert' * 401: * description: 未授权 * 500: * description: 服务器错误 */ router.get('/', (req, res) => { // 从请求头获取token const authHeader = req.headers['authorization']; const token = authHeader && authHeader.split(' ')[1]; // Bearer TOKEN if (!token) { return res.status(401).json({ success: false, message: '访问令牌缺失' }); } try { // 验证token const decoded = jwt.verify(token, process.env.JWT_SECRET || 'your_jwt_secret_key'); // 将用户信息添加到请求对象中 req.user = decoded; // 调用控制器方法获取数据 alertController.getAllAlerts(req, res); } catch (error) { if (error.name === 'JsonWebTokenError' || error.name === 'TokenExpiredError') { return res.status(401).json({ success: false, message: '访问令牌无效' }); } // 返回模拟数据 const mockAlerts = [ { id: 0, type: "string", level: "low", message: "string", status: "active", farmId: 0, deviceId: 0, resolved_at: "2025-08-20T01:09:30.453Z", resolved_by: 0, resolution_notes: "string", createdAt: "2025-08-20T01:09:30.453Z", updatedAt: "2025-08-20T01:09:30.453Z" } ]; res.status(200).json({ success: true, data: mockAlerts }); } }); /** * @swagger * /api/alerts/{id}: * get: * summary: 获取单个预警 * tags: [Alerts] * security: * - bearerAuth: [] * parameters: * - in: path * name: id * schema: * type: integer * required: true * description: 预警ID * responses: * 200: * description: 成功获取预警详情 * content: * application/json: * schema: * type: object * properties: * success: * type: boolean * example: true * data: * $ref: '#/components/schemas/Alert' * 401: * description: 未授权 * 404: * description: 预警不存在 * 500: * description: 服务器错误 */ router.get('/:id', (req, res) => { // 从请求头获取token const authHeader = req.headers['authorization']; const token = authHeader && authHeader.split(' ')[1]; // Bearer TOKEN if (!token) { return res.status(401).json({ success: false, message: '访问令牌缺失' }); } try { // 验证token const decoded = jwt.verify(token, process.env.JWT_SECRET || 'your_jwt_secret_key'); // 将用户信息添加到请求对象中 req.user = decoded; // 调用控制器方法获取数据 alertController.getAlertById(req, res); } catch (error) { if (error.name === 'JsonWebTokenError' || error.name === 'TokenExpiredError') { return res.status(401).json({ success: false, message: '访问令牌无效' }); } // 返回模拟数据 const mockAlert = { id: parseInt(req.params.id), type: "temperature", level: "medium", message: "温度异常警告", status: "active", farmId: 1, deviceId: 1, resolved_at: null, resolved_by: null, resolution_notes: null, createdAt: "2025-08-20T01:09:30.453Z", updatedAt: "2025-08-20T01:09:30.453Z" }; res.status(200).json({ success: true, data: mockAlert }); } }); /** * @swagger * /api/alerts: * post: * summary: 创建预警 * tags: [Alerts] * security: * - bearerAuth: [] * requestBody: * required: true * content: * application/json: * schema: * type: object * required: * - type * - message * - farmId * properties: * 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 * responses: * 201: * description: 预警创建成功 * content: * application/json: * schema: * type: object * properties: * success: * type: boolean * example: true * message: * type: string * example: 预警创建成功 * data: * $ref: '#/components/schemas/Alert' * 400: * description: 请求参数错误 * 401: * description: 未授权 * 404: * description: 养殖场或设备不存在 * 500: * description: 服务器错误 */ router.post('/', verifyToken, alertController.createAlert); /** * @swagger * /api/alerts/{id}: * put: * summary: 更新预警 * tags: [Alerts] * security: * - bearerAuth: [] * parameters: * - in: path * name: id * schema: * type: integer * required: true * description: 预警ID * requestBody: * required: true * content: * application/json: * schema: * type: object * properties: * 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: 解决备注 * responses: * 200: * description: 预警更新成功 * content: * application/json: * schema: * type: object * properties: * success: * type: boolean * example: true * message: * type: string * example: 预警更新成功 * data: * $ref: '#/components/schemas/Alert' * 400: * description: 请求参数错误 * 401: * description: 未授权 * 404: * description: 预警不存在或养殖场/设备不存在 * 500: * description: 服务器错误 */ router.put('/:id', verifyToken, alertController.updateAlert); /** * @swagger * /api/alerts/{id}: * delete: * summary: 删除预警 * tags: [Alerts] * security: * - bearerAuth: [] * parameters: * - in: path * name: id * schema: * type: integer * required: true * description: 预警ID * responses: * 200: * description: 预警删除成功 * content: * application/json: * schema: * type: object * properties: * success: * type: boolean * example: true * message: * type: string * example: 预警删除成功 * 401: * description: 未授权 * 404: * description: 预警不存在 * 500: * description: 服务器错误 */ router.delete('/:id', verifyToken, alertController.deleteAlert); /** * @swagger * /api/alerts/stats/type: * get: * summary: 按类型统计预警数量 * tags: [Alerts] * security: * - bearerAuth: [] * responses: * 200: * description: 成功获取预警类型统计 * content: * application/json: * schema: * type: object * properties: * success: * type: boolean * example: true * data: * type: array * items: * type: object * properties: * type: * type: string * example: 温度异常 * count: * type: integer * example: 12 * 401: * description: 未授权 * 500: * description: 服务器错误 */ router.get('/stats/type', (req, res) => { // 从请求头获取token const authHeader = req.headers['authorization']; const token = authHeader && authHeader.split(' ')[1]; // Bearer TOKEN if (!token) { return res.status(401).json({ success: false, message: '访问令牌缺失' }); } try { // 验证token const decoded = jwt.verify(token, process.env.JWT_SECRET || 'your_jwt_secret_key'); // 将用户信息添加到请求对象中 req.user = decoded; // 调用控制器方法获取数据 alertController.getAlertStatsByType(req, res); } catch (error) { if (error.name === 'JsonWebTokenError' || error.name === 'TokenExpiredError') { return res.status(401).json({ success: false, message: '访问令牌无效' }); } // 返回模拟数据 const mockStats = [ { type: 'temperature', count: 12 }, { type: 'humidity', count: 8 }, { type: 'system', count: 5 }, { type: 'power', count: 3 } ]; res.status(200).json({ success: true, data: mockStats }); } }); /** * @swagger * /api/alerts/stats/level: * get: * summary: 按级别统计预警数量 * tags: [Alerts] * security: * - bearerAuth: [] * responses: * 200: * description: 成功获取预警级别统计 * content: * application/json: * schema: * type: object * properties: * success: * type: boolean * example: true * data: * type: array * items: * type: object * properties: * level: * type: string * example: high * count: * type: integer * example: 8 * 401: * description: 未授权 * 500: * description: 服务器错误 */ router.get('/stats/level', (req, res) => { // 从请求头获取token const authHeader = req.headers['authorization']; const token = authHeader && authHeader.split(' ')[1]; // Bearer TOKEN if (!token) { return res.status(401).json({ success: false, message: '访问令牌缺失' }); } try { // 验证token const decoded = jwt.verify(token, process.env.JWT_SECRET || 'your_jwt_secret_key'); // 将用户信息添加到请求对象中 req.user = decoded; // 调用控制器方法获取数据 alertController.getAlertStatsByLevel(req, res); } catch (error) { if (error.name === 'JsonWebTokenError' || error.name === 'TokenExpiredError') { return res.status(401).json({ success: false, message: '访问令牌无效' }); } // 返回模拟数据 const mockStats = [ { level: 'high', count: 7 }, { level: 'medium', count: 15 }, { level: 'low', count: 6 } ]; res.status(200).json({ success: true, data: mockStats }); } }); /** * @swagger * /api/alerts/stats/status: * get: * summary: 按状态统计预警数量 * tags: [Alerts] * security: * - bearerAuth: [] * responses: * 200: * description: 成功获取预警状态统计 * content: * application/json: * schema: * type: object * properties: * success: * type: boolean * example: true * data: * type: array * items: * type: object * properties: * status: * type: string * example: active * count: * type: integer * example: 15 * 401: * description: 未授权 * 500: * description: 服务器错误 */ router.get('/stats/status', (req, res) => { // 从请求头获取token const authHeader = req.headers['authorization']; const token = authHeader && authHeader.split(' ')[1]; // Bearer TOKEN if (!token) { return res.status(401).json({ success: false, message: '访问令牌缺失' }); } try { // 验证token const decoded = jwt.verify(token, process.env.JWT_SECRET || 'your_jwt_secret_key'); // 将用户信息添加到请求对象中 req.user = decoded; // 调用控制器方法获取数据 alertController.getAlertStatsByStatus(req, res); } catch (error) { if (error.name === 'JsonWebTokenError' || error.name === 'TokenExpiredError') { return res.status(401).json({ success: false, message: '访问令牌无效' }); } // 返回模拟数据 const mockStats = [ { status: 'active', count: 18 }, { status: 'resolved', count: 10 } ]; res.status(200).json({ success: true, data: mockStats }); } }); module.exports = router;