修改管理后台
This commit is contained in:
414
backend/controllers/bindingController.js
Normal file
414
backend/controllers/bindingController.js
Normal file
@@ -0,0 +1,414 @@
|
||||
/**
|
||||
* 绑定信息控制器
|
||||
* @file bindingController.js
|
||||
* @description 处理耳标与牛只档案的绑定信息查询
|
||||
*/
|
||||
|
||||
const { IotJbqClient, IotCattle, Farm, CattlePen, CattleBatch } = require('../models');
|
||||
const { Op } = require('sequelize');
|
||||
|
||||
/**
|
||||
* 获取耳标绑定信息
|
||||
* @param {Object} req - 请求对象
|
||||
* @param {Object} res - 响应对象
|
||||
*/
|
||||
const getBindingInfo = async (req, res) => {
|
||||
try {
|
||||
const { cid } = req.params;
|
||||
|
||||
if (!cid) {
|
||||
return res.status(400).json({
|
||||
success: false,
|
||||
message: '耳标编号不能为空',
|
||||
data: null
|
||||
});
|
||||
}
|
||||
|
||||
// 查询耳标信息
|
||||
const jbqDevice = await IotJbqClient.findOne({
|
||||
where: { cid: cid },
|
||||
attributes: [
|
||||
'id', 'cid', 'aaid', 'org_id', 'uid', 'time', 'uptime', 'sid',
|
||||
'walk', 'y_steps', 'r_walk', 'lat', 'lon', 'gps_state', 'voltage',
|
||||
'temperature', 'temperature_two', 'state', 'type', 'sort', 'ver',
|
||||
'weight', 'start_time', 'run_days', 'zenowalk', 'zenotime',
|
||||
'is_read', 'read_end_time', 'bank_userid', 'bank_item_id',
|
||||
'bank_house', 'bank_lanwei', 'bank_place', 'is_home',
|
||||
'distribute_time', 'bandge_status', 'is_wear', 'is_temperature',
|
||||
'source_id', 'expire_time'
|
||||
]
|
||||
});
|
||||
|
||||
if (!jbqDevice) {
|
||||
return res.status(404).json({
|
||||
success: false,
|
||||
message: '未找到指定的耳标设备',
|
||||
data: null
|
||||
});
|
||||
}
|
||||
|
||||
// 查询绑定的牛只档案信息
|
||||
const cattleInfo = await IotCattle.findOne({
|
||||
where: { ear_number: cid },
|
||||
include: [
|
||||
{
|
||||
model: Farm,
|
||||
as: 'farm',
|
||||
attributes: ['id', 'name', 'address', 'contact', 'phone']
|
||||
},
|
||||
{
|
||||
model: CattlePen,
|
||||
as: 'pen',
|
||||
attributes: ['id', 'name', 'description']
|
||||
},
|
||||
{
|
||||
model: CattleBatch,
|
||||
as: 'batch',
|
||||
attributes: ['id', 'name', 'description', 'start_date', 'end_date']
|
||||
}
|
||||
],
|
||||
attributes: [
|
||||
'id', 'orgId', 'earNumber', 'sex', 'strain', 'varieties', 'cate',
|
||||
'birthWeight', 'birthday', 'penId', 'intoTime', 'parity', 'source',
|
||||
'sourceDay', 'sourceWeight', 'weight', 'event', 'eventTime',
|
||||
'lactationDay', 'semenNum', 'isWear', 'batchId', 'imgs',
|
||||
'isEleAuth', 'isQuaAuth', 'isDelete', 'isOut', 'createUid',
|
||||
'createTime', 'algebra', 'colour', 'infoWeight', 'descent',
|
||||
'isVaccin', 'isInsemination', 'isInsure', 'isMortgage',
|
||||
'updateTime', 'breedBullTime', 'level', 'sixWeight',
|
||||
'eighteenWeight', 'twelveDayWeight', 'eighteenDayWeight',
|
||||
'xxivDayWeight', 'semenBreedImgs', 'sellStatus',
|
||||
'weightCalculateTime', 'dayOfBirthday'
|
||||
]
|
||||
});
|
||||
|
||||
// 构建响应数据
|
||||
const bindingInfo = {
|
||||
device: {
|
||||
id: jbqDevice.id,
|
||||
cid: jbqDevice.cid,
|
||||
aaid: jbqDevice.aaid,
|
||||
orgId: jbqDevice.org_id,
|
||||
uid: jbqDevice.uid,
|
||||
time: jbqDevice.time,
|
||||
uptime: jbqDevice.uptime,
|
||||
sid: jbqDevice.sid,
|
||||
walk: jbqDevice.walk,
|
||||
ySteps: jbqDevice.y_steps,
|
||||
rWalk: jbqDevice.r_walk,
|
||||
lat: jbqDevice.lat,
|
||||
lon: jbqDevice.lon,
|
||||
gpsState: jbqDevice.gps_state,
|
||||
voltage: jbqDevice.voltage,
|
||||
temperature: jbqDevice.temperature,
|
||||
temperatureTwo: jbqDevice.temperature_two,
|
||||
state: jbqDevice.state,
|
||||
type: jbqDevice.type,
|
||||
sort: jbqDevice.sort,
|
||||
ver: jbqDevice.ver,
|
||||
weight: jbqDevice.weight,
|
||||
startTime: jbqDevice.start_time,
|
||||
runDays: jbqDevice.run_days,
|
||||
zenowalk: jbqDevice.zenowalk,
|
||||
zenotime: jbqDevice.zenotime,
|
||||
isRead: jbqDevice.is_read,
|
||||
readEndTime: jbqDevice.read_end_time,
|
||||
bankUserid: jbqDevice.bank_userid,
|
||||
bankItemId: jbqDevice.bank_item_id,
|
||||
bankHouse: jbqDevice.bank_house,
|
||||
bankLanwei: jbqDevice.bank_lanwei,
|
||||
bankPlace: jbqDevice.bank_place,
|
||||
isHome: jbqDevice.is_home,
|
||||
distributeTime: jbqDevice.distribute_time,
|
||||
bandgeStatus: jbqDevice.bandge_status,
|
||||
isWear: jbqDevice.is_wear,
|
||||
isTemperature: jbqDevice.is_temperature,
|
||||
sourceId: jbqDevice.source_id,
|
||||
expireTime: jbqDevice.expire_time
|
||||
},
|
||||
cattle: cattleInfo ? {
|
||||
id: cattleInfo.id,
|
||||
orgId: cattleInfo.orgId,
|
||||
earNumber: cattleInfo.earNumber,
|
||||
sex: cattleInfo.sex,
|
||||
strain: cattleInfo.strain,
|
||||
varieties: cattleInfo.varieties,
|
||||
cate: cattleInfo.cate,
|
||||
birthWeight: cattleInfo.birthWeight,
|
||||
birthday: cattleInfo.birthday,
|
||||
penId: cattleInfo.penId,
|
||||
intoTime: cattleInfo.intoTime,
|
||||
parity: cattleInfo.parity,
|
||||
source: cattleInfo.source,
|
||||
sourceDay: cattleInfo.sourceDay,
|
||||
sourceWeight: cattleInfo.sourceWeight,
|
||||
weight: cattleInfo.weight,
|
||||
event: cattleInfo.event,
|
||||
eventTime: cattleInfo.eventTime,
|
||||
lactationDay: cattleInfo.lactationDay,
|
||||
semenNum: cattleInfo.semenNum,
|
||||
isWear: cattleInfo.isWear,
|
||||
batchId: cattleInfo.batchId,
|
||||
imgs: cattleInfo.imgs,
|
||||
isEleAuth: cattleInfo.isEleAuth,
|
||||
isQuaAuth: cattleInfo.isQuaAuth,
|
||||
isDelete: cattleInfo.isDelete,
|
||||
isOut: cattleInfo.isOut,
|
||||
createUid: cattleInfo.createUid,
|
||||
createTime: cattleInfo.createTime,
|
||||
algebra: cattleInfo.algebra,
|
||||
colour: cattleInfo.colour,
|
||||
infoWeight: cattleInfo.infoWeight,
|
||||
descent: cattleInfo.descent,
|
||||
isVaccin: cattleInfo.isVaccin,
|
||||
isInsemination: cattleInfo.isInsemination,
|
||||
isInsure: cattleInfo.isInsure,
|
||||
isMortgage: cattleInfo.isMortgage,
|
||||
updateTime: cattleInfo.updateTime,
|
||||
breedBullTime: cattleInfo.breedBullTime,
|
||||
level: cattleInfo.level,
|
||||
sixWeight: cattleInfo.sixWeight,
|
||||
eighteenWeight: cattleInfo.eighteenWeight,
|
||||
twelveDayWeight: cattleInfo.twelveDayWeight,
|
||||
eighteenDayWeight: cattleInfo.eighteenDayWeight,
|
||||
xxivDayWeight: cattleInfo.xxivDayWeight,
|
||||
semenBreedImgs: cattleInfo.semenBreedImgs,
|
||||
sellStatus: cattleInfo.sellStatus,
|
||||
weightCalculateTime: cattleInfo.weightCalculateTime,
|
||||
dayOfBirthday: cattleInfo.dayOfBirthday,
|
||||
farm: cattleInfo.farm,
|
||||
pen: cattleInfo.pen,
|
||||
batch: cattleInfo.batch
|
||||
} : null,
|
||||
isBound: !!cattleInfo,
|
||||
bindingStatus: cattleInfo ? '已绑定' : '未绑定'
|
||||
};
|
||||
|
||||
res.json({
|
||||
success: true,
|
||||
message: '获取绑定信息成功',
|
||||
data: bindingInfo,
|
||||
timestamp: new Date().toISOString()
|
||||
});
|
||||
|
||||
} catch (error) {
|
||||
console.error('获取绑定信息失败:', error);
|
||||
res.status(500).json({
|
||||
success: false,
|
||||
message: '获取绑定信息失败: ' + error.message,
|
||||
data: null,
|
||||
timestamp: new Date().toISOString()
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* 获取所有绑定状态统计
|
||||
* @param {Object} req - 请求对象
|
||||
* @param {Object} res - 响应对象
|
||||
*/
|
||||
const getBindingStats = async (req, res) => {
|
||||
try {
|
||||
// 统计绑定状态
|
||||
const stats = await IotJbqClient.findAll({
|
||||
attributes: [
|
||||
'bandge_status',
|
||||
[IotJbqClient.sequelize.fn('COUNT', IotJbqClient.sequelize.col('id')), 'count']
|
||||
],
|
||||
group: ['bandge_status'],
|
||||
raw: true
|
||||
});
|
||||
|
||||
// 统计匹配情况
|
||||
const matchStats = await IotJbqClient.findAll({
|
||||
attributes: [
|
||||
[IotJbqClient.sequelize.fn('COUNT', IotJbqClient.sequelize.col('IotJbqClient.id')), 'total_jbq'],
|
||||
[IotJbqClient.sequelize.fn('COUNT', IotJbqClient.sequelize.col('cattle.id')), 'matched_count']
|
||||
],
|
||||
include: [
|
||||
{
|
||||
model: IotCattle,
|
||||
as: 'cattle',
|
||||
attributes: [],
|
||||
required: false,
|
||||
where: {
|
||||
earNumber: IotJbqClient.sequelize.col('IotJbqClient.cid')
|
||||
}
|
||||
}
|
||||
],
|
||||
raw: true
|
||||
});
|
||||
|
||||
const result = {
|
||||
bindingStats: stats.map(stat => ({
|
||||
status: stat.bandge_status === 1 ? '已绑定' : '未绑定',
|
||||
count: parseInt(stat.count)
|
||||
})),
|
||||
matchStats: {
|
||||
totalJbq: parseInt(matchStats[0]?.total_jbq || 0),
|
||||
matchedCount: parseInt(matchStats[0]?.matched_count || 0),
|
||||
matchRate: matchStats[0]?.total_jbq > 0
|
||||
? ((matchStats[0]?.matched_count / matchStats[0]?.total_jbq) * 100).toFixed(2) + '%'
|
||||
: '0%'
|
||||
}
|
||||
};
|
||||
|
||||
res.json({
|
||||
success: true,
|
||||
message: '获取绑定统计成功',
|
||||
data: result,
|
||||
timestamp: new Date().toISOString()
|
||||
});
|
||||
|
||||
} catch (error) {
|
||||
console.error('获取绑定统计失败:', error);
|
||||
res.status(500).json({
|
||||
success: false,
|
||||
message: '获取绑定统计失败: ' + error.message,
|
||||
data: null,
|
||||
timestamp: new Date().toISOString()
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* 手动绑定耳标与牛只档案
|
||||
* @param {Object} req - 请求对象
|
||||
* @param {Object} res - 响应对象
|
||||
*/
|
||||
const bindCattle = async (req, res) => {
|
||||
try {
|
||||
const { cid, cattleId } = req.body;
|
||||
|
||||
if (!cid || !cattleId) {
|
||||
return res.status(400).json({
|
||||
success: false,
|
||||
message: '耳标编号和牛只ID不能为空',
|
||||
data: null
|
||||
});
|
||||
}
|
||||
|
||||
// 检查耳标是否存在
|
||||
const jbqDevice = await IotJbqClient.findOne({
|
||||
where: { cid: cid }
|
||||
});
|
||||
|
||||
if (!jbqDevice) {
|
||||
return res.status(404).json({
|
||||
success: false,
|
||||
message: '未找到指定的耳标设备',
|
||||
data: null
|
||||
});
|
||||
}
|
||||
|
||||
// 检查牛只档案是否存在
|
||||
const cattle = await IotCattle.findByPk(cattleId);
|
||||
if (!cattle) {
|
||||
return res.status(404).json({
|
||||
success: false,
|
||||
message: '未找到指定的牛只档案',
|
||||
data: null
|
||||
});
|
||||
}
|
||||
|
||||
// 更新牛只档案的耳标号
|
||||
await cattle.update({
|
||||
earNumber: cid,
|
||||
updateTime: Math.floor(Date.now() / 1000)
|
||||
});
|
||||
|
||||
// 更新耳标的绑定状态
|
||||
await jbqDevice.update({
|
||||
bandge_status: 1
|
||||
});
|
||||
|
||||
res.json({
|
||||
success: true,
|
||||
message: '绑定成功',
|
||||
data: {
|
||||
cid: cid,
|
||||
cattleId: cattleId,
|
||||
bindingStatus: '已绑定'
|
||||
},
|
||||
timestamp: new Date().toISOString()
|
||||
});
|
||||
|
||||
} catch (error) {
|
||||
console.error('绑定失败:', error);
|
||||
res.status(500).json({
|
||||
success: false,
|
||||
message: '绑定失败: ' + error.message,
|
||||
data: null,
|
||||
timestamp: new Date().toISOString()
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* 解绑耳标与牛只档案
|
||||
* @param {Object} req - 请求对象
|
||||
* @param {Object} res - 响应对象
|
||||
*/
|
||||
const unbindCattle = async (req, res) => {
|
||||
try {
|
||||
const { cid } = req.params;
|
||||
|
||||
if (!cid) {
|
||||
return res.status(400).json({
|
||||
success: false,
|
||||
message: '耳标编号不能为空',
|
||||
data: null
|
||||
});
|
||||
}
|
||||
|
||||
// 查找绑定的牛只档案
|
||||
const cattle = await IotCattle.findOne({
|
||||
where: { earNumber: cid }
|
||||
});
|
||||
|
||||
if (cattle) {
|
||||
// 清除牛只档案的耳标号
|
||||
await cattle.update({
|
||||
earNumber: null,
|
||||
updateTime: Math.floor(Date.now() / 1000)
|
||||
});
|
||||
}
|
||||
|
||||
// 更新耳标的绑定状态
|
||||
const jbqDevice = await IotJbqClient.findOne({
|
||||
where: { cid: cid }
|
||||
});
|
||||
|
||||
if (jbqDevice) {
|
||||
await jbqDevice.update({
|
||||
bandge_status: 0
|
||||
});
|
||||
}
|
||||
|
||||
res.json({
|
||||
success: true,
|
||||
message: '解绑成功',
|
||||
data: {
|
||||
cid: cid,
|
||||
bindingStatus: '未绑定'
|
||||
},
|
||||
timestamp: new Date().toISOString()
|
||||
});
|
||||
|
||||
} catch (error) {
|
||||
console.error('解绑失败:', error);
|
||||
res.status(500).json({
|
||||
success: false,
|
||||
message: '解绑失败: ' + error.message,
|
||||
data: null,
|
||||
timestamp: new Date().toISOString()
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
module.exports = {
|
||||
getBindingInfo,
|
||||
getBindingStats,
|
||||
bindCattle,
|
||||
unbindCattle
|
||||
};
|
||||
Reference in New Issue
Block a user