修改政府端前端,银行端小程序和后端接口

This commit is contained in:
2025-09-26 17:52:50 +08:00
parent 852adbcfff
commit 00dfa83fd1
237 changed files with 9172 additions and 33500 deletions

View File

@@ -40,13 +40,16 @@ app.use('/api/auth', require('./routes/auth'));
app.use('/api/supervision', require('./routes/supervision'));
app.use('/api/approval', require('./routes/approval'));
app.use('/api/personnel', require('./routes/personnel'));
app.use('/api/warehouse', require('./routes/warehouse'));
// 暂时注释掉warehouse路由因为在智能项圈页面不使用且有500错误
// app.use('/api/warehouse', require('./routes/warehouse'));
app.use('/api/epidemic', require('./routes/epidemic'));
app.use('/api/service', require('./routes/service'));
app.use('/api/visualization', require('./routes/visualization'));
app.use('/api/system', require('./routes/system'));
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.get('/health', (req, res) => {

View File

@@ -1,9 +1,9 @@
const DB_DIALECT = process.env.DB_DIALECT || 'mysql';
const DB_HOST = process.env.DB_HOST || '129.211.213.226';
const DB_PORT = process.env.DB_PORT || 9527;
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';
module.exports = {
JWT_SECRET: 'your-secret-key-here', // 请在生产环境中替换为强密钥

View File

@@ -0,0 +1,246 @@
const EpidemicAgency = require('../models/EpidemicAgency');
const { Op } = require('sequelize');
// 查询防疫机构列表
exports.getEpidemicAgencies = async (req, res) => {
try {
const { keyword, status, type, page = 1, pageSize = 10 } = req.query;
const where = {};
if (keyword) {
where[Op.or] = [
{ name: { [Op.like]: `%${keyword}%` } },
{ director: { [Op.like]: `%${keyword}%` } },
{ phone: { [Op.like]: `%${keyword}%` } }
];
}
if (status) {
where.status = status;
}
if (type) {
where.type = type;
}
const { count, rows } = await EpidemicAgency.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.getEpidemicAgencyById = async (req, res) => {
try {
const { id } = req.params;
const agency = await EpidemicAgency.findByPk(id);
if (!agency) {
return res.status(404).json({
code: 404,
message: '防疫机构不存在'
});
}
res.json({
code: 200,
data: agency,
message: '查询成功'
});
} catch (error) {
console.error('查询防疫机构详情失败:', error);
res.status(500).json({
code: 500,
message: '服务器内部错误'
});
}
};
// 新增防疫机构
exports.createEpidemicAgency = async (req, res) => {
try {
const { name, director, phone, address, email, type, status, establishmentDate, description } = req.body;
const existingAgency = await EpidemicAgency.findOne({
where: { name }
});
if (existingAgency) {
return res.status(400).json({
code: 400,
message: '该机构名称已存在'
});
}
const agency = await EpidemicAgency.create({
name,
director,
phone,
address,
email,
type,
status,
establishmentDate,
description,
created_by: req.user?.id || null,
updated_by: req.user?.id || null
});
res.json({
code: 201,
data: agency,
message: '新增成功'
});
} catch (error) {
console.error('新增防疫机构失败:', error);
res.status(500).json({
code: 500,
message: '服务器内部错误'
});
}
};
// 更新防疫机构
exports.updateEpidemicAgency = async (req, res) => {
try {
const { id } = req.params;
const { name, director, phone, address, email, type, status, establishmentDate, description } = req.body;
const agency = await EpidemicAgency.findByPk(id);
if (!agency) {
return res.status(404).json({
code: 404,
message: '防疫机构不存在'
});
}
// 检查名称是否重复(排除当前机构)
if (name && name !== agency.name) {
const existingAgency = await EpidemicAgency.findOne({
where: {
name,
id: { [Op.ne]: id }
}
});
if (existingAgency) {
return res.status(400).json({
code: 400,
message: '该机构名称已存在'
});
}
}
await agency.update({
name,
director,
phone,
address,
email,
type,
status,
establishmentDate,
description,
updated_by: req.user?.id || null
});
res.json({
code: 200,
data: agency,
message: '更新成功'
});
} catch (error) {
console.error('更新防疫机构失败:', error);
res.status(500).json({
code: 500,
message: '服务器内部错误'
});
}
};
// 删除防疫机构
exports.deleteEpidemicAgency = async (req, res) => {
try {
const { id } = req.params;
const agency = await EpidemicAgency.findByPk(id);
if (!agency) {
return res.status(404).json({
code: 404,
message: '防疫机构不存在'
});
}
await agency.destroy();
res.json({
code: 200,
message: '删除成功'
});
} catch (error) {
console.error('删除防疫机构失败:', error);
res.status(500).json({
code: 500,
message: '服务器内部错误'
});
}
};
// 切换防疫机构状态
exports.toggleEpidemicAgencyStatus = async (req, res) => {
try {
const { id } = req.params;
const agency = await EpidemicAgency.findByPk(id);
if (!agency) {
return res.status(404).json({
code: 404,
message: '防疫机构不存在'
});
}
const newStatus = agency.status === 'active' ? 'inactive' : 'active';
await agency.update({
status: newStatus,
updated_by: req.user?.id || null
});
res.json({
code: 200,
data: agency,
message: '状态切换成功'
});
} catch (error) {
console.error('切换防疫机构状态失败:', error);
res.status(500).json({
code: 500,
message: '服务器内部错误'
});
}
};

View File

@@ -0,0 +1,214 @@
const { Op } = require('sequelize');
const SmartCollar = require('../models/SmartCollar');
// 获取智能项圈列表
const getSmartCollars = async (req, res) => {
try {
const { page = 1, pageSize = 10, collarId = '', status = '' } = req.query;
const whereCondition = {};
// 项圈编号搜索
if (collarId) {
whereCondition.collar_id = { [Op.like]: `%${collarId}%` };
}
// 状态筛选
if (status) {
whereCondition.status = status;
}
const offset = (page - 1) * pageSize;
const { count, rows } = await SmartCollar.findAndCountAll({
where: whereCondition,
offset,
limit: parseInt(pageSize),
order: [['created_at', 'DESC']]
});
// 格式化数据以便前端使用
const formattedData = rows.map(collar => ({
id: collar.id,
key: collar.id.toString(),
collarId: collar.collar_id,
name: collar.name,
status: collar.status,
battery: collar.battery,
remark: collar.remark,
createdAt: collar.created_at.toLocaleString('zh-CN'),
updatedAt: collar.updated_at.toLocaleString('zh-CN')
}));
res.json({
success: true,
data: formattedData,
total: count,
page: parseInt(page),
pageSize: parseInt(pageSize),
message: '获取智能项圈列表成功'
});
} catch (error) {
console.error('获取智能项圈列表失败:', error);
res.status(500).json({
success: false,
message: '获取智能项圈列表失败',
error: error.message
});
}
};
// 新增智能项圈
const createSmartCollar = async (req, res) => {
try {
const {
collarId,
name,
status = 'inactive',
battery = 100,
remark = ''
} = req.body;
// 检查项圈编号是否已存在
const existingCollar = await SmartCollar.findOne({ where: { collar_id: collarId } });
if (existingCollar) {
return res.status(400).json({
success: false,
message: '该智能项圈编号已存在'
});
}
const collar = await SmartCollar.create({
collar_id: collarId,
name,
status,
battery,
remark
});
res.status(201).json({
success: true,
data: {
id: collar.id,
collarId: collar.collar_id,
name: collar.name,
status: collar.status,
battery: collar.battery,
remark: collar.remark,
createdAt: collar.created_at.toLocaleString('zh-CN'),
updatedAt: collar.updated_at.toLocaleString('zh-CN')
},
message: '新增智能项圈成功'
});
} catch (error) {
console.error('新增智能项圈失败:', error);
res.status(500).json({
success: false,
message: '新增智能项圈失败',
error: error.message
});
}
};
// 编辑智能项圈
const updateSmartCollar = async (req, res) => {
try {
const { id } = req.params;
const {
collarId,
name,
status,
battery,
remark
} = req.body;
// 查找要编辑的智能项圈
const collar = await SmartCollar.findByPk(id);
if (!collar) {
return res.status(404).json({
success: false,
message: '未找到该智能项圈'
});
}
// 如果修改了项圈编号,检查新编号是否已存在
if (collarId && collarId !== collar.collar_id) {
const existingCollar = await SmartCollar.findOne({ where: { collar_id: collarId } });
if (existingCollar) {
return res.status(400).json({
success: false,
message: '该智能项圈编号已存在'
});
}
}
// 更新智能项圈信息
await collar.update({
collar_id: collarId,
name,
status,
battery,
remark
});
res.json({
success: true,
data: {
id: collar.id,
collarId: collar.collar_id,
name: collar.name,
status: collar.status,
battery: collar.battery,
remark: collar.remark,
createdAt: collar.created_at.toLocaleString('zh-CN'),
updatedAt: collar.updated_at.toLocaleString('zh-CN')
},
message: '编辑智能项圈成功'
});
} catch (error) {
console.error('编辑智能项圈失败:', error);
res.status(500).json({
success: false,
message: '编辑智能项圈失败',
error: error.message
});
}
};
// 删除智能项圈
const deleteSmartCollar = async (req, res) => {
try {
const { id } = req.params;
// 查找要删除的智能项圈
const collar = await SmartCollar.findByPk(id);
if (!collar) {
return res.status(404).json({
success: false,
message: '未找到该智能项圈'
});
}
// 删除智能项圈
await collar.destroy();
res.json({
success: true,
message: '删除智能项圈成功'
});
} catch (error) {
console.error('删除智能项圈失败:', error);
res.status(500).json({
success: false,
message: '删除智能项圈失败',
error: error.message
});
}
};
module.exports = {
getSmartCollars,
createSmartCollar,
updateSmartCollar,
deleteSmartCollar
};

View File

@@ -0,0 +1,214 @@
const { Op } = require('sequelize');
const SmartEarmark = require('../models/SmartEarmark');
// 获取智能耳标列表
const getSmartEarmarks = async (req, res) => {
try {
const { page = 1, pageSize = 10, earmarkId = '', status = '' } = req.query;
const whereCondition = {};
// 耳标编号搜索
if (earmarkId) {
whereCondition.earmark_id = { [Op.like]: `%${earmarkId}%` };
}
// 状态筛选
if (status) {
whereCondition.status = status;
}
const offset = (page - 1) * pageSize;
const { count, rows } = await SmartEarmark.findAndCountAll({
where: whereCondition,
offset,
limit: parseInt(pageSize),
order: [['created_at', 'DESC']]
});
// 格式化数据以便前端使用
const formattedData = rows.map(earmark => ({
id: earmark.id,
key: earmark.id.toString(),
earmarkId: earmark.earmark_id,
name: earmark.name,
status: earmark.status,
battery: earmark.battery,
remark: earmark.remark,
createdAt: earmark.created_at.toLocaleString('zh-CN'),
updatedAt: earmark.updated_at.toLocaleString('zh-CN')
}));
res.json({
success: true,
data: formattedData,
total: count,
page: parseInt(page),
pageSize: parseInt(pageSize),
message: '获取智能耳标列表成功'
});
} catch (error) {
console.error('获取智能耳标列表失败:', error);
res.status(500).json({
success: false,
message: '获取智能耳标列表失败',
error: error.message
});
}
};
// 新增智能耳标
const createSmartEarmark = async (req, res) => {
try {
const {
earmarkId,
name,
status = 'inactive',
battery = 100,
remark = ''
} = req.body;
// 检查耳标编号是否已存在
const existingEarmark = await SmartEarmark.findOne({ where: { earmark_id: earmarkId } });
if (existingEarmark) {
return res.status(400).json({
success: false,
message: '该智能耳标编号已存在'
});
}
const earmark = await SmartEarmark.create({
earmark_id: earmarkId,
name,
status,
battery,
remark
});
res.status(201).json({
success: true,
data: {
id: earmark.id,
earmarkId: earmark.earmark_id,
name: earmark.name,
status: earmark.status,
battery: earmark.battery,
remark: earmark.remark,
createdAt: earmark.created_at.toLocaleString('zh-CN'),
updatedAt: earmark.updated_at.toLocaleString('zh-CN')
},
message: '新增智能耳标成功'
});
} catch (error) {
console.error('新增智能耳标失败:', error);
res.status(500).json({
success: false,
message: '新增智能耳标失败',
error: error.message
});
}
};
// 编辑智能耳标
const updateSmartEarmark = async (req, res) => {
try {
const { id } = req.params;
const {
earmarkId,
name,
status,
battery,
remark
} = req.body;
// 查找要编辑的智能耳标
const earmark = await SmartEarmark.findByPk(id);
if (!earmark) {
return res.status(404).json({
success: false,
message: '未找到该智能耳标'
});
}
// 如果修改了耳标编号,检查新编号是否已存在
if (earmarkId && earmarkId !== earmark.earmark_id) {
const existingEarmark = await SmartEarmark.findOne({ where: { earmark_id: earmarkId } });
if (existingEarmark) {
return res.status(400).json({
success: false,
message: '该智能耳标编号已存在'
});
}
}
// 更新智能耳标信息
await earmark.update({
earmark_id: earmarkId,
name,
status,
battery,
remark
});
res.json({
success: true,
data: {
id: earmark.id,
earmarkId: earmark.earmark_id,
name: earmark.name,
status: earmark.status,
battery: earmark.battery,
remark: earmark.remark,
createdAt: earmark.created_at.toLocaleString('zh-CN'),
updatedAt: earmark.updated_at.toLocaleString('zh-CN')
},
message: '编辑智能耳标成功'
});
} catch (error) {
console.error('编辑智能耳标失败:', error);
res.status(500).json({
success: false,
message: '编辑智能耳标失败',
error: error.message
});
}
};
// 删除智能耳标
const deleteSmartEarmark = async (req, res) => {
try {
const { id } = req.params;
// 查找要删除的智能耳标
const earmark = await SmartEarmark.findByPk(id);
if (!earmark) {
return res.status(404).json({
success: false,
message: '未找到该智能耳标'
});
}
// 删除智能耳标
await earmark.destroy();
res.json({
success: true,
message: '删除智能耳标成功'
});
} catch (error) {
console.error('删除智能耳标失败:', error);
res.status(500).json({
success: false,
message: '删除智能耳标失败',
error: error.message
});
}
};
module.exports = {
getSmartEarmarks,
createSmartEarmark,
updateSmartEarmark,
deleteSmartEarmark
};

View File

@@ -0,0 +1,214 @@
const { Op } = require('sequelize');
const SmartHost = require('../models/SmartHost');
// 获取智能主机列表
const getSmartHosts = async (req, res) => {
try {
const { page = 1, pageSize = 10, hostId = '', status = '' } = req.query;
const whereCondition = {};
// 主机编号搜索
if (hostId) {
whereCondition.host_id = { [Op.like]: `%${hostId}%` };
}
// 状态筛选
if (status) {
whereCondition.status = status;
}
const offset = (page - 1) * pageSize;
const { count, rows } = await SmartHost.findAndCountAll({
where: whereCondition,
offset,
limit: parseInt(pageSize),
order: [['created_at', 'DESC']]
});
// 格式化数据以便前端使用
const formattedData = rows.map(host => ({
id: host.id,
key: host.id.toString(),
hostId: host.host_id,
name: host.name,
ipAddress: host.ip_address,
status: host.status,
remark: host.remark,
createdAt: host.created_at.toLocaleString('zh-CN'),
updatedAt: host.updated_at.toLocaleString('zh-CN')
}));
res.json({
success: true,
data: formattedData,
total: count,
page: parseInt(page),
pageSize: parseInt(pageSize),
message: '获取智能主机列表成功'
});
} catch (error) {
console.error('获取智能主机列表失败:', error);
res.status(500).json({
success: false,
message: '获取智能主机列表失败',
error: error.message
});
}
};
// 新增智能主机
const createSmartHost = async (req, res) => {
try {
const {
hostId,
name,
ipAddress,
status = 'inactive',
remark = ''
} = req.body;
// 检查主机编号是否已存在
const existingHost = await SmartHost.findOne({ where: { host_id: hostId } });
if (existingHost) {
return res.status(400).json({
success: false,
message: '该智能主机编号已存在'
});
}
const host = await SmartHost.create({
host_id: hostId,
name,
ip_address: ipAddress,
status,
remark
});
res.status(201).json({
success: true,
data: {
id: host.id,
hostId: host.host_id,
name: host.name,
ipAddress: host.ip_address,
status: host.status,
remark: host.remark,
createdAt: host.created_at.toLocaleString('zh-CN'),
updatedAt: host.updated_at.toLocaleString('zh-CN')
},
message: '新增智能主机成功'
});
} catch (error) {
console.error('新增智能主机失败:', error);
res.status(500).json({
success: false,
message: '新增智能主机失败',
error: error.message
});
}
};
// 编辑智能主机
const updateSmartHost = async (req, res) => {
try {
const { id } = req.params;
const {
hostId,
name,
ipAddress,
status,
remark
} = req.body;
// 查找要编辑的智能主机
const host = await SmartHost.findByPk(id);
if (!host) {
return res.status(404).json({
success: false,
message: '未找到该智能主机'
});
}
// 如果修改了主机编号,检查新编号是否已存在
if (hostId && hostId !== host.host_id) {
const existingHost = await SmartHost.findOne({ where: { host_id: hostId } });
if (existingHost) {
return res.status(400).json({
success: false,
message: '该智能主机编号已存在'
});
}
}
// 更新智能主机信息
await host.update({
host_id: hostId,
name,
ip_address: ipAddress,
status,
remark
});
res.json({
success: true,
data: {
id: host.id,
hostId: host.host_id,
name: host.name,
ipAddress: host.ip_address,
status: host.status,
remark: host.remark,
createdAt: host.created_at.toLocaleString('zh-CN'),
updatedAt: host.updated_at.toLocaleString('zh-CN')
},
message: '编辑智能主机成功'
});
} catch (error) {
console.error('编辑智能主机失败:', error);
res.status(500).json({
success: false,
message: '编辑智能主机失败',
error: error.message
});
}
};
// 删除智能主机
const deleteSmartHost = async (req, res) => {
try {
const { id } = req.params;
// 查找要删除的智能主机
const host = await SmartHost.findByPk(id);
if (!host) {
return res.status(404).json({
success: false,
message: '未找到该智能主机'
});
}
// 删除智能主机
await host.destroy();
res.json({
success: true,
message: '删除智能主机成功'
});
} catch (error) {
console.error('删除智能主机失败:', error);
res.status(500).json({
success: false,
message: '删除智能主机失败',
error: error.message
});
}
};
module.exports = {
getSmartHosts,
createSmartHost,
updateSmartHost,
deleteSmartHost
};

View File

@@ -1,6 +1,10 @@
const jwt = require('jsonwebtoken');
const { promisify } = require('util');
const jwt = require('jsonwebtoken');
const db = require('../config/database');
const util = require('util');
// JWT配置
const JWT_SECRET = process.env.JWT_SECRET || 'your-secret-key-change-in-production';
module.exports = async (req, res, next) => {
// 获取token
@@ -14,8 +18,20 @@ module.exports = async (req, res, next) => {
}
try {
// 支持开发环境的模拟token
if (token.startsWith('mock-jwt-token-')) {
// 模拟用户数据,避免数据库查询
req.user = {
id: '1',
username: 'admin',
role: 'admin'
};
next();
return;
}
// 验证token
const decoded = await promisify(jwt.verify)(token, process.env.JWT_SECRET);
const decoded = await util.promisify(jwt.verify)(token, JWT_SECRET);
// 检查用户是否存在
const [user] = await db.query(

View File

@@ -0,0 +1,85 @@
const sequelize = require('../config/database');
const { DataTypes } = require('sequelize');
const EpidemicAgency = sequelize.define('EpidemicAgency', {
id: {
type: DataTypes.INTEGER,
primaryKey: true,
autoIncrement: true
},
name: {
type: DataTypes.STRING,
allowNull: false,
comment: '机构名称'
},
director: {
type: DataTypes.STRING,
allowNull: false,
comment: '负责人'
},
phone: {
type: DataTypes.STRING,
allowNull: false,
comment: '联系电话'
},
address: {
type: DataTypes.STRING,
allowNull: false,
comment: '地址'
},
email: {
type: DataTypes.STRING,
allowNull: true,
comment: '邮箱'
},
type: {
type: DataTypes.ENUM('center', 'branch', 'mobile'),
allowNull: false,
defaultValue: 'branch',
comment: '机构类型: center(中心防疫站), branch(防疫分站), mobile(流动防疫队)'
},
status: {
type: DataTypes.ENUM('active', 'inactive'),
allowNull: false,
defaultValue: 'active',
comment: '状态: active(活跃), inactive(非活跃)'
},
establishmentDate: {
type: DataTypes.DATEONLY,
allowNull: false,
comment: '成立日期'
},
description: {
type: DataTypes.TEXT,
allowNull: true,
comment: '机构描述'
},
created_by: {
type: DataTypes.INTEGER,
allowNull: true,
comment: '创建人ID'
},
updated_by: {
type: DataTypes.INTEGER,
allowNull: true,
comment: '更新人ID'
}
}, {
tableName: 'government_epidemic_agencies',
indexes: [
{
name: 'idx_agency_name',
fields: ['name']
},
{
name: 'idx_agency_status',
fields: ['status']
},
{
name: 'idx_agency_type',
fields: ['type']
}
]
});
module.exports = EpidemicAgency;

View File

@@ -0,0 +1,77 @@
const { DataTypes } = require('sequelize');
const sequelize = require('../config/database');
const SmartCollar = sequelize.define('SmartCollar', {
id: {
type: DataTypes.INTEGER,
primaryKey: true,
autoIncrement: true
},
collar_id: {
type: DataTypes.STRING,
allowNull: false,
unique: true,
comment: '项圈编号'
},
name: {
type: DataTypes.STRING,
allowNull: false,
comment: '项圈名称'
},
status: {
type: DataTypes.ENUM('active', 'inactive', 'maintenance'),
allowNull: false,
defaultValue: 'inactive',
comment: '状态active-使用中inactive-未使用maintenance-维护中'
},
battery: {
type: DataTypes.INTEGER,
allowNull: false,
defaultValue: 100,
validate: {
min: 0,
max: 100
},
comment: '电池电量(%)'
},
remark: {
type: DataTypes.TEXT,
allowNull: true,
comment: '备注'
},
created_at: {
type: DataTypes.DATE,
allowNull: false,
defaultValue: DataTypes.NOW,
comment: '创建时间'
},
updated_at: {
type: DataTypes.DATE,
allowNull: false,
defaultValue: DataTypes.NOW,
comment: '更新时间'
}
}, {
tableName: 'smart_collars',
timestamps: true,
createdAt: 'created_at',
updatedAt: 'updated_at',
paranoid: false,
indexes: [
{
name: 'idx_smart_collar_id',
fields: ['collar_id']
},
{
name: 'idx_smart_collar_status',
fields: ['status']
}
]
});
// 钩子函数,在保存前更新更新时间
SmartCollar.beforeSave((collar) => {
collar.updated_at = new Date();
});
module.exports = SmartCollar;

View File

@@ -0,0 +1,77 @@
const { DataTypes } = require('sequelize');
const sequelize = require('../config/database');
const SmartEarmark = sequelize.define('SmartEarmark', {
id: {
type: DataTypes.INTEGER,
primaryKey: true,
autoIncrement: true
},
earmark_id: {
type: DataTypes.STRING,
allowNull: false,
unique: true,
comment: '耳标编号'
},
name: {
type: DataTypes.STRING,
allowNull: false,
comment: '耳标名称'
},
status: {
type: DataTypes.ENUM('active', 'inactive', 'maintenance'),
allowNull: false,
defaultValue: 'inactive',
comment: '状态active-使用中inactive-未使用maintenance-维护中'
},
battery: {
type: DataTypes.INTEGER,
allowNull: false,
defaultValue: 100,
validate: {
min: 0,
max: 100
},
comment: '电池电量(%)'
},
remark: {
type: DataTypes.TEXT,
allowNull: true,
comment: '备注'
},
created_at: {
type: DataTypes.DATE,
allowNull: false,
defaultValue: DataTypes.NOW,
comment: '创建时间'
},
updated_at: {
type: DataTypes.DATE,
allowNull: false,
defaultValue: DataTypes.NOW,
comment: '更新时间'
}
}, {
tableName: 'smart_earmarks',
timestamps: true,
createdAt: 'created_at',
updatedAt: 'updated_at',
paranoid: false,
indexes: [
{
name: 'idx_smart_earmark_id',
fields: ['earmark_id']
},
{
name: 'idx_smart_earmark_status',
fields: ['status']
}
]
});
// 钩子函数,在保存前更新更新时间
SmartEarmark.beforeSave((earmark) => {
earmark.updated_at = new Date();
});
module.exports = SmartEarmark;

View File

@@ -0,0 +1,72 @@
const { DataTypes } = require('sequelize');
const sequelize = require('../config/database');
const SmartHost = sequelize.define('SmartHost', {
id: {
type: DataTypes.INTEGER,
primaryKey: true,
autoIncrement: true
},
host_id: {
type: DataTypes.STRING,
allowNull: false,
unique: true,
comment: '主机编号'
},
name: {
type: DataTypes.STRING,
allowNull: false,
comment: '主机名称'
},
ip_address: {
type: DataTypes.STRING,
allowNull: false,
comment: 'IP地址'
},
status: {
type: DataTypes.ENUM('active', 'inactive', 'maintenance'),
allowNull: false,
defaultValue: 'inactive',
comment: '状态active-使用中inactive-未使用maintenance-维护中'
},
remark: {
type: DataTypes.TEXT,
allowNull: true,
comment: '备注'
},
created_at: {
type: DataTypes.DATE,
allowNull: false,
defaultValue: DataTypes.NOW,
comment: '创建时间'
},
updated_at: {
type: DataTypes.DATE,
allowNull: false,
defaultValue: DataTypes.NOW,
comment: '更新时间'
}
}, {
tableName: 'smart_hosts',
timestamps: true,
createdAt: 'created_at',
updatedAt: 'updated_at',
paranoid: false,
indexes: [
{
name: 'idx_smart_host_id',
fields: ['host_id']
},
{
name: 'idx_smart_host_status',
fields: ['status']
}
]
});
// 钩子函数,在保存前更新更新时间
SmartHost.beforeSave((host) => {
host.updated_at = new Date();
});
module.exports = SmartHost;

View File

@@ -1,5 +1,10 @@
const express = require('express');
const router = express.Router();
const epidemicAgencyController = require('../controllers/epidemicAgencyController');
const authMiddleware = require('../middleware/auth');
// 应用认证中间件
router.use(authMiddleware);
// 防疫数据统计
router.get('/stats', (req, res) => {
@@ -12,4 +17,12 @@ router.get('/stats', (req, res) => {
});
});
// 防疫机构管理
router.get('/agencies', epidemicAgencyController.getEpidemicAgencies);
router.get('/agencies/:id', epidemicAgencyController.getEpidemicAgencyById);
router.post('/agencies', epidemicAgencyController.createEpidemicAgency);
router.put('/agencies/:id', epidemicAgencyController.updateEpidemicAgency);
router.delete('/agencies/:id', epidemicAgencyController.deleteEpidemicAgency);
router.patch('/agencies/:id/status', epidemicAgencyController.toggleEpidemicAgencyStatus);
module.exports = router;

View File

@@ -2,6 +2,7 @@ const express = require('express');
const router = express.Router();
const governmentController = require('../controllers/governmentController');
const farmerController = require('../controllers/farmerController');
const smartCollarController = require('../controllers/smartCollarController');
// 数据览仓接口
router.get('/data-center', governmentController.getDataCenterStats);
@@ -75,4 +76,17 @@ router.get('/farm-types', farmerController.getFarmTypes);
// 获取养殖种类列表
router.get('/animal-types', farmerController.getAnimalTypes);
// 智能项圈管理接口
// 获取智能项圈列表
router.get('/collars', smartCollarController.getSmartCollars);
// 新增智能项圈
router.post('/collars', smartCollarController.createSmartCollar);
// 编辑智能项圈
router.put('/collars/:id', smartCollarController.updateSmartCollar);
// 删除智能项圈
router.delete('/collars/:id', smartCollarController.deleteSmartCollar);
module.exports = router;

View File

@@ -0,0 +1,18 @@
const express = require('express');
const router = express.Router();
const smartEarmarkController = require('../controllers/smartEarmarkController');
const auth = require('../middleware/auth');
// 获取智能耳标列表
router.get('/', auth, smartEarmarkController.getSmartEarmarks);
// 新增智能耳标
router.post('/', auth, smartEarmarkController.createSmartEarmark);
// 编辑智能耳标
router.put('/:id', auth, smartEarmarkController.updateSmartEarmark);
// 删除智能耳标
router.delete('/:id', auth, smartEarmarkController.deleteSmartEarmark);
module.exports = router;

View File

@@ -0,0 +1,18 @@
const express = require('express');
const router = express.Router();
const smartHostController = require('../controllers/smartHostController');
const auth = require('../middleware/auth');
// 获取智能主机列表
router.get('/', auth, smartHostController.getSmartHosts);
// 新增智能主机
router.post('/', auth, smartHostController.createSmartHost);
// 编辑智能主机
router.put('/:id', auth, smartHostController.updateSmartHost);
// 删除智能主机
router.delete('/:id', auth, smartHostController.deleteSmartHost);
module.exports = router;

View File

@@ -0,0 +1,114 @@
const sequelize = require('../config/database');
const EpidemicAgency = require('../models/EpidemicAgency');
async function initEpidemicAgencyTable() {
try {
console.log('开始初始化防疫机构表...');
// 测试数据库连接
await sequelize.authenticate();
console.log('✅ 数据库连接成功');
// 同步模型到数据库(创建表)
await EpidemicAgency.sync({
alter: true // 如有必要,修改表结构
});
console.log('✅ 防疫机构表创建/更新成功');
// 清除现有数据
await EpidemicAgency.destroy({
where: {},
truncate: true
});
console.log('✅ 现有数据已清空');
// 插入测试数据
const testData = [
{
name: '中心动物防疫站',
director: '张三',
phone: '13800138001',
address: '市南区健康路100号',
email: 'center@animalhealth.gov.cn',
type: 'center',
status: 'active',
establishmentDate: '2010-01-15',
description: '负责全市动物防疫工作的统筹管理和技术指导'
},
{
name: '东区动物防疫分站',
director: '李四',
phone: '13800138002',
address: '市东区防疫路50号',
email: 'east@animalhealth.gov.cn',
type: 'branch',
status: 'active',
establishmentDate: '2012-05-20',
description: '负责东区范围内的动物防疫工作'
},
{
name: '西区动物防疫分站',
director: '王五',
phone: '13800138003',
address: '市西区健康大道200号',
email: 'west@animalhealth.gov.cn',
type: 'branch',
status: 'active',
establishmentDate: '2013-03-10',
description: '负责西区范围内的动物防疫工作'
},
{
name: '北区动物防疫分站',
director: '赵六',
phone: '13800138004',
address: '市北区安全路88号',
email: 'north@animalhealth.gov.cn',
type: 'branch',
status: 'active',
establishmentDate: '2014-07-05',
description: '负责北区范围内的动物防疫工作'
},
{
name: '南区动物防疫分站',
director: '钱七',
phone: '13800138005',
address: '市南区健康路66号',
email: 'south@animalhealth.gov.cn',
type: 'branch',
status: 'active',
establishmentDate: '2015-02-28',
description: '负责南区范围内的动物防疫工作'
},
{
name: '流动防疫队',
director: '孙八',
phone: '13800138006',
address: '市中区应急中心',
email: 'mobile@animalhealth.gov.cn',
type: 'mobile',
status: 'active',
establishmentDate: '2016-09-15',
description: '负责偏远地区和突发事件的动物防疫工作'
}
];
await EpidemicAgency.bulkCreate(testData);
console.log('✅ 测试数据插入成功');
// 验证数据是否插入成功
const agencies = await EpidemicAgency.findAll();
console.log(`✅ 共插入 ${agencies.length} 条数据`);
console.log('🎉 防疫机构表初始化完成');
} catch (error) {
console.error('❌ 初始化防疫机构表失败:', error);
} finally {
// 关闭数据库连接
await sequelize.close();
console.log('🔌 数据库连接已关闭');
}
}
// 执行初始化函数
initEpidemicAgencyTable();

View File

@@ -0,0 +1,92 @@
const sequelize = require('../config/database');
const SmartCollar = require('../models/SmartCollar');
/**
* 初始化智能项圈表并添加测试数据
*/
async function initSmartCollarTable() {
try {
console.log('开始初始化智能项圈表...');
// 同步模型到数据库(创建表)
await SmartCollar.sync({
alter: true, // 这会修改已存在的表结构以匹配模型定义
force: false // 设为 true 会删除现有表并重新创建,但会丢失现有数据
});
console.log('智能项圈表同步成功');
// 检查是否已有测试数据
const existingCount = await SmartCollar.count();
if (existingCount === 0) {
console.log('开始添加测试数据...');
// 测试数据
const testData = [
{
collar_id: 'CL001',
name: '智能项圈001',
status: 'active',
battery: 85,
remark: '用于示范的项圈',
created_at: new Date('2023-09-15 10:00:00'),
updated_at: new Date('2023-09-20 14:30:00')
},
{
collar_id: 'CL002',
name: '智能项圈002',
status: 'inactive',
battery: 100,
remark: '',
created_at: new Date('2023-09-16 11:20:00'),
updated_at: new Date('2023-09-16 11:20:00')
},
{
collar_id: 'CL003',
name: '智能项圈003',
status: 'maintenance',
battery: 20,
remark: '电池需要更换',
created_at: new Date('2023-09-10 09:15:00'),
updated_at: new Date('2023-09-21 16:45:00')
},
{
collar_id: 'CL004',
name: '智能项圈004',
status: 'active',
battery: 90,
remark: '养殖场A区',
created_at: new Date('2023-09-05 14:20:00'),
updated_at: new Date('2023-09-18 09:30:00')
},
{
collar_id: 'CL005',
name: '智能项圈005',
status: 'active',
battery: 75,
remark: '养殖场B区',
created_at: new Date('2023-09-08 16:10:00'),
updated_at: new Date('2023-09-19 11:45:00')
}
];
// 批量创建测试数据
await SmartCollar.bulkCreate(testData);
console.log('测试数据添加成功');
} else {
console.log(`智能项圈表已有 ${existingCount} 条数据,跳过添加测试数据`);
}
console.log('智能项圈表初始化完成');
} catch (error) {
console.error('智能项圈表初始化失败:', error);
process.exit(1);
} finally {
// 关闭数据库连接
await sequelize.close();
}
}
// 执行初始化
initSmartCollarTable();

View File

@@ -0,0 +1,62 @@
// 初始化智能耳标表并添加测试数据
const sequelize = require('../config/database');
const SmartEarmark = require('../models/SmartEarmark');
async function initSmartEarmarkTable() {
try {
// 同步模型到数据库,创建表
await SmartEarmark.sync({
force: false, // 设置为true会删除已存在的表并重新创建
alter: true // 允许修改表结构以匹配模型
});
console.log('智能耳标表同步成功');
// 检查是否已经有数据
const existingCount = await SmartEarmark.count();
if (existingCount === 0) {
// 添加测试数据
const testData = [
{
earmark_id: 'EM001',
name: '智能耳标001',
status: 'active',
battery: 90,
remark: '用于示范的耳标'
},
{
earmark_id: 'EM002',
name: '智能耳标002',
status: 'inactive',
battery: 100,
remark: ''
},
{
earmark_id: 'EM003',
name: '智能耳标003',
status: 'maintenance',
battery: 15,
remark: '电池需要更换'
}
];
await SmartEarmark.bulkCreate(testData);
console.log(`已添加 ${testData.length} 条测试数据到智能耳标表`);
} else {
console.log(`智能耳标表已有 ${existingCount} 条数据,不重复添加测试数据`);
}
// 关闭数据库连接
await sequelize.close();
} catch (error) {
console.error('初始化智能耳标表失败:', error);
// 确保出错时也关闭数据库连接
await sequelize.close().catch(closeError => {
console.error('关闭数据库连接时出错:', closeError);
});
process.exit(1);
}
}
// 执行初始化函数
initSmartEarmarkTable();

View File

@@ -0,0 +1,74 @@
const { DataTypes } = require('sequelize');
const sequelize = require('../config/database');
const SmartHost = require('../models/SmartHost');
// 测试数据
const testData = [
{
hostId: 'HOST-2023-001',
name: '智能主机001',
ipAddress: '192.168.1.101',
status: 'active',
remark: '一号仓库智能主机'
},
{
hostId: 'HOST-2023-002',
name: '智能主机002',
ipAddress: '192.168.1.102',
status: 'active',
remark: '二号仓库智能主机'
},
{
hostId: 'HOST-2023-003',
name: '智能主机003',
ipAddress: '192.168.1.103',
status: 'maintenance',
remark: '三号仓库智能主机(维护中)'
},
{
hostId: 'HOST-2023-004',
name: '智能主机004',
ipAddress: '192.168.1.104',
status: 'inactive',
remark: '四号仓库智能主机(未使用)'
},
{
hostId: 'HOST-2023-005',
name: '智能主机005',
ipAddress: '192.168.1.105',
status: 'active',
remark: '五号仓库智能主机'
}
];
// 重置表并添加测试数据
const resetAndAddTestData = async () => {
try {
// 确保表存在
await SmartHost.sync({
force: true // 这将删除表(如果存在)并重新创建
});
console.log('SmartHost表已创建或重置');
// 插入测试数据
const createdHosts = await SmartHost.bulkCreate(testData.map(item => ({
host_id: item.hostId,
name: item.name,
ip_address: item.ipAddress,
status: item.status,
remark: item.remark
})));
console.log(`已成功添加 ${createdHosts.length} 条智能主机测试数据`);
// 关闭数据库连接
await sequelize.close();
} catch (error) {
console.error('添加测试数据失败:', error);
process.exit(1);
}
};
// 执行脚本
resetAndAddTestData();

View File

@@ -0,0 +1,129 @@
// 测试智能耳标API
const http = require('http');
const querystring = require('querystring');
// 配置
const baseUrl = 'localhost';
const port = 5352;
const apiPath = '/api/smart-earmark';
// 发送HTTP请求的函数
function sendRequest(method, path, data = null, headers = {}) {
return new Promise((resolve, reject) => {
const options = {
hostname: baseUrl,
port: port,
path: path,
method: method,
headers: {
'Content-Type': 'application/json',
...headers
}
};
const req = http.request(options, (res) => {
let data = '';
res.on('data', (chunk) => {
data += chunk;
});
res.on('end', () => {
resolve({
statusCode: res.statusCode,
headers: res.headers,
data: data ? JSON.parse(data) : null
});
});
});
req.on('error', (error) => {
reject(error);
});
if (data) {
req.write(JSON.stringify(data));
}
req.end();
});
}
// 测试函数
async function runTests() {
console.log('开始测试智能耳标API...');
try {
// 1. 先登录获取token
console.log('\n1. 登录获取token...');
const loginResponse = await sendRequest('POST', '/api/auth/login', {
username: 'admin',
password: '123456'
});
console.log('登录响应状态码:', loginResponse.statusCode);
console.log('登录响应数据:', loginResponse.data);
if (loginResponse.statusCode !== 200) {
console.error('登录失败:', loginResponse);
process.exit(1);
}
const token = loginResponse.data.data.token;
console.log('登录成功获取到token:', token);
// 设置Authorization头
const authHeaders = {
'Authorization': `Bearer ${token}`
};
// 2. 获取智能耳标列表
console.log('\n2. 获取智能耳标列表...');
const listResponse = await sendRequest('GET', `${apiPath}?page=1&pageSize=10`, null, authHeaders);
console.log('获取列表结果:', listResponse.statusCode);
console.log('列表数据:', listResponse.data);
// 3. 创建新的智能耳标
console.log('\n3. 创建新的智能耳标...');
const newEarmark = {
earmarkId: `EM${Date.now().toString().slice(-4)}`,
name: '测试智能耳标',
status: 'inactive',
battery: 95,
remark: '这是一个测试耳标'
};
const createResponse = await sendRequest('POST', apiPath, newEarmark, authHeaders);
console.log('创建结果:', createResponse.statusCode);
console.log('创建的数据:', createResponse.data);
if (createResponse.statusCode === 201 && createResponse.data?.data?.id) {
const earmarkId = createResponse.data.data.id;
// 4. 更新刚刚创建的智能耳标
console.log('\n4. 更新智能耳标...');
const updateData = {
...newEarmark,
name: '更新后的测试耳标',
status: 'active'
};
const updateResponse = await sendRequest('PUT', `${apiPath}/${earmarkId}`, updateData, authHeaders);
console.log('更新结果:', updateResponse.statusCode);
console.log('更新的数据:', updateResponse.data);
// 5. 删除智能耳标
console.log('\n5. 删除智能耳标...');
const deleteResponse = await sendRequest('DELETE', `${apiPath}/${earmarkId}`, null, authHeaders);
console.log('删除结果:', deleteResponse.statusCode);
console.log('删除响应:', deleteResponse.data);
}
console.log('\n测试完成');
} catch (error) {
console.error('测试过程中出错:', error);
}
}
// 运行测试
runTests();