修改小程序,前端,官网跳转路径

This commit is contained in:
2025-09-28 18:01:25 +08:00
parent e79e5bb086
commit c429672517
102 changed files with 8653 additions and 544 deletions

View File

@@ -50,6 +50,9 @@ app.use('/api/files', require('./routes/files'));
app.use('/api/government', require('./routes/government'));
app.use('/api/smart-earmark', require('./routes/smartEarmark'));
app.use('/api/smart-host', require('./routes/smartHost'));
app.use('/api/slaughter', require('./routes/slaughter'));
app.use('/api/harmless', require('./routes/harmless'));
app.use('/api/harmless-place', require('./routes/harmlessPlace'));
// 健康检查
app.get('/health', (req, res) => {

View File

@@ -0,0 +1,77 @@
// 清除模块缓存
function clearModuleCache() {
const modulesToClear = Object.keys(require.cache).filter(key =>
key.includes('HarmlessPlace') || key.includes('database') || key.includes('controller')
);
console.log('清除以下模块的缓存:', modulesToClear.length, '个模块');
modulesToClear.forEach(key => {
console.log('-', key);
delete require.cache[key];
});
}
// 清除缓存后再导入
clearModuleCache();
// 直接导入HarmlessPlace模型和控制器
const HarmlessPlace = require('./models/HarmlessPlace');
const harmlessPlaceController = require('./controllers/HarmlessPlaceController');
// 检查直接导入的HarmlessPlace模型
console.log('=== 直接导入的HarmlessPlace模型 ===');
console.log('类型:', typeof HarmlessPlace);
console.log('是否有findAndCountAll方法:', typeof HarmlessPlace.findAndCountAll !== 'undefined');
if (HarmlessPlace.findAndCountAll) {
console.log('findAndCountAll的类型:', typeof HarmlessPlace.findAndCountAll);
}
// 检查控制器中的getList函数
console.log('\n=== 检查控制器的getList函数 ===');
console.log('getList的类型:', typeof harmlessPlaceController.getList);
// 分析控制器中如何使用HarmlessPlace模型
// 我们需要查看控制器的源代码
const fs = require('fs');
const path = require('path');
console.log('\n=== 查看控制器的源代码 ===');
const controllerPath = path.join(__dirname, 'controllers', 'HarmlessPlaceController.js');
const controllerContent = fs.readFileSync(controllerPath, 'utf8');
// 查找导入语句
const importStatementMatch = controllerContent.match(/require\(['"]\.\.?\/models\/[^'"]+['"]\)/g);
console.log('控制器中的导入语句:', importStatementMatch || '未找到');
// 查找HarmlessPlace的使用
const harmlessPlaceUsage = controllerContent.match(/HarmlessPlace\.\w+/g);
console.log('控制器中HarmlessPlace的使用:', harmlessPlaceUsage || '未找到');
console.log('\n=== 检查控制器中实际使用的HarmlessPlace ===');
// 创建一个模拟的req和res对象
const mockReq = {
query: {
page: 1,
pageSize: 10
}
};
const mockRes = {
json: function(data) {
console.log('res.json被调用:', data);
},
status: function(code) {
console.log('res.status被调用:', code);
return this;
}
};
// 尝试从控制器中获取实际使用的HarmlessPlace模型
// 我们需要查看控制器的导入方式
const controllerModule = require('./controllers/HarmlessPlaceController');
// 如果控制器导出了其使用的模型,我们可以检查
// 但通常控制器不会导出这种依赖
console.log('控制器模块导出:', Object.keys(controllerModule));
console.log('\n所有检查完成');

View File

@@ -0,0 +1,18 @@
// 直接检查slaughter路由模块的导出内容
const slaughterRoutes = require('./routes/slaughter');
console.log('模块类型:', typeof slaughterRoutes);
console.log('是否为Express Router:', slaughterRoutes && slaughterRoutes.constructor && slaughterRoutes.constructor.name);
console.log('是否有stack属性:', 'stack' in slaughterRoutes);
if (slaughterRoutes && slaughterRoutes.stack) {
console.log('stack长度:', slaughterRoutes.stack.length);
slaughterRoutes.stack.forEach((layer, index) => {
console.log(`Layer ${index}:`, layer);
});
}
// 也检查另一个已知正常的路由模块比如auth.js
const authRoutes = require('./routes/auth');
console.log('\nauth路由模块类型:', typeof authRoutes);
console.log('auth路由模块构造函数:', authRoutes && authRoutes.constructor && authRoutes.constructor.name);

View File

@@ -0,0 +1,31 @@
// 测试HarmlessPlace模型的导出和方法
const HarmlessPlace = require('./models/HarmlessPlace');
const User = require('./models/User');
console.log('=== 检查HarmlessPlace模型 ===');
console.log('HarmlessPlace的类型:', typeof HarmlessPlace);
console.log('HarmlessPlace是否为对象:', typeof HarmlessPlace === 'object' && HarmlessPlace !== null);
console.log('HarmlessPlace是否有findAndCountAll方法:', typeof HarmlessPlace.findAndCountAll !== 'undefined');
if (HarmlessPlace.findAndCountAll) {
console.log('findAndCountAll的类型:', typeof HarmlessPlace.findAndCountAll);
}
console.log('\nHarmlessPlace对象的所有属性和方法:');
console.log(Object.keys(HarmlessPlace));
console.log('\n=== 检查User模型作为对比===');
console.log('User的类型:', typeof User);
console.log('User是否为对象:', typeof User === 'object' && User !== null);
console.log('User是否有findAndCountAll方法:', typeof User.findAndCountAll !== 'undefined');
if (User.findAndCountAll) {
console.log('findAndCountAll的类型:', typeof User.findAndCountAll);
}
console.log('\nUser对象的所有属性和方法:');
console.log(Object.keys(User));
// 检查是否存在循环引用或其他问题
console.log('\n=== 检查模型实例化 ===');
try {
console.log('尝试实例化HarmlessPlace:', new HarmlessPlace());
} catch (error) {
console.log('实例化HarmlessPlace错误:', error.message);
}

View File

@@ -38,7 +38,10 @@ async function testConnection() {
}
}
// 导出连接测试函数,但不自动执行
module.exports.testConnection = testConnection;
// 导出sequelize实例
const db = sequelize;
module.exports = sequelize;
// 再添加测试连接方法
db.testConnection = testConnection;
module.exports = db;

View File

@@ -4,6 +4,7 @@ const DB_NAME = process.env.DB_NAME || 'ningxia_zhengfu';
const DB_USER = process.env.DB_USER || 'root';
const DB_PASSWORD = process.env.DB_PASSWORD || 'aiotAiot123!';
const DB_DIALECT = process.env.DB_DIALECT || 'mysql';
// const DB_HOST = process.env.DB_HOST || '129.211.213.226';
module.exports = {
JWT_SECRET: 'your-secret-key-here', // 请在生产环境中替换为强密钥

View File

@@ -0,0 +1,199 @@
const { validationResult } = require('express-validator');
const { Op } = require('sequelize');
const HarmlessPlace = require('../models/HarmlessPlace');
// 获取无害化场所列表
exports.getList = async (req, res) => {
try {
const { page = 1, pageSize = 10, keyword = '', status = '' } = req.query;
const offset = (page - 1) * pageSize;
const where = {};
if (keyword) {
where[Op.or] = [
{ name: { [Op.like]: `%${keyword}%` } },
{ licenseNumber: { [Op.like]: `%${keyword}%` } }
];
}
if (status) {
where.status = status;
}
// 移除排序部分避免使用不存在的created_at字段
const result = await HarmlessPlace.findAndCountAll({
where,
attributes: ['id', 'name', 'address', 'contactPerson', 'contactPhone', 'licenseNumber', 'status'],
limit: parseInt(pageSize),
offset: parseInt(offset)
});
res.json({
code: 200,
message: '获取成功',
data: {
list: result.rows,
total: result.count
}
});
} catch (error) {
console.error('获取无害化场所列表失败:', error);
res.status(500).json({
code: 500,
message: '获取失败',
error: error.message
});
}
};
// 获取无害化场所详情
exports.getDetail = async (req, res) => {
try {
const { id } = req.params;
const place = await HarmlessPlace.findByPk(id);
if (!place) {
return res.status(404).json({
code: 404,
message: '无害化场所不存在'
});
}
res.json({
code: 200,
message: '获取成功',
data: place
});
} catch (error) {
console.error('获取无害化场所详情失败:', error);
res.status(500).json({
code: 500,
message: '获取失败',
error: error.message
});
}
};
// 创建无害化场所
exports.create = async (req, res) => {
try {
// 验证请求数据
const errors = validationResult(req);
if (!errors.isEmpty()) {
return res.status(400).json({
code: 400,
message: '参数错误',
errors: errors.array()
});
}
const { name, address, contactPerson, contactPhone, licenseNumber, status } = req.body;
// 创建无害化场所
const place = await HarmlessPlace.create({
name,
address,
contactPerson,
contactPhone,
licenseNumber,
status: status || '正常'
});
res.json({
code: 200,
message: '创建成功',
data: place
});
} catch (error) {
console.error('创建无害化场所失败:', error);
res.status(500).json({
code: 500,
message: '创建失败',
error: error.message
});
}
};
// 更新无害化场所
exports.update = async (req, res) => {
try {
// 验证请求数据
const errors = validationResult(req);
if (!errors.isEmpty()) {
return res.status(400).json({
code: 400,
message: '参数错误',
errors: errors.array()
});
}
const { id } = req.params;
const { name, address, contactPerson, contactPhone, licenseNumber, status } = req.body;
// 查找无害化场所
const place = await HarmlessPlace.findByPk(id);
if (!place) {
return res.status(404).json({
code: 404,
message: '无害化场所不存在'
});
}
// 更新无害化场所
await place.update({
name,
address,
contactPerson,
contactPhone,
licenseNumber,
status
});
res.json({
code: 200,
message: '更新成功',
data: place
});
} catch (error) {
console.error('更新无害化场所失败:', error);
res.status(500).json({
code: 500,
message: '更新失败',
error: error.message
});
}
};
// 删除无害化场所
exports.delete = async (req, res) => {
try {
const { id } = req.params;
// 查找无害化场所
const place = await HarmlessPlace.findByPk(id);
if (!place) {
return res.status(404).json({
code: 404,
message: '无害化场所不存在'
});
}
// 删除无害化场所
await place.destroy();
res.json({
code: 200,
message: '删除成功'
});
} catch (error) {
console.error('删除无害化场所失败:', error);
res.status(500).json({
code: 500,
message: '删除失败',
error: error.message
});
}
};

View File

@@ -0,0 +1,235 @@
const { validationResult } = require('express-validator');
const { Op } = require('sequelize');
const HarmlessRegistration = require('../models/HarmlessRegistration');
// 获取无害化登记列表
exports.getList = async (req, res) => {
try {
const { page = 1, pageSize = 10, keyword = '', startDate = '', endDate = '' } = req.query;
const offset = (page - 1) * pageSize;
const where = {};
if (keyword) {
where.registrationNumber = { [Op.like]: `%${keyword}%` };
}
if (startDate) {
where.processingDate = where.processingDate || {};
where.processingDate[Op.gte] = startDate;
}
if (endDate) {
where.processingDate = where.processingDate || {};
where.processingDate[Op.lte] = endDate;
}
const result = await HarmlessRegistration.findAndCountAll({
where,
limit: parseInt(pageSize),
offset: parseInt(offset),
order: [['createTime', 'DESC']]
});
res.json({
code: 200,
message: '获取成功',
data: {
list: result.rows,
total: result.count
}
});
} catch (error) {
console.error('获取无害化登记列表失败:', error);
res.status(500).json({
code: 500,
message: '获取失败',
error: error.message
});
}
};
// 获取无害化登记详情
exports.getDetail = async (req, res) => {
try {
const { id } = req.params;
const registration = await HarmlessRegistration.findByPk(id);
if (!registration) {
return res.status(404).json({
code: 404,
message: '无害化登记不存在'
});
}
res.json({
code: 200,
message: '获取成功',
data: registration
});
} catch (error) {
console.error('获取无害化登记详情失败:', error);
res.status(500).json({
code: 500,
message: '获取失败',
error: error.message
});
}
};
// 创建无害化登记
exports.create = async (req, res) => {
try {
// 验证请求参数
const errors = validationResult(req);
if (!errors.isEmpty()) {
return res.status(400).json({
code: 400,
message: '参数验证失败',
errors: errors.array()
});
}
const { registrationNumber, animalType, quantity, reason,
processingMethod, processingPlace, processingDate, registrant, status } = req.body;
// 检查登记编号是否已存在
const existingRegistration = await HarmlessRegistration.findOne({
where: { registrationNumber }
});
if (existingRegistration) {
return res.status(400).json({
code: 400,
message: '登记编号已存在'
});
}
const registration = await HarmlessRegistration.create({
registrationNumber,
animalType,
quantity: parseInt(quantity),
reason,
processingMethod,
processingPlace,
processingDate,
registrant,
status: status || '待处理',
createTime: new Date(),
updateTime: new Date()
});
res.json({
code: 200,
message: '创建成功',
data: registration
});
} catch (error) {
console.error('创建无害化登记失败:', error);
res.status(500).json({
code: 500,
message: '创建失败',
error: error.message
});
}
};
// 更新无害化登记
exports.update = async (req, res) => {
try {
const { id } = req.params;
const errors = validationResult(req);
if (!errors.isEmpty()) {
return res.status(400).json({
code: 400,
message: '参数验证失败',
errors: errors.array()
});
}
const registration = await HarmlessRegistration.findByPk(id);
if (!registration) {
return res.status(404).json({
code: 404,
message: '无害化登记不存在'
});
}
const { registrationNumber, animalType, quantity, reason,
processingMethod, processingPlace, processingDate, registrant, status } = req.body;
// 检查登记编号是否已被其他记录使用
if (registrationNumber && registrationNumber !== registration.registrationNumber) {
const existingRegistration = await HarmlessRegistration.findOne({
where: {
registrationNumber,
id: { [Op.ne]: id }
}
});
if (existingRegistration) {
return res.status(400).json({
code: 400,
message: '登记编号已存在'
});
}
}
await registration.update({
registrationNumber: registrationNumber || registration.registrationNumber,
animalType: animalType || registration.animalType,
quantity: quantity !== undefined ? parseInt(quantity) : registration.quantity,
reason: reason || registration.reason,
processingMethod: processingMethod || registration.processingMethod,
processingPlace: processingPlace || registration.processingPlace,
processingDate: processingDate || registration.processingDate,
registrant: registrant || registration.registrant,
status: status !== undefined ? status : registration.status,
updateTime: new Date()
});
res.json({
code: 200,
message: '更新成功',
data: registration
});
} catch (error) {
console.error('更新无害化登记失败:', error);
res.status(500).json({
code: 500,
message: '更新失败',
error: error.message
});
}
};
// 删除无害化登记
exports.delete = async (req, res) => {
try {
const { id } = req.params;
const registration = await HarmlessRegistration.findByPk(id);
if (!registration) {
return res.status(404).json({
code: 404,
message: '无害化登记不存在'
});
}
await registration.destroy();
res.json({
code: 200,
message: '删除成功'
});
} catch (error) {
console.error('删除无害化登记失败:', error);
res.status(500).json({
code: 500,
message: '删除失败',
error: error.message
});
}
};

View File

@@ -0,0 +1,268 @@
const { Op } = require('sequelize');
const Slaughterhouse = require('../models/Slaughterhouse');
// 查询屠宰场列表
exports.getSlaughterhouses = async (req, res) => {
try {
const { keyword, status, page = 1, pageSize = 10 } = req.query;
const where = {};
if (keyword) {
where[Op.or] = [
{ name: { [Op.like]: `%${keyword}%` } },
{ contactPerson: { [Op.like]: `%${keyword}%` } },
{ contactPhone: { [Op.like]: `%${keyword}%` } },
{ licenseNumber: { [Op.like]: `%${keyword}%` } }
];
}
if (status) {
where.status = status;
}
const { count, rows } = await Slaughterhouse.findAndCountAll({
where,
offset: (page - 1) * pageSize,
limit: parseInt(pageSize),
order: [['created_at', 'DESC']]
});
res.json({
code: 200,
data: {
list: rows,
total: count,
page: parseInt(page),
pageSize: parseInt(pageSize)
},
message: '查询成功'
});
} catch (error) {
console.error('查询屠宰场列表失败:', error);
res.status(500).json({
code: 500,
message: '服务器内部错误'
});
}
};
// 查询单个屠宰场详情
exports.getSlaughterhouseById = async (req, res) => {
try {
const { id } = req.params;
const slaughterhouse = await Slaughterhouse.findByPk(id);
if (!slaughterhouse) {
return res.status(404).json({
code: 404,
message: '屠宰场不存在'
});
}
res.json({
code: 200,
data: slaughterhouse,
message: '查询成功'
});
} catch (error) {
console.error('查询屠宰场详情失败:', error);
res.status(500).json({
code: 500,
message: '服务器内部错误'
});
}
};
// 新增屠宰场
exports.createSlaughterhouse = async (req, res) => {
try {
const { name, address, contactPerson, contactPhone, licenseNumber, status } = req.body;
// 检查名称是否重复
const existingSlaughterhouse = await Slaughterhouse.findOne({
where: { name }
});
if (existingSlaughterhouse) {
return res.status(400).json({
code: 400,
message: '该屠宰场名称已存在'
});
}
// 检查许可证号是否重复
const existingLicense = await Slaughterhouse.findOne({
where: { licenseNumber }
});
if (existingLicense) {
return res.status(400).json({
code: 400,
message: '该许可证号已存在'
});
}
const slaughterhouse = await Slaughterhouse.create({
name,
address,
contactPerson,
contactPhone,
licenseNumber,
status,
createTime: new Date(),
created_by: req.user?.id || null,
updated_by: req.user?.id || null
});
res.json({
code: 201,
data: slaughterhouse,
message: '新增成功'
});
} catch (error) {
console.error('新增屠宰场失败:', error);
res.status(500).json({
code: 500,
message: '服务器内部错误'
});
}
};
// 更新屠宰场
exports.updateSlaughterhouse = async (req, res) => {
try {
const { id } = req.params;
const { name, address, contactPerson, contactPhone, licenseNumber, status } = req.body;
const slaughterhouse = await Slaughterhouse.findByPk(id);
if (!slaughterhouse) {
return res.status(404).json({
code: 404,
message: '屠宰场不存在'
});
}
// 检查名称是否重复(排除当前屠宰场)
if (name && name !== slaughterhouse.name) {
const existingSlaughterhouse = await Slaughterhouse.findOne({
where: {
name,
id: { [Op.ne]: id }
}
});
if (existingSlaughterhouse) {
return res.status(400).json({
code: 400,
message: '该屠宰场名称已存在'
});
}
}
// 检查许可证号是否重复(排除当前屠宰场)
if (licenseNumber && licenseNumber !== slaughterhouse.licenseNumber) {
const existingLicense = await Slaughterhouse.findOne({
where: {
licenseNumber,
id: { [Op.ne]: id }
}
});
if (existingLicense) {
return res.status(400).json({
code: 400,
message: '该许可证号已存在'
});
}
}
await slaughterhouse.update({
name,
address,
contactPerson,
contactPhone,
licenseNumber,
status,
updated_by: req.user?.id || null
});
res.json({
code: 200,
data: slaughterhouse,
message: '更新成功'
});
} catch (error) {
console.error('更新屠宰场失败:', error);
res.status(500).json({
code: 500,
message: '服务器内部错误'
});
}
};
// 删除屠宰场
exports.deleteSlaughterhouse = async (req, res) => {
try {
const { id } = req.params;
const slaughterhouse = await Slaughterhouse.findByPk(id);
if (!slaughterhouse) {
return res.status(404).json({
code: 404,
message: '屠宰场不存在'
});
}
await slaughterhouse.destroy();
res.json({
code: 200,
message: '删除成功'
});
} catch (error) {
console.error('删除屠宰场失败:', error);
res.status(500).json({
code: 500,
message: '服务器内部错误'
});
}
};
// 切换屠宰场状态
exports.toggleSlaughterhouseStatus = async (req, res) => {
try {
const { id } = req.params;
const slaughterhouse = await Slaughterhouse.findByPk(id);
if (!slaughterhouse) {
return res.status(404).json({
code: 404,
message: '屠宰场不存在'
});
}
const newStatus = slaughterhouse.status === 'active' ? 'inactive' : 'active';
await slaughterhouse.update({
status: newStatus,
updated_by: req.user?.id || null
});
res.json({
code: 200,
data: slaughterhouse,
message: '状态切换成功'
});
} catch (error) {
console.error('切换屠宰场状态失败:', error);
res.status(500).json({
code: 500,
message: '服务器内部错误'
});
}
};

View File

@@ -1,5 +1,5 @@
const EpidemicAgency = require('../models/EpidemicAgency');
const { Op } = require('sequelize');
const EpidemicAgency = require('../models/EpidemicAgency');
// 查询防疫机构列表
exports.getEpidemicAgencies = async (req, res) => {
@@ -28,7 +28,7 @@ exports.getEpidemicAgencies = async (req, res) => {
where,
offset: (page - 1) * pageSize,
limit: parseInt(pageSize),
order: [['created_at', 'DESC']]
attributes: ['id', 'name', 'director', 'phone', 'address', 'email', 'type', 'status', 'establishmentDate', 'epidemicScope', 'description']
});
res.json({
@@ -81,7 +81,7 @@ exports.getEpidemicAgencyById = async (req, res) => {
// 新增防疫机构
exports.createEpidemicAgency = async (req, res) => {
try {
const { name, director, phone, address, email, type, status, establishmentDate, description } = req.body;
const { name, director, phone, address, email, type, status, establishmentDate, epidemicScope, description } = req.body;
const existingAgency = await EpidemicAgency.findOne({
where: { name }
@@ -103,6 +103,7 @@ exports.createEpidemicAgency = async (req, res) => {
type,
status,
establishmentDate,
epidemicScope,
description,
created_by: req.user?.id || null,
updated_by: req.user?.id || null
@@ -126,7 +127,7 @@ exports.createEpidemicAgency = async (req, res) => {
exports.updateEpidemicAgency = async (req, res) => {
try {
const { id } = req.params;
const { name, director, phone, address, email, type, status, establishmentDate, description } = req.body;
const { name, director, phone, address, email, type, status, establishmentDate, epidemicScope, description } = req.body;
const agency = await EpidemicAgency.findByPk(id);
@@ -163,6 +164,7 @@ exports.updateEpidemicAgency = async (req, res) => {
type,
status,
establishmentDate,
epidemicScope,
description,
updated_by: req.user?.id || null
});

View File

@@ -1,7 +1,5 @@
const { promisify } = require('util');
const jwt = require('jsonwebtoken');
const db = require('../config/database');
const util = require('util');
const User = require('../models/User');
// JWT配置
const JWT_SECRET = process.env.JWT_SECRET || 'your-secret-key-change-in-production';
@@ -22,7 +20,7 @@ module.exports = async (req, res, next) => {
if (token.startsWith('mock-jwt-token-')) {
// 模拟用户数据,避免数据库查询
req.user = {
id: '1',
id: 1,
username: 'admin',
role: 'admin'
};
@@ -31,15 +29,18 @@ module.exports = async (req, res, next) => {
}
// 验证token
const decoded = await util.promisify(jwt.verify)(token, JWT_SECRET);
const decoded = jwt.verify(token, JWT_SECRET);
// 检查用户是否存在
const [user] = await db.query(
'SELECT id, username, role FROM users WHERE id = ?',
[decoded.id]
);
// 使用Sequelize模型检查用户是否存在
const user = await User.findOne({
where: {
id: decoded.id,
status: 'active'
},
attributes: ['id', 'username', 'role']
});
if (!user || user.length === 0) {
if (!user) {
return res.status(401).json({
code: 401,
message: '用户不存在或已被删除'
@@ -47,7 +48,7 @@ module.exports = async (req, res, next) => {
}
// 将用户信息添加到请求对象
req.user = user[0];
req.user = user;
next();
} catch (err) {
console.error(err);

View File

@@ -1,5 +1,5 @@
const sequelize = require('../config/database');
const { DataTypes } = require('sequelize');
const sequelize = require('../config/database.js');
const EpidemicAgency = sequelize.define('EpidemicAgency', {
id: {
@@ -49,6 +49,11 @@ const EpidemicAgency = sequelize.define('EpidemicAgency', {
allowNull: false,
comment: '成立日期'
},
epidemicScope: {
type: DataTypes.TEXT,
allowNull: true,
comment: '防疫范围'
},
description: {
type: DataTypes.TEXT,
allowNull: true,

View File

@@ -0,0 +1,67 @@
const sequelize = require('../config/database');
const { DataTypes } = require('sequelize');
const HarmlessPlace = sequelize.define('HarmlessPlace', {
id: {
type: DataTypes.UUID,
defaultValue: DataTypes.UUIDV4,
primaryKey: true,
allowNull: false
},
name: {
type: DataTypes.STRING(100),
allowNull: false,
comment: '场所名称'
},
address: {
type: DataTypes.STRING(255),
allowNull: false,
comment: '地址'
},
contactPerson: {
type: DataTypes.STRING(50),
allowNull: false,
comment: '联系人'
},
contactPhone: {
type: DataTypes.STRING(20),
allowNull: false,
comment: '联系电话'
},
licenseNumber: {
type: DataTypes.STRING(50),
allowNull: false,
unique: true,
comment: '许可证号'
},
status: {
type: DataTypes.ENUM('正常', '维护中', '停用'),
allowNull: false,
defaultValue: '正常',
comment: '状态'
}
}, {
tableName: 'government_harmless_places',
timestamps: true,
createdAt: 'created_at',
updatedAt: 'updated_at',
paranoid: false,
indexes: [
{
name: 'idx_name',
fields: ['name']
},
{
name: 'idx_status',
fields: ['status']
},
{
name: 'idx_license_number',
fields: ['licenseNumber'],
unique: true
}
],
comment: '无害化场所管理表'
});
module.exports = HarmlessPlace;

View File

@@ -0,0 +1,85 @@
const { DataTypes, Sequelize } = require('sequelize');
module.exports = (sequelize) => {
const HarmlessRegistration = sequelize.define('HarmlessRegistration', {
id: {
type: DataTypes.UUID,
defaultValue: DataTypes.UUIDV4,
primaryKey: true,
allowNull: false
},
registrationNumber: {
type: DataTypes.STRING(50),
allowNull: false,
unique: true,
comment: '登记编号'
},
animalType: {
type: DataTypes.STRING(50),
allowNull: false,
comment: '动物类型'
},
quantity: {
type: DataTypes.INTEGER,
allowNull: false,
comment: '数量',
validate: {
min: 1
}
},
reason: {
type: DataTypes.TEXT,
allowNull: false,
comment: '无害化处理原因'
},
processingMethod: {
type: DataTypes.STRING(100),
allowNull: false,
comment: '处理方式'
},
processingPlace: {
type: DataTypes.STRING(100),
allowNull: false,
comment: '处理场所'
},
processingDate: {
type: DataTypes.DATEONLY,
allowNull: false,
comment: '处理日期'
},
registrant: {
type: DataTypes.STRING(50),
allowNull: false,
comment: '登记人'
},
status: {
type: DataTypes.ENUM('待处理', '处理中', '已完成', '已取消'),
allowNull: false,
defaultValue: '待处理',
comment: '状态'
},
createTime: {
type: DataTypes.DATE,
defaultValue: Sequelize.fn('NOW'),
allowNull: false,
comment: '创建时间'
},
updateTime: {
type: DataTypes.DATE,
defaultValue: Sequelize.fn('NOW'),
allowNull: false,
comment: '更新时间'
}
}, {
tableName: 'government_harmless_registrations',
timestamps: false,
indexes: [
{ name: 'idx_registrationNumber', fields: ['registrationNumber'] },
{ name: 'idx_status', fields: ['status'] },
{ name: 'idx_processingDate', fields: ['processingDate'] }
],
comment: '无害化登记管理表'
});
return HarmlessRegistration;
};

View File

@@ -0,0 +1,78 @@
// 导入sequelize
const sequelize = require('../config/database');
const { DataTypes } = require('sequelize');
// 屠宰场数据模型
const Slaughterhouse = sequelize.define('Slaughterhouse', {
id: {
type: DataTypes.INTEGER,
primaryKey: true,
autoIncrement: true,
comment: '屠宰场ID'
},
name: {
type: DataTypes.STRING(100),
allowNull: false,
unique: true,
comment: '屠宰场名称'
},
address: {
type: DataTypes.STRING(255),
allowNull: false,
comment: '地址'
},
contactPerson: {
field: 'contactPerson',
type: DataTypes.STRING,
allowNull: true,
comment: '联系人'
},
contactPhone: {
field: 'contactPhone',
type: DataTypes.STRING,
allowNull: true,
comment: '联系电话'
},
licenseNumber: {
field: 'licenseNumber',
type: DataTypes.STRING,
allowNull: true,
comment: '许可证号'
},
status: {
type: DataTypes.ENUM('active', 'inactive'),
allowNull: false,
defaultValue: 'active',
comment: '状态active: 正常, inactive: 停用)'
},
createTime: {
field: 'createTime',
type: DataTypes.DATE,
allowNull: false,
defaultValue: DataTypes.NOW,
comment: '创建时间'
},
created_by: {
type: DataTypes.INTEGER,
allowNull: true,
comment: '创建人ID'
},
updated_by: {
type: DataTypes.INTEGER,
allowNull: true,
comment: '更新人ID'
}
}, {
tableName: 'government_slaughterhouses',
timestamps: true,
createdAt: 'created_at',
updatedAt: 'updated_at',
paranoid: false,
indexes: [
{ name: 'idx_name', fields: ['name'] },
{ name: 'idx_licenseNumber', fields: ['licenseNumber'] },
{ name: 'idx_status', fields: ['status'] }
]
});
module.exports = Slaughterhouse;

View File

@@ -0,0 +1,100 @@
/**
* 政府后端模型索引文件
* @file index.js
* @description 导出所有模型并建立关联关系
*/
const { sequelize } = require('../config/database');
// 导入所有模型
const User = require('./User');
const AdminStaff = require('./AdminStaff');
const Department = require('./Department');
const Position = require('./Position');
const Farmer = require('./Farmer');
const HarmlessPlace = require('./HarmlessPlace');
const HarmlessRegistration = require('./HarmlessRegistration');
const Material = require('./Material');
const Slaughterhouse = require('./Slaughterhouse');
const EpidemicAgency = require('./EpidemicAgency');
const SmartCollar = require('./SmartCollar');
const SmartEarmark = require('./SmartEarmark');
const SmartHost = require('./SmartHost');
const WarehouseTransaction = require('./WarehouseTransaction');
// 初始化所有模型
const initModels = () => {
try {
// 处理直接导出的模型
if (User && typeof User !== 'function') {
// User模型已经直接导出不需要额外处理
}
// 处理需要sequelize参数的模型
const modelsToInit = [
AdminStaff,
Department,
Position,
Farmer,
HarmlessPlace,
HarmlessRegistration,
Material,
Slaughterhouse,
EpidemicAgency,
SmartCollar,
SmartEarmark,
SmartHost,
WarehouseTransaction
];
// 初始化模型
modelsToInit.forEach(modelFactory => {
if (typeof modelFactory === 'function') {
// 调用函数获取模型实例
const model = modelFactory(sequelize);
// 将初始化后的模型赋值回原来的变量
Object.assign(module.exports, { [model.name]: model });
}
});
console.log('✅ 所有政府后端模型初始化完成');
} catch (error) {
console.error('❌ 政府后端模型初始化失败:', error);
}
};
// 初始化模型
initModels();
// 导出sequelize和所有模型
module.exports = {
sequelize,
User,
AdminStaff,
Department,
Position,
Farmer,
HarmlessPlace,
HarmlessRegistration,
Material,
Slaughterhouse,
EpidemicAgency,
SmartCollar,
SmartEarmark,
SmartHost,
WarehouseTransaction
};
// 同步所有模型到数据库(可选)
const syncModels = async (options = {}) => {
try {
await sequelize.sync(options);
console.log('✅ 政府后端所有模型已同步到数据库');
return true;
} catch (error) {
console.error('❌ 政府后端模型同步失败:', error);
return false;
}
};
// 添加syncModels到导出
module.exports.syncModels = syncModels;

View File

@@ -13,6 +13,7 @@
"cors": "^2.8.5",
"dotenv": "^16.3.1",
"express": "^4.18.2",
"express-validator": "^7.2.1",
"helmet": "^7.1.0",
"jsonwebtoken": "^9.0.2",
"morgan": "^1.10.0",
@@ -567,6 +568,28 @@
"url": "https://opencollective.com/express"
}
},
"node_modules/express-validator": {
"version": "7.2.1",
"resolved": "https://registry.npmmirror.com/express-validator/-/express-validator-7.2.1.tgz",
"integrity": "sha512-CjNE6aakfpuwGaHQZ3m8ltCG2Qvivd7RHtVMS/6nVxOM7xVGqr4bhflsm4+N5FP5zI7Zxp+Hae+9RE+o8e3ZOQ==",
"license": "MIT",
"dependencies": {
"lodash": "^4.17.21",
"validator": "~13.12.0"
},
"engines": {
"node": ">= 8.0.0"
}
},
"node_modules/express-validator/node_modules/validator": {
"version": "13.12.0",
"resolved": "https://registry.npmmirror.com/validator/-/validator-13.12.0.tgz",
"integrity": "sha512-c1Q0mCiPlgdTVVVIJIrBuxNicYE+t/7oKeI9MWLj3fh/uq2Pxh/3eeWbVZ4OcGW1TUf53At0njHw5SMdA3tmMg==",
"license": "MIT",
"engines": {
"node": ">= 0.10"
}
},
"node_modules/fill-range": {
"version": "7.1.1",
"resolved": "https://registry.npmmirror.com/fill-range/-/fill-range-7.1.1.tgz",

View File

@@ -13,6 +13,7 @@
"cors": "^2.8.5",
"dotenv": "^16.3.1",
"express": "^4.18.2",
"express-validator": "^7.2.1",
"helmet": "^7.1.0",
"jsonwebtoken": "^9.0.2",
"morgan": "^1.10.0",

View File

@@ -0,0 +1,44 @@
const express = require('express');
const router = express.Router();
const { body } = require('express-validator');
const harmlessRegistrationController = require('../controllers/HarmlessRegistrationController');
const authMiddleware = require('../middleware/auth');
// 应用身份验证中间件
router.use(authMiddleware);
// 获取无害化登记列表
router.get('/list', harmlessRegistrationController.getList);
// 获取无害化登记详情
router.get('/detail/:id', harmlessRegistrationController.getDetail);
// 创建无害化登记
router.post('/create', [
body('registrationNumber').notEmpty().withMessage('登记编号不能为空'),
body('animalType').notEmpty().withMessage('动物类型不能为空'),
body('quantity').isInt({ min: 1 }).withMessage('数量必须大于0'),
body('reason').notEmpty().withMessage('原因不能为空'),
body('processingMethod').notEmpty().withMessage('处理方式不能为空'),
body('processingPlace').notEmpty().withMessage('处理场所不能为空'),
body('processingDate').notEmpty().withMessage('处理日期不能为空'),
body('registrant').notEmpty().withMessage('登记人不能为空')
], harmlessRegistrationController.create);
// 更新无害化登记
router.put('/update/:id', [
body('registrationNumber').optional().notEmpty().withMessage('登记编号不能为空'),
body('animalType').optional().notEmpty().withMessage('动物类型不能为空'),
body('quantity').optional().isInt({ min: 1 }).withMessage('数量必须大于0'),
body('reason').optional().notEmpty().withMessage('原因不能为空'),
body('processingMethod').optional().notEmpty().withMessage('处理方式不能为空'),
body('processingPlace').optional().notEmpty().withMessage('处理场所不能为空'),
body('processingDate').optional().notEmpty().withMessage('处理日期不能为空'),
body('registrant').optional().notEmpty().withMessage('登记人不能为空'),
body('status').optional().isIn(['待处理', '处理中', '已完成', '已取消']).withMessage('状态必须是待处理、处理中、已完成或已取消')
], harmlessRegistrationController.update);
// 删除无害化登记
router.delete('/delete/:id', harmlessRegistrationController.delete);
module.exports = router;

View File

@@ -0,0 +1,38 @@
const express = require('express');
const router = express.Router();
const { body } = require('express-validator');
const harmlessPlaceController = require('../controllers/HarmlessPlaceController');
const authMiddleware = require('../middleware/auth');
// 应用身份验证中间件
router.use(authMiddleware);
// 获取无害化场所列表
router.get('/list', harmlessPlaceController.getList);
// 获取无害化场所详情
router.get('/detail/:id', harmlessPlaceController.getDetail);
// 创建无害化场所
router.post('/create', [
body('name').notEmpty().withMessage('场所名称不能为空'),
body('address').notEmpty().withMessage('地址不能为空'),
body('contactPerson').notEmpty().withMessage('联系人不能为空'),
body('contactPhone').notEmpty().withMessage('联系电话不能为空'),
body('licenseNumber').notEmpty().withMessage('许可证号不能为空')
], harmlessPlaceController.create);
// 更新无害化场所
router.put('/update/:id', [
body('name').optional().notEmpty().withMessage('场所名称不能为空'),
body('address').optional().notEmpty().withMessage('地址不能为空'),
body('contactPerson').optional().notEmpty().withMessage('联系人不能为空'),
body('contactPhone').optional().notEmpty().withMessage('联系电话不能为空'),
body('licenseNumber').optional().notEmpty().withMessage('许可证号不能为空'),
body('status').optional().isIn(['正常', '维护中', '停用']).withMessage('状态必须是正常、维护中或停用')
], harmlessPlaceController.update);
// 删除无害化场所
router.delete('/delete/:id', harmlessPlaceController.delete);
module.exports = router;

View File

@@ -0,0 +1,17 @@
const express = require('express');
const router = express.Router();
const slaughterhouseController = require('../controllers/SlaughterhouseController');
const authMiddleware = require('../middleware/auth');
// 应用认证中间件
router.use(authMiddleware);
// 屠宰场管理路由
router.get('/slaughterhouses', slaughterhouseController.getSlaughterhouses);
router.get('/slaughterhouses/:id', slaughterhouseController.getSlaughterhouseById);
router.post('/slaughterhouses', slaughterhouseController.createSlaughterhouse);
router.put('/slaughterhouses/:id', slaughterhouseController.updateSlaughterhouse);
router.delete('/slaughterhouses/:id', slaughterhouseController.deleteSlaughterhouse);
router.patch('/slaughterhouses/:id/status', slaughterhouseController.toggleSlaughterhouseStatus);
module.exports = router;

View File

@@ -0,0 +1,13 @@
const express = require('express');
const router = express.Router();
// 简单的测试路由
router.get('/test', (req, res) => {
res.json({
code: 200,
message: '测试路由工作正常',
timestamp: new Date()
});
});
module.exports = router;

View File

@@ -0,0 +1,150 @@
const mysql = require('mysql2/promise');
const createSlaughterhouseTable = async () => {
let connection = null;
try {
// 创建数据库连接
connection = await mysql.createConnection({
host: '129.211.213.226',
port: 9527,
user: 'root',
password: 'aiotAiot123!',
database: 'ningxia_zhengfu',
charset: 'utf8mb4'
});
console.log('数据库连接成功');
// SQL语句数组
const sqlStatements = [
// 删除旧表(如果存在)
'DROP TABLE IF EXISTS government_slaughterhouses;',
// 创建新表
`CREATE TABLE government_slaughterhouses (
id INT AUTO_INCREMENT PRIMARY KEY COMMENT '屠宰场ID',
name VARCHAR(100) NOT NULL UNIQUE COMMENT '屠宰场名称',
address VARCHAR(255) NOT NULL COMMENT '地址',
contactPerson VARCHAR(50) NOT NULL COMMENT '联系人',
contactPhone VARCHAR(20) NOT NULL COMMENT '联系电话',
licenseNumber VARCHAR(50) NOT NULL UNIQUE COMMENT '许可证号',
status ENUM('active', 'inactive') NOT NULL DEFAULT 'active' COMMENT '状态active: 正常, inactive: 停用)',
createTime DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
created_by INT NULL COMMENT '创建人ID',
updated_by INT NULL COMMENT '更新人ID',
created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
updated_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
deleted_at DATETIME NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='政府系统屠宰场表';`,
// 添加索引
'CREATE INDEX idx_name ON government_slaughterhouses (name);',
'CREATE INDEX idx_licenseNumber ON government_slaughterhouses (licenseNumber);',
'CREATE INDEX idx_status ON government_slaughterhouses (status);'
];
// 执行表创建相关SQL
for (const sql of sqlStatements) {
await connection.execute(sql);
console.log(`执行SQL成功: ${sql.substring(0, 50)}...`);
}
// 准备测试数据(使用参数化查询避免字符编码问题)
const testData = [
[
'宁夏银川市第一屠宰场',
'宁夏回族自治区银川市金凤区良田镇植物园路',
'张明',
'13800138001',
'SC1234567890123',
'active',
'2023-01-15 00:00:00',
1,
1
],
[
'宁夏石嘴山市肉类加工厂',
'宁夏回族自治区石嘴山市大武口区星海镇',
'李强',
'13900139002',
'SC1234567890124',
'active',
'2023-02-10 00:00:00',
1,
1
],
[
'宁夏吴忠市清真屠宰场',
'宁夏回族自治区吴忠市利通区金银滩镇',
'王芳',
'13700137003',
'SC1234567890125',
'active',
'2023-03-05 00:00:00',
1,
1
],
[
'宁夏固原市牲畜屠宰场',
'宁夏回族自治区固原市原州区官厅镇',
'赵伟',
'13600136004',
'SC1234567890126',
'inactive',
'2023-04-20 00:00:00',
1,
1
],
[
'宁夏中卫市肉类屠宰加工中心',
'宁夏回族自治区中卫市沙坡头区迎水桥镇',
'陈静',
'13500135005',
'SC1234567890127',
'active',
'2023-05-15 00:00:00',
1,
1
]
];
// 插入测试数据
const insertSql = `
INSERT INTO government_slaughterhouses (
name,
address,
contactPerson,
contactPhone,
licenseNumber,
status,
createTime,
created_by,
updated_by
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)
`;
let insertedCount = 0;
for (const data of testData) {
await connection.execute(insertSql, data);
insertedCount++;
console.log(`插入测试数据成功: ${data[0]}`);
}
// 查询插入的记录数
const [result] = await connection.execute('SELECT COUNT(*) AS total_records FROM government_slaughterhouses;');
console.log(`
成功创建屠宰场表并插入 ${result[0].total_records} 条测试数据!`);
} catch (error) {
console.error('创建屠宰场表或插入测试数据失败:', error);
} finally {
// 关闭数据库连接
if (connection) {
await connection.end();
console.log('数据库连接已关闭');
}
}
};
// 执行函数
createSlaughterhouseTable();

View File

@@ -0,0 +1,98 @@
-- 直接使用SQL创建屠宰场表并添加测试数据
USE ningxia_zhengfu;
-- 删除旧表(如果存在)
DROP TABLE IF EXISTS government_slaughterhouses;
-- 创建新表,指定字符集支持中文
CREATE TABLE government_slaughterhouses (
id INT AUTO_INCREMENT PRIMARY KEY COMMENT '屠宰场ID',
name VARCHAR(100) NOT NULL UNIQUE COMMENT '屠宰场名称',
address VARCHAR(255) NOT NULL COMMENT '地址',
contactPerson VARCHAR(50) NOT NULL COMMENT '联系人',
contactPhone VARCHAR(20) NOT NULL COMMENT '联系电话',
licenseNumber VARCHAR(50) NOT NULL UNIQUE COMMENT '许可证号',
status ENUM('active', 'inactive') NOT NULL DEFAULT 'active' COMMENT '状态active: 正常, inactive: 停用)',
createTime DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
created_by INT NULL COMMENT '创建人ID',
updated_by INT NULL COMMENT '更新人ID',
created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
updated_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
deleted_at DATETIME NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='政府系统屠宰场表';
-- 添加索引
CREATE INDEX idx_name ON government_slaughterhouses (name);
CREATE INDEX idx_licenseNumber ON government_slaughterhouses (licenseNumber);
CREATE INDEX idx_status ON government_slaughterhouses (status);
-- 插入测试数据
INSERT INTO government_slaughterhouses (
name,
address,
contactPerson,
contactPhone,
licenseNumber,
status,
createTime,
created_by,
updated_by
) VALUES
(
'宁夏银川市第一屠宰场',
'宁夏回族自治区银川市金凤区良田镇植物园路',
'张明',
'13800138001',
'SC1234567890123',
'active',
'2023-01-15 00:00:00',
1,
1
),
(
'宁夏石嘴山市肉类加工厂',
'宁夏回族自治区石嘴山市大武口区星海镇',
'李强',
'13900139002',
'SC1234567890124',
'active',
'2023-02-10 00:00:00',
1,
1
),
(
'宁夏吴忠市清真屠宰场',
'宁夏回族自治区吴忠市利通区金银滩镇',
'王芳',
'13700137003',
'SC1234567890125',
'active',
'2023-03-05 00:00:00',
1,
1
),
(
'宁夏固原市牲畜屠宰场',
'宁夏回族自治区固原市原州区官厅镇',
'赵伟',
'13600136004',
'SC1234567890126',
'inactive',
'2023-04-20 00:00:00',
1,
1
),
(
'宁夏中卫市肉类屠宰加工中心',
'宁夏回族自治区中卫市沙坡头区迎水桥镇',
'陈静',
'13500135005',
'SC1234567890127',
'active',
'2023-05-15 00:00:00',
1,
1
);
-- 查询插入的记录数
SELECT COUNT(*) AS total_records FROM government_slaughterhouses;

View File

@@ -1,4 +1,4 @@
const sequelize = require('../config/database');
const sequelize = require('../config/database.js');
const EpidemicAgency = require('../models/EpidemicAgency');
async function initEpidemicAgencyTable() {
@@ -33,6 +33,7 @@ async function initEpidemicAgencyTable() {
type: 'center',
status: 'active',
establishmentDate: '2010-01-15',
epidemicScope: '负责全市所有区域的动物防疫工作统筹管理和技术指导',
description: '负责全市动物防疫工作的统筹管理和技术指导'
},
{
@@ -44,6 +45,7 @@ async function initEpidemicAgencyTable() {
type: 'branch',
status: 'active',
establishmentDate: '2012-05-20',
epidemicScope: '负责东区所有街道、乡镇的动物防疫工作',
description: '负责东区范围内的动物防疫工作'
},
{
@@ -55,6 +57,7 @@ async function initEpidemicAgencyTable() {
type: 'branch',
status: 'active',
establishmentDate: '2013-03-10',
epidemicScope: '负责西区所有街道、乡镇的动物防疫工作',
description: '负责西区范围内的动物防疫工作'
},
{
@@ -66,6 +69,7 @@ async function initEpidemicAgencyTable() {
type: 'branch',
status: 'active',
establishmentDate: '2014-07-05',
epidemicScope: '负责北区所有街道、乡镇的动物防疫工作',
description: '负责北区范围内的动物防疫工作'
},
{
@@ -77,6 +81,7 @@ async function initEpidemicAgencyTable() {
type: 'branch',
status: 'active',
establishmentDate: '2015-02-28',
epidemicScope: '负责南区所有街道、乡镇的动物防疫工作',
description: '负责南区范围内的动物防疫工作'
},
{
@@ -88,6 +93,7 @@ async function initEpidemicAgencyTable() {
type: 'mobile',
status: 'active',
establishmentDate: '2016-09-15',
epidemicScope: '负责全市偏远地区、山区及突发事件的动物防疫工作',
description: '负责偏远地区和突发事件的动物防疫工作'
}
];

View File

@@ -0,0 +1,115 @@
const config = require('../config/index');
const mysql = require('mysql2/promise');
// 初始化无害化场所表
async function initHarmlessPlaceTable() {
let connection = null;
try {
// 创建数据库连接
console.log('测试数据库连接...');
connection = await mysql.createConnection({
host: config.DB_CONFIG.host,
port: config.DB_CONFIG.port,
user: config.DB_CONFIG.user,
password: config.DB_CONFIG.password,
database: config.DB_CONFIG.database
});
console.log('数据库连接成功');
// 检查表是否存在
console.log('检查无害化场所表是否存在...');
const [tables] = await connection.execute(
"SHOW TABLES LIKE 'government_harmless_places'"
);
// 如果表存在,删除它
if (tables.length > 0) {
console.log('无害化场所表已存在,删除它...');
await connection.execute('DROP TABLE government_harmless_places');
console.log('无害化场所表删除成功');
}
// 创建无害化场所表
console.log('创建无害化场所表...');
await connection.execute(`
CREATE TABLE government_harmless_places (
id VARCHAR(36) PRIMARY KEY NOT NULL,
name VARCHAR(100) NOT NULL COMMENT '场所名称',
address VARCHAR(255) NOT NULL COMMENT '地址',
contact_person VARCHAR(50) NOT NULL COMMENT '联系人',
contact_phone VARCHAR(20) NOT NULL COMMENT '联系电话',
license_number VARCHAR(50) NOT NULL UNIQUE COMMENT '许可证号',
status ENUM('正常', '维护中', '停用') NOT NULL DEFAULT '正常' COMMENT '状态',
create_time DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
update_time DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
INDEX idx_name (name),
INDEX idx_license_number (license_number),
INDEX idx_status (status)
) COMMENT '无害化场所管理表'
`);
console.log('无害化场所表创建成功!');
// 添加测试数据
console.log('开始添加测试数据...');
const testData = [
[
'1', '银川市无害化处理中心', '宁夏银川市金凤区科技园路88号',
'张经理', '13895112345', 'HP20240001', '正常',
'2024-06-01 10:00:00', '2024-06-01 10:00:00'
],
[
'2', '石嘴山市无害化处理站', '宁夏石嘴山市大武口区环保路56号',
'李站长', '13995123456', 'HP20240002', '正常',
'2024-06-02 11:30:00', '2024-06-02 11:30:00'
],
[
'3', '吴忠市无害化处理厂', '宁夏吴忠市利通区产业路34号',
'王厂长', '13795134567', 'HP20240003', '维护中',
'2024-06-03 09:15:00', '2024-06-10 14:20:00'
],
[
'4', '固原市无害化处理中心', '宁夏固原市原州区生态路12号',
'赵主任', '13695145678', 'HP20240004', '正常',
'2024-06-04 14:45:00', '2024-06-04 14:45:00'
],
[
'5', '中卫市无害化处理站', '宁夏中卫市沙坡头区环卫路23号',
'孙主任', '13595156789', 'HP20240005', '停用',
'2024-06-05 16:20:00', '2024-06-15 09:30:00'
]
];
// 批量插入数据
for (const row of testData) {
await connection.execute(
`INSERT INTO government_harmless_places
(id, name, address, contact_person, contact_phone, license_number, status, create_time, update_time)
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)`,
row
);
}
console.log('测试数据添加成功!');
console.log('无害化场所表初始化完成!');
} catch (error) {
console.error('初始化无害化场所表失败:', error);
throw error;
} finally {
// 关闭数据库连接
if (connection) {
await connection.end();
console.log('数据库连接已关闭');
}
}
}
// 执行初始化
if (require.main === module) {
initHarmlessPlaceTable().catch(err => {
console.error('程序执行失败:', err);
process.exit(1);
});
}
module.exports = initHarmlessPlaceTable;

View File

@@ -0,0 +1,110 @@
const config = require('../config');
const mysql = require('mysql2/promise');
// 初始化无害化登记表
async function initHarmlessRegistrationTable() {
let connection = null;
try {
// 创建数据库连接
console.log('测试数据库连接...');
connection = await mysql.createConnection({
host: config.DB_CONFIG.host,
port: config.DB_CONFIG.port,
user: config.DB_CONFIG.user,
password: config.DB_CONFIG.password,
database: config.DB_CONFIG.database
});
console.log('数据库连接成功');
// 检查表是否存在
console.log('检查无害化登记表是否存在...');
const [tables] = await connection.execute(
"SHOW TABLES LIKE 'government_harmless_registrations'"
);
// 如果表存在,删除它
if (tables.length > 0) {
console.log('无害化登记表已存在,删除它...');
await connection.execute('DROP TABLE government_harmless_registrations');
console.log('无害化登记表删除成功');
}
// 创建无害化登记表
console.log('创建无害化登记表...');
await connection.execute(`
CREATE TABLE government_harmless_registrations (
id VARCHAR(36) PRIMARY KEY NOT NULL,
registrationNumber VARCHAR(50) NOT NULL UNIQUE COMMENT '登记编号',
animalType VARCHAR(50) NOT NULL COMMENT '动物类型',
quantity INT NOT NULL COMMENT '数量',
reason TEXT NOT NULL COMMENT '无害化处理原因',
processingMethod VARCHAR(100) NOT NULL COMMENT '处理方式',
processingPlace VARCHAR(100) NOT NULL COMMENT '处理场所',
processingDate DATE NOT NULL COMMENT '处理日期',
registrant VARCHAR(50) NOT NULL COMMENT '登记人',
status ENUM('待处理', '处理中', '已完成', '已取消') NOT NULL DEFAULT '待处理' COMMENT '状态',
createTime DATETIME NOT NULL COMMENT '创建时间',
updateTime DATETIME NOT NULL COMMENT '更新时间',
INDEX idx_registrationNumber (registrationNumber),
INDEX idx_status (status),
INDEX idx_processingDate (processingDate)
) COMMENT '无害化登记管理表'
`);
console.log('无害化登记表创建成功!');
// 添加测试数据
console.log('开始添加测试数据...');
const testData = [
[
'1', 'WH20240601001', '牛', 5, '疾病死亡', '焚烧处理',
'银川市无害化处理中心', '2024-06-01', '张兽医', '已完成',
'2024-06-01 08:30:00', '2024-06-02 14:20:00'
],
[
'2', 'WH20240602002', '羊', 10, '自然灾害', '深埋处理',
'中卫市无害化处理中心', '2024-06-02', '李技术员', '处理中',
'2024-06-02 09:15:00', '2024-06-02 16:45:00'
],
[
'3', 'WH20240603003', '猪', 8, '检疫不合格', '化制处理',
'吴忠市无害化处理中心', '2024-06-03', '王检疫员', '待处理',
'2024-06-03 10:00:00', '2024-06-03 10:00:00'
],
[
'4', 'WH20240604004', '牛', 3, '意外死亡', '焚烧处理',
'石嘴山市无害化处理中心', '2024-06-04', '赵管理员', '已取消',
'2024-06-04 11:20:00', '2024-06-04 15:30:00'
],
[
'5', 'WH20240605005', '羊', 12, '疫情防控', '深埋处理',
'固原市无害化处理中心', '2024-06-05', '陈兽医', '已完成',
'2024-06-05 09:45:00', '2024-06-06 11:15:00'
]
];
// 批量插入数据
for (const row of testData) {
await connection.execute(
`INSERT INTO government_harmless_registrations
(id, registrationNumber, animalType, quantity, reason, processingMethod,
processingPlace, processingDate, registrant, status, createTime, updateTime)
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`,
row
);
}
console.log('测试数据添加成功!添加了', testData.length, '条数据。');
} catch (error) {
console.error('初始化无害化登记表失败:', error);
} finally {
// 关闭数据库连接
if (connection) {
await connection.close();
}
}
}
// 执行初始化
initHarmlessRegistrationTable();

View File

@@ -0,0 +1,92 @@
const sequelize = require('../config/database');
const Slaughterhouse = require('../models/Slaughterhouse');
// 初始化屠宰场表并添加测试数据
const initSlaughterhouseData = async () => {
try {
// 先删除旧表,再重新创建
await Slaughterhouse.drop().catch(() => console.log('旧表不存在,跳过删除'));
await sequelize.sync({ force: true });
console.log('数据库同步成功,表已重新创建');
// 检查是否已有数据
const existingCount = await Slaughterhouse.count();
if (existingCount > 0) {
console.log(`已存在 ${existingCount} 条屠宰场数据,跳过初始化`);
return;
}
// 准备测试数据
const testData = [
{
name: '宁夏银川市第一屠宰场',
address: '宁夏回族自治区银川市金凤区良田镇植物园路',
contactPerson: '张明',
contactPhone: '13800138001',
licenseNumber: 'SC1234567890123',
status: 'active',
createTime: new Date('2023-01-15'),
created_by: 1,
updated_by: 1
},
{
name: '宁夏石嘴山市肉类加工厂',
address: '宁夏回族自治区石嘴山市大武口区星海镇',
contactPerson: '李强',
contactPhone: '13900139002',
licenseNumber: 'SC1234567890124',
status: 'active',
createTime: new Date('2023-02-10'),
created_by: 1,
updated_by: 1
},
{
name: '宁夏吴忠市清真屠宰场',
address: '宁夏回族自治区吴忠市利通区金银滩镇',
contactPerson: '王芳',
contactPhone: '13700137003',
licenseNumber: 'SC1234567890125',
status: 'active',
createTime: new Date('2023-03-05'),
created_by: 1,
updated_by: 1
},
{
name: '宁夏固原市牲畜屠宰场',
address: '宁夏回族自治区固原市原州区官厅镇',
contactPerson: '赵伟',
contactPhone: '13600136004',
licenseNumber: 'SC1234567890126',
status: 'inactive',
createTime: new Date('2023-04-20'),
created_by: 1,
updated_by: 1
},
{
name: '宁夏中卫市肉类屠宰加工中心',
address: '宁夏回族自治区中卫市沙坡头区迎水桥镇',
contactPerson: '陈静',
contactPhone: '13500135005',
licenseNumber: 'SC1234567890127',
status: 'active',
createTime: new Date('2023-05-15'),
created_by: 1,
updated_by: 1
}
];
// 批量创建测试数据
const createdSlaughterhouses = await Slaughterhouse.bulkCreate(testData);
console.log(`成功创建 ${createdSlaughterhouses.length} 条屠宰场测试数据`);
} catch (error) {
console.error('初始化屠宰场数据失败:', error);
} finally {
// 关闭数据库连接
await sequelize.close();
console.log('数据库连接已关闭');
}
};
// 执行初始化函数
initSlaughterhouseData();

View File

@@ -0,0 +1,24 @@
// 简洁地检查路由模块的基本信息
const express = require('express');
const slaughterRoutes = require('./routes/slaughter');
const authRoutes = require('./routes/auth');
console.log('=== slaughter路由模块 ===');
console.log('类型:', typeof slaughterRoutes);
console.log('构造函数:', slaughterRoutes && slaughterRoutes.constructor && slaughterRoutes.constructor.name);
console.log('是否有stack:', 'stack' in slaughterRoutes);
console.log('是否有get方法:', 'get' in slaughterRoutes);
console.log('\n=== auth路由模块 ===');
console.log('类型:', typeof authRoutes);
console.log('构造函数:', authRoutes && authRoutes.constructor && authRoutes.constructor.name);
console.log('是否有stack:', 'stack' in authRoutes);
console.log('是否有get方法:', 'get' in authRoutes);
// 创建一个新的Router实例进行比较
const newRouter = express.Router();
console.log('\n=== 新创建的Router实例 ===');
console.log('类型:', typeof newRouter);
console.log('构造函数:', newRouter && newRouter.constructor && newRouter.constructor.name);
console.log('是否有stack:', 'stack' in newRouter);
console.log('是否有get方法:', 'get' in newRouter);

View File

@@ -0,0 +1,103 @@
// 清除指定模块的缓存
function clearModuleCache() {
const modulesToClear = Object.keys(require.cache).filter(key =>
key.includes('HarmlessPlace') || key.includes('database') || key.includes('controller')
);
console.log('清除以下模块的缓存:', modulesToClear.length, '个模块');
modulesToClear.forEach(key => {
console.log('-', key);
delete require.cache[key];
});
}
// 模拟服务器启动过程
async function simulateServerStartup() {
try {
// 1. 首先清除模块缓存
clearModuleCache();
// 2. 记录加载顺序
console.log('\n=== 开始模拟服务器启动过程 ===');
// 3. 先加载数据库配置 - 注意这里使用正确的路径
console.log('\n1. 加载数据库配置...');
const sequelize = require('./config/database');
console.log('数据库实例加载完成');
console.log('sequelize的类型:', typeof sequelize);
// 4. 测试数据库连接
console.log('\n2. 测试数据库连接...');
try {
await sequelize.authenticate();
console.log('数据库连接成功');
} catch (error) {
console.error('数据库连接失败:', error.message);
}
// 5. 加载HarmlessPlace模型
console.log('\n3. 加载HarmlessPlace模型...');
const HarmlessPlace = require('./models/HarmlessPlace');
console.log('HarmlessPlace模型加载完成');
console.log('HarmlessPlace的类型:', typeof HarmlessPlace);
console.log('HarmlessPlace是否有findAndCountAll方法:', typeof HarmlessPlace.findAndCountAll !== 'undefined');
if (HarmlessPlace.findAndCountAll) {
console.log('findAndCountAll的类型:', typeof HarmlessPlace.findAndCountAll);
}
// 6. 尝试调用findAndCountAll方法
console.log('\n4. 尝试调用findAndCountAll方法...');
try {
const result = await HarmlessPlace.findAndCountAll({
limit: 10,
offset: 0
});
console.log('findAndCountAll调用成功结果:', result);
} catch (error) {
console.error('findAndCountAll调用失败:', error.message);
}
// 7. 加载控制器
console.log('\n5. 加载HarmlessPlaceController控制器...');
const harmlessPlaceController = require('./controllers/HarmlessPlaceController');
console.log('控制器加载完成');
// 8. 创建模拟的req和res对象
const mockReq = {
query: {
page: 1,
pageSize: 10
}
};
const mockRes = {
json: function(data) {
console.log('res.json被调用:', data);
},
status: function(code) {
console.log('res.status被调用:', code);
return this;
}
};
// 9. 尝试调用控制器的getList方法
console.log('\n6. 尝试调用控制器的getList方法...');
try {
await harmlessPlaceController.getList(mockReq, mockRes);
console.log('控制器getList方法调用成功');
} catch (error) {
console.error('控制器getList方法调用失败:', error.message);
console.error('错误堆栈:', error.stack);
}
console.log('\n=== 服务器启动模拟完成 ===');
} catch (error) {
console.error('模拟服务器启动过程中发生错误:', error.message);
console.error('错误堆栈:', error.stack);
}
}
// 运行模拟
console.log('开始执行服务器启动模拟测试...');
simulateServerStartup().catch(err => console.error('测试过程中出错:', err));

View File

@@ -0,0 +1,27 @@
const http = require('http');
const options = {
hostname: 'localhost',
port: 5352,
path: '/api/slaughter/slaughterhouses',
method: 'GET',
headers: {
'Authorization': 'Bearer mock-jwt-token-test',
'Content-Type': 'application/json'
}
};
const req = http.request(options, (res) => {
console.log(`状态码: ${res.statusCode}`);
console.log(`响应头: ${JSON.stringify(res.headers)}`);
res.on('data', (d) => {
process.stdout.write(d);
});
});
req.on('error', (error) => {
console.error(error);
});
req.end();

View File

@@ -0,0 +1,84 @@
const http = require('http');
// 测试函数
function testRoute(path, description) {
return new Promise((resolve, reject) => {
const options = {
hostname: 'localhost',
port: 5353,
path: path,
method: 'GET',
headers: {
'Authorization': 'Bearer mock-jwt-token-test',
'Content-Type': 'application/json'
}
};
const req = http.request(options, (res) => {
let data = '';
res.on('data', (chunk) => {
data += chunk;
});
res.on('end', () => {
resolve({
path: path,
description: description,
statusCode: res.statusCode,
headers: res.headers,
body: data
});
});
});
req.on('error', (error) => {
reject({
path: path,
description: description,
error: error.message
});
});
req.end();
});
}
// 运行所有测试
async function runTests() {
console.log('开始测试路由...\n');
try {
// 测试健康检查路由
const healthResult = await testRoute('/health', '健康检查');
console.log(`${healthResult.description} - 状态码: ${healthResult.statusCode}`);
console.log(`响应: ${healthResult.body}\n`);
// 测试测试路由
const testResult = await testRoute('/api/test/test', '测试路由');
console.log(`${testResult.description} - 状态码: ${testResult.statusCode}`);
console.log(`响应: ${testResult.body}\n`);
// 测试slaughter路由
const slaughterResult = await testRoute('/api/slaughter/slaughterhouses', 'Slaughter路由');
console.log(`${slaughterResult.description} - 状态码: ${slaughterResult.statusCode}`);
console.log(`响应: ${slaughterResult.body}\n`);
// 测试不存在的路由
const notFoundResult = await testRoute('/api/not-exist', '不存在的路由');
console.log(`${notFoundResult.description} - 状态码: ${notFoundResult.statusCode}`);
console.log(`响应: ${notFoundResult.body}\n`);
} catch (error) {
console.error('测试失败:', error);
}
}
// 等待一会儿再运行测试,给服务器启动时间
sleep(2000).then(() => {
runTests();
});
// 简单的sleep函数
function sleep(ms) {
return new Promise(resolve => setTimeout(resolve, ms));
}

View File

@@ -0,0 +1,95 @@
// 测试无害化场所API
const axios = require('axios');
// 政府后端服务地址
const BASE_URL = 'http://localhost:5352/api';
// 登录获取token
async function login() {
try {
console.log('开始登录...');
const response = await axios.post(`${BASE_URL}/auth/login`, {
username: 'admin',
password: '123456'
});
console.log('登录响应:', response.data);
if (response.data.code === 200 && response.data.data && response.data.data.token) {
console.log('登录成功获取到token');
return response.data.data.token;
} else {
console.log('登录失败未获取到token');
console.log('错误信息:', response.data.message || '未知错误');
return null;
}
} catch (error) {
console.error('登录请求失败:', error.message);
if (error.response) {
console.error('错误状态码:', error.response.status);
console.error('错误数据:', error.response.data);
}
return null;
}
}
// 测试无害化场所列表API
async function testHarmlessPlaceList(token) {
try {
console.log('\n测试无害化场所列表API...');
const response = await axios.get(`${BASE_URL}/harmless-place/list`, {
headers: {
'Authorization': `Bearer ${token}`
},
params: {
page: 1,
pageSize: 10
}
});
console.log('API调用成功状态码:', response.status);
console.log('返回数据结构:', Object.keys(response.data));
console.log('无害化场所总数:', response.data.total || '未知');
if (response.data.data && Array.isArray(response.data.data)) {
console.log('返回的无害化场所列表长度:', response.data.data.length);
if (response.data.data.length > 0) {
console.log('第一条无害化场所数据:');
console.log(response.data.data[0]);
}
}
return response.data;
} catch (error) {
console.error('无害化场所列表API调用失败:', error.message);
if (error.response) {
console.error('错误状态码:', error.response.status);
console.error('错误数据:', error.response.data);
}
return null;
}
}
// 主测试函数
const runTests = async () => {
console.log('开始测试无害化场所管理API...');
try {
// 1. 登录获取token
const token = await login();
if (!token) {
console.error('无法继续测试因为未获取到有效的token');
return;
}
// 2. 测试获取无害化场所列表
await testHarmlessPlaceList(token);
console.log('\n所有测试完成');
} catch (error) {
console.error('测试过程中发生错误:', error);
}
};
// 运行测试
runTests();

View File

@@ -0,0 +1,89 @@
// 清除模块缓存
function clearModuleCache() {
const modulesToClear = Object.keys(require.cache).filter(key =>
key.includes('HarmlessPlace') || key.includes('database')
);
console.log('清除以下模块的缓存:', modulesToClear.length, '个模块');
modulesToClear.forEach(key => {
console.log('-', key);
delete require.cache[key];
});
}
// 清除缓存后再导入
clearModuleCache();
const axios = require('axios');
const HarmlessPlace = require('./models/HarmlessPlace');
console.log('=== 检查HarmlessPlace模型 ===');
console.log('HarmlessPlace的类型:', typeof HarmlessPlace);
console.log('HarmlessPlace是否为对象:', typeof HarmlessPlace === 'object' && HarmlessPlace !== null);
console.log('HarmlessPlace是否有findAndCountAll方法:', typeof HarmlessPlace.findAndCountAll !== 'undefined');
if (HarmlessPlace.findAndCountAll) {
console.log('findAndCountAll的类型:', typeof HarmlessPlace.findAndCountAll);
}
// 登录函数
async function login() {
try {
const response = await axios.post('http://localhost:3000/api/auth/login', {
username: 'admin',
password: '123456'
});
console.log('登录成功token:', response.data.data.token);
return response.data.data.token;
} catch (error) {
console.error('登录失败:', error.response ? error.response.data : error.message);
return null;
}
}
// 测试无害化场所列表API
async function testHarmlessPlaceList(token) {
try {
const response = await axios.get('http://localhost:3000/api/harmless-place/list', {
headers: {
'Authorization': `Bearer ${token}`
},
params: {
page: 1,
pageSize: 10
}
});
console.log('无害化场所列表API调用成功:', response.data);
return response.data;
} catch (error) {
console.error('无害化场所列表API调用失败:', error.message);
if (error.response) {
console.error('错误数据:', error.response.data);
}
return null;
}
}
// 主函数
async function main() {
console.log('开始测试无害化场所管理API...');
// 登录获取token
const token = await login();
if (!token) {
console.log('登录失败,无法继续测试');
return;
}
// 再次检查模型类型确保在API调用前没有被修改
console.log('\n=== API调用前再次检查HarmlessPlace模型 ===');
console.log('HarmlessPlace的类型:', typeof HarmlessPlace);
console.log('HarmlessPlace是否有findAndCountAll方法:', typeof HarmlessPlace.findAndCountAll !== 'undefined');
// 测试API
await testHarmlessPlaceList(token);
console.log('\n所有测试完成');
}
// 运行测试
main().catch(err => console.error('测试过程中出错:', err));

View File

@@ -0,0 +1,51 @@
// 测试Express应用的路由注册情况
const express = require('express');
const path = require('path');
// 创建一个简单的Express应用来测试路由
const app = express();
// 尝试加载slaughter路由
try {
const slaughterRoutes = require('./routes/slaughter');
console.log('成功加载slaughter路由模块');
// 检查路由模块的内容
console.log('路由模块导出:', typeof slaughterRoutes);
// 模拟注册路由
app.use('/api/slaughter', slaughterRoutes);
console.log('成功注册slaughter路由到/api/slaughter');
// 检查路由是否有方法
if (slaughterRoutes && slaughterRoutes.stack) {
console.log('路由处理程序数量:', slaughterRoutes.stack.length);
slaughterRoutes.stack.forEach((layer, index) => {
if (layer.route) {
console.log(`路由${index + 1}:`, layer.route.path, Object.keys(layer.route.methods));
}
});
} else {
console.log('路由模块没有stack属性可能不是Express Router实例');
}
} catch (error) {
console.error('加载slaughter路由失败:', error);
}
// 检查routes目录下的文件
const fs = require('fs');
const routesDir = path.join(__dirname, 'routes');
fs.readdir(routesDir, (err, files) => {
if (err) {
console.error('读取routes目录失败:', err);
return;
}
console.log('\nroutes目录下的文件:');
files.forEach(file => {
console.log('-', file);
// 检查文件大小,确认文件不为空
const stats = fs.statSync(path.join(routesDir, file));
console.log(` 大小: ${stats.size} 字节`);
});
});

View File

@@ -0,0 +1,44 @@
const express = require('express');
const cors = require('cors');
const bodyParser = require('body-parser');
const app = express();
// 中间件
app.use(cors());
app.use(bodyParser.json());
// 简单的认证中间件,允许所有请求通过
app.use((req, res, next) => {
console.log(`接收到请求: ${req.method} ${req.path}`);
// 模拟用户数据
req.user = {
id: '1',
username: 'admin',
role: 'admin'
};
next();
});
// 加载测试路由
app.use('/api/test', require('./routes/test-route'));
// 加载slaughter路由
app.use('/api/slaughter', require('./routes/slaughter'));
// 简单的健康检查路由
app.get('/health', (req, res) => {
res.json({ status: 'ok' });
});
// 错误处理
app.use((err, req, res, next) => {
console.error('错误:', err);
res.status(500).json({ error: '服务器错误' });
});
// 启动服务器在不同端口
const PORT = 5353;
app.listen(PORT, () => {
console.log(`测试服务器已启动在端口 ${PORT}`);
});