/** * 动物信息路由 */ 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;