完善保险端前后端和养殖端小程序
This commit is contained in:
688
backend/controllers/smartCollarAlertController.js
Normal file
688
backend/controllers/smartCollarAlertController.js
Normal file
@@ -0,0 +1,688 @@
|
||||
/**
|
||||
* 智能项圈预警控制器
|
||||
* @file smartCollarAlertController.js
|
||||
* @description 处理智能项圈预警相关的请求
|
||||
*/
|
||||
|
||||
const { IotXqClient } = require('../models');
|
||||
const { Op } = require('sequelize');
|
||||
|
||||
/**
|
||||
* 获取智能项圈预警统计
|
||||
* @param {Object} req - 请求对象
|
||||
* @param {Object} res - 响应对象
|
||||
*/
|
||||
exports.getCollarAlertStats = async (req, res) => {
|
||||
try {
|
||||
console.log('=== 获取智能项圈预警统计 ===');
|
||||
|
||||
// 获取项圈设备总数
|
||||
const totalDevices = await IotXqClient.count();
|
||||
console.log('项圈设备总数:', totalDevices);
|
||||
|
||||
// 获取所有设备数据用于生成预警统计
|
||||
const allDevices = await IotXqClient.findAll({
|
||||
order: [['uptime', 'DESC'], ['id', 'DESC']]
|
||||
});
|
||||
|
||||
// 统计各类预警数量
|
||||
let stats = {
|
||||
totalDevices: totalDevices,
|
||||
lowBattery: 0,
|
||||
offline: 0,
|
||||
highTemperature: 0,
|
||||
lowTemperature: 0,
|
||||
abnormalMovement: 0,
|
||||
wearOff: 0,
|
||||
totalAlerts: 0
|
||||
};
|
||||
|
||||
allDevices.forEach(device => {
|
||||
const actualBattery = parseInt(device.battery) || 0;
|
||||
const actualTemperature = parseFloat(device.temperature) || 0;
|
||||
const totalSteps = parseInt(device.steps) || 0;
|
||||
const yesterdaySteps = parseInt(device.y_steps) || 0;
|
||||
const dailySteps = totalSteps - yesterdaySteps;
|
||||
|
||||
// 离线预警
|
||||
if (device.state === 0) {
|
||||
stats.offline++;
|
||||
stats.totalAlerts++;
|
||||
}
|
||||
|
||||
// 低电量预警
|
||||
if (actualBattery > 0 && actualBattery < 20) {
|
||||
stats.lowBattery++;
|
||||
stats.totalAlerts++;
|
||||
}
|
||||
|
||||
// 温度预警
|
||||
if (actualTemperature > 0) {
|
||||
if (actualTemperature < 30) {
|
||||
stats.lowTemperature++;
|
||||
stats.totalAlerts++;
|
||||
} else if (actualTemperature > 40) {
|
||||
stats.highTemperature++;
|
||||
stats.totalAlerts++;
|
||||
}
|
||||
}
|
||||
|
||||
// 异常运动预警
|
||||
if (dailySteps === 0 && totalSteps > 0) {
|
||||
stats.abnormalMovement++;
|
||||
stats.totalAlerts++;
|
||||
}
|
||||
|
||||
// 项圈脱落预警
|
||||
if (device.bandge_status === 0) {
|
||||
stats.wearOff++;
|
||||
stats.totalAlerts++;
|
||||
}
|
||||
});
|
||||
|
||||
console.log('预警统计结果:', stats);
|
||||
|
||||
res.json({
|
||||
success: true,
|
||||
data: stats,
|
||||
message: '获取智能项圈预警统计成功'
|
||||
});
|
||||
} catch (error) {
|
||||
console.error('获取智能项圈预警统计失败:', error);
|
||||
res.status(500).json({
|
||||
success: false,
|
||||
message: '获取智能项圈预警统计失败',
|
||||
error: error.message
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* 获取智能项圈预警列表
|
||||
* @param {Object} req - 请求对象
|
||||
* @param {Object} res - 响应对象
|
||||
*/
|
||||
exports.getCollarAlerts = async (req, res) => {
|
||||
try {
|
||||
const {
|
||||
page = 1,
|
||||
limit = 10,
|
||||
status,
|
||||
search,
|
||||
alertType,
|
||||
alertLevel,
|
||||
startDate,
|
||||
endDate
|
||||
} = req.query;
|
||||
|
||||
const offset = (page - 1) * limit;
|
||||
|
||||
console.log('智能项圈预警API请求参数:', {
|
||||
page, limit, status, search, alertType, alertLevel, startDate, endDate
|
||||
});
|
||||
|
||||
// 构建查询条件
|
||||
const whereConditions = {};
|
||||
|
||||
// 状态筛选
|
||||
if (status) {
|
||||
switch (status) {
|
||||
case 'online':
|
||||
whereConditions.state = 1;
|
||||
break;
|
||||
case 'offline':
|
||||
whereConditions.state = 0;
|
||||
break;
|
||||
case 'alarm':
|
||||
whereConditions.state = 2;
|
||||
break;
|
||||
case 'maintenance':
|
||||
whereConditions.state = 3;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// 搜索条件
|
||||
if (search) {
|
||||
whereConditions[Op.or] = [
|
||||
{ sn: { [Op.like]: `%${search}%` } },
|
||||
{ deviceId: { [Op.like]: `%${search}%` } }
|
||||
];
|
||||
}
|
||||
|
||||
// 时间范围筛选
|
||||
if (startDate || endDate) {
|
||||
whereConditions.uptime = {};
|
||||
if (startDate) {
|
||||
whereConditions.uptime[Op.gte] = new Date(startDate);
|
||||
}
|
||||
if (endDate) {
|
||||
whereConditions.uptime[Op.lte] = new Date(endDate);
|
||||
}
|
||||
}
|
||||
|
||||
// 查询所有符合条件的设备数据
|
||||
const allDevices = await IotXqClient.findAll({
|
||||
where: whereConditions,
|
||||
order: [['uptime', 'DESC'], ['id', 'DESC']]
|
||||
});
|
||||
|
||||
// 生成预警数据
|
||||
const allAlerts = [];
|
||||
|
||||
allDevices.forEach(device => {
|
||||
const deviceId = device.sn || `COLLAR${device.id}`;
|
||||
const alertTime = new Date(device.uptime || Date.now()).toISOString().replace('T', ' ').substring(0, 19);
|
||||
|
||||
const actualBattery = parseInt(device.battery) || 0;
|
||||
const actualTemperature = parseFloat(device.temperature) || 0;
|
||||
const totalSteps = parseInt(device.steps) || 0;
|
||||
const yesterdaySteps = parseInt(device.y_steps) || 0;
|
||||
const dailySteps = totalSteps - yesterdaySteps;
|
||||
|
||||
// 添加基础信息到预警的函数
|
||||
const addBaseInfoToAlert = (alert) => {
|
||||
alert.deviceId = device.id;
|
||||
alert.deviceName = deviceId;
|
||||
alert.collarNumber = deviceId;
|
||||
alert.dailySteps = dailySteps;
|
||||
alert.totalSteps = totalSteps;
|
||||
alert.yesterdaySteps = yesterdaySteps;
|
||||
alert.battery = actualBattery;
|
||||
alert.temperature = actualTemperature;
|
||||
alert.alertTime = alertTime;
|
||||
alert.deviceStatus = device.state === 1 ? '在线' : '离线';
|
||||
alert.gpsSignal = device.state === 1 ? '强' : '无';
|
||||
alert.wearStatus = device.bandge_status === 1 ? '已佩戴' : '未佩戴';
|
||||
alert.longitude = 116.3974 + (device.id % 100) * 0.0001;
|
||||
alert.latitude = 39.9093 + (device.id % 100) * 0.0001;
|
||||
return alert;
|
||||
};
|
||||
|
||||
// 离线预警
|
||||
if (device.state === 0) {
|
||||
allAlerts.push(addBaseInfoToAlert({
|
||||
id: `${device.id}_offline`,
|
||||
alertType: 'offline',
|
||||
alertLevel: 'high',
|
||||
description: '设备已离线超过30分钟',
|
||||
movementStatus: '静止'
|
||||
}));
|
||||
}
|
||||
|
||||
// 低电量预警
|
||||
if (actualBattery > 0 && actualBattery < 20) {
|
||||
allAlerts.push(addBaseInfoToAlert({
|
||||
id: `${device.id}_battery`,
|
||||
alertType: 'battery',
|
||||
alertLevel: actualBattery < 10 ? 'high' : 'medium',
|
||||
description: `设备电量低于20%,当前电量${actualBattery}%`,
|
||||
movementStatus: '正常'
|
||||
}));
|
||||
}
|
||||
|
||||
// 温度预警
|
||||
if (actualTemperature > 0) {
|
||||
if (actualTemperature < 30) {
|
||||
allAlerts.push(addBaseInfoToAlert({
|
||||
id: `${device.id}_temperature_low`,
|
||||
alertType: 'temperature',
|
||||
alertLevel: actualTemperature < 20 ? 'high' : 'medium',
|
||||
description: `设备温度过低,当前温度${actualTemperature}°C`,
|
||||
movementStatus: '正常'
|
||||
}));
|
||||
} else if (actualTemperature > 40) {
|
||||
allAlerts.push(addBaseInfoToAlert({
|
||||
id: `${device.id}_temperature_high`,
|
||||
alertType: 'temperature',
|
||||
alertLevel: actualTemperature > 45 ? 'high' : 'medium',
|
||||
description: `设备温度过高,当前温度${actualTemperature}°C`,
|
||||
movementStatus: '正常'
|
||||
}));
|
||||
}
|
||||
}
|
||||
|
||||
// 异常运动预警
|
||||
if (dailySteps === 0 && totalSteps > 0) {
|
||||
allAlerts.push(addBaseInfoToAlert({
|
||||
id: `${device.id}_movement_zero`,
|
||||
alertType: 'movement',
|
||||
alertLevel: 'high',
|
||||
description: '检测到步数异常,当日运动量为0步,可能为设备故障或动物异常',
|
||||
movementStatus: '异常'
|
||||
}));
|
||||
}
|
||||
|
||||
// 项圈脱落预警
|
||||
if (device.bandge_status === 0) {
|
||||
allAlerts.push(addBaseInfoToAlert({
|
||||
id: `${device.id}_wear`,
|
||||
alertType: 'wear',
|
||||
alertLevel: 'high',
|
||||
description: '设备佩戴状态异常,可能已脱落',
|
||||
movementStatus: '正常'
|
||||
}));
|
||||
}
|
||||
});
|
||||
|
||||
// 预警类型筛选
|
||||
let filteredAlerts = allAlerts;
|
||||
if (alertType && alertType.trim() !== '') {
|
||||
filteredAlerts = allAlerts.filter(alert => alert.alertType === alertType);
|
||||
}
|
||||
|
||||
// 预警级别筛选
|
||||
if (alertLevel && alertLevel.trim() !== '') {
|
||||
filteredAlerts = filteredAlerts.filter(alert => alert.alertLevel === alertLevel);
|
||||
}
|
||||
|
||||
// 计算统计数据
|
||||
const stats = {
|
||||
lowBattery: filteredAlerts.filter(alert => alert.alertType === 'battery').length,
|
||||
offline: filteredAlerts.filter(alert => alert.alertType === 'offline').length,
|
||||
highTemperature: filteredAlerts.filter(alert => alert.alertType === 'temperature').length,
|
||||
abnormalMovement: filteredAlerts.filter(alert => alert.alertType === 'movement').length,
|
||||
wearOff: filteredAlerts.filter(alert => alert.alertType === 'wear').length
|
||||
};
|
||||
|
||||
// 分页处理
|
||||
const startIndex = parseInt(offset);
|
||||
const endIndex = startIndex + parseInt(limit);
|
||||
const paginatedAlerts = filteredAlerts.slice(startIndex, endIndex);
|
||||
|
||||
res.json({
|
||||
success: true,
|
||||
data: paginatedAlerts,
|
||||
total: filteredAlerts.length,
|
||||
stats: stats,
|
||||
pagination: {
|
||||
page: parseInt(page),
|
||||
limit: parseInt(limit),
|
||||
total: filteredAlerts.length,
|
||||
pages: Math.ceil(filteredAlerts.length / limit)
|
||||
},
|
||||
message: '获取智能项圈预警列表成功'
|
||||
});
|
||||
} catch (error) {
|
||||
console.error('获取智能项圈预警列表失败:', error);
|
||||
res.status(500).json({
|
||||
success: false,
|
||||
message: '获取智能项圈预警列表失败',
|
||||
error: error.message
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* 获取单个智能项圈预警详情
|
||||
* @param {Object} req - 请求对象
|
||||
* @param {Object} res - 响应对象
|
||||
*/
|
||||
exports.getCollarAlertById = async (req, res) => {
|
||||
try {
|
||||
const { id } = req.params;
|
||||
|
||||
// 解析预警ID,格式为 deviceId_alertType
|
||||
const [deviceId, alertType] = id.split('_');
|
||||
|
||||
if (!deviceId || !alertType) {
|
||||
return res.status(400).json({
|
||||
success: false,
|
||||
message: '无效的预警ID格式'
|
||||
});
|
||||
}
|
||||
|
||||
// 查找设备
|
||||
const device = await IotXqClient.findByPk(deviceId);
|
||||
if (!device) {
|
||||
return res.status(404).json({
|
||||
success: false,
|
||||
message: '设备不存在'
|
||||
});
|
||||
}
|
||||
|
||||
const deviceNumber = device.sn || `COLLAR${device.id}`;
|
||||
const alertTime = new Date(device.uptime || Date.now()).toISOString().replace('T', ' ').substring(0, 19);
|
||||
|
||||
const actualBattery = parseInt(device.battery) || 0;
|
||||
const actualTemperature = parseFloat(device.temperature) || 0;
|
||||
const totalSteps = parseInt(device.steps) || 0;
|
||||
const yesterdaySteps = parseInt(device.y_steps) || 0;
|
||||
const dailySteps = totalSteps - yesterdaySteps;
|
||||
|
||||
// 根据预警类型生成详情
|
||||
let alertDetail = {
|
||||
id: id,
|
||||
deviceId: device.id,
|
||||
deviceName: deviceNumber,
|
||||
collarNumber: deviceNumber,
|
||||
alertType: alertType,
|
||||
alertTime: alertTime,
|
||||
battery: actualBattery,
|
||||
temperature: actualTemperature,
|
||||
dailySteps: dailySteps,
|
||||
totalSteps: totalSteps,
|
||||
yesterdaySteps: yesterdaySteps,
|
||||
deviceStatus: device.state === 1 ? '在线' : '离线',
|
||||
gpsSignal: device.state === 1 ? '强' : '无',
|
||||
wearStatus: device.bandge_status === 1 ? '已佩戴' : '未佩戴',
|
||||
longitude: 116.3974 + (device.id % 100) * 0.0001,
|
||||
latitude: 39.9093 + (device.id % 100) * 0.0001,
|
||||
movementStatus: '正常'
|
||||
};
|
||||
|
||||
// 根据预警类型设置具体信息
|
||||
switch (alertType) {
|
||||
case 'offline':
|
||||
alertDetail.alertLevel = 'high';
|
||||
alertDetail.description = '设备已离线超过30分钟';
|
||||
alertDetail.movementStatus = '静止';
|
||||
break;
|
||||
case 'battery':
|
||||
alertDetail.alertLevel = actualBattery < 10 ? 'high' : 'medium';
|
||||
alertDetail.description = `设备电量低于20%,当前电量${actualBattery}%`;
|
||||
break;
|
||||
case 'temperature':
|
||||
if (actualTemperature < 30) {
|
||||
alertDetail.alertLevel = actualTemperature < 20 ? 'high' : 'medium';
|
||||
alertDetail.description = `设备温度过低,当前温度${actualTemperature}°C`;
|
||||
} else if (actualTemperature > 40) {
|
||||
alertDetail.alertLevel = actualTemperature > 45 ? 'high' : 'medium';
|
||||
alertDetail.description = `设备温度过高,当前温度${actualTemperature}°C`;
|
||||
}
|
||||
break;
|
||||
case 'movement':
|
||||
alertDetail.alertLevel = 'high';
|
||||
alertDetail.description = '检测到步数异常,当日运动量为0步,可能为设备故障或动物异常';
|
||||
alertDetail.movementStatus = '异常';
|
||||
break;
|
||||
case 'wear':
|
||||
alertDetail.alertLevel = 'high';
|
||||
alertDetail.description = '设备佩戴状态异常,可能已脱落';
|
||||
break;
|
||||
}
|
||||
|
||||
res.json({
|
||||
success: true,
|
||||
data: alertDetail,
|
||||
message: '获取智能项圈预警详情成功'
|
||||
});
|
||||
} catch (error) {
|
||||
console.error('获取智能项圈预警详情失败:', error);
|
||||
res.status(500).json({
|
||||
success: false,
|
||||
message: '获取智能项圈预警详情失败',
|
||||
error: error.message
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* 处理智能项圈预警
|
||||
* @param {Object} req - 请求对象
|
||||
* @param {Object} res - 响应对象
|
||||
*/
|
||||
exports.handleCollarAlert = async (req, res) => {
|
||||
try {
|
||||
const { id } = req.params;
|
||||
const { action, notes, handler } = req.body;
|
||||
|
||||
// 解析预警ID
|
||||
const [deviceId, alertType] = id.split('_');
|
||||
|
||||
if (!deviceId || !alertType) {
|
||||
return res.status(400).json({
|
||||
success: false,
|
||||
message: '无效的预警ID格式'
|
||||
});
|
||||
}
|
||||
|
||||
// 这里可以实现预警处理逻辑,比如记录处理历史、发送通知等
|
||||
// 目前只是返回成功响应
|
||||
const result = {
|
||||
alertId: id,
|
||||
action: action || 'acknowledged',
|
||||
notes: notes || '',
|
||||
handler: handler || 'system',
|
||||
processedAt: new Date().toISOString(),
|
||||
status: 'processed'
|
||||
};
|
||||
|
||||
console.log('处理智能项圈预警:', result);
|
||||
|
||||
res.json({
|
||||
success: true,
|
||||
data: result,
|
||||
message: '预警处理成功'
|
||||
});
|
||||
} catch (error) {
|
||||
console.error('处理智能项圈预警失败:', error);
|
||||
res.status(500).json({
|
||||
success: false,
|
||||
message: '处理智能项圈预警失败',
|
||||
error: error.message
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* 批量处理智能项圈预警
|
||||
* @param {Object} req - 请求对象
|
||||
* @param {Object} res - 响应对象
|
||||
*/
|
||||
exports.batchHandleCollarAlerts = async (req, res) => {
|
||||
try {
|
||||
const { alertIds, action, notes, handler } = req.body;
|
||||
|
||||
if (!alertIds || !Array.isArray(alertIds) || alertIds.length === 0) {
|
||||
return res.status(400).json({
|
||||
success: false,
|
||||
message: '请提供有效的预警ID列表'
|
||||
});
|
||||
}
|
||||
|
||||
const results = [];
|
||||
|
||||
for (const alertId of alertIds) {
|
||||
const [deviceId, alertType] = alertId.split('_');
|
||||
|
||||
if (deviceId && alertType) {
|
||||
results.push({
|
||||
alertId: alertId,
|
||||
action: action || 'acknowledged',
|
||||
notes: notes || '',
|
||||
handler: handler || 'system',
|
||||
processedAt: new Date().toISOString(),
|
||||
status: 'processed'
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
console.log('批量处理智能项圈预警:', results);
|
||||
|
||||
res.json({
|
||||
success: true,
|
||||
data: {
|
||||
processedCount: results.length,
|
||||
results: results
|
||||
},
|
||||
message: `成功处理 ${results.length} 个预警`
|
||||
});
|
||||
} catch (error) {
|
||||
console.error('批量处理智能项圈预警失败:', error);
|
||||
res.status(500).json({
|
||||
success: false,
|
||||
message: '批量处理智能项圈预警失败',
|
||||
error: error.message
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* 导出智能项圈预警数据
|
||||
* @param {Object} req - 请求对象
|
||||
* @param {Object} res - 响应对象
|
||||
*/
|
||||
exports.exportCollarAlerts = async (req, res) => {
|
||||
try {
|
||||
const {
|
||||
search,
|
||||
alertType,
|
||||
alertLevel,
|
||||
startDate,
|
||||
endDate,
|
||||
format = 'json'
|
||||
} = req.query;
|
||||
|
||||
// 构建查询条件(与获取列表相同的逻辑)
|
||||
const whereConditions = {};
|
||||
|
||||
if (search) {
|
||||
whereConditions[Op.or] = [
|
||||
{ sn: { [Op.like]: `%${search}%` } },
|
||||
{ deviceId: { [Op.like]: `%${search}%` } }
|
||||
];
|
||||
}
|
||||
|
||||
if (startDate || endDate) {
|
||||
whereConditions.uptime = {};
|
||||
if (startDate) {
|
||||
whereConditions.uptime[Op.gte] = new Date(startDate);
|
||||
}
|
||||
if (endDate) {
|
||||
whereConditions.uptime[Op.lte] = new Date(endDate);
|
||||
}
|
||||
}
|
||||
|
||||
// 获取所有设备数据
|
||||
const allDevices = await IotXqClient.findAll({
|
||||
where: whereConditions,
|
||||
order: [['uptime', 'DESC'], ['id', 'DESC']]
|
||||
});
|
||||
|
||||
// 生成预警数据(与获取列表相同的逻辑)
|
||||
const allAlerts = [];
|
||||
|
||||
allDevices.forEach(device => {
|
||||
const deviceId = device.sn || `COLLAR${device.id}`;
|
||||
const alertTime = new Date(device.uptime || Date.now()).toISOString().replace('T', ' ').substring(0, 19);
|
||||
|
||||
const actualBattery = parseInt(device.battery) || 0;
|
||||
const actualTemperature = parseFloat(device.temperature) || 0;
|
||||
const totalSteps = parseInt(device.steps) || 0;
|
||||
const yesterdaySteps = parseInt(device.y_steps) || 0;
|
||||
const dailySteps = totalSteps - yesterdaySteps;
|
||||
|
||||
// 添加基础信息到预警的函数
|
||||
const addBaseInfoToAlert = (alert) => {
|
||||
alert.deviceId = device.id;
|
||||
alert.deviceName = deviceId;
|
||||
alert.collarNumber = deviceId;
|
||||
alert.dailySteps = dailySteps;
|
||||
alert.totalSteps = totalSteps;
|
||||
alert.yesterdaySteps = yesterdaySteps;
|
||||
alert.battery = actualBattery;
|
||||
alert.temperature = actualTemperature;
|
||||
alert.alertTime = alertTime;
|
||||
alert.deviceStatus = device.state === 1 ? '在线' : '离线';
|
||||
alert.gpsSignal = device.state === 1 ? '强' : '无';
|
||||
alert.wearStatus = device.bandge_status === 1 ? '已佩戴' : '未佩戴';
|
||||
alert.longitude = 116.3974 + (device.id % 100) * 0.0001;
|
||||
alert.latitude = 39.9093 + (device.id % 100) * 0.0001;
|
||||
return alert;
|
||||
};
|
||||
|
||||
// 生成各类预警(与获取列表相同的逻辑)
|
||||
if (device.state === 0) {
|
||||
allAlerts.push(addBaseInfoToAlert({
|
||||
id: `${device.id}_offline`,
|
||||
alertType: 'offline',
|
||||
alertLevel: 'high',
|
||||
description: '设备已离线超过30分钟',
|
||||
movementStatus: '静止'
|
||||
}));
|
||||
}
|
||||
|
||||
if (actualBattery > 0 && actualBattery < 20) {
|
||||
allAlerts.push(addBaseInfoToAlert({
|
||||
id: `${device.id}_battery`,
|
||||
alertType: 'battery',
|
||||
alertLevel: actualBattery < 10 ? 'high' : 'medium',
|
||||
description: `设备电量低于20%,当前电量${actualBattery}%`,
|
||||
movementStatus: '正常'
|
||||
}));
|
||||
}
|
||||
|
||||
if (actualTemperature > 0) {
|
||||
if (actualTemperature < 30) {
|
||||
allAlerts.push(addBaseInfoToAlert({
|
||||
id: `${device.id}_temperature_low`,
|
||||
alertType: 'temperature',
|
||||
alertLevel: actualTemperature < 20 ? 'high' : 'medium',
|
||||
description: `设备温度过低,当前温度${actualTemperature}°C`,
|
||||
movementStatus: '正常'
|
||||
}));
|
||||
} else if (actualTemperature > 40) {
|
||||
allAlerts.push(addBaseInfoToAlert({
|
||||
id: `${device.id}_temperature_high`,
|
||||
alertType: 'temperature',
|
||||
alertLevel: actualTemperature > 45 ? 'high' : 'medium',
|
||||
description: `设备温度过高,当前温度${actualTemperature}°C`,
|
||||
movementStatus: '正常'
|
||||
}));
|
||||
}
|
||||
}
|
||||
|
||||
if (dailySteps === 0 && totalSteps > 0) {
|
||||
allAlerts.push(addBaseInfoToAlert({
|
||||
id: `${device.id}_movement_zero`,
|
||||
alertType: 'movement',
|
||||
alertLevel: 'high',
|
||||
description: '检测到步数异常,当日运动量为0步,可能为设备故障或动物异常',
|
||||
movementStatus: '异常'
|
||||
}));
|
||||
}
|
||||
|
||||
if (device.bandge_status === 0) {
|
||||
allAlerts.push(addBaseInfoToAlert({
|
||||
id: `${device.id}_wear`,
|
||||
alertType: 'wear',
|
||||
alertLevel: 'high',
|
||||
description: '设备佩戴状态异常,可能已脱落',
|
||||
movementStatus: '正常'
|
||||
}));
|
||||
}
|
||||
});
|
||||
|
||||
// 应用筛选条件
|
||||
let filteredAlerts = allAlerts;
|
||||
if (alertType && alertType.trim() !== '') {
|
||||
filteredAlerts = allAlerts.filter(alert => alert.alertType === alertType);
|
||||
}
|
||||
if (alertLevel && alertLevel.trim() !== '') {
|
||||
filteredAlerts = filteredAlerts.filter(alert => alert.alertLevel === alertLevel);
|
||||
}
|
||||
|
||||
// 根据格式返回数据
|
||||
if (format === 'csv') {
|
||||
// 这里可以实现CSV格式导出
|
||||
res.setHeader('Content-Type', 'text/csv');
|
||||
res.setHeader('Content-Disposition', 'attachment; filename="collar_alerts.csv"');
|
||||
res.send('CSV格式导出功能待实现');
|
||||
} else {
|
||||
res.json({
|
||||
success: true,
|
||||
data: filteredAlerts,
|
||||
total: filteredAlerts.length,
|
||||
message: '导出智能项圈预警数据成功'
|
||||
});
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('导出智能项圈预警数据失败:', error);
|
||||
res.status(500).json({
|
||||
success: false,
|
||||
message: '导出智能项圈预警数据失败',
|
||||
error: error.message
|
||||
});
|
||||
}
|
||||
};
|
||||
Reference in New Issue
Block a user