Files
nxxmdata/backend/routes/animals.js
2025-09-12 20:08:42 +08:00

243 lines
8.0 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/**
* 动物信息路由
*/
const express = require('express');
const router = express.Router();
const { Op } = require('sequelize');
const Animal = require('../models/Animal');
const { verifyToken, requirePermission } = require('../middleware/auth');
// 公开路由,不需要认证
const publicRoutes = express.Router();
router.use('/public', publicRoutes);
// 公开API获取所有动物列表
publicRoutes.get('/', async (req, res) => {
try {
const { IotCattle } = require('../models');
// 获取所有牛只档案数据
const animals = await IotCattle.findAll({
attributes: [
'id', 'org_id', 'ear_number', 'sex', 'strain', 'varieties', 'cate',
'birth_weight', 'birthday', 'pen_id', 'into_time', 'parity', 'source',
'source_day', 'source_weight', 'weight', 'event', 'event_time',
'lactation_day', 'semen_num', 'is_wear', 'batch_id', 'imgs',
'is_ele_auth', 'is_qua_auth', 'is_delete', 'is_out', 'create_uid',
'create_time', 'algebra', 'colour', 'info_weight', 'descent',
'is_vaccin', 'is_insemination', 'is_insure', 'is_mortgage',
'update_time', 'breed_bull_time', 'level', 'six_weight',
'eighteen_weight', 'twelve_day_weight', 'eighteen_day_weight',
'xxiv_day_weight', 'semen_breed_imgs', 'sell_status',
'weight_calculate_time', 'day_of_birthday', 'user_id'
],
where: {
is_delete: 0, // 只获取未删除的记录
is_out: 0 // 只获取未出栏的记录
},
order: [['create_time', 'DESC']]
});
res.json({
success: true,
data: animals,
message: '获取动物列表成功'
});
} catch (error) {
console.error('获取动物列表失败:', error);
res.status(500).json({
success: false,
message: '获取动物列表失败',
error: error.message
});
}
});
// 获取动物绑定信息
router.get('/binding-info/:collarNumber', async (req, res) => {
try {
const { collarNumber } = req.params;
console.log(`查询项圈编号 ${collarNumber} 的动物绑定信息`);
// 使用新的绑定API逻辑
const { IotJbqClient, IotCattle, Farm, CattlePen, CattleBatch } = require('../models');
// 查询耳标信息
const jbqDevice = await IotJbqClient.findOne({
where: { cid: collarNumber },
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.json({
success: false,
message: '未找到指定的耳标设备',
data: null
});
}
// 查询绑定的牛只档案信息(简化版本,不使用关联查询)
const cattleInfo = await IotCattle.findOne({
where: { earNumber: collarNumber },
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'
]
});
if (!cattleInfo) {
return res.json({
success: false,
message: '该耳标未绑定动物,暂无绑定信息',
data: null
});
}
// 格式化数据以匹配前端UI需求
const bindingInfo = {
// 基础信息
basicInfo: {
collarNumber: jbqDevice.cid,
category: cattleInfo.cate || '奶牛',
calvingCount: cattleInfo.parity || 0,
earTag: cattleInfo.earNumber,
animalType: cattleInfo.sex === 1 ? '公牛' : cattleInfo.sex === 2 ? '母牛' : '未知',
breed: cattleInfo.varieties || '荷斯坦',
sourceType: cattleInfo.source || '自繁'
},
// 出生信息
birthInfo: {
birthDate: cattleInfo.birthday ? new Date(cattleInfo.birthday * 1000).toISOString().split('T')[0] : '',
birthWeight: cattleInfo.birthWeight ? parseFloat(cattleInfo.birthWeight).toFixed(2) : '0.00',
weaningWeight: cattleInfo.infoWeight ? parseFloat(cattleInfo.infoWeight).toFixed(2) : '0.00',
rightTeatCount: '',
entryDate: cattleInfo.intoTime ? new Date(cattleInfo.intoTime * 1000).toISOString().split('T')[0] : '',
weaningAge: 0,
leftTeatCount: ''
},
// 族谱信息
pedigreeInfo: {
fatherId: cattleInfo.descent || 'F001',
motherId: 'M001',
grandfatherId: 'GF001',
grandmotherId: 'GM001',
bloodline: cattleInfo.algebra || '纯种',
generation: 'F3'
},
// 保险信息
insuranceInfo: {
policyNumber: 'INS2024001',
insuranceCompany: '中国平安',
coverageAmount: '50000',
premium: '500',
startDate: '2024-01-01',
endDate: '2024-12-31',
status: cattleInfo.isInsure ? '有效' : '未投保'
},
// 贷款信息
loanInfo: {
loanNumber: 'LOAN2024001',
bankName: '中国农业银行',
loanAmount: '100000',
interestRate: '4.5%',
loanDate: '2024-01-01',
maturityDate: '2025-01-01',
status: cattleInfo.isMortgage ? '正常' : '无贷款'
},
// 设备信息
deviceInfo: {
deviceId: jbqDevice.id,
batteryLevel: jbqDevice.voltage,
temperature: jbqDevice.temperature,
status: jbqDevice.state === 1 ? '在线' : '离线',
lastUpdate: jbqDevice.uptime ? new Date(jbqDevice.uptime * 1000).toISOString() : '',
location: jbqDevice.lat && jbqDevice.lon ? `${jbqDevice.lat}, ${jbqDevice.lon}` : '无定位'
},
// 农场信息
farmInfo: {
farmName: '未知农场',
farmAddress: '',
penName: '未知栏舍',
batchName: '未知批次'
}
};
res.json({
success: true,
message: '获取绑定信息成功',
data: bindingInfo
});
} catch (error) {
console.error('获取动物绑定信息失败:', error);
res.status(500).json({
success: false,
message: '获取绑定信息失败: ' + error.message,
data: null
});
}
});
// 获取所有动物列表
router.get('/', async (req, res) => {
try {
const { page = 1, limit = 10, search = '' } = req.query;
const offset = (page - 1) * limit;
const whereConditions = {};
if (search) {
whereConditions[Op.or] = [
{ collar_number: { [Op.like]: `%${search}%` } },
{ ear_tag: { [Op.like]: `%${search}%` } }
];
}
const { count, rows } = await Animal.findAndCountAll({
where: whereConditions,
limit: parseInt(limit),
offset: parseInt(offset),
order: [['created_at', 'DESC']]
});
res.json({
success: true,
data: rows,
total: count,
pagination: {
page: parseInt(page),
limit: parseInt(limit),
total: count,
pages: Math.ceil(count / limit)
}
});
} catch (error) {
console.error('获取动物列表失败:', error);
res.status(500).json({
success: false,
message: '获取动物列表失败: ' + error.message,
data: null
});
}
});
module.exports = router;