293 lines
9.2 KiB
JavaScript
293 lines
9.2 KiB
JavaScript
/**
|
||
* 动物信息路由
|
||
*/
|
||
const express = require('express');
|
||
const router = express.Router();
|
||
const { Op } = require('sequelize');
|
||
const Animal = require('../models/Animal');
|
||
const CattleType = require('../models/CattleType');
|
||
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
|
||
});
|
||
}
|
||
|
||
// 类别映射函数(与前端保持一致)
|
||
const getCategoryName = (cate) => {
|
||
const categoryMap = {
|
||
1: '犊牛',
|
||
2: '育成母牛',
|
||
3: '架子牛',
|
||
4: '青年牛',
|
||
5: '基础母牛',
|
||
6: '育肥牛'
|
||
};
|
||
return categoryMap[cate] || '未知';
|
||
};
|
||
|
||
// 性别映射函数
|
||
const getSexName = (sex) => {
|
||
const sexMap = {
|
||
1: '公牛',
|
||
2: '母牛'
|
||
};
|
||
return sexMap[sex] || '未知';
|
||
};
|
||
|
||
// 来源类型映射函数
|
||
const getSourceTypeName = (source) => {
|
||
const sourceMap = {
|
||
1: '合作社',
|
||
2: '农户',
|
||
3: '养殖场',
|
||
4: '进口',
|
||
5: '自繁'
|
||
};
|
||
return sourceMap[source] || '未知';
|
||
};
|
||
|
||
// 动态查询品种名称
|
||
const getBreedName = async (varieties) => {
|
||
if (!varieties) return '未知品种';
|
||
|
||
try {
|
||
const breed = await CattleType.findByPk(varieties, {
|
||
attributes: ['id', 'name']
|
||
});
|
||
return breed ? breed.name : '未知品种';
|
||
} catch (error) {
|
||
console.error('查询品种信息失败:', error);
|
||
return '未知品种';
|
||
}
|
||
};
|
||
|
||
// 格式化数据以匹配前端UI需求
|
||
const bindingInfo = {
|
||
// 基础信息
|
||
basicInfo: {
|
||
collarNumber: jbqDevice.cid,
|
||
category: getCategoryName(cattleInfo.cate),
|
||
calvingCount: cattleInfo.parity || 0,
|
||
earTag: cattleInfo.earNumber,
|
||
animalType: getSexName(cattleInfo.sex),
|
||
breed: await getBreedName(cattleInfo.varieties), // 使用动态查询品种名称
|
||
sourceType: getSourceTypeName(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; |