2025-10-09 18:01:06 +08:00
|
|
|
const DeviceWarning = require('../models/DeviceWarning');
|
|
|
|
|
const { Op, fn, col } = require('sequelize');
|
2025-10-11 08:53:47 +08:00
|
|
|
const { QueryTypes } = require('sequelize');
|
2025-10-09 18:01:06 +08:00
|
|
|
|
|
|
|
|
// 获取设备预警列表
|
|
|
|
|
exports.getDeviceWarnings = async (req, res) => {
|
|
|
|
|
try {
|
|
|
|
|
const { page = 1, pageSize = 20, deviceType, alertType, status, farmerName } = req.query;
|
|
|
|
|
const limit = parseInt(pageSize);
|
|
|
|
|
const offset = (parseInt(page) - 1) * limit;
|
|
|
|
|
|
2025-10-11 08:53:47 +08:00
|
|
|
// 构建WHERE条件
|
|
|
|
|
let whereConditions = [];
|
|
|
|
|
let whereParams = {};
|
|
|
|
|
|
2025-10-09 18:01:06 +08:00
|
|
|
if (deviceType) {
|
2025-10-11 08:53:47 +08:00
|
|
|
whereConditions.push('deviceType = :deviceType');
|
|
|
|
|
whereParams.deviceType = deviceType;
|
2025-10-09 18:01:06 +08:00
|
|
|
}
|
|
|
|
|
if (alertType) {
|
2025-10-11 08:53:47 +08:00
|
|
|
whereConditions.push('alertType = :alertType');
|
|
|
|
|
whereParams.alertType = alertType;
|
2025-10-09 18:01:06 +08:00
|
|
|
}
|
|
|
|
|
if (status) {
|
2025-10-11 08:53:47 +08:00
|
|
|
whereConditions.push('status = :status');
|
|
|
|
|
whereParams.status = status;
|
2025-10-09 18:01:06 +08:00
|
|
|
}
|
|
|
|
|
if (farmerName) {
|
2025-10-11 08:53:47 +08:00
|
|
|
whereConditions.push('farmerName LIKE :farmerName');
|
|
|
|
|
whereParams.farmerName = `%${farmerName}%`;
|
2025-10-09 18:01:06 +08:00
|
|
|
}
|
|
|
|
|
|
2025-10-11 08:53:47 +08:00
|
|
|
const whereClause = whereConditions.length > 0 ? 'WHERE ' + whereConditions.join(' AND ') : '';
|
|
|
|
|
|
|
|
|
|
// 查询总数
|
|
|
|
|
const countQuery = `SELECT COUNT(*) as count FROM device_warnings ${whereClause}`;
|
|
|
|
|
const countResult = await DeviceWarning.sequelize.query(countQuery, {
|
|
|
|
|
replacements: whereParams,
|
|
|
|
|
type: QueryTypes.SELECT
|
|
|
|
|
});
|
|
|
|
|
const total = countResult[0].count;
|
|
|
|
|
|
|
|
|
|
// 查询数据
|
|
|
|
|
const dataQuery = `
|
|
|
|
|
SELECT id, farmName, farmerName, phone, deviceType, deviceNumber,
|
|
|
|
|
alertType, alertLevel, alertTime, status, description,
|
|
|
|
|
location, batteryLevel, signalStrength, temperature,
|
|
|
|
|
resolvedBy, resolvedAt, remarks, createdAt, updatedAt
|
|
|
|
|
FROM device_warnings
|
|
|
|
|
${whereClause}
|
|
|
|
|
ORDER BY alertTime DESC
|
|
|
|
|
LIMIT :limit OFFSET :offset
|
|
|
|
|
`;
|
|
|
|
|
|
|
|
|
|
const rows = await DeviceWarning.sequelize.query(dataQuery, {
|
|
|
|
|
replacements: { ...whereParams, limit, offset },
|
|
|
|
|
type: QueryTypes.SELECT
|
2025-10-09 18:01:06 +08:00
|
|
|
});
|
|
|
|
|
|
|
|
|
|
res.status(200).json({
|
|
|
|
|
code: 200,
|
|
|
|
|
message: '获取成功',
|
|
|
|
|
data: {
|
|
|
|
|
list: rows,
|
2025-10-11 08:53:47 +08:00
|
|
|
total: total,
|
2025-10-09 18:01:06 +08:00
|
|
|
page: parseInt(page),
|
|
|
|
|
pageSize: limit,
|
|
|
|
|
},
|
|
|
|
|
});
|
|
|
|
|
} catch (error) {
|
|
|
|
|
console.error('获取设备预警列表失败:', error);
|
|
|
|
|
res.status(500).json({ code: 500, message: '获取设备预警列表失败', error: error.message });
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
// 根据ID获取单个设备预警详情
|
|
|
|
|
exports.getDeviceWarningById = async (req, res) => {
|
|
|
|
|
try {
|
|
|
|
|
const { id } = req.params;
|
2025-10-11 08:53:47 +08:00
|
|
|
|
|
|
|
|
const query = `
|
|
|
|
|
SELECT id, farmName, farmerName, phone, deviceType, deviceNumber,
|
|
|
|
|
alertType, alertLevel, alertTime, status, description,
|
|
|
|
|
location, batteryLevel, signalStrength, temperature,
|
|
|
|
|
resolvedBy, resolvedAt, remarks, createdAt, updatedAt
|
|
|
|
|
FROM device_warnings
|
|
|
|
|
WHERE id = :id
|
|
|
|
|
`;
|
|
|
|
|
|
|
|
|
|
const results = await DeviceWarning.sequelize.query(query, {
|
|
|
|
|
replacements: { id },
|
|
|
|
|
type: QueryTypes.SELECT
|
|
|
|
|
});
|
2025-10-09 18:01:06 +08:00
|
|
|
|
2025-10-11 08:53:47 +08:00
|
|
|
if (results.length === 0) {
|
2025-10-09 18:01:06 +08:00
|
|
|
return res.status(404).json({ code: 404, message: '设备预警未找到' });
|
|
|
|
|
}
|
|
|
|
|
|
2025-10-11 08:53:47 +08:00
|
|
|
res.status(200).json({ code: 200, message: '获取成功', data: results[0] });
|
2025-10-09 18:01:06 +08:00
|
|
|
} catch (error) {
|
|
|
|
|
console.error('获取设备预警详情失败:', error);
|
|
|
|
|
res.status(500).json({ code: 500, message: '获取设备预警详情失败', error: error.message });
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
// 创建新的设备预警
|
|
|
|
|
exports.createDeviceWarning = async (req, res) => {
|
|
|
|
|
try {
|
2025-10-11 08:53:47 +08:00
|
|
|
const {
|
|
|
|
|
farmName, farmerName, phone, deviceType, deviceNumber,
|
|
|
|
|
alertType, alertLevel = 'medium', description, location, batteryLevel,
|
|
|
|
|
signalStrength, temperature, remarks
|
|
|
|
|
} = req.body;
|
|
|
|
|
|
|
|
|
|
const insertQuery = `
|
|
|
|
|
INSERT INTO device_warnings
|
|
|
|
|
(farmName, farmerName, phone, deviceType, deviceNumber, alertType, alertLevel,
|
|
|
|
|
description, location, batteryLevel, signalStrength, temperature, remarks,
|
|
|
|
|
alertTime, status, createdAt, updatedAt)
|
|
|
|
|
VALUES
|
|
|
|
|
(:farmName, :farmerName, :phone, :deviceType, :deviceNumber, :alertType, :alertLevel,
|
|
|
|
|
:description, :location, :batteryLevel, :signalStrength, :temperature, :remarks,
|
|
|
|
|
NOW(), 'active', NOW(), NOW())
|
|
|
|
|
`;
|
|
|
|
|
|
|
|
|
|
await DeviceWarning.sequelize.query(insertQuery, {
|
|
|
|
|
replacements: {
|
|
|
|
|
farmName, farmerName, phone, deviceType, deviceNumber,
|
|
|
|
|
alertType, alertLevel,
|
|
|
|
|
description: description || null,
|
|
|
|
|
location: location || null,
|
|
|
|
|
batteryLevel: batteryLevel || null,
|
|
|
|
|
signalStrength: signalStrength || null,
|
|
|
|
|
temperature: temperature || null,
|
|
|
|
|
remarks: remarks || null
|
|
|
|
|
},
|
|
|
|
|
type: QueryTypes.INSERT
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
// 获取刚插入的记录
|
|
|
|
|
const selectQuery = `
|
|
|
|
|
SELECT id, farmName, farmerName, phone, deviceType, deviceNumber,
|
|
|
|
|
alertType, alertLevel, alertTime, status, description,
|
|
|
|
|
location, batteryLevel, signalStrength, temperature,
|
|
|
|
|
resolvedBy, resolvedAt, remarks, createdAt, updatedAt
|
|
|
|
|
FROM device_warnings
|
|
|
|
|
ORDER BY id DESC
|
|
|
|
|
LIMIT 1
|
|
|
|
|
`;
|
|
|
|
|
|
|
|
|
|
const results = await DeviceWarning.sequelize.query(selectQuery, {
|
|
|
|
|
type: QueryTypes.SELECT
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
res.status(201).json({ code: 201, message: '创建成功', data: results[0] });
|
2025-10-09 18:01:06 +08:00
|
|
|
} catch (error) {
|
|
|
|
|
console.error('创建设备预警失败:', error);
|
|
|
|
|
res.status(500).json({ code: 500, message: '创建设备预警失败', error: error.message });
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
// 更新设备预警
|
|
|
|
|
exports.updateDeviceWarning = async (req, res) => {
|
|
|
|
|
try {
|
|
|
|
|
const { id } = req.params;
|
2025-10-11 08:53:47 +08:00
|
|
|
const updateFields = [];
|
|
|
|
|
const replacements = { id };
|
|
|
|
|
|
|
|
|
|
// 动态构建更新字段
|
|
|
|
|
const allowedFields = [
|
|
|
|
|
'farmName', 'farmerName', 'phone', 'deviceType', 'deviceNumber',
|
|
|
|
|
'alertType', 'alertLevel', 'description', 'location', 'batteryLevel',
|
|
|
|
|
'signalStrength', 'temperature', 'remarks', 'status', 'resolvedBy', 'resolvedAt'
|
|
|
|
|
];
|
|
|
|
|
|
|
|
|
|
for (const field of allowedFields) {
|
|
|
|
|
if (req.body[field] !== undefined) {
|
|
|
|
|
updateFields.push(`${field} = :${field}`);
|
|
|
|
|
replacements[field] = req.body[field];
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (updateFields.length === 0) {
|
|
|
|
|
return res.status(400).json({ code: 400, message: '没有需要更新的字段' });
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
updateFields.push('updatedAt = NOW()');
|
|
|
|
|
|
|
|
|
|
const updateQuery = `
|
|
|
|
|
UPDATE device_warnings
|
|
|
|
|
SET ${updateFields.join(', ')}
|
|
|
|
|
WHERE id = :id
|
|
|
|
|
`;
|
|
|
|
|
|
|
|
|
|
const [result] = await DeviceWarning.sequelize.query(updateQuery, {
|
|
|
|
|
replacements,
|
|
|
|
|
type: QueryTypes.UPDATE
|
2025-10-09 18:01:06 +08:00
|
|
|
});
|
|
|
|
|
|
2025-10-11 08:53:47 +08:00
|
|
|
if (result === 0) {
|
2025-10-09 18:01:06 +08:00
|
|
|
return res.status(404).json({ code: 404, message: '设备预警未找到或无更新' });
|
|
|
|
|
}
|
|
|
|
|
|
2025-10-11 08:53:47 +08:00
|
|
|
// 获取更新后的记录
|
|
|
|
|
const selectQuery = `
|
|
|
|
|
SELECT id, farmName, farmerName, phone, deviceType, deviceNumber,
|
|
|
|
|
alertType, alertLevel, alertTime, status, description,
|
|
|
|
|
location, batteryLevel, signalStrength, temperature,
|
|
|
|
|
resolvedBy, resolvedAt, remarks, createdAt, updatedAt
|
|
|
|
|
FROM device_warnings
|
|
|
|
|
WHERE id = :id
|
|
|
|
|
`;
|
|
|
|
|
|
|
|
|
|
const results = await DeviceWarning.sequelize.query(selectQuery, {
|
|
|
|
|
replacements: { id },
|
|
|
|
|
type: QueryTypes.SELECT
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
res.status(200).json({ code: 200, message: '更新成功', data: results[0] });
|
2025-10-09 18:01:06 +08:00
|
|
|
} catch (error) {
|
|
|
|
|
console.error('更新设备预警失败:', error);
|
|
|
|
|
res.status(500).json({ code: 500, message: '更新设备预警失败', error: error.message });
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
// 删除设备预警
|
|
|
|
|
exports.deleteDeviceWarning = async (req, res) => {
|
|
|
|
|
try {
|
|
|
|
|
const { id } = req.params;
|
2025-10-11 08:53:47 +08:00
|
|
|
|
|
|
|
|
const deleteQuery = 'DELETE FROM device_warnings WHERE id = :id';
|
|
|
|
|
const [result] = await DeviceWarning.sequelize.query(deleteQuery, {
|
|
|
|
|
replacements: { id },
|
|
|
|
|
type: QueryTypes.DELETE
|
2025-10-09 18:01:06 +08:00
|
|
|
});
|
|
|
|
|
|
2025-10-11 08:53:47 +08:00
|
|
|
if (result === 0) {
|
2025-10-09 18:01:06 +08:00
|
|
|
return res.status(404).json({ code: 404, message: '设备预警未找到' });
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
res.status(200).json({ code: 200, message: '删除成功' });
|
|
|
|
|
} catch (error) {
|
|
|
|
|
console.error('删除设备预警失败:', error);
|
|
|
|
|
res.status(500).json({ code: 500, message: '删除设备预警失败', error: error.message });
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
// 更新预警状态
|
|
|
|
|
exports.updateWarningStatus = async (req, res) => {
|
|
|
|
|
try {
|
|
|
|
|
const { id } = req.params;
|
|
|
|
|
const { status, resolvedBy } = req.body;
|
|
|
|
|
|
|
|
|
|
const warning = await DeviceWarning.findByPk(id);
|
|
|
|
|
if (!warning) {
|
|
|
|
|
return res.status(404).json({ code: 404, message: '设备预警未找到' });
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
warning.status = status;
|
|
|
|
|
if (status === 'resolved') {
|
|
|
|
|
warning.resolvedBy = resolvedBy;
|
|
|
|
|
warning.resolvedAt = new Date();
|
|
|
|
|
}
|
|
|
|
|
await warning.save();
|
|
|
|
|
|
|
|
|
|
res.status(200).json({ code: 200, message: '状态更新成功', data: warning });
|
|
|
|
|
} catch (error) {
|
|
|
|
|
console.error('更新预警状态失败:', error);
|
|
|
|
|
res.status(500).json({ code: 500, message: '更新预警状态失败', error: error.message });
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
// 获取预警统计
|
|
|
|
|
exports.getWarningStats = async (req, res) => {
|
|
|
|
|
try {
|
2025-10-11 08:53:47 +08:00
|
|
|
// 使用原始SQL查询每种设备类型的活跃预警数量
|
|
|
|
|
const earTagQuery = 'SELECT COUNT(*) as count FROM device_warnings WHERE deviceType = :deviceType AND status = :status';
|
|
|
|
|
const earTagResult = await DeviceWarning.sequelize.query(earTagQuery, {
|
|
|
|
|
replacements: { deviceType: '智能耳标', status: 'active' },
|
|
|
|
|
type: QueryTypes.SELECT
|
2025-10-09 18:01:06 +08:00
|
|
|
});
|
|
|
|
|
|
2025-10-11 08:53:47 +08:00
|
|
|
const neckbandResult = await DeviceWarning.sequelize.query(earTagQuery, {
|
|
|
|
|
replacements: { deviceType: '智能项圈', status: 'active' },
|
|
|
|
|
type: QueryTypes.SELECT
|
2025-10-09 18:01:06 +08:00
|
|
|
});
|
|
|
|
|
|
2025-10-11 08:53:47 +08:00
|
|
|
const hostResult = await DeviceWarning.sequelize.query(earTagQuery, {
|
|
|
|
|
replacements: { deviceType: '智能主机', status: 'active' },
|
|
|
|
|
type: QueryTypes.SELECT
|
2025-10-09 18:01:06 +08:00
|
|
|
});
|
|
|
|
|
|
|
|
|
|
const result = {
|
2025-10-11 08:53:47 +08:00
|
|
|
earTag: earTagResult[0].count,
|
|
|
|
|
neckband: neckbandResult[0].count,
|
|
|
|
|
host: hostResult[0].count
|
2025-10-09 18:01:06 +08:00
|
|
|
};
|
|
|
|
|
|
|
|
|
|
res.status(200).json({ code: 200, message: '获取成功', data: result });
|
|
|
|
|
} catch (error) {
|
|
|
|
|
console.error('获取预警统计失败:', error);
|
|
|
|
|
res.status(500).json({ code: 500, message: '获取预警统计失败', error: error.message });
|
|
|
|
|
}
|
|
|
|
|
};
|