Files
nxxmdata/backend/controllers/cattleBatchController.js

664 lines
18 KiB
JavaScript
Raw Normal View History

2025-09-16 16:07:32 +08:00
const { CattleBatch, IotCattle, Farm, CattleBatchAnimal, User, CattleType, CattleUser, CattlePen } = require('../models');
2025-09-12 20:08:42 +08:00
const { Op } = require('sequelize');
/**
* 批次设置控制器
*/
class CattleBatchController {
/**
* 获取批次列表
*/
async getBatches(req, res) {
try {
const { page = 1, pageSize = 10, search, type, status } = req.query;
const offset = (page - 1) * pageSize;
console.log('🔍 [后端-批次设置] 搜索请求参数:', { page, pageSize, search, type, status });
// 构建查询条件
const where = {};
if (search) {
where[Op.or] = [
{ name: { [Op.like]: `%${search}%` } },
{ code: { [Op.like]: `%${search}%` } }
];
console.log('🔍 [后端-批次设置] 搜索条件:', where[Op.or]);
}
if (type) {
where.type = type;
}
if (status) {
where.status = status;
}
const { count, rows } = await CattleBatch.findAndCountAll({
where,
include: [
{
model: Farm,
as: 'farm',
attributes: ['id', 'name']
}
],
limit: parseInt(pageSize),
offset: offset,
order: [['created_at', 'DESC']]
});
console.log('🔍 [后端-批次设置] 查询结果:', {
总数: count,
当前页数据量: rows.length,
搜索关键词: search,
查询条件: where
});
res.json({
success: true,
data: {
list: rows,
total: count,
page: parseInt(page),
pageSize: parseInt(pageSize)
},
message: '获取批次列表成功'
});
} catch (error) {
console.error('获取批次列表失败:', error);
res.status(500).json({
success: false,
message: '获取批次列表失败',
error: error.message
});
}
}
/**
* 获取批次详情
*/
async getBatchById(req, res) {
try {
const { id } = req.params;
const batch = await CattleBatch.findByPk(id, {
include: [
{
model: Farm,
as: 'farm',
attributes: ['id', 'name']
}
]
});
if (!batch) {
return res.status(404).json({
success: false,
message: '批次不存在'
});
}
res.json({
success: true,
data: batch,
message: '获取批次详情成功'
});
} catch (error) {
console.error('获取批次详情失败:', error);
res.status(500).json({
success: false,
message: '获取批次详情失败',
error: error.message
});
}
}
/**
* 创建批次
*/
async createBatch(req, res) {
try {
console.log('🆕 [后端-批次设置] 开始创建操作');
console.log('📋 [后端-批次设置] 请求数据:', req.body);
const {
name,
code,
type,
startDate,
expectedEndDate,
actualEndDate,
targetCount,
currentCount,
manager,
status,
remark,
farmId
} = req.body;
// 验证必填字段
if (!name || !code || !type || !startDate || !targetCount || !manager) {
console.log('❌ [后端-批次设置] 必填字段验证失败:', {
name: !!name,
code: !!code,
type: !!type,
startDate: !!startDate,
targetCount: !!targetCount,
manager: !!manager
});
return res.status(400).json({
success: false,
message: '请填写所有必填字段(批次名称、编号、类型、开始日期、目标数量、负责人)'
});
}
// 检查批次编号是否已存在
const existingBatch = await CattleBatch.findOne({
where: { code }
});
if (existingBatch) {
console.log('❌ [后端-批次设置] 批次编号已存在:', code);
return res.status(400).json({
success: false,
message: '批次编号已存在'
});
}
// 检查农场是否存在
const farm = await Farm.findByPk(farmId);
if (!farm) {
console.log('❌ [后端-批次设置] 农场不存在:', farmId);
return res.status(400).json({
success: false,
message: '农场不存在'
});
}
// 准备创建数据
const createData = {
name,
code,
type,
startDate: new Date(startDate),
expectedEndDate: expectedEndDate ? new Date(expectedEndDate) : null,
actualEndDate: actualEndDate ? new Date(actualEndDate) : null,
targetCount: parseInt(targetCount),
currentCount: currentCount ? parseInt(currentCount) : 0,
manager,
status: status || '进行中',
remark: remark || '',
farmId: farmId || 1
};
console.log('📝 [后端-批次设置] 准备创建的数据:', createData);
const batch = await CattleBatch.create(createData);
console.log('✅ [后端-批次设置] 批次创建成功:', batch.id);
res.status(201).json({
success: true,
data: batch,
message: '创建批次成功'
});
} catch (error) {
console.error('❌ [后端-批次设置] 创建失败:', error);
res.status(500).json({
success: false,
message: '创建批次失败',
error: error.message
});
}
}
/**
* 更新批次
*/
async updateBatch(req, res) {
try {
const { id } = req.params;
const updateData = req.body;
console.log('🔄 [后端-批次设置] 开始更新操作');
console.log('📋 [后端-批次设置] 请求参数:', {
batchId: id,
updateData: updateData
});
const batch = await CattleBatch.findByPk(id);
if (!batch) {
console.log('❌ [后端-批次设置] 批次不存在ID:', id);
return res.status(404).json({
success: false,
message: '批次不存在'
});
}
console.log('📝 [后端-批次设置] 原始批次数据:', {
id: batch.id,
name: batch.name,
code: batch.code,
type: batch.type,
description: batch.description,
status: batch.status,
startDate: batch.startDate,
expectedEndDate: batch.expectedEndDate,
actualEndDate: batch.actualEndDate,
targetCount: batch.targetCount,
currentCount: batch.currentCount,
manager: batch.manager,
remark: batch.remark,
farmId: batch.farmId
});
// 如果更新编号,检查是否已存在
if (updateData.code && updateData.code !== batch.code) {
console.log('🔄 [后端-批次设置] 检测到编号变更,检查是否已存在');
console.log('📝 [后端-批次设置] 编号变更详情:', {
oldCode: batch.code,
newCode: updateData.code
});
const existingBatch = await CattleBatch.findOne({
where: { code: updateData.code, id: { [Op.ne]: id } }
});
if (existingBatch) {
console.log('❌ [后端-批次设置] 批次编号已存在');
return res.status(400).json({
success: false,
message: '批次编号已存在'
});
}
console.log('✅ [后端-批次设置] 批次编号可用');
}
await batch.update(updateData);
console.log('✅ [后端-批次设置] 批次更新成功');
res.json({
success: true,
data: batch,
message: '更新批次成功'
});
} catch (error) {
console.error('❌ [后端-批次设置] 更新失败:', error);
res.status(500).json({
success: false,
message: '更新批次失败',
error: error.message
});
}
}
/**
* 删除批次
*/
async deleteBatch(req, res) {
try {
const { id } = req.params;
const batch = await CattleBatch.findByPk(id);
if (!batch) {
return res.status(404).json({
success: false,
message: '批次不存在'
});
}
// 检查是否有牛只在批次中
const animalCount = await CattleBatchAnimal.count({
where: { batchId: id }
});
if (animalCount > 0) {
return res.status(400).json({
success: false,
message: '批次中还有牛只,无法删除'
});
}
await batch.destroy();
res.json({
success: true,
message: '删除批次成功'
});
} catch (error) {
console.error('删除批次失败:', error);
res.status(500).json({
success: false,
message: '删除批次失败',
error: error.message
});
}
}
/**
* 批量删除批次
*/
async batchDeleteBatches(req, res) {
try {
const { ids } = req.body;
if (!ids || !Array.isArray(ids) || ids.length === 0) {
return res.status(400).json({
success: false,
message: '请选择要删除的批次'
});
}
// 检查是否有批次包含牛只
const animalCount = await CattleBatchAnimal.count({
where: { batchId: { [Op.in]: ids } }
});
if (animalCount > 0) {
return res.status(400).json({
success: false,
message: '部分批次中还有牛只,无法删除'
});
}
await CattleBatch.destroy({
where: { id: { [Op.in]: ids } }
});
res.json({
success: true,
message: `成功删除 ${ids.length} 个批次`
});
} catch (error) {
console.error('批量删除批次失败:', error);
res.status(500).json({
success: false,
message: '批量删除批次失败',
error: error.message
});
}
}
/**
* 获取批次中的牛只
*/
async getBatchAnimals(req, res) {
try {
const { id } = req.params;
const { page = 1, pageSize = 10 } = req.query;
const offset = (page - 1) * pageSize;
2025-09-16 16:07:32 +08:00
console.log('🔍 开始获取批次牛只数据');
console.log('📋 批次信息:', { id, page, pageSize, offset });
2025-09-12 20:08:42 +08:00
// 检查批次是否存在
const batch = await CattleBatch.findByPk(id);
if (!batch) {
return res.status(404).json({
success: false,
message: '批次不存在'
});
}
2025-09-16 16:07:32 +08:00
console.log('✅ 批次存在:', batch.name);
// 获取批次中的牛只直接通过batchId字段查询
2025-09-12 20:08:42 +08:00
const { count, rows } = await IotCattle.findAndCountAll({
2025-09-16 16:07:32 +08:00
where: { batchId: id },
attributes: [
'id',
'earNumber',
'sex',
'strain',
'varieties',
'birthday',
'parity',
'orgId',
'penId'
],
2025-09-12 20:08:42 +08:00
include: [
{
model: Farm,
as: 'farm',
attributes: ['id', 'name']
}
],
limit: parseInt(pageSize),
offset: offset,
order: [['earNumber', 'ASC']]
});
2025-09-16 16:07:32 +08:00
console.log(`📊 查询结果: 总记录数=${count}, 返回记录数=${rows.length}`);
// 获取品种和品系映射数据
const typeIds = [...new Set(rows.map(cattle => cattle.varieties).filter(id => id))];
const strainIds = [...new Set(rows.map(cattle => cattle.strain).filter(id => id))];
const penIds = [...new Set(rows.map(cattle => cattle.penId).filter(id => id))];
const typeNames = {};
if (typeIds.length > 0) {
const types = await CattleType.findAll({
where: { id: typeIds },
attributes: ['id', 'name']
});
types.forEach(type => {
typeNames[type.id] = type.name;
});
}
const userNames = {};
if (strainIds.length > 0) {
const users = await CattleUser.findAll({
where: { id: strainIds },
attributes: ['id', 'name']
});
users.forEach(user => {
userNames[user.id] = user.name;
});
}
const penNames = {};
if (penIds.length > 0) {
const pens = await CattlePen.findAll({
where: { id: penIds },
attributes: ['id', 'name']
});
pens.forEach(pen => {
penNames[pen.id] = pen.name;
});
}
// 转换数据格式,添加计算字段
const transformedRows = rows.map(cattle => {
// 计算月龄(基于出生日期)
let ageInMonths = 0;
if (cattle.birthday) {
const birthDate = new Date(cattle.birthday * 1000);
const now = new Date();
ageInMonths = Math.floor((now - birthDate) / (1000 * 60 * 60 * 24 * 30));
}
// 性别转换
const genderMap = { 1: '公', 2: '母', 0: '未知' };
const gender = genderMap[cattle.sex] || '未知';
// 品种转换(动态查询)
const breed = typeNames[cattle.varieties] || `品种ID:${cattle.varieties}`;
// 生理阶段判断
let physiologicalStage = '未知';
if (ageInMonths < 6) {
physiologicalStage = '犊牛';
} else if (ageInMonths < 12) {
physiologicalStage = '育成牛';
} else if (ageInMonths < 24) {
physiologicalStage = '青年牛';
} else if (cattle.sex === 2) {
if (cattle.parity > 0) {
physiologicalStage = '泌乳牛';
} else {
physiologicalStage = '后备母牛';
}
} else {
physiologicalStage = '种公牛';
}
return {
id: cattle.id,
earTag: cattle.earNumber,
breed: breed,
gender: gender,
ageInMonths: ageInMonths,
physiologicalStage: physiologicalStage,
pen: cattle.penId ? (penNames[cattle.penId] || `栏舍ID:${cattle.penId}`) : '未分配栏舍',
farm: cattle.farm
};
});
console.log('🔄 转换后的数据示例:', transformedRows.slice(0, 2));
2025-09-12 20:08:42 +08:00
res.json({
success: true,
data: {
2025-09-16 16:07:32 +08:00
list: transformedRows,
2025-09-12 20:08:42 +08:00
total: count,
page: parseInt(page),
pageSize: parseInt(pageSize)
},
message: '获取批次牛只成功'
});
} catch (error) {
console.error('获取批次牛只失败:', error);
res.status(500).json({
success: false,
message: '获取批次牛只失败',
error: error.message
});
}
}
/**
* 添加牛只到批次
*/
async addAnimalsToBatch(req, res) {
try {
const { id } = req.params;
const { animalIds } = req.body;
if (!animalIds || !Array.isArray(animalIds) || animalIds.length === 0) {
return res.status(400).json({
success: false,
message: '请选择要添加的牛只'
});
}
// 检查批次是否存在
const batch = await CattleBatch.findByPk(id);
if (!batch) {
return res.status(404).json({
success: false,
message: '批次不存在'
});
}
// 检查牛只是否存在
const animals = await IotCattle.findAll({
where: { id: { [Op.in]: animalIds } }
});
if (animals.length !== animalIds.length) {
return res.status(400).json({
success: false,
message: '部分牛只不存在'
});
}
// 检查哪些牛只已经在批次中
const existingAssociations = await CattleBatchAnimal.findAll({
where: {
batchId: id,
animalId: { [Op.in]: animalIds }
}
});
const existingAnimalIds = existingAssociations.map(assoc => assoc.animalId);
const newAnimalIds = animalIds.filter(id => !existingAnimalIds.includes(id));
if (newAnimalIds.length === 0) {
return res.status(400).json({
success: false,
message: '所有牛只都已在该批次中'
});
}
// 添加新的关联
const associations = newAnimalIds.map(animalId => ({
batchId: id,
animalId: animalId,
joinDate: new Date()
}));
await CattleBatchAnimal.bulkCreate(associations);
res.json({
success: true,
message: `成功添加 ${newAnimalIds.length} 头牛只到批次`,
data: {
addedCount: newAnimalIds.length,
skippedCount: existingAnimalIds.length
}
});
} catch (error) {
console.error('添加牛只到批次失败:', error);
res.status(500).json({
success: false,
message: '添加牛只到批次失败',
error: error.message
});
}
}
/**
* 从批次中移除牛只
*/
async removeAnimalFromBatch(req, res) {
try {
const { id, animalId } = req.params;
// 检查批次是否存在
const batch = await CattleBatch.findByPk(id);
if (!batch) {
return res.status(404).json({
success: false,
message: '批次不存在'
});
}
// 检查关联是否存在
const association = await CattleBatchAnimal.findOne({
where: { batchId: id, animalId }
});
if (!association) {
return res.status(404).json({
success: false,
message: '牛只不在该批次中'
});
}
await association.destroy();
res.json({
success: true,
message: '从批次中移除牛只成功'
});
} catch (error) {
console.error('从批次中移除牛只失败:', error);
res.status(500).json({
success: false,
message: '从批次中移除牛只失败',
error: error.message
});
}
}
}
module.exports = new CattleBatchController();