保险前后端,养殖端和保险端小程序

This commit is contained in:
xuqiuyun
2025-09-17 19:01:52 +08:00
parent e4287b83fe
commit 473891163c
218 changed files with 109331 additions and 14103 deletions

292
backend/routes/api-demo.js Normal file
View File

@@ -0,0 +1,292 @@
/**
* API接口演示路由
* 展示如何使用统一的API响应格式和筛选条件管理
*/
const express = require('express');
const router = express.Router();
const { Op } = require('sequelize');
const Animal = require('../models/Animal');
const Device = require('../models/Device');
const Alert = require('../models/Alert');
/**
* 获取动物列表(支持筛选、分页、排序)
* GET /api/demo/animals
* 查询参数:
* - page: 页码默认1
* - limit: 每页数量默认20
* - sort: 排序字段默认createTime
* - order: 排序方式ASC/DESC默认DESC
* - name: 动物名称(模糊搜索)
* - category: 动物类别
* - status: 状态
* - minWeight: 最小体重
* - maxWeight: 最大体重
*/
router.get('/animals', async (req, res) => {
try {
// 获取分页参数
const { page, limit, offset } = req.getPagination();
// 获取筛选条件
const filters = req.getFilters(['name', 'category', 'status', 'penId']);
// 获取排序参数
const order = req.getSorting(['name', 'category', 'status', 'weight', 'createTime', 'updateTime']);
// 构建查询条件
const where = {};
// 处理名称模糊搜索
if (filters.name) {
where.name = { [Op.like]: `%${filters.name}%` };
}
// 处理其他筛选条件
if (filters.category) {
where.category = filters.category;
}
if (filters.status) {
where.status = filters.status;
}
if (filters.penId) {
where.penId = filters.penId;
}
// 处理体重范围筛选
if (req.query.minWeight || req.query.maxWeight) {
where.weight = {};
if (req.query.minWeight) {
where.weight[Op.gte] = parseFloat(req.query.minWeight);
}
if (req.query.maxWeight) {
where.weight[Op.lte] = parseFloat(req.query.maxWeight);
}
}
// 查询数据
const { count, rows } = await Animal.findAndCountAll({
where,
limit,
offset,
order,
attributes: [
'id', 'name', 'category', 'status', 'weight', 'birthDate',
'penId', 'createTime', 'updateTime'
]
});
// 返回统一格式的响应
res.apiSuccess(rows, '获取动物列表成功', {
total: count,
page,
limit
});
} catch (error) {
console.error('获取动物列表失败:', error);
res.apiError('获取动物列表失败', 'DATABASE_ERROR', 500);
}
});
/**
* 获取设备列表(支持筛选、分页、排序)
* GET /api/demo/devices
* 查询参数:
* - page: 页码默认1
* - limit: 每页数量默认20
* - sort: 排序字段默认installDate
* - order: 排序方式ASC/DESC默认DESC
* - name: 设备名称(模糊搜索)
* - type: 设备类型
* - status: 设备状态
* - location: 安装位置
*/
router.get('/devices', async (req, res) => {
try {
// 获取分页参数
const { page, limit, offset } = req.getPagination();
// 获取筛选条件
const filters = req.getFilters(['name', 'type', 'status', 'location']);
// 获取排序参数
const order = req.getSorting(['name', 'type', 'status', 'installDate', 'createTime']);
// 构建查询条件
const where = {};
// 处理名称模糊搜索
if (filters.name) {
where.name = { [Op.like]: `%${filters.name}%` };
}
// 处理其他筛选条件
if (filters.type) {
where.type = filters.type;
}
if (filters.status) {
where.status = filters.status;
}
if (filters.location) {
where.location = { [Op.like]: `%${filters.location}%` };
}
// 查询数据
const { count, rows } = await Device.findAndCountAll({
where,
limit,
offset,
order,
attributes: [
'id', 'name', 'type', 'status', 'location', 'installDate',
'lastMaintenance', 'createTime', 'updateTime'
]
});
// 返回统一格式的响应
res.apiSuccess(rows, '获取设备列表成功', {
total: count,
page,
limit
});
} catch (error) {
console.error('获取设备列表失败:', error);
res.apiError('获取设备列表失败', 'DATABASE_ERROR', 500);
}
});
/**
* 获取告警列表(支持筛选、分页、排序)
* GET /api/demo/alerts
* 查询参数:
* - page: 页码默认1
* - limit: 每页数量默认20
* - sort: 排序字段默认createTime
* - order: 排序方式ASC/DESC默认DESC
* - type: 告警类型
* - level: 告警级别
* - status: 处理状态
* - startDate: 开始时间
* - endDate: 结束时间
*/
router.get('/alerts', async (req, res) => {
try {
// 获取分页参数
const { page, limit, offset } = req.getPagination();
// 获取筛选条件
const filters = req.getFilters(['type', 'level', 'status']);
// 获取排序参数
const order = req.getSorting(['type', 'level', 'status', 'createTime', 'updateTime']);
// 构建查询条件
const where = {};
// 处理筛选条件
if (filters.type) {
where.type = filters.type;
}
if (filters.level) {
where.level = filters.level;
}
if (filters.status) {
where.status = filters.status;
}
// 处理时间范围筛选
if (req.query.startDate || req.query.endDate) {
where.createTime = {};
if (req.query.startDate) {
where.createTime[Op.gte] = new Date(req.query.startDate);
}
if (req.query.endDate) {
where.createTime[Op.lte] = new Date(req.query.endDate);
}
}
// 查询数据
const { count, rows } = await Alert.findAndCountAll({
where,
limit,
offset,
order,
include: [
{
model: Animal,
attributes: ['id', 'name', 'category']
},
{
model: Device,
attributes: ['id', 'name', 'type']
}
],
attributes: [
'id', 'type', 'level', 'status', 'description', 'createTime',
'updateTime', 'handler', 'handleTime', 'handleNote'
]
});
// 返回统一格式的响应
res.apiSuccess(rows, '获取告警列表成功', {
total: count,
page,
limit
});
} catch (error) {
console.error('获取告警列表失败:', error);
res.apiError('获取告警列表失败', 'DATABASE_ERROR', 500);
}
});
/**
* 获取统计仪表盘数据
* GET /api/demo/dashboard
*/
router.get('/dashboard', async (req, res) => {
try {
// 并行获取所有统计数据
const [
animalCount,
deviceCount,
alertCount,
onlineDevices
] = await Promise.all([
Animal.count({ where: { status: 'active' } }),
Device.count(),
Alert.count({ where: { status: 'pending' } }),
Device.count({ where: { status: 'online' } })
]);
const dashboardData = {
animalCount,
deviceCount,
alertCount,
onlineDeviceRate: deviceCount > 0 ? (onlineDevices / deviceCount).toFixed(2) : 0,
alertsByLevel: {
low: await Alert.count({ where: { level: 'low', status: 'pending' } }),
medium: await Alert.count({ where: { level: 'medium', status: 'pending' } }),
high: await Alert.count({ where: { level: 'high', status: 'pending' } }),
critical: await Alert.count({ where: { level: 'critical', status: 'pending' } })
}
};
res.apiSuccess(dashboardData, '获取仪表盘数据成功');
} catch (error) {
console.error('获取仪表盘数据失败:', error);
res.apiError('获取仪表盘数据失败', 'DATABASE_ERROR', 500);
}
});
module.exports = router;

View File

@@ -1111,6 +1111,11 @@ router.get('/roles', async (req, res) => {
router.get('/validate', verifyToken, async (req, res) => {
try {
// 设置禁用缓存的响应头
res.setHeader('Cache-Control', 'no-cache, no-store, must-revalidate');
res.setHeader('Pragma', 'no-cache');
res.setHeader('Expires', '0');
// 如果能到达这里说明token是有效的
const user = await User.findByPk(req.user.id, {
attributes: ['id', 'username', 'email', 'status'],

View File

@@ -2,6 +2,7 @@ const express = require('express');
const router = express.Router();
const farmController = require('../controllers/farmController');
const searchLogger = require('../middleware/search-logger');
const { createSuccessResponse, createErrorResponse, createPaginatedResponse, SUCCESS_MESSAGES, ERROR_CODES } = require('../utils/apiResponse');
/**
* @swagger

View File

@@ -9,6 +9,7 @@ const { verifyToken, checkRole } = require('../middleware/auth');
const { requirePermission } = require('../middleware/permission');
const { IotXqClient, IotJbqServer, IotJbqClient } = require('../models');
const { Op } = require('sequelize');
const { createSuccessResponse, createErrorResponse, createPaginatedResponse, SUCCESS_MESSAGES, ERROR_CODES } = require('../utils/apiResponse');
// 公开API路由不需要验证token
const publicRoutes = express.Router();
@@ -84,18 +85,15 @@ publicRoutes.get('/eartags/export', async (req, res) => {
};
});
res.json({
success: true,
data: formattedData,
total: formattedData.length,
message: '导出数据获取成功'
});
res.json(createSuccessResponse(formattedData, SUCCESS_MESSAGES.DATA_RETRIEVED, {
total: formattedData.length
}));
} catch (error) {
console.error('导出智能耳标数据失败:', error);
res.status(500).json({
success: false,
message: '导出数据获取失败: ' + error.message
});
res.status(500).json(createErrorResponse(
'导出数据获取失败: ' + error.message,
ERROR_CODES.DATABASE_ERROR
));
}
});
@@ -181,28 +179,23 @@ publicRoutes.get('/eartags', async (req, res) => {
maintenance: rows.filter(item => item.state === 3).length
};
res.json({
success: true,
data: {
res.json(createPaginatedResponse(
{
list: formattedData,
pagination: {
current: parseInt(page),
pageSize: parseInt(limit),
total: count,
pages: Math.ceil(count / parseInt(limit))
},
stats
stats: stats
},
message: '获取智能耳标列表成功'
});
count,
parseInt(page),
parseInt(limit),
SUCCESS_MESSAGES.DATA_RETRIEVED
));
} catch (error) {
console.error('获取智能耳标列表失败:', error);
res.status(500).json({
success: false,
message: '获取智能耳标列表失败',
error: error.message
});
res.status(500).json(createErrorResponse(
'获取智能耳标列表失败: ' + error.message,
ERROR_CODES.DATABASE_ERROR
));
}
});