461 lines
11 KiB
JavaScript
461 lines
11 KiB
JavaScript
const { Project, User } = require('../models');
|
|
const { Op } = require('sequelize');
|
|
|
|
// 获取项目列表
|
|
const getProjects = async (req, res) => {
|
|
try {
|
|
const {
|
|
page = 1,
|
|
limit = 10,
|
|
search = '',
|
|
status = '',
|
|
sortBy = 'createdAt',
|
|
sortOrder = 'DESC'
|
|
} = req.query;
|
|
|
|
const offset = (page - 1) * limit;
|
|
|
|
// 构建查询条件
|
|
const where = {};
|
|
|
|
// 搜索条件
|
|
if (search) {
|
|
where[Op.or] = [
|
|
{ name: { [Op.like]: `%${search}%` } },
|
|
{ farmName: { [Op.like]: `%${search}%` } },
|
|
{ loanOfficer: { [Op.like]: `%${search}%` } }
|
|
];
|
|
}
|
|
|
|
// 状态筛选
|
|
if (status) {
|
|
where.status = status;
|
|
}
|
|
|
|
// 查询项目列表
|
|
const { count, rows: projects } = await Project.findAndCountAll({
|
|
where,
|
|
include: [
|
|
{
|
|
model: User,
|
|
as: 'creator',
|
|
attributes: ['id', 'username', 'real_name']
|
|
},
|
|
{
|
|
model: User,
|
|
as: 'updater',
|
|
attributes: ['id', 'username', 'real_name']
|
|
}
|
|
],
|
|
order: [[sortBy, sortOrder.toUpperCase()]],
|
|
limit: parseInt(limit),
|
|
offset: parseInt(offset)
|
|
});
|
|
|
|
// 计算分页信息
|
|
const totalPages = Math.ceil(count / limit);
|
|
const hasNextPage = page < totalPages;
|
|
const hasPrevPage = page > 1;
|
|
|
|
res.json({
|
|
success: true,
|
|
data: {
|
|
projects,
|
|
pagination: {
|
|
current: parseInt(page),
|
|
pageSize: parseInt(limit),
|
|
total: count,
|
|
totalPages,
|
|
hasNextPage,
|
|
hasPrevPage
|
|
}
|
|
},
|
|
message: '获取项目列表成功'
|
|
});
|
|
} catch (error) {
|
|
console.error('获取项目列表失败:', error);
|
|
res.status(500).json({
|
|
success: false,
|
|
message: '获取项目列表失败',
|
|
error: process.env.NODE_ENV === 'development' ? error.message : undefined
|
|
});
|
|
}
|
|
};
|
|
|
|
// 获取项目详情
|
|
const getProjectById = async (req, res) => {
|
|
try {
|
|
const { id } = req.params;
|
|
|
|
const project = await Project.findByPk(id, {
|
|
include: [
|
|
{
|
|
model: User,
|
|
as: 'creator',
|
|
attributes: ['id', 'username', 'name']
|
|
},
|
|
{
|
|
model: User,
|
|
as: 'updater',
|
|
attributes: ['id', 'username', 'name']
|
|
}
|
|
]
|
|
});
|
|
|
|
if (!project) {
|
|
return res.status(404).json({
|
|
success: false,
|
|
message: '项目不存在'
|
|
});
|
|
}
|
|
|
|
res.json({
|
|
success: true,
|
|
data: project,
|
|
message: '获取项目详情成功'
|
|
});
|
|
} catch (error) {
|
|
console.error('获取项目详情失败:', error);
|
|
res.status(500).json({
|
|
success: false,
|
|
message: '获取项目详情失败',
|
|
error: process.env.NODE_ENV === 'development' ? error.message : undefined
|
|
});
|
|
}
|
|
};
|
|
|
|
// 创建项目
|
|
const createProject = async (req, res) => {
|
|
try {
|
|
const {
|
|
name,
|
|
status = 'supervision',
|
|
farmName,
|
|
supervisionObject,
|
|
supervisionQuantity = 0,
|
|
supervisionPeriod,
|
|
supervisionAmount = 0.00,
|
|
startTime,
|
|
endTime,
|
|
earTag = 0,
|
|
collar = 0,
|
|
host = 0,
|
|
loanOfficer,
|
|
description
|
|
} = req.body;
|
|
|
|
// 验证必填字段
|
|
const requiredFields = ['name', 'farmName', 'supervisionObject', 'supervisionPeriod', 'startTime', 'endTime'];
|
|
const missingFields = requiredFields.filter(field => !req.body[field]);
|
|
|
|
if (missingFields.length > 0) {
|
|
return res.status(400).json({
|
|
success: false,
|
|
message: `请填写所有必填字段: ${missingFields.join(', ')}`
|
|
});
|
|
}
|
|
|
|
// 验证字段长度
|
|
if (name.length > 100) {
|
|
return res.status(400).json({
|
|
success: false,
|
|
message: '项目名称不能超过100个字符'
|
|
});
|
|
}
|
|
|
|
if (farmName.length > 200) {
|
|
return res.status(400).json({
|
|
success: false,
|
|
message: '养殖场名称不能超过200个字符'
|
|
});
|
|
}
|
|
|
|
// 验证数值字段
|
|
if (supervisionQuantity < 0) {
|
|
return res.status(400).json({
|
|
success: false,
|
|
message: '监管数量不能为负数'
|
|
});
|
|
}
|
|
|
|
if (supervisionAmount < 0) {
|
|
return res.status(400).json({
|
|
success: false,
|
|
message: '监管金额不能为负数'
|
|
});
|
|
}
|
|
|
|
if (earTag < 0 || collar < 0 || host < 0) {
|
|
return res.status(400).json({
|
|
success: false,
|
|
message: '设备数量不能为负数'
|
|
});
|
|
}
|
|
|
|
// 验证状态
|
|
if (!['supervision', 'completed'].includes(status)) {
|
|
return res.status(400).json({
|
|
success: false,
|
|
message: '项目状态只能是 supervision 或 completed'
|
|
});
|
|
}
|
|
|
|
// 验证日期格式和逻辑
|
|
const startDate = new Date(startTime);
|
|
const endDate = new Date(endTime);
|
|
|
|
if (isNaN(startDate.getTime()) || isNaN(endDate.getTime())) {
|
|
return res.status(400).json({
|
|
success: false,
|
|
message: '日期格式不正确'
|
|
});
|
|
}
|
|
|
|
if (startDate >= endDate) {
|
|
return res.status(400).json({
|
|
success: false,
|
|
message: '结束时间必须晚于开始时间'
|
|
});
|
|
}
|
|
|
|
// 检查项目名称是否已存在
|
|
const existingProject = await Project.findOne({
|
|
where: { name }
|
|
});
|
|
|
|
if (existingProject) {
|
|
return res.status(400).json({
|
|
success: false,
|
|
message: '项目名称已存在,请使用其他名称'
|
|
});
|
|
}
|
|
|
|
// 创建项目
|
|
const project = await Project.create({
|
|
name,
|
|
status,
|
|
farmName,
|
|
supervisionObject,
|
|
supervisionQuantity: parseInt(supervisionQuantity),
|
|
supervisionPeriod,
|
|
supervisionAmount: parseFloat(supervisionAmount),
|
|
startTime,
|
|
endTime,
|
|
earTag: parseInt(earTag),
|
|
collar: parseInt(collar),
|
|
host: parseInt(host),
|
|
loanOfficer,
|
|
description,
|
|
createdBy: req.user?.userId || req.user?.id,
|
|
updatedBy: req.user?.userId || req.user?.id
|
|
});
|
|
|
|
// 获取创建的项目详情(包含关联信息)
|
|
const createdProject = await Project.findByPk(project.id, {
|
|
include: [
|
|
{
|
|
model: User,
|
|
as: 'creator',
|
|
attributes: ['id', 'username', 'real_name']
|
|
},
|
|
{
|
|
model: User,
|
|
as: 'updater',
|
|
attributes: ['id', 'username', 'real_name']
|
|
}
|
|
]
|
|
});
|
|
|
|
res.status(201).json({
|
|
success: true,
|
|
data: createdProject,
|
|
message: '创建项目成功'
|
|
});
|
|
} catch (error) {
|
|
console.error('创建项目失败:', error);
|
|
|
|
// 处理数据库约束错误
|
|
if (error.name === 'SequelizeValidationError') {
|
|
const validationErrors = error.errors.map(err => err.message).join(', ');
|
|
return res.status(400).json({
|
|
success: false,
|
|
message: `数据验证失败: ${validationErrors}`
|
|
});
|
|
}
|
|
|
|
if (error.name === 'SequelizeUniqueConstraintError') {
|
|
return res.status(400).json({
|
|
success: false,
|
|
message: '项目名称已存在,请使用其他名称'
|
|
});
|
|
}
|
|
|
|
res.status(500).json({
|
|
success: false,
|
|
message: '创建项目失败',
|
|
error: process.env.NODE_ENV === 'development' ? error.message : undefined
|
|
});
|
|
}
|
|
};
|
|
|
|
// 更新项目
|
|
const updateProject = async (req, res) => {
|
|
try {
|
|
const { id } = req.params;
|
|
const updateData = req.body;
|
|
|
|
// 验证日期
|
|
if (updateData.startTime && updateData.endTime) {
|
|
if (new Date(updateData.startTime) >= new Date(updateData.endTime)) {
|
|
return res.status(400).json({
|
|
success: false,
|
|
message: '结束时间必须晚于开始时间'
|
|
});
|
|
}
|
|
}
|
|
|
|
const project = await Project.findByPk(id);
|
|
if (!project) {
|
|
return res.status(404).json({
|
|
success: false,
|
|
message: '项目不存在'
|
|
});
|
|
}
|
|
|
|
// 更新项目
|
|
await project.update({
|
|
...updateData,
|
|
updatedBy: req.user?.id
|
|
});
|
|
|
|
res.json({
|
|
success: true,
|
|
data: project,
|
|
message: '更新项目成功'
|
|
});
|
|
} catch (error) {
|
|
console.error('更新项目失败:', error);
|
|
res.status(500).json({
|
|
success: false,
|
|
message: '更新项目失败',
|
|
error: process.env.NODE_ENV === 'development' ? error.message : undefined
|
|
});
|
|
}
|
|
};
|
|
|
|
// 删除项目
|
|
const deleteProject = async (req, res) => {
|
|
try {
|
|
const { id } = req.params;
|
|
|
|
const project = await Project.findByPk(id);
|
|
if (!project) {
|
|
return res.status(404).json({
|
|
success: false,
|
|
message: '项目不存在'
|
|
});
|
|
}
|
|
|
|
await project.destroy();
|
|
|
|
res.json({
|
|
success: true,
|
|
message: '删除项目成功'
|
|
});
|
|
} catch (error) {
|
|
console.error('删除项目失败:', error);
|
|
res.status(500).json({
|
|
success: false,
|
|
message: '删除项目失败',
|
|
error: process.env.NODE_ENV === 'development' ? error.message : undefined
|
|
});
|
|
}
|
|
};
|
|
|
|
// 获取项目统计
|
|
const getProjectStats = async (req, res) => {
|
|
try {
|
|
const totalProjects = await Project.count();
|
|
const supervisionProjects = await Project.count({ where: { status: 'supervision' } });
|
|
const completedProjects = await Project.count({ where: { status: 'completed' } });
|
|
|
|
// 计算总监管金额
|
|
const totalAmount = await Project.sum('supervisionAmount');
|
|
|
|
// 计算总监管数量
|
|
const totalQuantity = await Project.sum('supervisionQuantity');
|
|
|
|
res.json({
|
|
success: true,
|
|
data: {
|
|
total: totalProjects,
|
|
supervision: supervisionProjects,
|
|
completed: completedProjects,
|
|
totalAmount: totalAmount || 0,
|
|
totalQuantity: totalQuantity || 0
|
|
},
|
|
message: '获取项目统计成功'
|
|
});
|
|
} catch (error) {
|
|
console.error('获取项目统计失败:', error);
|
|
res.status(500).json({
|
|
success: false,
|
|
message: '获取项目统计失败',
|
|
error: process.env.NODE_ENV === 'development' ? error.message : undefined
|
|
});
|
|
}
|
|
};
|
|
|
|
// 批量更新项目状态
|
|
const batchUpdateStatus = async (req, res) => {
|
|
try {
|
|
const { projectIds, status } = req.body;
|
|
|
|
if (!projectIds || !Array.isArray(projectIds) || projectIds.length === 0) {
|
|
return res.status(400).json({
|
|
success: false,
|
|
message: '请选择要更新的项目'
|
|
});
|
|
}
|
|
|
|
if (!['supervision', 'completed'].includes(status)) {
|
|
return res.status(400).json({
|
|
success: false,
|
|
message: '无效的项目状态'
|
|
});
|
|
}
|
|
|
|
await Project.update(
|
|
{
|
|
status,
|
|
updatedBy: req.user?.id
|
|
},
|
|
{
|
|
where: { id: { [Op.in]: projectIds } }
|
|
}
|
|
);
|
|
|
|
res.json({
|
|
success: true,
|
|
message: `成功更新 ${projectIds.length} 个项目的状态`
|
|
});
|
|
} catch (error) {
|
|
console.error('批量更新项目状态失败:', error);
|
|
res.status(500).json({
|
|
success: false,
|
|
message: '批量更新项目状态失败',
|
|
error: process.env.NODE_ENV === 'development' ? error.message : undefined
|
|
});
|
|
}
|
|
};
|
|
|
|
module.exports = {
|
|
getProjects,
|
|
getProjectById,
|
|
createProject,
|
|
updateProject,
|
|
deleteProject,
|
|
getProjectStats,
|
|
batchUpdateStatus
|
|
};
|