Initial commit: 宁夏智慧养殖监管平台
This commit is contained in:
626
backend/routes/alerts.js
Normal file
626
backend/routes/alerts.js
Normal file
@@ -0,0 +1,626 @@
|
||||
/**
|
||||
* 预警路由
|
||||
* @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;
|
||||
464
backend/routes/animals.js
Normal file
464
backend/routes/animals.js
Normal file
@@ -0,0 +1,464 @@
|
||||
/**
|
||||
* 动物路由
|
||||
* @file animals.js
|
||||
* @description 定义动物相关的API路由
|
||||
*/
|
||||
|
||||
const express = require('express');
|
||||
const router = express.Router();
|
||||
const animalController = require('../controllers/animalController');
|
||||
const { verifyToken } = require('../middleware/auth');
|
||||
const jwt = require('jsonwebtoken');
|
||||
|
||||
// 公开API路由,不需要验证token
|
||||
const publicRoutes = express.Router();
|
||||
router.use('/public', publicRoutes);
|
||||
|
||||
// 公开获取所有动物数据
|
||||
publicRoutes.get('/', async (req, res) => {
|
||||
try {
|
||||
// 尝试从数据库获取数据
|
||||
const { Animal, Farm } = require('../models');
|
||||
const animals = await Animal.findAll({
|
||||
include: [{ model: Farm, as: 'farm', attributes: ['id', 'name'] }]
|
||||
});
|
||||
|
||||
res.status(200).json({
|
||||
success: true,
|
||||
data: animals,
|
||||
source: 'database'
|
||||
});
|
||||
} catch (error) {
|
||||
console.error('从数据库获取动物列表失败,使用模拟数据:', error.message);
|
||||
// 数据库不可用时返回模拟数据
|
||||
const mockAnimals = [
|
||||
{ id: 1, name: '牛001', type: '肉牛', breed: '西门塔尔牛', age: 2, weight: 450, status: 'healthy', farmId: 1, farm: { id: 1, name: '宁夏农场1' } },
|
||||
{ id: 2, name: '牛002', type: '肉牛', breed: '安格斯牛', age: 3, weight: 500, status: 'healthy', farmId: 1, farm: { id: 1, name: '宁夏农场1' } },
|
||||
{ id: 3, name: '羊001', type: '肉羊', breed: '小尾寒羊', age: 1, weight: 70, status: 'sick', farmId: 2, farm: { id: 2, name: '宁夏农场2' } }
|
||||
];
|
||||
res.status(200).json({
|
||||
success: true,
|
||||
data: mockAnimals,
|
||||
source: 'mock',
|
||||
message: '数据库不可用,使用模拟数据'
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* @swagger
|
||||
* tags:
|
||||
* name: Animals
|
||||
* description: 动物管理API
|
||||
*/
|
||||
|
||||
/**
|
||||
* @swagger
|
||||
* /api/animals:
|
||||
* get:
|
||||
* summary: 获取所有动物
|
||||
* tags: [Animals]
|
||||
* security:
|
||||
* - bearerAuth: []
|
||||
* responses:
|
||||
* 200:
|
||||
* description: 成功获取动物列表
|
||||
* content:
|
||||
* application/json:
|
||||
* schema:
|
||||
* type: object
|
||||
* properties:
|
||||
* success:
|
||||
* type: boolean
|
||||
* example: true
|
||||
* data:
|
||||
* type: array
|
||||
* items:
|
||||
* $ref: '#/components/schemas/Animal'
|
||||
* 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;
|
||||
|
||||
// 调用控制器方法获取数据
|
||||
animalController.getAllAnimals(req, res);
|
||||
} catch (error) {
|
||||
if (error.name === 'JsonWebTokenError' || error.name === 'TokenExpiredError') {
|
||||
return res.status(401).json({
|
||||
success: false,
|
||||
message: '访问令牌无效'
|
||||
});
|
||||
}
|
||||
|
||||
// 返回模拟数据
|
||||
const mockAnimals = [
|
||||
{ id: 1, name: '牛001', type: '肉牛', breed: '西门塔尔牛', age: 2, weight: 450, status: 'healthy', farmId: 1, farm: { id: 1, name: '示例养殖场1' } },
|
||||
{ id: 2, name: '牛002', type: '肉牛', breed: '安格斯牛', age: 3, weight: 500, status: 'healthy', farmId: 1, farm: { id: 1, name: '示例养殖场1' } },
|
||||
{ id: 3, name: '羊001', type: '肉羊', breed: '小尾寒羊', age: 1, weight: 70, status: 'sick', farmId: 2, farm: { id: 2, name: '示例养殖场2' } }
|
||||
];
|
||||
|
||||
res.status(200).json({
|
||||
success: true,
|
||||
data: mockAnimals
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* @swagger
|
||||
* /api/animals/{id}:
|
||||
* get:
|
||||
* summary: 获取单个动物
|
||||
* tags: [Animals]
|
||||
* 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/Animal'
|
||||
* 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;
|
||||
|
||||
// 调用控制器方法获取数据
|
||||
animalController.getAnimalById(req, res);
|
||||
} catch (error) {
|
||||
if (error.name === 'JsonWebTokenError' || error.name === 'TokenExpiredError') {
|
||||
return res.status(401).json({
|
||||
success: false,
|
||||
message: '访问令牌无效'
|
||||
});
|
||||
}
|
||||
|
||||
// 返回模拟数据
|
||||
const animalId = parseInt(req.params.id);
|
||||
const mockAnimal = {
|
||||
id: animalId,
|
||||
name: `动物${animalId}`,
|
||||
type: animalId % 2 === 0 ? '肉牛' : '肉羊',
|
||||
breed: animalId % 2 === 0 ? '西门塔尔牛' : '小尾寒羊',
|
||||
age: Math.floor(Math.random() * 5) + 1,
|
||||
weight: animalId % 2 === 0 ? Math.floor(Math.random() * 200) + 400 : Math.floor(Math.random() * 50) + 50,
|
||||
status: Math.random() > 0.7 ? 'sick' : 'healthy',
|
||||
farmId: Math.ceil(animalId / 3),
|
||||
farm: { id: Math.ceil(animalId / 3), name: `示例养殖场${Math.ceil(animalId / 3)}` }
|
||||
};
|
||||
|
||||
res.status(200).json({
|
||||
success: true,
|
||||
data: mockAnimal
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* @swagger
|
||||
* /api/animals:
|
||||
* post:
|
||||
* summary: 创建动物
|
||||
* tags: [Animals]
|
||||
* security:
|
||||
* - bearerAuth: []
|
||||
* requestBody:
|
||||
* required: true
|
||||
* content:
|
||||
* application/json:
|
||||
* schema:
|
||||
* type: object
|
||||
* required:
|
||||
* - type
|
||||
* - count
|
||||
* - farmId
|
||||
* properties:
|
||||
* type:
|
||||
* type: string
|
||||
* description: 动物类型
|
||||
* count:
|
||||
* type: integer
|
||||
* description: 数量
|
||||
* farmId:
|
||||
* type: integer
|
||||
* description: 所属养殖场ID
|
||||
* health_status:
|
||||
* type: string
|
||||
* enum: [healthy, sick, quarantine]
|
||||
* description: 健康状态
|
||||
* last_inspection:
|
||||
* type: string
|
||||
* format: date-time
|
||||
* description: 最近检查时间
|
||||
* notes:
|
||||
* type: string
|
||||
* description: 备注
|
||||
* responses:
|
||||
* 201:
|
||||
* description: 动物创建成功
|
||||
* content:
|
||||
* application/json:
|
||||
* schema:
|
||||
* type: object
|
||||
* properties:
|
||||
* success:
|
||||
* type: boolean
|
||||
* example: true
|
||||
* message:
|
||||
* type: string
|
||||
* example: 动物创建成功
|
||||
* data:
|
||||
* $ref: '#/components/schemas/Animal'
|
||||
* 400:
|
||||
* description: 请求参数错误
|
||||
* 401:
|
||||
* description: 未授权
|
||||
* 404:
|
||||
* description: 养殖场不存在
|
||||
* 500:
|
||||
* description: 服务器错误
|
||||
*/
|
||||
router.post('/', verifyToken, animalController.createAnimal);
|
||||
|
||||
/**
|
||||
* @swagger
|
||||
* /api/animals/{id}:
|
||||
* put:
|
||||
* summary: 更新动物
|
||||
* tags: [Animals]
|
||||
* 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: 动物类型
|
||||
* count:
|
||||
* type: integer
|
||||
* description: 数量
|
||||
* farmId:
|
||||
* type: integer
|
||||
* description: 所属养殖场ID
|
||||
* health_status:
|
||||
* type: string
|
||||
* enum: [healthy, sick, quarantine]
|
||||
* description: 健康状态
|
||||
* last_inspection:
|
||||
* type: string
|
||||
* format: date-time
|
||||
* description: 最近检查时间
|
||||
* 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/Animal'
|
||||
* 400:
|
||||
* description: 请求参数错误
|
||||
* 401:
|
||||
* description: 未授权
|
||||
* 404:
|
||||
* description: 动物不存在或养殖场不存在
|
||||
* 500:
|
||||
* description: 服务器错误
|
||||
*/
|
||||
router.put('/:id', verifyToken, animalController.updateAnimal);
|
||||
|
||||
/**
|
||||
* @swagger
|
||||
* /api/animals/{id}:
|
||||
* delete:
|
||||
* summary: 删除动物
|
||||
* tags: [Animals]
|
||||
* 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, animalController.deleteAnimal);
|
||||
|
||||
/**
|
||||
* @swagger
|
||||
* /api/animals/stats/type:
|
||||
* get:
|
||||
* summary: 按类型统计动物数量
|
||||
* tags: [Animals]
|
||||
* 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: 牛
|
||||
* total:
|
||||
* type: integer
|
||||
* example: 5000
|
||||
* 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;
|
||||
|
||||
// 调用控制器方法获取数据
|
||||
animalController.getAnimalStatsByType(req, res);
|
||||
} catch (error) {
|
||||
if (error.name === 'JsonWebTokenError' || error.name === 'TokenExpiredError') {
|
||||
return res.status(401).json({
|
||||
success: false,
|
||||
message: '访问令牌无效'
|
||||
});
|
||||
}
|
||||
|
||||
// 返回模拟数据
|
||||
const mockStats = [
|
||||
{ type: '肉牛', total: 5280 },
|
||||
{ type: '奶牛', total: 2150 },
|
||||
{ type: '肉羊', total: 8760 },
|
||||
{ type: '奶羊', total: 1430 },
|
||||
{ type: '猪', total: 12500 }
|
||||
];
|
||||
|
||||
res.status(200).json({
|
||||
success: true,
|
||||
data: mockStats
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
module.exports = router;
|
||||
1174
backend/routes/auth.js
Normal file
1174
backend/routes/auth.js
Normal file
File diff suppressed because it is too large
Load Diff
366
backend/routes/devices.js
Normal file
366
backend/routes/devices.js
Normal file
@@ -0,0 +1,366 @@
|
||||
/**
|
||||
* 设备路由
|
||||
* @file devices.js
|
||||
* @description 定义设备相关的API路由
|
||||
*/
|
||||
|
||||
const express = require('express');
|
||||
const router = express.Router();
|
||||
const deviceController = require('../controllers/deviceController');
|
||||
const { verifyToken } = require('../middleware/auth');
|
||||
|
||||
// 公开API路由,不需要验证token
|
||||
const publicRoutes = express.Router();
|
||||
router.use('/public', publicRoutes);
|
||||
|
||||
// 公开创建设备接口
|
||||
publicRoutes.post('/', deviceController.createDevice);
|
||||
|
||||
// 公开获取单个设备接口
|
||||
publicRoutes.get('/:id', deviceController.getDeviceById);
|
||||
|
||||
// 公开更新设备接口
|
||||
publicRoutes.put('/:id', deviceController.updateDevice);
|
||||
|
||||
// 公开删除设备接口
|
||||
publicRoutes.delete('/:id', deviceController.deleteDevice);
|
||||
|
||||
// 公开获取设备状态统计接口
|
||||
publicRoutes.get('/stats/status', deviceController.getDeviceStatsByStatus);
|
||||
|
||||
// 公开获取设备类型统计接口
|
||||
publicRoutes.get('/stats/type', deviceController.getDeviceStatsByType);
|
||||
|
||||
// 公开获取所有设备数据
|
||||
publicRoutes.get('/', deviceController.getAllDevices);
|
||||
|
||||
/**
|
||||
* @swagger
|
||||
* tags:
|
||||
* name: Devices
|
||||
* description: 设备管理API
|
||||
*/
|
||||
|
||||
/**
|
||||
* @swagger
|
||||
* /api/devices:
|
||||
* get:
|
||||
* summary: 获取所有设备
|
||||
* tags: [Devices]
|
||||
* security:
|
||||
* - bearerAuth: []
|
||||
* responses:
|
||||
* 200:
|
||||
* description: 成功获取设备列表
|
||||
* content:
|
||||
* application/json:
|
||||
* schema:
|
||||
* type: object
|
||||
* properties:
|
||||
* success:
|
||||
* type: boolean
|
||||
* example: true
|
||||
* data:
|
||||
* type: array
|
||||
* items:
|
||||
* $ref: '#/components/schemas/Device'
|
||||
* 401:
|
||||
* description: 未授权
|
||||
* 500:
|
||||
* description: 服务器错误
|
||||
*/
|
||||
router.get('/', verifyToken, deviceController.getAllDevices);
|
||||
|
||||
/**
|
||||
* @swagger
|
||||
* /api/devices/{id}:
|
||||
* get:
|
||||
* summary: 获取单个设备
|
||||
* tags: [Devices]
|
||||
* 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/Device'
|
||||
* 401:
|
||||
* description: 未授权
|
||||
* 404:
|
||||
* description: 设备不存在
|
||||
* 500:
|
||||
* description: 服务器错误
|
||||
*/
|
||||
router.get('/:id', verifyToken, deviceController.getDeviceById);
|
||||
|
||||
/**
|
||||
* @swagger
|
||||
* /api/devices:
|
||||
* post:
|
||||
* summary: 创建设备
|
||||
* tags: [Devices]
|
||||
* security:
|
||||
* - bearerAuth: []
|
||||
* requestBody:
|
||||
* required: true
|
||||
* content:
|
||||
* application/json:
|
||||
* schema:
|
||||
* type: object
|
||||
* required:
|
||||
* - name
|
||||
* - type
|
||||
* - farmId
|
||||
* properties:
|
||||
* 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: 设备指标数据
|
||||
* responses:
|
||||
* 201:
|
||||
* description: 设备创建成功
|
||||
* content:
|
||||
* application/json:
|
||||
* schema:
|
||||
* type: object
|
||||
* properties:
|
||||
* success:
|
||||
* type: boolean
|
||||
* example: true
|
||||
* message:
|
||||
* type: string
|
||||
* example: 设备创建成功
|
||||
* data:
|
||||
* $ref: '#/components/schemas/Device'
|
||||
* 400:
|
||||
* description: 请求参数错误
|
||||
* 401:
|
||||
* description: 未授权
|
||||
* 404:
|
||||
* description: 养殖场不存在
|
||||
* 500:
|
||||
* description: 服务器错误
|
||||
*/
|
||||
router.post('/', verifyToken, deviceController.createDevice);
|
||||
|
||||
/**
|
||||
* @swagger
|
||||
* /api/devices/{id}:
|
||||
* put:
|
||||
* summary: 更新设备
|
||||
* tags: [Devices]
|
||||
* security:
|
||||
* - bearerAuth: []
|
||||
* parameters:
|
||||
* - in: path
|
||||
* name: id
|
||||
* schema:
|
||||
* type: integer
|
||||
* required: true
|
||||
* description: 设备ID
|
||||
* requestBody:
|
||||
* required: true
|
||||
* content:
|
||||
* application/json:
|
||||
* schema:
|
||||
* type: object
|
||||
* properties:
|
||||
* 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: 设备指标数据
|
||||
* responses:
|
||||
* 200:
|
||||
* description: 设备更新成功
|
||||
* content:
|
||||
* application/json:
|
||||
* schema:
|
||||
* type: object
|
||||
* properties:
|
||||
* success:
|
||||
* type: boolean
|
||||
* example: true
|
||||
* message:
|
||||
* type: string
|
||||
* example: 设备更新成功
|
||||
* data:
|
||||
* $ref: '#/components/schemas/Device'
|
||||
* 400:
|
||||
* description: 请求参数错误
|
||||
* 401:
|
||||
* description: 未授权
|
||||
* 404:
|
||||
* description: 设备不存在或养殖场不存在
|
||||
* 500:
|
||||
* description: 服务器错误
|
||||
*/
|
||||
router.put('/:id', verifyToken, deviceController.updateDevice);
|
||||
|
||||
/**
|
||||
* @swagger
|
||||
* /api/devices/{id}:
|
||||
* delete:
|
||||
* summary: 删除设备
|
||||
* tags: [Devices]
|
||||
* 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, deviceController.deleteDevice);
|
||||
|
||||
/**
|
||||
* @swagger
|
||||
* /api/devices/stats/status:
|
||||
* get:
|
||||
* summary: 按状态统计设备数量
|
||||
* tags: [Devices]
|
||||
* 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: online
|
||||
* count:
|
||||
* type: integer
|
||||
* example: 25
|
||||
* 401:
|
||||
* description: 未授权
|
||||
* 500:
|
||||
* description: 服务器错误
|
||||
*/
|
||||
router.get('/stats/status', verifyToken, deviceController.getDeviceStatsByStatus);
|
||||
|
||||
/**
|
||||
* @swagger
|
||||
* /api/devices/stats/type:
|
||||
* get:
|
||||
* summary: 按类型统计设备数量
|
||||
* tags: [Devices]
|
||||
* 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: 15
|
||||
* 401:
|
||||
* description: 未授权
|
||||
* 500:
|
||||
* description: 服务器错误
|
||||
*/
|
||||
router.get('/stats/type', verifyToken, deviceController.getDeviceStatsByType);
|
||||
|
||||
module.exports = router;
|
||||
163
backend/routes/farms.js
Normal file
163
backend/routes/farms.js
Normal file
@@ -0,0 +1,163 @@
|
||||
const express = require('express');
|
||||
const router = express.Router();
|
||||
const farmController = require('../controllers/farmController');
|
||||
|
||||
/**
|
||||
* @swagger
|
||||
* /api/farms:
|
||||
* get:
|
||||
* summary: 获取所有养殖场
|
||||
* tags: [Farms]
|
||||
* responses:
|
||||
* 200:
|
||||
* description: 成功获取养殖场列表
|
||||
* content:
|
||||
* application/json:
|
||||
* schema:
|
||||
* type: object
|
||||
* properties:
|
||||
* success:
|
||||
* type: boolean
|
||||
* data:
|
||||
* type: array
|
||||
* items:
|
||||
* $ref: '#/components/schemas/Farm'
|
||||
*/
|
||||
router.get('/', farmController.getAllFarms);
|
||||
|
||||
// 公共路由必须在参数路由之前定义
|
||||
router.get('/public', farmController.getAllFarms);
|
||||
|
||||
/**
|
||||
* @swagger
|
||||
* /api/farms/{id}:
|
||||
* get:
|
||||
* summary: 根据ID获取养殖场
|
||||
* tags: [Farms]
|
||||
* parameters:
|
||||
* - in: path
|
||||
* name: id
|
||||
* required: true
|
||||
* schema:
|
||||
* type: integer
|
||||
* description: 养殖场ID
|
||||
* responses:
|
||||
* 200:
|
||||
* description: 成功获取养殖场详情
|
||||
* 404:
|
||||
* description: 养殖场不存在
|
||||
*/
|
||||
router.get('/:id', farmController.getFarmById);
|
||||
|
||||
/**
|
||||
* @swagger
|
||||
* /api/farms:
|
||||
* post:
|
||||
* summary: 创建新养殖场
|
||||
* tags: [Farms]
|
||||
* requestBody:
|
||||
* required: true
|
||||
* content:
|
||||
* application/json:
|
||||
* schema:
|
||||
* $ref: '#/components/schemas/FarmInput'
|
||||
* responses:
|
||||
* 201:
|
||||
* description: 养殖场创建成功
|
||||
* 400:
|
||||
* description: 请求参数错误
|
||||
*/
|
||||
router.post('/', farmController.createFarm);
|
||||
|
||||
/**
|
||||
* @swagger
|
||||
* /api/farms/{id}:
|
||||
* put:
|
||||
* summary: 更新养殖场信息
|
||||
* tags: [Farms]
|
||||
* parameters:
|
||||
* - in: path
|
||||
* name: id
|
||||
* required: true
|
||||
* schema:
|
||||
* type: integer
|
||||
* description: 养殖场ID
|
||||
* requestBody:
|
||||
* required: true
|
||||
* content:
|
||||
* application/json:
|
||||
* schema:
|
||||
* $ref: '#/components/schemas/FarmInput'
|
||||
* responses:
|
||||
* 200:
|
||||
* description: 养殖场更新成功
|
||||
* 404:
|
||||
* description: 养殖场不存在
|
||||
*/
|
||||
router.put('/:id', farmController.updateFarm);
|
||||
|
||||
/**
|
||||
* @swagger
|
||||
* /api/farms/{id}:
|
||||
* delete:
|
||||
* summary: 删除养殖场
|
||||
* tags: [Farms]
|
||||
* parameters:
|
||||
* - in: path
|
||||
* name: id
|
||||
* required: true
|
||||
* schema:
|
||||
* type: integer
|
||||
* description: 养殖场ID
|
||||
* responses:
|
||||
* 200:
|
||||
* description: 养殖场删除成功
|
||||
* 404:
|
||||
* description: 养殖场不存在
|
||||
*/
|
||||
router.delete('/:id', farmController.deleteFarm);
|
||||
|
||||
/**
|
||||
* @swagger
|
||||
* /api/farms/{id}/animals:
|
||||
* get:
|
||||
* summary: 获取养殖场的动物列表
|
||||
* tags: [Farms]
|
||||
* parameters:
|
||||
* - in: path
|
||||
* name: id
|
||||
* required: true
|
||||
* schema:
|
||||
* type: integer
|
||||
* description: 养殖场ID
|
||||
* responses:
|
||||
* 200:
|
||||
* description: 成功获取动物列表
|
||||
* 404:
|
||||
* description: 养殖场不存在
|
||||
*/
|
||||
router.get('/:id/animals', farmController.getFarmAnimals);
|
||||
|
||||
/**
|
||||
* @swagger
|
||||
* /api/farms/{id}/devices:
|
||||
* get:
|
||||
* summary: 获取养殖场的设备列表
|
||||
* tags: [Farms]
|
||||
* parameters:
|
||||
* - in: path
|
||||
* name: id
|
||||
* required: true
|
||||
* schema:
|
||||
* type: integer
|
||||
* description: 养殖场ID
|
||||
* responses:
|
||||
* 200:
|
||||
* description: 成功获取设备列表
|
||||
* 404:
|
||||
* description: 养殖场不存在
|
||||
*/
|
||||
router.get('/:id/devices', farmController.getFarmDevices);
|
||||
|
||||
// 公共农场数据接口(保留兼容性)
|
||||
module.exports = router;
|
||||
333
backend/routes/map.js
Normal file
333
backend/routes/map.js
Normal file
@@ -0,0 +1,333 @@
|
||||
const express = require('express');
|
||||
const router = express.Router();
|
||||
const mapController = require('../controllers/mapController');
|
||||
const farmController = require('../controllers/farmController');
|
||||
const { verifyToken } = require('../middleware/auth');
|
||||
|
||||
// 公开API路由,不需要验证token
|
||||
const publicRoutes = express.Router();
|
||||
router.use('/public', publicRoutes);
|
||||
|
||||
// 公开地理编码接口
|
||||
publicRoutes.get('/geocode', mapController.geocode);
|
||||
|
||||
// 公开反向地理编码接口
|
||||
publicRoutes.get('/reverse-geocode', mapController.reverseGeocode);
|
||||
|
||||
// 公开路线规划接口
|
||||
publicRoutes.get('/direction', mapController.direction);
|
||||
|
||||
// 公开周边搜索接口
|
||||
publicRoutes.get('/place-search', mapController.placeSearch);
|
||||
|
||||
// 公开静态地图接口
|
||||
publicRoutes.get('/static-map', mapController.staticMap);
|
||||
|
||||
// 公开IP定位接口
|
||||
publicRoutes.get('/ip-location', mapController.ipLocation);
|
||||
|
||||
// 公开获取养殖场地理位置数据
|
||||
publicRoutes.get('/farms', farmController.getAllFarms);
|
||||
|
||||
/**
|
||||
* @swagger
|
||||
* tags:
|
||||
* name: Map
|
||||
* description: 百度地图API服务
|
||||
*/
|
||||
|
||||
/**
|
||||
* @swagger
|
||||
* /api/map/geocode:
|
||||
* get:
|
||||
* summary: 地理编码 - 将地址转换为经纬度坐标
|
||||
* tags: [Map]
|
||||
* security:
|
||||
* - bearerAuth: []
|
||||
* parameters:
|
||||
* - in: query
|
||||
* name: address
|
||||
* schema:
|
||||
* type: string
|
||||
* required: true
|
||||
* description: 地址
|
||||
* responses:
|
||||
* 200:
|
||||
* description: 地理编码成功
|
||||
* content:
|
||||
* application/json:
|
||||
* schema:
|
||||
* type: object
|
||||
* properties:
|
||||
* success:
|
||||
* type: boolean
|
||||
* example: true
|
||||
* result:
|
||||
* type: object
|
||||
* properties:
|
||||
* location:
|
||||
* type: object
|
||||
* properties:
|
||||
* lng:
|
||||
* type: number
|
||||
* description: 经度
|
||||
* lat:
|
||||
* type: number
|
||||
* description: 纬度
|
||||
* 400:
|
||||
* description: 请求参数错误
|
||||
* 401:
|
||||
* description: 未授权
|
||||
* 500:
|
||||
* description: 服务器错误
|
||||
*/
|
||||
router.get('/geocode', verifyToken, mapController.geocode);
|
||||
|
||||
/**
|
||||
* @swagger
|
||||
* /api/map/reverse-geocode:
|
||||
* get:
|
||||
* summary: 逆地理编码 - 将经纬度坐标转换为地址
|
||||
* tags: [Map]
|
||||
* security:
|
||||
* - bearerAuth: []
|
||||
* parameters:
|
||||
* - in: query
|
||||
* name: lat
|
||||
* schema:
|
||||
* type: number
|
||||
* required: true
|
||||
* description: 纬度
|
||||
* - in: query
|
||||
* name: lng
|
||||
* schema:
|
||||
* type: number
|
||||
* required: true
|
||||
* description: 经度
|
||||
* responses:
|
||||
* 200:
|
||||
* description: 逆地理编码成功
|
||||
* content:
|
||||
* application/json:
|
||||
* schema:
|
||||
* type: object
|
||||
* properties:
|
||||
* success:
|
||||
* type: boolean
|
||||
* example: true
|
||||
* result:
|
||||
* type: object
|
||||
* properties:
|
||||
* formatted_address:
|
||||
* type: string
|
||||
* description: 结构化地址
|
||||
* addressComponent:
|
||||
* type: object
|
||||
* description: 地址组成部分
|
||||
* 400:
|
||||
* description: 请求参数错误
|
||||
* 401:
|
||||
* description: 未授权
|
||||
* 500:
|
||||
* description: 服务器错误
|
||||
*/
|
||||
router.get('/reverse-geocode', verifyToken, mapController.reverseGeocode);
|
||||
|
||||
/**
|
||||
* @swagger
|
||||
* /api/map/direction:
|
||||
* get:
|
||||
* summary: 路线规划
|
||||
* tags: [Map]
|
||||
* security:
|
||||
* - bearerAuth: []
|
||||
* parameters:
|
||||
* - in: query
|
||||
* name: origin
|
||||
* schema:
|
||||
* type: string
|
||||
* required: true
|
||||
* description: 起点坐标,格式:纬度,经度
|
||||
* - in: query
|
||||
* name: destination
|
||||
* schema:
|
||||
* type: string
|
||||
* required: true
|
||||
* description: 终点坐标,格式:纬度,经度
|
||||
* - in: query
|
||||
* name: mode
|
||||
* schema:
|
||||
* type: string
|
||||
* enum: [driving, walking, riding, transit]
|
||||
* required: false
|
||||
* description: 交通方式:driving(驾车)、walking(步行)、riding(骑行)、transit(公交)
|
||||
* responses:
|
||||
* 200:
|
||||
* description: 路线规划成功
|
||||
* content:
|
||||
* application/json:
|
||||
* schema:
|
||||
* type: object
|
||||
* properties:
|
||||
* success:
|
||||
* type: boolean
|
||||
* example: true
|
||||
* result:
|
||||
* type: object
|
||||
* description: 路线规划结果
|
||||
* 400:
|
||||
* description: 请求参数错误
|
||||
* 401:
|
||||
* description: 未授权
|
||||
* 500:
|
||||
* description: 服务器错误
|
||||
*/
|
||||
router.get('/direction', verifyToken, mapController.direction);
|
||||
|
||||
/**
|
||||
* @swagger
|
||||
* /api/map/place-search:
|
||||
* get:
|
||||
* summary: 周边搜索
|
||||
* tags: [Map]
|
||||
* security:
|
||||
* - bearerAuth: []
|
||||
* parameters:
|
||||
* - in: query
|
||||
* name: query
|
||||
* schema:
|
||||
* type: string
|
||||
* required: true
|
||||
* description: 搜索关键词
|
||||
* - in: query
|
||||
* name: location
|
||||
* schema:
|
||||
* type: string
|
||||
* required: true
|
||||
* description: 中心点坐标,格式:纬度,经度
|
||||
* - in: query
|
||||
* name: radius
|
||||
* schema:
|
||||
* type: number
|
||||
* required: false
|
||||
* description: 搜索半径,单位:米,默认1000米
|
||||
* responses:
|
||||
* 200:
|
||||
* description: 周边搜索成功
|
||||
* content:
|
||||
* application/json:
|
||||
* schema:
|
||||
* type: object
|
||||
* properties:
|
||||
* success:
|
||||
* type: boolean
|
||||
* example: true
|
||||
* results:
|
||||
* type: array
|
||||
* items:
|
||||
* type: object
|
||||
* description: 搜索结果
|
||||
* 400:
|
||||
* description: 请求参数错误
|
||||
* 401:
|
||||
* description: 未授权
|
||||
* 500:
|
||||
* description: 服务器错误
|
||||
*/
|
||||
router.get('/place-search', verifyToken, mapController.placeSearch);
|
||||
|
||||
/**
|
||||
* @swagger
|
||||
* /api/map/static-map:
|
||||
* get:
|
||||
* summary: 获取静态地图
|
||||
* tags: [Map]
|
||||
* security:
|
||||
* - bearerAuth: []
|
||||
* parameters:
|
||||
* - in: query
|
||||
* name: center
|
||||
* schema:
|
||||
* type: string
|
||||
* required: true
|
||||
* description: 地图中心点坐标,格式:纬度,经度
|
||||
* - in: query
|
||||
* name: width
|
||||
* schema:
|
||||
* type: number
|
||||
* required: false
|
||||
* description: 地图图片宽度,默认400
|
||||
* - in: query
|
||||
* name: height
|
||||
* schema:
|
||||
* type: number
|
||||
* required: false
|
||||
* description: 地图图片高度,默认300
|
||||
* - in: query
|
||||
* name: zoom
|
||||
* schema:
|
||||
* type: number
|
||||
* required: false
|
||||
* description: 地图缩放级别,默认12
|
||||
* responses:
|
||||
* 200:
|
||||
* description: 获取静态地图成功
|
||||
* content:
|
||||
* application/json:
|
||||
* schema:
|
||||
* type: object
|
||||
* properties:
|
||||
* success:
|
||||
* type: boolean
|
||||
* example: true
|
||||
* url:
|
||||
* type: string
|
||||
* description: 静态地图URL
|
||||
* 400:
|
||||
* description: 请求参数错误
|
||||
* 401:
|
||||
* description: 未授权
|
||||
* 500:
|
||||
* description: 服务器错误
|
||||
*/
|
||||
router.get('/static-map', verifyToken, mapController.staticMap);
|
||||
|
||||
/**
|
||||
* @swagger
|
||||
* /api/map/ip-location:
|
||||
* get:
|
||||
* summary: IP定位
|
||||
* tags: [Map]
|
||||
* security:
|
||||
* - bearerAuth: []
|
||||
* parameters:
|
||||
* - in: query
|
||||
* name: ip
|
||||
* schema:
|
||||
* type: string
|
||||
* required: false
|
||||
* description: IP地址,可选,默认使用用户当前IP
|
||||
* responses:
|
||||
* 200:
|
||||
* description: IP定位成功
|
||||
* content:
|
||||
* application/json:
|
||||
* schema:
|
||||
* type: object
|
||||
* properties:
|
||||
* success:
|
||||
* type: boolean
|
||||
* example: true
|
||||
* result:
|
||||
* type: object
|
||||
* description: IP定位结果
|
||||
* 400:
|
||||
* description: 请求参数错误
|
||||
* 401:
|
||||
* description: 未授权
|
||||
* 500:
|
||||
* description: 服务器错误
|
||||
*/
|
||||
router.get('/ip-location', verifyToken, mapController.ipLocation);
|
||||
|
||||
module.exports = router;
|
||||
118
backend/routes/orders.js
Normal file
118
backend/routes/orders.js
Normal file
@@ -0,0 +1,118 @@
|
||||
const express = require('express');
|
||||
const router = express.Router();
|
||||
const orderController = require('../controllers/orderController');
|
||||
|
||||
/**
|
||||
* @swagger
|
||||
* tags:
|
||||
* name: Orders
|
||||
* description: 订单管理
|
||||
*/
|
||||
|
||||
/**
|
||||
* @swagger
|
||||
* components:
|
||||
* schemas:
|
||||
* Order:
|
||||
* type: object
|
||||
* required:
|
||||
* - id
|
||||
* - userId
|
||||
* - totalAmount
|
||||
* - status
|
||||
* properties:
|
||||
* id:
|
||||
* type: integer
|
||||
* description: 订单ID
|
||||
* userId:
|
||||
* type: integer
|
||||
* description: 用户ID
|
||||
* totalAmount:
|
||||
* type: number
|
||||
* format: float
|
||||
* description: 订单总金额
|
||||
* status:
|
||||
* type: string
|
||||
* description: 订单状态
|
||||
* enum: [pending, paid, shipped, delivered, cancelled]
|
||||
* example:
|
||||
* id: 1
|
||||
* userId: 2
|
||||
* totalAmount: 199.98
|
||||
* status: "paid"
|
||||
*/
|
||||
|
||||
/**
|
||||
* @swagger
|
||||
* /api/orders:
|
||||
* get:
|
||||
* summary: 获取所有订单
|
||||
* tags: [Orders]
|
||||
* responses:
|
||||
* 200:
|
||||
* description: 订单列表
|
||||
* content:
|
||||
* application/json:
|
||||
* schema:
|
||||
* type: object
|
||||
* properties:
|
||||
* success:
|
||||
* type: boolean
|
||||
* data:
|
||||
* type: array
|
||||
* items:
|
||||
* $ref: '#/components/schemas/Order'
|
||||
* 500:
|
||||
* description: 服务器错误
|
||||
*/
|
||||
|
||||
// 获取所有订单
|
||||
router.get('/', orderController.getAllOrders);
|
||||
|
||||
/**
|
||||
* @swagger
|
||||
* /api/orders/{id}:
|
||||
* get:
|
||||
* summary: 根据ID获取订单
|
||||
* tags: [Orders]
|
||||
* 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
|
||||
* data:
|
||||
* $ref: '#/components/schemas/Order'
|
||||
* 404:
|
||||
* description: 订单未找到
|
||||
* 500:
|
||||
* description: 服务器错误
|
||||
*/
|
||||
|
||||
// 根据ID获取订单
|
||||
router.get('/:id', orderController.getOrderById);
|
||||
|
||||
// 创建订单
|
||||
router.post('/', orderController.createOrder);
|
||||
|
||||
// 更新订单
|
||||
router.put('/:id', orderController.updateOrder);
|
||||
|
||||
// 删除订单
|
||||
router.delete('/:id', orderController.deleteOrder);
|
||||
|
||||
// 获取用户的订单列表
|
||||
router.get('/user/:userId', orderController.getOrdersByUserId);
|
||||
|
||||
module.exports = router;
|
||||
192
backend/routes/performance-routes.js
Normal file
192
backend/routes/performance-routes.js
Normal file
@@ -0,0 +1,192 @@
|
||||
/**
|
||||
* 性能监控路由
|
||||
* @file performance-routes.js
|
||||
* @description 提供性能监控数据的API路由
|
||||
*/
|
||||
const express = require('express');
|
||||
const router = express.Router();
|
||||
const { performanceMonitor } = require('../utils/performance-monitor');
|
||||
const { apiPerformanceMonitor, apiErrorMonitor } = require('../middleware/performance-middleware');
|
||||
const logger = require('../utils/logger');
|
||||
|
||||
// 应用性能监控中间件到所有路由
|
||||
router.use(apiPerformanceMonitor);
|
||||
|
||||
/**
|
||||
* @api {get} /api/performance/metrics 获取所有性能指标
|
||||
* @apiName GetAllMetrics
|
||||
* @apiGroup Performance
|
||||
* @apiDescription 获取系统、数据库和API的所有性能指标
|
||||
* @apiSuccess {Object} metrics 所有性能指标数据
|
||||
*/
|
||||
router.get('/metrics', async (req, res) => {
|
||||
try {
|
||||
const metrics = await performanceMonitor.getAllMetrics();
|
||||
res.json(metrics);
|
||||
} catch (error) {
|
||||
logger.error('获取性能指标失败:', error);
|
||||
res.status(500).json({ error: '获取性能指标失败', message: error.message });
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* @api {get} /api/performance/system 获取系统资源指标
|
||||
* @apiName GetSystemMetrics
|
||||
* @apiGroup Performance
|
||||
* @apiDescription 获取CPU、内存和磁盘使用情况
|
||||
* @apiSuccess {Object} metrics 系统资源指标数据
|
||||
*/
|
||||
router.get('/system', (req, res) => {
|
||||
try {
|
||||
const metrics = performanceMonitor.getSystemMetrics();
|
||||
res.json(metrics);
|
||||
} catch (error) {
|
||||
logger.error('获取系统资源指标失败:', error);
|
||||
res.status(500).json({ error: '获取系统资源指标失败', message: error.message });
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* @api {get} /api/performance/database 获取数据库性能指标
|
||||
* @apiName GetDatabaseMetrics
|
||||
* @apiGroup Performance
|
||||
* @apiDescription 获取数据库连接池状态、慢查询和查询模式统计
|
||||
* @apiSuccess {Object} metrics 数据库性能指标数据
|
||||
*/
|
||||
router.get('/database', async (req, res) => {
|
||||
try {
|
||||
const metrics = await performanceMonitor.getDatabaseMetrics();
|
||||
res.json(metrics);
|
||||
} catch (error) {
|
||||
logger.error('获取数据库性能指标失败:', error);
|
||||
res.status(500).json({ error: '获取数据库性能指标失败', message: error.message });
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* @api {get} /api/performance/api 获取API性能指标
|
||||
* @apiName GetApiMetrics
|
||||
* @apiGroup Performance
|
||||
* @apiDescription 获取API请求统计、响应时间和错误率
|
||||
* @apiSuccess {Object} metrics API性能指标数据
|
||||
*/
|
||||
router.get('/api', (req, res) => {
|
||||
try {
|
||||
const metrics = performanceMonitor.getApiStats();
|
||||
res.json(metrics);
|
||||
} catch (error) {
|
||||
logger.error('获取API性能指标失败:', error);
|
||||
res.status(500).json({ error: '获取API性能指标失败', message: error.message });
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* @api {post} /api/performance/start 启动性能监控
|
||||
* @apiName StartMonitoring
|
||||
* @apiGroup Performance
|
||||
* @apiDescription 启动系统性能监控
|
||||
* @apiParam {Number} [interval] 监控间隔(毫秒)
|
||||
* @apiSuccess {Object} result 操作结果
|
||||
*/
|
||||
router.post('/start', (req, res) => {
|
||||
try {
|
||||
const interval = req.body.interval;
|
||||
const result = performanceMonitor.startMonitoring(interval);
|
||||
res.json(result);
|
||||
} catch (error) {
|
||||
logger.error('启动性能监控失败:', error);
|
||||
res.status(500).json({ error: '启动性能监控失败', message: error.message });
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* @api {post} /api/performance/stop 停止性能监控
|
||||
* @apiName StopMonitoring
|
||||
* @apiGroup Performance
|
||||
* @apiDescription 停止系统性能监控
|
||||
* @apiSuccess {Object} result 操作结果
|
||||
*/
|
||||
router.post('/stop', (req, res) => {
|
||||
try {
|
||||
const result = performanceMonitor.stopMonitoring();
|
||||
res.json(result);
|
||||
} catch (error) {
|
||||
logger.error('停止性能监控失败:', error);
|
||||
res.status(500).json({ error: '停止性能监控失败', message: error.message });
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* @api {get} /api/performance/status 获取监控状态
|
||||
* @apiName GetMonitoringStatus
|
||||
* @apiGroup Performance
|
||||
* @apiDescription 获取当前性能监控的状态
|
||||
* @apiSuccess {Object} status 监控状态
|
||||
*/
|
||||
router.get('/status', (req, res) => {
|
||||
try {
|
||||
const status = performanceMonitor.getMonitoringStatus();
|
||||
res.json(status);
|
||||
} catch (error) {
|
||||
logger.error('获取监控状态失败:', error);
|
||||
res.status(500).json({ error: '获取监控状态失败', message: error.message });
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* @api {post} /api/performance/thresholds 设置警报阈值
|
||||
* @apiName SetAlertThresholds
|
||||
* @apiGroup Performance
|
||||
* @apiDescription 设置性能监控的警报阈值
|
||||
* @apiParam {Object} thresholds 警报阈值配置
|
||||
* @apiSuccess {Object} result 操作结果
|
||||
*/
|
||||
router.post('/thresholds', (req, res) => {
|
||||
try {
|
||||
const thresholds = req.body;
|
||||
const result = performanceMonitor.setAlertThresholds(thresholds);
|
||||
res.json(result);
|
||||
} catch (error) {
|
||||
logger.error('设置警报阈值失败:', error);
|
||||
res.status(500).json({ error: '设置警报阈值失败', message: error.message });
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* @api {get} /api/performance/thresholds 获取警报阈值
|
||||
* @apiName GetAlertThresholds
|
||||
* @apiGroup Performance
|
||||
* @apiDescription 获取当前设置的警报阈值
|
||||
* @apiSuccess {Object} thresholds 警报阈值配置
|
||||
*/
|
||||
router.get('/thresholds', (req, res) => {
|
||||
try {
|
||||
const thresholds = performanceMonitor.getAlertThresholds();
|
||||
res.json(thresholds);
|
||||
} catch (error) {
|
||||
logger.error('获取警报阈值失败:', error);
|
||||
res.status(500).json({ error: '获取警报阈值失败', message: error.message });
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* @api {post} /api/performance/api/reset 重置API统计
|
||||
* @apiName ResetApiStats
|
||||
* @apiGroup Performance
|
||||
* @apiDescription 重置API性能统计数据
|
||||
* @apiSuccess {Object} result 操作结果
|
||||
*/
|
||||
router.post('/api/reset', (req, res) => {
|
||||
try {
|
||||
const result = performanceMonitor.resetApiStats();
|
||||
res.json(result);
|
||||
} catch (error) {
|
||||
logger.error('重置API统计失败:', error);
|
||||
res.status(500).json({ error: '重置API统计失败', message: error.message });
|
||||
}
|
||||
});
|
||||
|
||||
// 应用错误处理中间件
|
||||
router.use(apiErrorMonitor);
|
||||
|
||||
module.exports = router;
|
||||
230
backend/routes/products.js
Normal file
230
backend/routes/products.js
Normal file
@@ -0,0 +1,230 @@
|
||||
const express = require('express');
|
||||
const router = express.Router();
|
||||
const productController = require('../controllers/productController');
|
||||
const { verifyToken } = require('../middleware/auth');
|
||||
|
||||
/**
|
||||
* @swagger
|
||||
* tags:
|
||||
* name: Products
|
||||
* description: 产品管理
|
||||
*/
|
||||
|
||||
/**
|
||||
* @swagger
|
||||
* components:
|
||||
* schemas:
|
||||
* Product:
|
||||
* type: object
|
||||
* required:
|
||||
* - id
|
||||
* - name
|
||||
* - price
|
||||
* - stock
|
||||
* properties:
|
||||
* id:
|
||||
* type: integer
|
||||
* description: 产品ID
|
||||
* name:
|
||||
* type: string
|
||||
* description: 产品名称
|
||||
* description:
|
||||
* type: string
|
||||
* description: 产品描述
|
||||
* price:
|
||||
* type: number
|
||||
* format: float
|
||||
* description: 产品价格
|
||||
* stock:
|
||||
* type: integer
|
||||
* description: 产品库存
|
||||
* status:
|
||||
* type: string
|
||||
* enum: [active, inactive]
|
||||
* description: 产品状态
|
||||
* created_at:
|
||||
* type: string
|
||||
* format: date-time
|
||||
* description: 创建时间
|
||||
* updated_at:
|
||||
* type: string
|
||||
* format: date-time
|
||||
* description: 更新时间
|
||||
* example:
|
||||
* id: 1
|
||||
* name: "示例产品1"
|
||||
* description: "这是一个示例产品"
|
||||
* price: 99.99
|
||||
* stock: 100
|
||||
* status: "active"
|
||||
|
||||
/**
|
||||
* @swagger
|
||||
* /api/products:
|
||||
* get:
|
||||
* summary: 获取所有产品
|
||||
* tags: [Products]
|
||||
* responses:
|
||||
* 200:
|
||||
* description: 产品列表
|
||||
* content:
|
||||
* application/json:
|
||||
* schema:
|
||||
* type: object
|
||||
* properties:
|
||||
* success:
|
||||
* type: boolean
|
||||
* data:
|
||||
* type: array
|
||||
* items:
|
||||
* $ref: '#/components/schemas/Product'
|
||||
* 500:
|
||||
* description: 服务器错误
|
||||
*/
|
||||
router.get('/', productController.getAllProducts);
|
||||
|
||||
/**
|
||||
* @swagger
|
||||
* /api/products:
|
||||
* post:
|
||||
* summary: 创建新产品
|
||||
* tags: [Products]
|
||||
* security:
|
||||
* - bearerAuth: []
|
||||
* requestBody:
|
||||
* required: true
|
||||
* content:
|
||||
* application/json:
|
||||
* schema:
|
||||
* type: object
|
||||
* required:
|
||||
* - name
|
||||
* - price
|
||||
* - stock
|
||||
* properties:
|
||||
* name:
|
||||
* type: string
|
||||
* description:
|
||||
* type: string
|
||||
* price:
|
||||
* type: number
|
||||
* stock:
|
||||
* type: integer
|
||||
* status:
|
||||
* type: string
|
||||
* enum: [active, inactive]
|
||||
* responses:
|
||||
* 201:
|
||||
* description: 产品创建成功
|
||||
* 400:
|
||||
* description: 请求参数错误
|
||||
* 401:
|
||||
* description: 未授权
|
||||
*/
|
||||
router.post('/', verifyToken, productController.createProduct);
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @swagger
|
||||
* /api/products/{id}:
|
||||
* get:
|
||||
* summary: 根据ID获取产品
|
||||
* tags: [Products]
|
||||
* 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
|
||||
* data:
|
||||
* $ref: '#/components/schemas/Product'
|
||||
* 404:
|
||||
* description: 产品未找到
|
||||
* 500:
|
||||
* description: 服务器错误
|
||||
*/
|
||||
router.get('/:id', productController.getProductById);
|
||||
|
||||
/**
|
||||
* @swagger
|
||||
* /api/products/{id}:
|
||||
* put:
|
||||
* summary: 更新产品
|
||||
* tags: [Products]
|
||||
* security:
|
||||
* - bearerAuth: []
|
||||
* parameters:
|
||||
* - in: path
|
||||
* name: id
|
||||
* schema:
|
||||
* type: integer
|
||||
* required: true
|
||||
* description: 产品ID
|
||||
* requestBody:
|
||||
* required: true
|
||||
* content:
|
||||
* application/json:
|
||||
* schema:
|
||||
* type: object
|
||||
* properties:
|
||||
* name:
|
||||
* type: string
|
||||
* description:
|
||||
* type: string
|
||||
* price:
|
||||
* type: number
|
||||
* stock:
|
||||
* type: integer
|
||||
* status:
|
||||
* type: string
|
||||
* enum: [active, inactive]
|
||||
* responses:
|
||||
* 200:
|
||||
* description: 产品更新成功
|
||||
* 400:
|
||||
* description: 请求参数错误
|
||||
* 401:
|
||||
* description: 未授权
|
||||
* 404:
|
||||
* description: 产品未找到
|
||||
*/
|
||||
router.put('/:id', verifyToken, productController.updateProduct);
|
||||
|
||||
/**
|
||||
* @swagger
|
||||
* /api/products/{id}:
|
||||
* delete:
|
||||
* summary: 删除产品
|
||||
* tags: [Products]
|
||||
* security:
|
||||
* - bearerAuth: []
|
||||
* parameters:
|
||||
* - in: path
|
||||
* name: id
|
||||
* schema:
|
||||
* type: integer
|
||||
* required: true
|
||||
* description: 产品ID
|
||||
* responses:
|
||||
* 200:
|
||||
* description: 产品删除成功
|
||||
* 401:
|
||||
* description: 未授权
|
||||
* 404:
|
||||
* description: 产品未找到
|
||||
*/
|
||||
router.delete('/:id', verifyToken, productController.deleteProduct);
|
||||
|
||||
module.exports = router;
|
||||
484
backend/routes/stats.js
Normal file
484
backend/routes/stats.js
Normal file
@@ -0,0 +1,484 @@
|
||||
/**
|
||||
* 统计数据路由
|
||||
* @file stats.js
|
||||
* @description 定义统计数据相关的API路由
|
||||
*/
|
||||
|
||||
const express = require('express');
|
||||
const router = express.Router();
|
||||
const statsController = require('../controllers/statsController');
|
||||
const { verifyToken } = require('../middleware/auth');
|
||||
|
||||
// 公开API路由,不需要验证token
|
||||
const publicRoutes = express.Router();
|
||||
router.use('/public', publicRoutes);
|
||||
|
||||
// 公开获取仪表盘统计数据
|
||||
publicRoutes.get('/dashboard', statsController.getDashboardStats);
|
||||
|
||||
// 公开获取监控数据
|
||||
publicRoutes.get('/monitoring', statsController.getMonitorData);
|
||||
|
||||
// 公开获取月度数据趋势
|
||||
publicRoutes.get('/monthly-trends', statsController.getMonthlyTrends);
|
||||
|
||||
/**
|
||||
* @swagger
|
||||
* tags:
|
||||
* name: Statistics
|
||||
* description: 统计数据API
|
||||
*/
|
||||
|
||||
/**
|
||||
* @swagger
|
||||
* /api/stats/dashboard:
|
||||
* get:
|
||||
* summary: 获取仪表盘统计数据
|
||||
* tags: [Statistics]
|
||||
* security:
|
||||
* - bearerAuth: []
|
||||
* responses:
|
||||
* 200:
|
||||
* description: 成功获取仪表盘统计数据
|
||||
* content:
|
||||
* application/json:
|
||||
* schema:
|
||||
* type: object
|
||||
* properties:
|
||||
* success:
|
||||
* type: boolean
|
||||
* example: true
|
||||
* data:
|
||||
* type: object
|
||||
* properties:
|
||||
* farmCount:
|
||||
* type: integer
|
||||
* example: 12
|
||||
* animalCount:
|
||||
* type: integer
|
||||
* example: 5000
|
||||
* deviceCount:
|
||||
* type: integer
|
||||
* example: 150
|
||||
* alertCount:
|
||||
* type: integer
|
||||
* example: 25
|
||||
* deviceOnlineRate:
|
||||
* type: number
|
||||
* format: float
|
||||
* example: 0.95
|
||||
* alertsByLevel:
|
||||
* type: object
|
||||
* properties:
|
||||
* low:
|
||||
* type: integer
|
||||
* example: 5
|
||||
* medium:
|
||||
* type: integer
|
||||
* example: 10
|
||||
* high:
|
||||
* type: integer
|
||||
* example: 8
|
||||
* critical:
|
||||
* type: integer
|
||||
* example: 2
|
||||
* 401:
|
||||
* description: 未授权
|
||||
* 500:
|
||||
* description: 服务器错误
|
||||
*/
|
||||
router.get('/dashboard', verifyToken, statsController.getDashboardStats);
|
||||
|
||||
/**
|
||||
* @swagger
|
||||
* /api/stats/farms:
|
||||
* get:
|
||||
* summary: 获取养殖场统计数据
|
||||
* tags: [Statistics]
|
||||
* security:
|
||||
* - bearerAuth: []
|
||||
* responses:
|
||||
* 200:
|
||||
* description: 成功获取养殖场统计数据
|
||||
* content:
|
||||
* application/json:
|
||||
* schema:
|
||||
* type: object
|
||||
* properties:
|
||||
* success:
|
||||
* type: boolean
|
||||
* example: true
|
||||
* data:
|
||||
* type: object
|
||||
* properties:
|
||||
* totalFarms:
|
||||
* type: integer
|
||||
* example: 12
|
||||
* farmsByType:
|
||||
* type: array
|
||||
* items:
|
||||
* type: object
|
||||
* properties:
|
||||
* type:
|
||||
* type: string
|
||||
* example: 猪场
|
||||
* count:
|
||||
* type: integer
|
||||
* example: 5
|
||||
* farmsByStatus:
|
||||
* type: array
|
||||
* items:
|
||||
* type: object
|
||||
* properties:
|
||||
* status:
|
||||
* type: string
|
||||
* example: active
|
||||
* count:
|
||||
* type: integer
|
||||
* example: 10
|
||||
* 401:
|
||||
* description: 未授权
|
||||
* 500:
|
||||
* description: 服务器错误
|
||||
*/
|
||||
router.get('/farms', verifyToken, statsController.getFarmStats);
|
||||
|
||||
/**
|
||||
* @swagger
|
||||
* /api/stats/animals:
|
||||
* get:
|
||||
* summary: 获取动物统计数据
|
||||
* tags: [Statistics]
|
||||
* security:
|
||||
* - bearerAuth: []
|
||||
* responses:
|
||||
* 200:
|
||||
* description: 成功获取动物统计数据
|
||||
* content:
|
||||
* application/json:
|
||||
* schema:
|
||||
* type: object
|
||||
* properties:
|
||||
* success:
|
||||
* type: boolean
|
||||
* example: true
|
||||
* data:
|
||||
* type: object
|
||||
* properties:
|
||||
* totalAnimals:
|
||||
* type: integer
|
||||
* example: 5000
|
||||
* animalsByType:
|
||||
* type: array
|
||||
* items:
|
||||
* type: object
|
||||
* properties:
|
||||
* type:
|
||||
* type: string
|
||||
* example: 猪
|
||||
* count:
|
||||
* type: integer
|
||||
* example: 3000
|
||||
* animalsByHealth:
|
||||
* type: array
|
||||
* items:
|
||||
* type: object
|
||||
* properties:
|
||||
* health_status:
|
||||
* type: string
|
||||
* example: healthy
|
||||
* count:
|
||||
* type: integer
|
||||
* example: 4500
|
||||
* 401:
|
||||
* description: 未授权
|
||||
* 500:
|
||||
* description: 服务器错误
|
||||
*/
|
||||
router.get('/animals', verifyToken, statsController.getAnimalStats);
|
||||
|
||||
/**
|
||||
* @swagger
|
||||
* /api/stats/devices:
|
||||
* get:
|
||||
* summary: 获取设备统计数据
|
||||
* tags: [Statistics]
|
||||
* security:
|
||||
* - bearerAuth: []
|
||||
* responses:
|
||||
* 200:
|
||||
* description: 成功获取设备统计数据
|
||||
* content:
|
||||
* application/json:
|
||||
* schema:
|
||||
* type: object
|
||||
* properties:
|
||||
* success:
|
||||
* type: boolean
|
||||
* example: true
|
||||
* data:
|
||||
* type: object
|
||||
* properties:
|
||||
* totalDevices:
|
||||
* type: integer
|
||||
* example: 150
|
||||
* devicesByType:
|
||||
* type: array
|
||||
* items:
|
||||
* type: object
|
||||
* properties:
|
||||
* type:
|
||||
* type: string
|
||||
* example: 温度传感器
|
||||
* count:
|
||||
* type: integer
|
||||
* example: 50
|
||||
* devicesByStatus:
|
||||
* type: array
|
||||
* items:
|
||||
* type: object
|
||||
* properties:
|
||||
* status:
|
||||
* type: string
|
||||
* example: online
|
||||
* count:
|
||||
* type: integer
|
||||
* example: 140
|
||||
* onlineRate:
|
||||
* type: number
|
||||
* format: float
|
||||
* example: 0.95
|
||||
* 401:
|
||||
* description: 未授权
|
||||
* 500:
|
||||
* description: 服务器错误
|
||||
*/
|
||||
router.get('/devices', verifyToken, statsController.getDeviceStats);
|
||||
|
||||
/**
|
||||
* @swagger
|
||||
* /api/stats/alerts:
|
||||
* get:
|
||||
* summary: 获取预警统计数据
|
||||
* tags: [Statistics]
|
||||
* security:
|
||||
* - bearerAuth: []
|
||||
* responses:
|
||||
* 200:
|
||||
* description: 成功获取预警统计数据
|
||||
* content:
|
||||
* application/json:
|
||||
* schema:
|
||||
* type: object
|
||||
* properties:
|
||||
* success:
|
||||
* type: boolean
|
||||
* example: true
|
||||
* data:
|
||||
* type: object
|
||||
* properties:
|
||||
* totalAlerts:
|
||||
* type: integer
|
||||
* example: 25
|
||||
* alertsByType:
|
||||
* type: array
|
||||
* items:
|
||||
* type: object
|
||||
* properties:
|
||||
* type:
|
||||
* type: string
|
||||
* example: 温度异常
|
||||
* count:
|
||||
* type: integer
|
||||
* example: 10
|
||||
* alertsByLevel:
|
||||
* type: array
|
||||
* items:
|
||||
* type: object
|
||||
* properties:
|
||||
* level:
|
||||
* type: string
|
||||
* example: high
|
||||
* count:
|
||||
* type: integer
|
||||
* example: 8
|
||||
* alertsByStatus:
|
||||
* type: array
|
||||
* items:
|
||||
* type: object
|
||||
* properties:
|
||||
* status:
|
||||
* type: string
|
||||
* example: active
|
||||
* count:
|
||||
* type: integer
|
||||
* example: 15
|
||||
* recentAlerts:
|
||||
* type: array
|
||||
* items:
|
||||
* type: object
|
||||
* properties:
|
||||
* id:
|
||||
* type: integer
|
||||
* example: 1
|
||||
* type:
|
||||
* type: string
|
||||
* example: 温度异常
|
||||
* level:
|
||||
* type: string
|
||||
* example: high
|
||||
* message:
|
||||
* type: string
|
||||
* example: 温度超过阈值
|
||||
* createdAt:
|
||||
* type: string
|
||||
* format: date-time
|
||||
* example: 2023-01-01T12:00:00Z
|
||||
* 401:
|
||||
* description: 未授权
|
||||
* 500:
|
||||
* description: 服务器错误
|
||||
*/
|
||||
router.get('/alerts', verifyToken, statsController.getAlertStats);
|
||||
|
||||
/**
|
||||
* @swagger
|
||||
* /api/stats/monitoring:
|
||||
* get:
|
||||
* summary: 获取实时监控数据
|
||||
* tags: [Statistics]
|
||||
* security:
|
||||
* - bearerAuth: []
|
||||
* responses:
|
||||
* 200:
|
||||
* description: 成功获取实时监控数据
|
||||
* content:
|
||||
* application/json:
|
||||
* schema:
|
||||
* type: object
|
||||
* properties:
|
||||
* success:
|
||||
* type: boolean
|
||||
* example: true
|
||||
* data:
|
||||
* type: object
|
||||
* properties:
|
||||
* deviceStatus:
|
||||
* type: object
|
||||
* properties:
|
||||
* online:
|
||||
* type: integer
|
||||
* example: 140
|
||||
* offline:
|
||||
* type: integer
|
||||
* example: 10
|
||||
* maintenance:
|
||||
* type: integer
|
||||
* example: 5
|
||||
* recentAlerts:
|
||||
* type: array
|
||||
* items:
|
||||
* type: object
|
||||
* properties:
|
||||
* id:
|
||||
* type: integer
|
||||
* example: 1
|
||||
* type:
|
||||
* type: string
|
||||
* example: 温度异常
|
||||
* level:
|
||||
* type: string
|
||||
* example: high
|
||||
* message:
|
||||
* type: string
|
||||
* example: 温度超过阈值
|
||||
* createdAt:
|
||||
* type: string
|
||||
* format: date-time
|
||||
* example: 2023-01-01T12:00:00Z
|
||||
* environmentalData:
|
||||
* type: object
|
||||
* properties:
|
||||
* temperature:
|
||||
* type: array
|
||||
* items:
|
||||
* type: object
|
||||
* properties:
|
||||
* timestamp:
|
||||
* type: string
|
||||
* format: date-time
|
||||
* example: 2023-01-01T12:00:00Z
|
||||
* value:
|
||||
* type: number
|
||||
* format: float
|
||||
* example: 25.5
|
||||
* humidity:
|
||||
* type: array
|
||||
* items:
|
||||
* type: object
|
||||
* properties:
|
||||
* timestamp:
|
||||
* type: string
|
||||
* format: date-time
|
||||
* example: 2023-01-01T12:00:00Z
|
||||
* value:
|
||||
* type: number
|
||||
* format: float
|
||||
* example: 60.2
|
||||
* 401:
|
||||
* description: 未授权
|
||||
* 500:
|
||||
* description: 服务器错误
|
||||
*/
|
||||
router.get('/monitoring', verifyToken, statsController.getMonitorData);
|
||||
|
||||
/**
|
||||
* @swagger
|
||||
* /api/stats/monthly-trends:
|
||||
* get:
|
||||
* summary: 获取月度数据趋势
|
||||
* tags: [Statistics]
|
||||
* security:
|
||||
* - bearerAuth: []
|
||||
* responses:
|
||||
* 200:
|
||||
* description: 成功获取月度数据趋势
|
||||
* content:
|
||||
* application/json:
|
||||
* schema:
|
||||
* type: object
|
||||
* properties:
|
||||
* success:
|
||||
* type: boolean
|
||||
* example: true
|
||||
* data:
|
||||
* type: object
|
||||
* properties:
|
||||
* xAxis:
|
||||
* type: array
|
||||
* items:
|
||||
* type: string
|
||||
* description: 月份标签
|
||||
* series:
|
||||
* type: array
|
||||
* items:
|
||||
* type: object
|
||||
* properties:
|
||||
* name:
|
||||
* type: string
|
||||
* type:
|
||||
* type: string
|
||||
* data:
|
||||
* type: array
|
||||
* items:
|
||||
* type: number
|
||||
* itemStyle:
|
||||
* type: object
|
||||
* areaStyle:
|
||||
* type: object
|
||||
* 500:
|
||||
* description: 服务器错误
|
||||
*/
|
||||
router.get('/monthly-trends', verifyToken, statsController.getMonthlyTrends);
|
||||
|
||||
module.exports = router;
|
||||
116
backend/routes/users.js
Normal file
116
backend/routes/users.js
Normal file
@@ -0,0 +1,116 @@
|
||||
const express = require('express');
|
||||
const { verifyToken } = require('../middleware/auth');
|
||||
const router = express.Router();
|
||||
const userController = require('../controllers/userController');
|
||||
|
||||
/**
|
||||
* @swagger
|
||||
* tags:
|
||||
* name: Users
|
||||
* description: 用户管理
|
||||
*/
|
||||
|
||||
/**
|
||||
* @swagger
|
||||
* components:
|
||||
* schemas:
|
||||
* User:
|
||||
* type: object
|
||||
* required:
|
||||
* - id
|
||||
* - username
|
||||
* - email
|
||||
* properties:
|
||||
* id:
|
||||
* type: integer
|
||||
* description: 用户ID
|
||||
* username:
|
||||
* type: string
|
||||
* description: 用户名
|
||||
* email:
|
||||
* type: string
|
||||
* description: 邮箱地址
|
||||
* example:
|
||||
* id: 1
|
||||
* username: "john_doe"
|
||||
* email: "john@example.com"
|
||||
*/
|
||||
|
||||
/**
|
||||
* @swagger
|
||||
* /api/users:
|
||||
* get:
|
||||
* summary: 获取所有用户 (需要认证)
|
||||
* tags: [Users]
|
||||
* security:
|
||||
* - bearerAuth: []
|
||||
* responses:
|
||||
* 200:
|
||||
* description: 用户列表
|
||||
* content:
|
||||
* application/json:
|
||||
* schema:
|
||||
* type: object
|
||||
* properties:
|
||||
* success:
|
||||
* type: boolean
|
||||
* data:
|
||||
* type: array
|
||||
* items:
|
||||
* $ref: '#/components/schemas/User'
|
||||
* 401:
|
||||
* description: 未认证
|
||||
* 500:
|
||||
* description: 服务器错误
|
||||
*/
|
||||
// 获取所有用户 (需要认证)
|
||||
router.get('/', verifyToken, userController.getAllUsers);
|
||||
|
||||
/**
|
||||
* @swagger
|
||||
* /api/users/{id}:
|
||||
* get:
|
||||
* summary: 根据ID获取用户 (需要认证)
|
||||
* tags: [Users]
|
||||
* 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
|
||||
* data:
|
||||
* $ref: '#/components/schemas/User'
|
||||
* 401:
|
||||
* description: 未认证
|
||||
* 404:
|
||||
* description: 用户未找到
|
||||
* 500:
|
||||
* description: 服务器错误
|
||||
*/
|
||||
|
||||
// 根据ID获取用户 (需要认证)
|
||||
router.get('/:id', verifyToken, userController.getUserById);
|
||||
|
||||
// 创建用户 (需要认证)
|
||||
router.post('/', verifyToken, userController.createUser);
|
||||
|
||||
// 更新用户 (需要认证)
|
||||
router.put('/:id', verifyToken, userController.updateUser);
|
||||
|
||||
// 删除用户 (需要认证)
|
||||
router.delete('/:id', verifyToken, userController.deleteUser);
|
||||
|
||||
module.exports = router;
|
||||
Reference in New Issue
Block a user