565 lines
15 KiB
JavaScript
565 lines
15 KiB
JavaScript
|
|
const { CattleBatch, IotCattle, Farm, CattleBatchAnimal, User } = require('../models');
|
|||
|
|
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;
|
|||
|
|
|
|||
|
|
// 检查批次是否存在
|
|||
|
|
const batch = await CattleBatch.findByPk(id);
|
|||
|
|
if (!batch) {
|
|||
|
|
return res.status(404).json({
|
|||
|
|
success: false,
|
|||
|
|
message: '批次不存在'
|
|||
|
|
});
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 获取批次中的牛只
|
|||
|
|
const { count, rows } = await IotCattle.findAndCountAll({
|
|||
|
|
include: [
|
|||
|
|
{
|
|||
|
|
model: CattleBatchAnimal,
|
|||
|
|
as: 'batchAnimals',
|
|||
|
|
where: { batchId: id },
|
|||
|
|
attributes: ['id', 'joinDate', 'notes']
|
|||
|
|
},
|
|||
|
|
{
|
|||
|
|
model: Farm,
|
|||
|
|
as: 'farm',
|
|||
|
|
attributes: ['id', 'name']
|
|||
|
|
}
|
|||
|
|
],
|
|||
|
|
attributes: ['id', 'earNumber', 'sex', 'strain', 'orgId'],
|
|||
|
|
limit: parseInt(pageSize),
|
|||
|
|
offset: offset,
|
|||
|
|
order: [['earNumber', 'ASC']]
|
|||
|
|
});
|
|||
|
|
|
|||
|
|
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 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();
|