修改后端接口

This commit is contained in:
2025-09-25 17:43:54 +08:00
parent 5b6b7e0a96
commit 76b5393182
31 changed files with 2155 additions and 468 deletions

View File

@@ -23,8 +23,17 @@ const accessLogStream = fs.createWriteStream(
);
app.use(morgan('combined', { stream: accessLogStream }));
// 数据库连接(暂时注释掉,使用内存数据)
// const sequelize = require('./config/database');
// 数据库连接
const sequelize = require('./config/database');
// 测试数据库连接
sequelize.authenticate()
.then(() => {
console.log('数据库连接成功');
})
.catch(err => {
console.error('数据库连接失败:', err);
});
// 路由
app.use('/api/auth', require('./routes/auth'));
@@ -58,5 +67,4 @@ app.use((err, req, res, next) => {
const PORT = process.env.PORT || 5352;
app.listen(PORT, () => {
console.log(`政府管理系统后端服务已启动,端口: ${PORT}`);
console.log(`使用内存数据,无需数据库连接`);
});

View File

@@ -1,14 +1,14 @@
require('dotenv').config();
const { Sequelize } = require('sequelize');
const config = require('./index.js');
const sequelize = new Sequelize(
process.env.DB_NAME,
process.env.DB_USER,
process.env.DB_PASSWORD,
config.DB_CONFIG.database,
config.DB_CONFIG.user,
config.DB_CONFIG.password,
{
host: process.env.DB_HOST,
port: process.env.DB_PORT,
dialect: process.env.DB_DIALECT,
host: config.DB_CONFIG.host,
port: config.DB_CONFIG.port,
dialect: config.DB_CONFIG.dialect,
logging: process.env.NODE_ENV === 'development' ? console.log : false,
pool: {
max: 5,
@@ -31,12 +31,14 @@ async function testConnection() {
try {
await sequelize.authenticate();
console.log('数据库连接成功');
return true;
} catch (error) {
console.error('数据库连接失败:', error);
process.exit(1);
return false;
}
}
testConnection();
// 导出连接测试函数,但不自动执行
module.exports.testConnection = testConnection;
module.exports = sequelize;

View File

@@ -1,11 +1,19 @@
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!';
module.exports = {
JWT_SECRET: 'your-secret-key-here', // 请在生产环境中替换为强密钥
DB_CONFIG: {
host: 'localhost',
user: 'root',
password: '',
database: 'government_db',
port: 3306
host: DB_HOST,
user: DB_USER,
password: DB_PASSWORD,
database: DB_NAME,
port: DB_PORT,
dialect: DB_DIALECT
},
PORT: 5352
}

View File

@@ -1,51 +1,63 @@
const jwt = require('jsonwebtoken')
const jwt = require('jsonwebtoken');
const User = require('../models/User');
const AdminStaff = require('../models/AdminStaff');
const bcrypt = require('bcryptjs');
// JWT配置
const JWT_SECRET = process.env.JWT_SECRET || 'your-secret-key-change-in-production'
// 临时用户数据(实际项目中应该从数据库获取)
const users = [
{
id: 1,
username: 'admin',
password: '123456',
name: '系统管理员',
role: 'admin',
email: 'admin@example.com'
}
]
const JWT_SECRET = process.env.JWT_SECRET || 'your-secret-key-change-in-production';
exports.login = async (req, res) => {
try {
const { username, password } = req.body
const { username, password } = req.body;
// 查找用户
const user = users.find(u => u.username === username && u.password === password)
// 从数据库查找用户
const user = await User.findOne({
where: {
username,
status: 'active'
}
});
if (user) {
const token = jwt.sign({
id: user.id,
username: user.username,
role: user.role
}, JWT_SECRET, { expiresIn: '2h' })
return res.json({
code: 200,
message: '登录成功',
data: { token }
})
if (!user) {
return res.status(401).json({
code: 401,
message: '用户名或密码错误'
});
}
res.status(401).json({
code: 401,
message: '用户名或密码错误'
})
// 验证密码
const isPasswordValid = await bcrypt.compare(password, user.password);
if (!isPasswordValid) {
return res.status(401).json({
code: 401,
message: '用户名或密码错误'
});
}
// 更新最后登录时间
await user.update({
last_login: new Date()
});
const token = jwt.sign({
id: user.id,
username: user.username,
role: user.role
}, JWT_SECRET, { expiresIn: '2h' });
return res.json({
code: 200,
message: '登录成功',
data: { token }
});
} catch (err) {
console.error('登录错误:', err);
res.status(500).json({
code: 500,
message: '服务器错误',
error: err.message
})
});
}
}
@@ -53,51 +65,104 @@ exports.login = async (req, res) => {
exports.getUserInfo = async (req, res) => {
try {
// 从token中解析用户信息
const token = req.headers.authorization?.replace('Bearer ', '')
const token = req.headers.authorization?.replace('Bearer ', '');
if (!token) {
return res.status(401).json({
code: 401,
message: '未提供认证令牌'
})
});
}
try {
const decoded = jwt.verify(token, JWT_SECRET)
const user = users.find(u => u.id === decoded.id)
const decoded = jwt.verify(token, JWT_SECRET);
if (user) {
const userInfo = {
id: user.id,
username: user.username,
name: user.name,
role: user.role,
avatar: '',
email: user.email,
permissions: ['dashboard', 'users', 'settings']
}
return res.json({
code: 200,
message: '获取用户信息成功',
data: userInfo
})
} else {
// 从数据库获取用户信息
const user = await User.findByPk(decoded.id, {
include: [
{
model: AdminStaff,
as: 'staffInfo'
}
]
});
if (!user || user.status !== 'active') {
return res.status(401).json({
code: 401,
message: '用户不存在'
})
message: '用户不存在或已禁用'
});
}
// 获取员工信息
let staffInfo = null;
try {
staffInfo = await AdminStaff.findOne({
where: {
phone: user.username
}
});
} catch (error) {
console.warn('获取员工信息失败:', error);
}
// 根据角色设置权限
const permissions = getPermissionsByRole(user.role);
const userInfo = {
id: user.id,
username: user.username,
name: staffInfo?.name || user.username,
role: user.role,
avatar: '',
email: '',
phone: staffInfo?.phone || user.username,
department: staffInfo?.department_id ? {
id: staffInfo.department_id,
name: ''
} : null,
position: staffInfo?.position_id ? {
id: staffInfo.position_id,
name: ''
} : null,
permissions
};
return res.json({
code: 200,
message: '获取用户信息成功',
data: userInfo
});
} catch (jwtError) {
console.error('JWT验证错误:', jwtError);
return res.status(401).json({
code: 401,
message: '认证令牌无效'
})
});
}
} catch (err) {
console.error('获取用户信息错误:', err);
res.status(500).json({
code: 500,
message: '服务器错误',
error: err.message
})
});
}
}
};
// 根据角色获取权限
exports.getPermissionsByRole = (role) => {
const basePermissions = ['dashboard'];
switch (role) {
case 'admin':
return [...basePermissions, 'users', 'settings', 'supervision', 'approval', 'personnel', 'warehouse', 'epidemic', 'service', 'visualization'];
case 'manager':
return [...basePermissions, 'supervision', 'approval', 'personnel', 'warehouse', 'epidemic', 'service'];
case 'inspector':
return [...basePermissions, 'supervision', 'epidemic'];
case 'clerk':
return [...basePermissions, 'approval', 'personnel', 'warehouse', 'service'];
default:
return basePermissions;
}
};

View File

@@ -0,0 +1,248 @@
const Farmer = require('../models/Farmer');
const { Op } = require('sequelize');
// 获取养殖户列表
const getFarmers = async (req, res) => {
try {
const { page = 1, pageSize = 10, search = '', farmType = '', animalType = '', status = '' } = req.query;
const whereCondition = {};
// 搜索条件
if (search) {
whereCondition[Op.or] = [
{ nickname: { [Op.like]: `%${search}%` } },
{ real_name: { [Op.like]: `%${search}%` } },
{ farm_name: { [Op.like]: `%${search}%` } },
{ account: { [Op.like]: `%${search}%` } }
];
}
// 养殖场类型筛选
if (farmType) {
whereCondition.farm_type = farmType;
}
// 养殖种类筛选
if (animalType) {
whereCondition.animal_type = animalType;
}
// 状态筛选
if (status) {
whereCondition.status = status;
}
const offset = (page - 1) * pageSize;
const { count, rows } = await Farmer.findAndCountAll({
where: whereCondition,
offset,
limit: parseInt(pageSize),
order: [['register_time', 'DESC']]
});
// 格式化数据以便前端使用
const formattedData = rows.map(farmer => ({
id: farmer.id,
key: farmer.id.toString(),
account: farmer.account,
nickname: farmer.nickname,
real_name: farmer.real_name,
farm_name: farmer.farm_name,
farm_type: farmer.farm_type,
animal_type: farmer.animal_type,
animal_count: farmer.animal_count,
address: farmer.address,
register_time: farmer.register_time.toLocaleString('zh-CN'),
registrar: farmer.registrar,
status: farmer.status === 'active' ? '正常' : farmer.status === 'inactive' ? '暂停' : '关闭',
status_value: farmer.status
}));
res.json({
data: formattedData,
total: count,
page: parseInt(page),
pageSize: parseInt(pageSize)
});
} catch (error) {
console.error('获取养殖户列表失败:', error);
res.status(500).json({ message: error.message });
}
};
// 新增养殖户
const createFarmer = async (req, res) => {
try {
const {
account,
nickname,
real_name,
farm_name,
farm_type,
animal_type,
animal_count,
address,
status = 'active'
} = req.body;
// 检查账号是否已存在
const existingFarmer = await Farmer.findOne({ where: { account } });
if (existingFarmer) {
return res.status(400).json({ message: '该账号已存在' });
}
const farmer = await Farmer.create({
account,
nickname,
real_name,
farm_name,
farm_type,
animal_type,
animal_count,
address,
registrar: req.user?.username || 'system',
status
});
res.status(201).json({
success: true,
message: '养殖户创建成功',
data: farmer
});
} catch (error) {
console.error('创建养殖户失败:', error);
res.status(500).json({ message: error.message });
}
};
// 编辑养殖户
const updateFarmer = async (req, res) => {
try {
const { id } = req.params;
const {
nickname,
real_name,
farm_name,
farm_type,
animal_type,
animal_count,
address,
status
} = req.body;
const farmer = await Farmer.findByPk(id);
if (!farmer) {
return res.status(404).json({ message: '养殖户不存在' });
}
await farmer.update({
nickname,
real_name,
farm_name,
farm_type,
animal_type,
animal_count,
address,
status
});
res.json({
success: true,
message: '养殖户信息更新成功',
data: farmer
});
} catch (error) {
console.error('更新养殖户信息失败:', error);
res.status(500).json({ message: error.message });
}
};
// 删除养殖户
const deleteFarmer = async (req, res) => {
try {
const { id } = req.params;
const farmer = await Farmer.findByPk(id);
if (!farmer) {
return res.status(404).json({ message: '养殖户不存在' });
}
await farmer.destroy();
res.json({
success: true,
message: '养殖户删除成功'
});
} catch (error) {
console.error('删除养殖户失败:', error);
res.status(500).json({ message: error.message });
}
};
// 重置养殖户密码(如果需要)
const resetFarmerPassword = async (req, res) => {
try {
const { id } = req.params;
const farmer = await Farmer.findByPk(id);
if (!farmer) {
return res.status(404).json({ message: '养殖户不存在' });
}
// 在实际应用中,这里应该生成一个临时密码并发送给用户
// 为了演示,我们只返回成功信息
res.json({
success: true,
message: '密码重置成功,新密码已发送到用户手机'
});
} catch (error) {
console.error('重置养殖户密码失败:', error);
res.status(500).json({ message: error.message });
}
};
// 获取养殖类型列表
const getFarmTypes = async (req, res) => {
try {
const farmTypes = [
{ value: '规模', label: '规模' },
{ value: '散养', label: '散养' },
{ value: '其他', label: '其他' }
];
res.json(farmTypes);
} catch (error) {
console.error('获取养殖类型列表失败:', error);
res.status(500).json({ message: error.message });
}
};
// 获取养殖种类列表
const getAnimalTypes = async (req, res) => {
try {
const animalTypes = [
{ value: '牛', label: '牛' },
{ value: '羊', label: '羊' },
{ value: '猪', label: '猪' },
{ value: '鸡', label: '鸡' },
{ value: '其他', label: '其他' }
];
res.json(animalTypes);
} catch (error) {
console.error('获取养殖种类列表失败:', error);
res.status(500).json({ message: error.message });
}
};
module.exports = {
getFarmers,
createFarmer,
updateFarmer,
deleteFarmer,
resetFarmerPassword,
getFarmTypes,
getAnimalTypes
};

View File

@@ -0,0 +1,113 @@
const sequelize = require('../config/database');
const { DataTypes } = require('sequelize');
const Farmer = sequelize.define('Farmer', {
id: {
type: DataTypes.INTEGER,
primaryKey: true,
autoIncrement: true
},
account: {
type: DataTypes.STRING,
allowNull: false,
unique: true,
comment: '账号'
},
org_code: {
type: DataTypes.STRING,
allowNull: true,
comment: '机构识别码'
},
nickname: {
type: DataTypes.STRING,
allowNull: false,
comment: '账号昵称'
},
real_name: {
type: DataTypes.STRING,
allowNull: false,
comment: '真实姓名'
},
farm_name: {
type: DataTypes.STRING,
allowNull: false,
comment: '养殖场名称'
},
farm_type: {
type: DataTypes.STRING,
allowNull: false,
comment: '养殖场类型',
validate: {
isIn: [['规模', '散养', '其他']]
}
},
animal_type: {
type: DataTypes.STRING,
allowNull: false,
comment: '养殖场种类',
validate: {
isIn: [['牛', '羊', '猪', '鸡', '其他']]
}
},
animal_count: {
type: DataTypes.INTEGER,
allowNull: false,
defaultValue: 0,
comment: '养殖数量'
},
address: {
type: DataTypes.STRING,
allowNull: false,
comment: '养殖场地址'
},
register_time: {
type: DataTypes.DATE,
allowNull: false,
defaultValue: DataTypes.NOW,
comment: '登记时间'
},
registrar: {
type: DataTypes.STRING,
allowNull: false,
comment: '登记人'
},
update_time: {
type: DataTypes.DATE,
allowNull: false,
defaultValue: DataTypes.NOW,
comment: '更新时间'
},
status: {
type: DataTypes.ENUM('active', 'inactive', 'closed'),
allowNull: false,
defaultValue: 'active',
comment: '状态active-正常inactive-暂停closed-关闭'
}
}, {
tableName: 'farmers',
timestamps: true,
createdAt: 'register_time',
updatedAt: 'update_time',
paranoid: false,
indexes: [
{
name: 'idx_farmer_account',
fields: ['account']
},
{
name: 'idx_farmer_farm_name',
fields: ['farm_name']
},
{
name: 'idx_farmer_status',
fields: ['status']
}
]
});
// 钩子函数,在保存前更新更新时间
Farmer.beforeSave((farmer) => {
farmer.update_time = new Date();
});
module.exports = Farmer;

View File

@@ -0,0 +1,59 @@
const sequelize = require('../config/database');
const { DataTypes } = require('sequelize');
const User = sequelize.define('User', {
id: {
type: DataTypes.INTEGER,
primaryKey: true,
autoIncrement: true
},
username: {
type: DataTypes.STRING,
allowNull: false,
unique: true,
comment: '用户名'
},
password: {
type: DataTypes.STRING,
allowNull: false,
comment: '密码'
},
role: {
type: DataTypes.ENUM('admin', 'manager', 'inspector', 'clerk'),
allowNull: false,
comment: '角色'
},
status: {
type: DataTypes.ENUM('active', 'inactive'),
allowNull: false,
defaultValue: 'active',
comment: '状态'
},
last_login: {
type: DataTypes.DATE,
allowNull: true,
comment: '最后登录时间'
}
}, {
tableName: 'users',
timestamps: true,
createdAt: 'created_at',
updatedAt: 'updated_at',
paranoid: false,
indexes: [
{
name: 'idx_username',
fields: ['username']
},
{
name: 'idx_role',
fields: ['role']
},
{
name: 'idx_status',
fields: ['status']
}
]
});
module.exports = User;

View File

@@ -20,6 +20,7 @@
"sequelize": "^6.37.1"
},
"devDependencies": {
"axios": "^1.12.2",
"nodemon": "^3.1.0"
}
},
@@ -86,6 +87,13 @@
"integrity": "sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg==",
"license": "MIT"
},
"node_modules/asynckit": {
"version": "0.4.0",
"resolved": "https://registry.npmmirror.com/asynckit/-/asynckit-0.4.0.tgz",
"integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==",
"dev": true,
"license": "MIT"
},
"node_modules/aws-ssl-profiles": {
"version": "1.1.2",
"resolved": "https://registry.npmmirror.com/aws-ssl-profiles/-/aws-ssl-profiles-1.1.2.tgz",
@@ -95,6 +103,18 @@
"node": ">= 6.0.0"
}
},
"node_modules/axios": {
"version": "1.12.2",
"resolved": "https://registry.npmmirror.com/axios/-/axios-1.12.2.tgz",
"integrity": "sha512-vMJzPewAlRyOgxV2dU0Cuz2O8zzzx9VYtbJOaBgXFeLc4IV/Eg50n4LowmehOOR61S8ZMpc2K5Sa7g6A4jfkUw==",
"dev": true,
"license": "MIT",
"dependencies": {
"follow-redirects": "^1.15.6",
"form-data": "^4.0.4",
"proxy-from-env": "^1.1.0"
}
},
"node_modules/balanced-match": {
"version": "1.0.2",
"resolved": "https://registry.npmmirror.com/balanced-match/-/balanced-match-1.0.2.tgz",
@@ -268,6 +288,19 @@
"fsevents": "~2.3.2"
}
},
"node_modules/combined-stream": {
"version": "1.0.8",
"resolved": "https://registry.npmmirror.com/combined-stream/-/combined-stream-1.0.8.tgz",
"integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==",
"dev": true,
"license": "MIT",
"dependencies": {
"delayed-stream": "~1.0.0"
},
"engines": {
"node": ">= 0.8"
}
},
"node_modules/concat-map": {
"version": "0.0.1",
"resolved": "https://registry.npmmirror.com/concat-map/-/concat-map-0.0.1.tgz",
@@ -333,6 +366,16 @@
"ms": "2.0.0"
}
},
"node_modules/delayed-stream": {
"version": "1.0.0",
"resolved": "https://registry.npmmirror.com/delayed-stream/-/delayed-stream-1.0.0.tgz",
"integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==",
"dev": true,
"license": "MIT",
"engines": {
"node": ">=0.4.0"
}
},
"node_modules/denque": {
"version": "2.1.0",
"resolved": "https://registry.npmmirror.com/denque/-/denque-2.1.0.tgz",
@@ -447,6 +490,22 @@
"node": ">= 0.4"
}
},
"node_modules/es-set-tostringtag": {
"version": "2.1.0",
"resolved": "https://registry.npmmirror.com/es-set-tostringtag/-/es-set-tostringtag-2.1.0.tgz",
"integrity": "sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==",
"dev": true,
"license": "MIT",
"dependencies": {
"es-errors": "^1.3.0",
"get-intrinsic": "^1.2.6",
"has-tostringtag": "^1.0.2",
"hasown": "^2.0.2"
},
"engines": {
"node": ">= 0.4"
}
},
"node_modules/escape-html": {
"version": "1.0.3",
"resolved": "https://registry.npmmirror.com/escape-html/-/escape-html-1.0.3.tgz",
@@ -539,6 +598,44 @@
"node": ">= 0.8"
}
},
"node_modules/follow-redirects": {
"version": "1.15.11",
"resolved": "https://registry.npmmirror.com/follow-redirects/-/follow-redirects-1.15.11.tgz",
"integrity": "sha512-deG2P0JfjrTxl50XGCDyfI97ZGVCxIpfKYmfyrQ54n5FO/0gfIES8C/Psl6kWVDolizcaaxZJnTS0QSMxvnsBQ==",
"dev": true,
"funding": [
{
"type": "individual",
"url": "https://github.com/sponsors/RubenVerborgh"
}
],
"license": "MIT",
"engines": {
"node": ">=4.0"
},
"peerDependenciesMeta": {
"debug": {
"optional": true
}
}
},
"node_modules/form-data": {
"version": "4.0.4",
"resolved": "https://registry.npmmirror.com/form-data/-/form-data-4.0.4.tgz",
"integrity": "sha512-KrGhL9Q4zjj0kiUt5OO4Mr/A/jlI2jDYs5eHBpYHPcBEVSiipAvn2Ko2HnPe20rmcuuvMHNdZFp+4IlGTMF0Ow==",
"dev": true,
"license": "MIT",
"dependencies": {
"asynckit": "^0.4.0",
"combined-stream": "^1.0.8",
"es-set-tostringtag": "^2.1.0",
"hasown": "^2.0.2",
"mime-types": "^2.1.12"
},
"engines": {
"node": ">= 6"
}
},
"node_modules/forwarded": {
"version": "0.2.0",
"resolved": "https://registry.npmmirror.com/forwarded/-/forwarded-0.2.0.tgz",
@@ -674,6 +771,22 @@
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/has-tostringtag": {
"version": "1.0.2",
"resolved": "https://registry.npmmirror.com/has-tostringtag/-/has-tostringtag-1.0.2.tgz",
"integrity": "sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==",
"dev": true,
"license": "MIT",
"dependencies": {
"has-symbols": "^1.0.3"
},
"engines": {
"node": ">= 0.4"
},
"funding": {
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/hasown": {
"version": "2.0.2",
"resolved": "https://registry.npmmirror.com/hasown/-/hasown-2.0.2.tgz",
@@ -1268,6 +1381,13 @@
"node": ">= 0.10"
}
},
"node_modules/proxy-from-env": {
"version": "1.1.0",
"resolved": "https://registry.npmmirror.com/proxy-from-env/-/proxy-from-env-1.1.0.tgz",
"integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==",
"dev": true,
"license": "MIT"
},
"node_modules/pstree.remy": {
"version": "1.1.8",
"resolved": "https://registry.npmmirror.com/pstree.remy/-/pstree.remy-1.1.8.tgz",

View File

@@ -8,19 +8,19 @@
"dev": "nodemon app.js"
},
"dependencies": {
"express": "^4.18.2",
"mysql2": "^3.6.5",
"jsonwebtoken": "^9.0.2",
"bcryptjs": "^2.4.3",
"body-parser": "^1.20.2",
"cors": "^2.8.5",
"dotenv": "^16.3.1",
"body-parser": "^1.20.2",
"express": "^4.18.2",
"helmet": "^7.1.0",
"jsonwebtoken": "^9.0.2",
"morgan": "^1.10.0",
"sequelize": "^6.37.1",
"mysql2": "^3.9.7"
"mysql2": "^3.9.7",
"sequelize": "^6.37.1"
},
"devDependencies": {
"axios": "^1.12.2",
"nodemon": "^3.1.0"
}
}
}

View File

@@ -1,6 +1,7 @@
const express = require('express');
const router = express.Router();
const governmentController = require('../controllers/governmentController');
const farmerController = require('../controllers/farmerController');
// 数据览仓接口
router.get('/data-center', governmentController.getDataCenterStats);
@@ -52,4 +53,26 @@ router.delete('/admin-staff/:id', governmentController.deleteAdminStaff);
// 重置行政人员密码
router.post('/admin-staff/:id/reset-password', governmentController.resetAdminStaffPassword);
// 养殖户管理接口
// 获取养殖户列表
router.get('/farmers', farmerController.getFarmers);
// 新增养殖户
router.post('/farmers', farmerController.createFarmer);
// 编辑养殖户
router.put('/farmers/:id', farmerController.updateFarmer);
// 删除养殖户
router.delete('/farmers/:id', farmerController.deleteFarmer);
// 重置养殖户密码
router.post('/farmers/:id/reset-password', farmerController.resetFarmerPassword);
// 获取养殖类型列表
router.get('/farm-types', farmerController.getFarmTypes);
// 获取养殖种类列表
router.get('/animal-types', farmerController.getAnimalTypes);
module.exports = router;

View File

@@ -1,12 +1,20 @@
const express = require('express');
const router = express.Router();
const governmentController = require('../controllers/governmentController');
// 人员列表
router.get('/', (req, res) => {
res.json({
code: 200,
data: []
});
});
router.get('/', governmentController.getAdminStaff);
// 新增行政人员
router.post('/', governmentController.createAdminStaff);
// 编辑行政人员
router.put('/:id', governmentController.updateAdminStaff);
// 删除行政人员
router.delete('/:id', governmentController.deleteAdminStaff);
// 重置行政人员密码
router.post('/:id/reset-password', governmentController.resetAdminStaffPassword);
module.exports = router;

View File

@@ -0,0 +1,55 @@
const User = require('../models/User');
const bcrypt = require('bcryptjs');
// 初始化管理员用户
async function initAdminUser() {
try {
console.log('正在初始化管理员用户...');
// 检查是否已存在管理员用户
const existingAdmin = await User.findOne({
where: {
username: 'admin',
role: 'admin'
}
});
if (existingAdmin) {
console.log('管理员用户已存在,更新密码...');
// 加密密码
const hashedPassword = await bcrypt.hash('123456', 10);
// 更新用户密码
await existingAdmin.update({
password: hashedPassword,
status: 'active'
});
console.log('管理员用户密码更新成功');
} else {
console.log('创建新的管理员用户...');
// 加密密码
const hashedPassword = await bcrypt.hash('123456', 10);
// 创建管理员用户
await User.create({
username: 'admin',
password: hashedPassword,
role: 'admin',
status: 'active'
});
console.log('管理员用户创建成功');
}
console.log('初始化管理员用户完成');
} catch (error) {
console.error('初始化管理员用户失败:', error);
} finally {
// 关闭数据库连接
process.exit(0);
}
}
// 执行初始化
initAdminUser();

View File

@@ -0,0 +1,95 @@
// 数据库模型同步脚本
const sequelize = require('../config/database');
const Farmer = require('../models/Farmer');
// 同步数据库模型并添加测试数据
async function syncAndSeed() {
try {
// 同步模型到数据库
await sequelize.sync({ alter: true });
console.log('数据库模型同步成功');
// 检查是否已存在测试数据
const existingCount = await Farmer.count();
if (existingCount === 0) {
// 添加测试数据
const testFarmers = [
{
account: 'farmer001',
nickname: '牛场小王',
real_name: '王小明',
farm_name: '明辉养殖场',
farm_type: '规模',
animal_type: '牛',
animal_count: 200,
address: '内蒙古自治区通辽市科尔沁区',
registrar: 'admin',
status: 'active'
},
{
account: 'farmer002',
nickname: '草原小李',
real_name: '李草原',
farm_name: '草原牧业',
farm_type: '规模',
animal_type: '羊',
animal_count: 500,
address: '内蒙古自治区通辽市开鲁县',
registrar: 'admin',
status: 'active'
},
{
account: 'farmer003',
nickname: '家庭养殖户老张',
real_name: '张家庭',
farm_name: '张记养殖场',
farm_type: '散养',
animal_type: '猪',
animal_count: 50,
address: '内蒙古自治区通辽市扎鲁特旗',
registrar: 'admin',
status: 'active'
},
{
account: 'farmer004',
nickname: '家禽养殖',
real_name: '刘家禽',
farm_name: '刘家养殖场',
farm_type: '规模',
animal_type: '鸡',
animal_count: 2000,
address: '内蒙古自治区通辽市霍林郭勒市',
registrar: 'admin',
status: 'active'
},
{
account: 'farmer005',
nickname: '特种养殖',
real_name: '赵特种',
farm_name: '特种养殖场',
farm_type: '其他',
animal_type: '其他',
animal_count: 100,
address: '内蒙古自治区通辽市库伦旗',
registrar: 'admin',
status: 'inactive'
}
];
await Farmer.bulkCreate(testFarmers);
console.log('测试数据添加成功');
} else {
console.log('已存在测试数据,跳过添加');
}
// 关闭数据库连接
await sequelize.close();
} catch (error) {
console.error('同步数据库模型或添加测试数据失败:', error);
// 确保即使出错也关闭连接
await sequelize.close();
}
}
syncAndSeed();

View File

@@ -0,0 +1,31 @@
// 测试数据库连接
const sequelize = require('./config/database');
async function testDbConnection() {
try {
console.log('正在尝试连接数据库...');
console.log('连接配置:', {
host: sequelize.config.host,
port: sequelize.config.port,
database: sequelize.config.database,
username: sequelize.config.username,
dialect: sequelize.config.dialect
});
await sequelize.authenticate();
console.log('✅ 数据库连接成功!');
// 尝试查询数据库版本信息
const [results] = await sequelize.query('SELECT VERSION() AS version');
console.log('数据库版本:', results[0].version);
// 关闭连接
await sequelize.close();
console.log('数据库连接已关闭');
} catch (error) {
console.error('❌ 数据库连接失败:', error.message);
console.error('详细错误:', error);
}
}
testDbConnection();

View File

@@ -0,0 +1,50 @@
// 测试行政人员列表接口
const axios = require('axios');
// 政府后端服务地址
const BASE_URL = 'http://localhost:5352/api';
// 测试行政人员列表接口
async function testAdminStaffList() {
try {
// 先登录获取token
const loginResponse = await axios.post(`${BASE_URL}/auth/login`, {
username: 'admin',
password: '123456'
});
const token = loginResponse.data.token;
console.log('登录成功获取到token');
// 使用token访问行政人员列表接口
const response = await axios.get(`${BASE_URL}/personnel`, {
headers: {
'Authorization': `Bearer ${token}`
}
});
console.log('行政人员列表接口测试结果:');
console.log(`- 状态码: ${response.status}`);
console.log(`- 返回数据结构:`, Object.keys(response.data));
console.log(`- 行政人员总数: ${response.data.total}`);
console.log(`- 返回的行政人员列表长度: ${response.data.data ? response.data.data.length : 0}`);
if (response.data.data && response.data.data.length > 0) {
console.log(`- 第一条行政人员数据:`, response.data.data[0]);
} else {
console.log('- 行政人员列表为空');
}
console.log('\n测试完成');
} catch (error) {
console.error('测试失败:', error.message);
if (error.response) {
console.error('错误状态码:', error.response.status);
console.error('错误数据:', error.response.data);
}
}
}
// 执行测试
console.log('开始测试行政人员列表接口...');
testAdminStaffList();