更新项目文件结构,统一文档风格

This commit is contained in:
ylweng
2025-09-04 01:39:31 +08:00
parent 216cf80eab
commit 3ae7b4db8c
45 changed files with 17218 additions and 642 deletions

554
backend/api/routes/auth.js Normal file
View File

@@ -0,0 +1,554 @@
const express = require('express');
const bcrypt = require('bcrypt');
const jwt = require('jsonwebtoken');
const router = express.Router();
// 导入数据库连接(假设从主服务器文件导入)
// 这里暂时用模拟数据,待数据库连接修复后更新
let pool = null;
// 设置数据库连接池(将从主服务器导入)
function setPool(dbPool) {
pool = dbPool;
}
// JWT中间件验证
const authenticateToken = (req, res, next) => {
const authHeader = req.headers['authorization'];
const token = authHeader && authHeader.split(' ')[1];
if (!token) {
return res.status(401).json({
success: false,
message: '访问令牌缺失',
code: 'TOKEN_MISSING'
});
}
jwt.verify(token, process.env.JWT_SECRET, (err, user) => {
if (err) {
return res.status(403).json({
success: false,
message: '访问令牌无效或已过期',
code: 'TOKEN_INVALID'
});
}
req.user = user;
next();
});
};
// 权限检查中间件
const checkPermission = (requiredPermission) => {
return async (req, res, next) => {
try {
if (!pool) {
return res.status(500).json({
success: false,
message: '数据库连接不可用',
code: 'DB_UNAVAILABLE'
});
}
// 查询用户权限
const [permissions] = await pool.execute(`
SELECT p.name as permission_name
FROM users u
JOIN user_roles ur ON u.id = ur.user_id
JOIN role_permissions rp ON ur.role_id = rp.role_id
JOIN permissions p ON rp.permission_id = p.id
WHERE u.id = ?
`, [req.user.userId]);
const userPermissions = permissions.map(p => p.permission_name);
if (!userPermissions.includes(requiredPermission)) {
return res.status(403).json({
success: false,
message: '权限不足',
code: 'INSUFFICIENT_PERMISSION',
required: requiredPermission
});
}
req.userPermissions = userPermissions;
next();
} catch (error) {
console.error('权限检查错误:', error);
res.status(500).json({
success: false,
message: '权限检查失败',
code: 'PERMISSION_CHECK_ERROR'
});
}
};
};
// 用户注册
router.post('/register', async (req, res) => {
try {
const { username, email, phone, password, real_name, user_type } = req.body;
// 输入验证
if (!username || !password || !user_type) {
return res.status(400).json({
success: false,
message: '用户名、密码和用户类型为必填项',
code: 'MISSING_REQUIRED_FIELDS'
});
}
if (!pool) {
return res.status(500).json({
success: false,
message: '数据库连接不可用,请稍后重试',
code: 'DB_UNAVAILABLE'
});
}
// 检查用户名是否已存在
const [existingUsers] = await pool.execute(
'SELECT id FROM users WHERE username = ? OR email = ? OR phone = ?',
[username, email || null, phone || null]
);
if (existingUsers.length > 0) {
return res.status(409).json({
success: false,
message: '用户名、邮箱或手机号已存在',
code: 'USER_EXISTS'
});
}
// 密码加密
const saltRounds = 10;
const password_hash = await bcrypt.hash(password, saltRounds);
// 插入新用户
const [result] = await pool.execute(
'INSERT INTO users (username, email, phone, password_hash, real_name, user_type) VALUES (?, ?, ?, ?, ?, ?)',
[username, email || null, phone || null, password_hash, real_name || null, user_type]
);
res.status(201).json({
success: true,
message: '用户注册成功',
data: {
userId: result.insertId,
username,
user_type
}
});
} catch (error) {
console.error('用户注册错误:', error);
res.status(500).json({
success: false,
message: '注册失败,请稍后重试',
code: 'REGISTRATION_ERROR'
});
}
});
// 用户登录
router.post('/login', async (req, res) => {
try {
const { username, password } = req.body;
if (!username || !password) {
return res.status(400).json({
success: false,
message: '用户名和密码为必填项',
code: 'MISSING_CREDENTIALS'
});
}
if (!pool) {
// 数据库不可用时返回模拟数据(用于测试)
if (username === 'admin' && password === 'admin123') {
const token = jwt.sign(
{ userId: 1, username: 'admin', user_type: 'admin' },
process.env.JWT_SECRET,
{ expiresIn: process.env.JWT_EXPIRES_IN || '24h' }
);
return res.json({
success: true,
message: '登录成功(测试模式)',
data: {
token,
user: {
id: 1,
username: 'admin',
user_type: 'admin',
real_name: '系统管理员'
}
}
});
} else {
return res.status(401).json({
success: false,
message: '用户名或密码错误',
code: 'INVALID_CREDENTIALS'
});
}
}
// 检查数据库连接是否可用
try {
await pool.execute('SELECT 1');
} catch (dbError) {
// 数据库连接失败,使用测试模式
if (username === 'admin' && password === 'admin123') {
const token = jwt.sign(
{ userId: 1, username: 'admin', user_type: 'admin' },
process.env.JWT_SECRET,
{ expiresIn: process.env.JWT_EXPIRES_IN || '24h' }
);
return res.json({
success: true,
message: '登录成功(测试模式 - 数据库不可用)',
data: {
token,
user: {
id: 1,
username: 'admin',
user_type: 'admin',
real_name: '系统管理员'
}
}
});
} else {
return res.status(401).json({
success: false,
message: '用户名或密码错误(测试模式)',
code: 'INVALID_CREDENTIALS'
});
}
}
// 查询用户
const [users] = await pool.execute(
'SELECT id, username, password_hash, user_type, real_name, status FROM users WHERE username = ?',
[username]
);
if (users.length === 0) {
return res.status(401).json({
success: false,
message: '用户名或密码错误',
code: 'INVALID_CREDENTIALS'
});
}
const user = users[0];
// 检查用户状态
if (user.status === 0) {
return res.status(403).json({
success: false,
message: '用户账号已被禁用',
code: 'ACCOUNT_DISABLED'
});
}
// 验证密码
const isPasswordValid = await bcrypt.compare(password, user.password_hash);
if (!isPasswordValid) {
return res.status(401).json({
success: false,
message: '用户名或密码错误',
code: 'INVALID_CREDENTIALS'
});
}
// 生成JWT令牌
const token = jwt.sign(
{
userId: user.id,
username: user.username,
user_type: user.user_type
},
process.env.JWT_SECRET,
{ expiresIn: process.env.JWT_EXPIRES_IN || '24h' }
);
// 更新最后登录时间
await pool.execute(
'UPDATE users SET last_login = CURRENT_TIMESTAMP WHERE id = ?',
[user.id]
);
res.json({
success: true,
message: '登录成功',
data: {
token,
user: {
id: user.id,
username: user.username,
user_type: user.user_type,
real_name: user.real_name
}
}
});
} catch (error) {
console.error('用户登录错误:', error);
res.status(500).json({
success: false,
message: '登录失败,请稍后重试',
code: 'LOGIN_ERROR'
});
}
});
// 获取当前用户信息
router.get('/profile', authenticateToken, async (req, res) => {
try {
if (!pool) {
// 数据库不可用时返回模拟数据
return res.json({
success: true,
data: {
id: req.user.userId,
username: req.user.username,
user_type: req.user.user_type,
real_name: '系统管理员',
email: 'admin@xlxumu.com',
status: 1
}
});
}
// 检查数据库连接
try {
await pool.execute('SELECT 1');
} catch (dbError) {
// 数据库连接失败,返回模拟数据
return res.json({
success: true,
data: {
id: req.user.userId,
username: req.user.username,
user_type: req.user.user_type,
real_name: '系统管理员',
email: 'admin@xlxumu.com',
status: 1
}
});
}
const [users] = await pool.execute(
'SELECT id, username, email, phone, real_name, user_type, status, last_login, created_at FROM users WHERE id = ?',
[req.user.userId]
);
if (users.length === 0) {
return res.status(404).json({
success: false,
message: '用户不存在',
code: 'USER_NOT_FOUND'
});
}
res.json({
success: true,
data: users[0]
});
} catch (error) {
console.error('获取用户信息错误:', error);
res.status(500).json({
success: false,
message: '获取用户信息失败',
code: 'PROFILE_ERROR'
});
}
});
// 更新用户信息
router.put('/profile', authenticateToken, async (req, res) => {
try {
const { real_name, email, phone } = req.body;
const userId = req.user.userId;
if (!pool) {
return res.status(500).json({
success: false,
message: '数据库连接不可用',
code: 'DB_UNAVAILABLE'
});
}
// 检查邮箱和手机号是否被其他用户使用
if (email || phone) {
const [existingUsers] = await pool.execute(
'SELECT id FROM users WHERE (email = ? OR phone = ?) AND id != ?',
[email || null, phone || null, userId]
);
if (existingUsers.length > 0) {
return res.status(409).json({
success: false,
message: '邮箱或手机号已被其他用户使用',
code: 'CONTACT_EXISTS'
});
}
}
// 更新用户信息
await pool.execute(
'UPDATE users SET real_name = ?, email = ?, phone = ? WHERE id = ?',
[real_name || null, email || null, phone || null, userId]
);
res.json({
success: true,
message: '用户信息更新成功'
});
} catch (error) {
console.error('更新用户信息错误:', error);
res.status(500).json({
success: false,
message: '更新用户信息失败',
code: 'UPDATE_PROFILE_ERROR'
});
}
});
// 修改密码
router.post('/change-password', authenticateToken, async (req, res) => {
try {
const { current_password, new_password } = req.body;
const userId = req.user.userId;
if (!current_password || !new_password) {
return res.status(400).json({
success: false,
message: '当前密码和新密码为必填项',
code: 'MISSING_PASSWORDS'
});
}
if (!pool) {
return res.status(500).json({
success: false,
message: '数据库连接不可用',
code: 'DB_UNAVAILABLE'
});
}
// 获取当前密码哈希
const [users] = await pool.execute(
'SELECT password_hash FROM users WHERE id = ?',
[userId]
);
if (users.length === 0) {
return res.status(404).json({
success: false,
message: '用户不存在',
code: 'USER_NOT_FOUND'
});
}
// 验证当前密码
const isCurrentPasswordValid = await bcrypt.compare(current_password, users[0].password_hash);
if (!isCurrentPasswordValid) {
return res.status(401).json({
success: false,
message: '当前密码错误',
code: 'INVALID_CURRENT_PASSWORD'
});
}
// 加密新密码
const saltRounds = 10;
const new_password_hash = await bcrypt.hash(new_password, saltRounds);
// 更新密码
await pool.execute(
'UPDATE users SET password_hash = ? WHERE id = ?',
[new_password_hash, userId]
);
res.json({
success: true,
message: '密码修改成功'
});
} catch (error) {
console.error('修改密码错误:', error);
res.status(500).json({
success: false,
message: '修改密码失败',
code: 'CHANGE_PASSWORD_ERROR'
});
}
});
// 获取用户权限
router.get('/permissions', authenticateToken, async (req, res) => {
try {
if (!pool) {
// 数据库不可用时返回模拟权限数据
const mockPermissions = ['user_manage', 'cattle_manage', 'data_view', 'system_config'];
return res.json({
success: true,
data: {
permissions: mockPermissions,
roles: ['admin']
}
});
}
// 查询用户角色和权限
const [results] = await pool.execute(`
SELECT r.name as role_name, p.name as permission_name, p.module
FROM users u
JOIN user_roles ur ON u.id = ur.user_id
JOIN roles r ON ur.role_id = r.id
LEFT JOIN role_permissions rp ON r.id = rp.role_id
LEFT JOIN permissions p ON rp.permission_id = p.id
WHERE u.id = ?
`, [req.user.userId]);
const roles = [...new Set(results.map(r => r.role_name))];
const permissions = [...new Set(results.filter(r => r.permission_name).map(r => r.permission_name))];
res.json({
success: true,
data: {
roles,
permissions
}
});
} catch (error) {
console.error('获取权限错误:', error);
res.status(500).json({
success: false,
message: '获取权限失败',
code: 'PERMISSIONS_ERROR'
});
}
});
// 登出主要用于前端清除token后端不需要处理
router.post('/logout', authenticateToken, (req, res) => {
res.json({
success: true,
message: '登出成功'
});
});
// 导出模块
module.exports = {
router,
authenticateToken,
checkPermission,
setPool
};

View File

@@ -0,0 +1,774 @@
const express = require('express');
const router = express.Router();
// 中间件将在服务器启动时设置
let authenticateToken = (req, res, next) => {
return res.status(500).json({
success: false,
message: '认证中间件未初始化',
code: 'AUTH_NOT_INITIALIZED'
});
};
let checkPermission = (permission) => {
return (req, res, next) => {
return res.status(500).json({
success: false,
message: '权限中间件未初始化',
code: 'PERMISSION_NOT_INITIALIZED'
});
};
};
let pool = null;
// 设置中间件和数据库连接(从主服务器导入)
function setMiddleware(auth, permission, dbPool) {
authenticateToken = auth;
checkPermission = permission;
pool = dbPool;
}
// 获取牛只列表
router.get('/', authenticateToken, checkPermission('cattle_manage'), async (req, res) => {
try {
const {
page = 1,
limit = 10,
owner_id,
breed,
status,
health_status,
search
} = req.query;
const offset = (page - 1) * limit;
if (!pool) {
// 数据库不可用时返回模拟数据
const mockCattle = [
{
id: 1,
ear_tag: 'XL001',
name: '小花',
breed: '西门塔尔牛',
gender: 'female',
birth_date: '2022-03-15',
color: '黄白花',
weight: 450.50,
health_status: 'healthy',
status: 'active',
farm_location: '锡林浩特市第一牧场',
created_at: '2024-01-01 00:00:00'
},
{
id: 2,
ear_tag: 'XL002',
name: '壮壮',
breed: '安格斯牛',
gender: 'male',
birth_date: '2021-08-20',
color: '黑色',
weight: 580.75,
health_status: 'healthy',
status: 'active',
farm_location: '锡林浩特市第一牧场',
created_at: '2024-01-01 01:00:00'
},
{
id: 3,
ear_tag: 'XL003',
name: '美美',
breed: '夏洛莱牛',
gender: 'female',
birth_date: '2022-05-10',
color: '白色',
weight: 420.30,
health_status: 'healthy',
status: 'active',
farm_location: '东乌旗牧场A',
created_at: '2024-01-01 02:00:00'
}
];
return res.json({
success: true,
data: {
cattle: mockCattle,
pagination: {
total: mockCattle.length,
page: parseInt(page),
limit: parseInt(limit),
pages: Math.ceil(mockCattle.length / limit)
}
}
});
}
// 检查数据库连接
try {
await pool.execute('SELECT 1');
} catch (dbError) {
// 数据库连接失败,返回模拟数据
const mockCattle = [
{
id: 1,
ear_tag: 'XL001',
name: '小花',
breed: '西门塔尔牛',
gender: 'female',
birth_date: '2022-03-15',
color: '黄白花',
weight: 450.50,
health_status: 'healthy',
status: 'active',
farm_location: '锡林浩特市第一牧场',
created_at: '2024-01-01 00:00:00'
}
];
return res.json({
success: true,
message: '数据库连接不可用,返回模拟数据',
data: {
cattle: mockCattle,
pagination: {
total: mockCattle.length,
page: parseInt(page),
limit: parseInt(limit),
pages: Math.ceil(mockCattle.length / limit)
}
}
});
}
// 构建查询条件
let whereClause = '1=1';
let queryParams = [];
if (owner_id) {
whereClause += ' AND owner_id = ?';
queryParams.push(owner_id);
}
if (breed) {
whereClause += ' AND breed = ?';
queryParams.push(breed);
}
if (status) {
whereClause += ' AND status = ?';
queryParams.push(status);
}
if (health_status) {
whereClause += ' AND health_status = ?';
queryParams.push(health_status);
}
if (search) {
whereClause += ' AND (ear_tag LIKE ? OR name LIKE ? OR breed LIKE ?)';
const searchTerm = `%${search}%`;
queryParams.push(searchTerm, searchTerm, searchTerm);
}
// 获取总数
const [countResult] = await pool.execute(
`SELECT COUNT(*) as total FROM cattle WHERE ${whereClause}`,
queryParams
);
const total = countResult[0].total;
// 获取牛只列表
const [cattle] = await pool.execute(
`SELECT c.*, u.real_name as owner_name
FROM cattle c
LEFT JOIN users u ON c.owner_id = u.id
WHERE ${whereClause}
ORDER BY c.created_at DESC
LIMIT ? OFFSET ?`,
[...queryParams, parseInt(limit), offset]
);
res.json({
success: true,
data: {
cattle,
pagination: {
total,
page: parseInt(page),
limit: parseInt(limit),
pages: Math.ceil(total / limit)
}
}
});
} catch (error) {
console.error('获取牛只列表错误:', error);
res.status(500).json({
success: false,
message: '获取牛只列表失败',
code: 'GET_CATTLE_ERROR'
});
}
});
// 获取牛只详情
router.get('/:id', authenticateToken, checkPermission('cattle_manage'), async (req, res) => {
try {
const cattleId = req.params.id;
if (!pool) {
return res.status(500).json({
success: false,
message: '数据库连接不可用',
code: 'DB_UNAVAILABLE'
});
}
// 检查数据库连接
try {
await pool.execute('SELECT 1');
} catch (dbError) {
return res.status(500).json({
success: false,
message: '数据库连接不可用',
code: 'DB_UNAVAILABLE'
});
}
// 获取牛只基本信息
const [cattle] = await pool.execute(
`SELECT c.*, u.real_name as owner_name, u.phone as owner_phone
FROM cattle c
LEFT JOIN users u ON c.owner_id = u.id
WHERE c.id = ?`,
[cattleId]
);
if (cattle.length === 0) {
return res.status(404).json({
success: false,
message: '牛只不存在',
code: 'CATTLE_NOT_FOUND'
});
}
// 获取最近的饲养记录
const [feedingRecords] = await pool.execute(
`SELECT * FROM feeding_records
WHERE cattle_id = ?
ORDER BY record_date DESC
LIMIT 10`,
[cattleId]
);
// 获取繁殖记录
const [breedingRecords] = await pool.execute(
`SELECT * FROM breeding_records
WHERE cattle_id = ?
ORDER BY breeding_date DESC
LIMIT 5`,
[cattleId]
);
res.json({
success: true,
data: {
cattle: cattle[0],
feeding_records: feedingRecords,
breeding_records: breedingRecords
}
});
} catch (error) {
console.error('获取牛只详情错误:', error);
res.status(500).json({
success: false,
message: '获取牛只详情失败',
code: 'GET_CATTLE_DETAIL_ERROR'
});
}
});
// 创建牛只档案
router.post('/', authenticateToken, checkPermission('cattle_manage'), async (req, res) => {
try {
const {
ear_tag,
name,
breed,
gender,
birth_date,
color,
weight,
owner_id,
farm_location
} = req.body;
// 输入验证
if (!ear_tag || !breed || !gender) {
return res.status(400).json({
success: false,
message: '耳标号、品种和性别为必填项',
code: 'MISSING_REQUIRED_FIELDS'
});
}
if (!pool) {
return res.status(500).json({
success: false,
message: '数据库连接不可用',
code: 'DB_UNAVAILABLE'
});
}
// 检查数据库连接
try {
await pool.execute('SELECT 1');
} catch (dbError) {
return res.status(500).json({
success: false,
message: '数据库连接不可用',
code: 'DB_UNAVAILABLE'
});
}
// 检查耳标是否已存在
const [existingCattle] = await pool.execute(
'SELECT id FROM cattle WHERE ear_tag = ?',
[ear_tag]
);
if (existingCattle.length > 0) {
return res.status(409).json({
success: false,
message: '耳标号已存在',
code: 'EAR_TAG_EXISTS'
});
}
// 插入新牛只
const [result] = await pool.execute(
`INSERT INTO cattle (ear_tag, name, breed, gender, birth_date, color, weight, owner_id, farm_location)
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)`,
[ear_tag, name || null, breed, gender, birth_date || null, color || null, weight || null, owner_id || null, farm_location || null]
);
res.status(201).json({
success: true,
message: '牛只档案创建成功',
data: {
cattle_id: result.insertId,
ear_tag,
name,
breed
}
});
} catch (error) {
console.error('创建牛只档案错误:', error);
res.status(500).json({
success: false,
message: '创建牛只档案失败',
code: 'CREATE_CATTLE_ERROR'
});
}
});
// 更新牛只信息
router.put('/:id', authenticateToken, checkPermission('cattle_manage'), async (req, res) => {
try {
const cattleId = req.params.id;
const {
name,
color,
weight,
health_status,
status,
farm_location,
owner_id
} = req.body;
if (!pool) {
return res.status(500).json({
success: false,
message: '数据库连接不可用',
code: 'DB_UNAVAILABLE'
});
}
// 检查数据库连接
try {
await pool.execute('SELECT 1');
} catch (dbError) {
return res.status(500).json({
success: false,
message: '数据库连接不可用',
code: 'DB_UNAVAILABLE'
});
}
// 检查牛只是否存在
const [cattle] = await pool.execute('SELECT id FROM cattle WHERE id = ?', [cattleId]);
if (cattle.length === 0) {
return res.status(404).json({
success: false,
message: '牛只不存在',
code: 'CATTLE_NOT_FOUND'
});
}
// 更新牛只信息
await pool.execute(
`UPDATE cattle
SET name = ?, color = ?, weight = ?, health_status = ?, status = ?, farm_location = ?, owner_id = ?
WHERE id = ?`,
[
name || null,
color || null,
weight || null,
health_status || 'healthy',
status || 'active',
farm_location || null,
owner_id || null,
cattleId
]
);
res.json({
success: true,
message: '牛只信息更新成功'
});
} catch (error) {
console.error('更新牛只信息错误:', error);
res.status(500).json({
success: false,
message: '更新牛只信息失败',
code: 'UPDATE_CATTLE_ERROR'
});
}
});
// 删除牛只档案
router.delete('/:id', authenticateToken, checkPermission('cattle_manage'), async (req, res) => {
try {
const cattleId = req.params.id;
if (!pool) {
return res.status(500).json({
success: false,
message: '数据库连接不可用',
code: 'DB_UNAVAILABLE'
});
}
// 检查数据库连接
try {
await pool.execute('SELECT 1');
} catch (dbError) {
return res.status(500).json({
success: false,
message: '数据库连接不可用',
code: 'DB_UNAVAILABLE'
});
}
// 检查牛只是否存在
const [cattle] = await pool.execute('SELECT id FROM cattle WHERE id = ?', [cattleId]);
if (cattle.length === 0) {
return res.status(404).json({
success: false,
message: '牛只不存在',
code: 'CATTLE_NOT_FOUND'
});
}
// 删除牛只(级联删除相关记录)
await pool.execute('DELETE FROM cattle WHERE id = ?', [cattleId]);
res.json({
success: true,
message: '牛只档案删除成功'
});
} catch (error) {
console.error('删除牛只档案错误:', error);
res.status(500).json({
success: false,
message: '删除牛只档案失败',
code: 'DELETE_CATTLE_ERROR'
});
}
});
// 获取饲养记录
router.get('/:id/feeding-records', authenticateToken, checkPermission('cattle_manage'), async (req, res) => {
try {
const cattleId = req.params.id;
const { page = 1, limit = 10, record_type } = req.query;
const offset = (page - 1) * limit;
if (!pool) {
return res.status(500).json({
success: false,
message: '数据库连接不可用',
code: 'DB_UNAVAILABLE'
});
}
// 检查数据库连接
try {
await pool.execute('SELECT 1');
} catch (dbError) {
return res.status(500).json({
success: false,
message: '数据库连接不可用',
code: 'DB_UNAVAILABLE'
});
}
// 构建查询条件
let whereClause = 'cattle_id = ?';
let queryParams = [cattleId];
if (record_type) {
whereClause += ' AND record_type = ?';
queryParams.push(record_type);
}
// 获取总数
const [countResult] = await pool.execute(
`SELECT COUNT(*) as total FROM feeding_records WHERE ${whereClause}`,
queryParams
);
const total = countResult[0].total;
// 获取饲养记录
const [records] = await pool.execute(
`SELECT fr.*, u.real_name as operator_name
FROM feeding_records fr
LEFT JOIN users u ON fr.operator_id = u.id
WHERE ${whereClause}
ORDER BY fr.record_date DESC
LIMIT ? OFFSET ?`,
[...queryParams, parseInt(limit), offset]
);
res.json({
success: true,
data: {
records,
pagination: {
total,
page: parseInt(page),
limit: parseInt(limit),
pages: Math.ceil(total / limit)
}
}
});
} catch (error) {
console.error('获取饲养记录错误:', error);
res.status(500).json({
success: false,
message: '获取饲养记录失败',
code: 'GET_FEEDING_RECORDS_ERROR'
});
}
});
// 添加饲养记录
router.post('/:id/feeding-records', authenticateToken, checkPermission('cattle_manage'), async (req, res) => {
try {
const cattleId = req.params.id;
const {
record_type,
feed_type,
feed_amount,
vaccine_name,
treatment_desc,
medicine_name,
dosage,
veterinarian,
cost,
record_date,
notes
} = req.body;
// 输入验证
if (!record_type || !record_date) {
return res.status(400).json({
success: false,
message: '记录类型和记录日期为必填项',
code: 'MISSING_REQUIRED_FIELDS'
});
}
if (!pool) {
return res.status(500).json({
success: false,
message: '数据库连接不可用',
code: 'DB_UNAVAILABLE'
});
}
// 检查数据库连接
try {
await pool.execute('SELECT 1');
} catch (dbError) {
return res.status(500).json({
success: false,
message: '数据库连接不可用',
code: 'DB_UNAVAILABLE'
});
}
// 检查牛只是否存在
const [cattle] = await pool.execute('SELECT id FROM cattle WHERE id = ?', [cattleId]);
if (cattle.length === 0) {
return res.status(404).json({
success: false,
message: '牛只不存在',
code: 'CATTLE_NOT_FOUND'
});
}
// 插入饲养记录
const [result] = await pool.execute(
`INSERT INTO feeding_records
(cattle_id, record_type, feed_type, feed_amount, vaccine_name, treatment_desc,
medicine_name, dosage, veterinarian, cost, record_date, notes, operator_id)
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`,
[
cattleId,
record_type,
feed_type || null,
feed_amount || null,
vaccine_name || null,
treatment_desc || null,
medicine_name || null,
dosage || null,
veterinarian || null,
cost || null,
record_date,
notes || null,
req.user.userId
]
);
res.status(201).json({
success: true,
message: '饲养记录添加成功',
data: {
record_id: result.insertId,
record_type,
record_date
}
});
} catch (error) {
console.error('添加饲养记录错误:', error);
res.status(500).json({
success: false,
message: '添加饲养记录失败',
code: 'CREATE_FEEDING_RECORD_ERROR'
});
}
});
// 获取牛只统计信息
router.get('/stats/overview', authenticateToken, checkPermission('data_view'), async (req, res) => {
try {
if (!pool) {
// 数据库不可用时返回模拟数据
const mockStats = {
total_cattle: 156,
healthy_cattle: 148,
sick_cattle: 8,
by_breed: [
{ breed: '西门塔尔牛', count: 68 },
{ breed: '安格斯牛', count: 45 },
{ breed: '夏洛莱牛', count: 43 }
],
by_status: [
{ status: 'active', count: 142 },
{ status: 'sold', count: 12 },
{ status: 'quarantine', count: 2 }
]
};
return res.json({
success: true,
data: mockStats
});
}
// 检查数据库连接
try {
await pool.execute('SELECT 1');
} catch (dbError) {
// 数据库连接失败,返回模拟数据
const mockStats = {
total_cattle: 156,
healthy_cattle: 148,
sick_cattle: 8,
by_breed: [
{ breed: '西门塔尔牛', count: 68 },
{ breed: '安格斯牛', count: 45 },
{ breed: '夏洛莱牛', count: 43 }
],
by_status: [
{ status: 'active', count: 142 },
{ status: 'sold', count: 12 },
{ status: 'quarantine', count: 2 }
]
};
return res.json({
success: true,
message: '数据库连接不可用,返回模拟数据',
data: mockStats
});
}
// 获取总体统计
const [totalResult] = await pool.execute('SELECT COUNT(*) as total FROM cattle');
const [healthyResult] = await pool.execute('SELECT COUNT(*) as healthy FROM cattle WHERE health_status = "healthy"');
const [sickResult] = await pool.execute('SELECT COUNT(*) as sick FROM cattle WHERE health_status IN ("sick", "quarantine")');
// 按品种统计
const [breedStats] = await pool.execute(
'SELECT breed, COUNT(*) as count FROM cattle GROUP BY breed ORDER BY count DESC LIMIT 10'
);
// 按状态统计
const [statusStats] = await pool.execute(
'SELECT status, COUNT(*) as count FROM cattle GROUP BY status'
);
res.json({
success: true,
data: {
total_cattle: totalResult[0].total,
healthy_cattle: healthyResult[0].healthy,
sick_cattle: sickResult[0].sick,
by_breed: breedStats,
by_status: statusStats
}
});
} catch (error) {
console.error('获取牛只统计错误:', error);
res.status(500).json({
success: false,
message: '获取牛只统计失败',
code: 'GET_CATTLE_STATS_ERROR'
});
}
});
module.exports = {
router,
setMiddleware
};

View File

@@ -0,0 +1,919 @@
const express = require('express');
const router = express.Router();
// 中间件将在服务器启动时设置
let authenticateToken = (req, res, next) => {
return res.status(500).json({
success: false,
message: '认证中间件未初始化',
code: 'AUTH_NOT_INITIALIZED'
});
};
let checkPermission = (permission) => {
return (req, res, next) => {
return res.status(500).json({
success: false,
message: '权限中间件未初始化',
code: 'PERMISSION_NOT_INITIALIZED'
});
};
};
let pool = null;
// 设置中间件和数据库连接(从主服务器导入)
function setMiddleware(auth, permission, dbPool) {
authenticateToken = auth;
checkPermission = permission;
pool = dbPool;
}
// ======================================
// 贷款管理相关接口
// ======================================
// 获取贷款申请列表
router.get('/loans', authenticateToken, checkPermission('loan_manage'), async (req, res) => {
try {
const {
page = 1,
limit = 10,
status,
loan_type,
applicant_id,
search
} = req.query;
const offset = (page - 1) * limit;
if (!pool) {
// 数据库不可用时返回模拟数据
const mockLoans = [
{
id: 1,
applicant_id: 2,
applicant_name: '张三',
loan_type: 'cattle',
loan_amount: 500000.00,
interest_rate: 0.0450,
term_months: 24,
status: 'approved',
purpose: '购买西门塔尔牛30头用于扩大养殖规模',
approved_amount: 450000.00,
approved_date: '2024-01-15 10:30:00',
disbursement_date: '2024-01-20 14:00:00',
created_at: '2024-01-10 09:00:00'
},
{
id: 2,
applicant_id: 3,
applicant_name: '李四',
loan_type: 'equipment',
loan_amount: 300000.00,
interest_rate: 0.0520,
term_months: 36,
status: 'under_review',
purpose: '购买饲料加工设备和自动饮水系统',
approved_amount: null,
approved_date: null,
disbursement_date: null,
created_at: '2024-01-18 16:45:00'
},
{
id: 3,
applicant_id: 4,
applicant_name: '王五',
loan_type: 'operating',
loan_amount: 200000.00,
interest_rate: 0.0480,
term_months: 12,
status: 'disbursed',
purpose: '购买饲料和兽药,维持日常运营',
approved_amount: 200000.00,
approved_date: '2024-01-12 11:20:00',
disbursement_date: '2024-01-16 09:30:00',
created_at: '2024-01-08 14:15:00'
}
];
return res.json({
success: true,
data: {
loans: mockLoans,
pagination: {
total: mockLoans.length,
page: parseInt(page),
limit: parseInt(limit),
pages: Math.ceil(mockLoans.length / limit)
}
}
});
}
// 数据库可用时的实际查询逻辑
try {
await pool.execute('SELECT 1');
} catch (dbError) {
// 数据库连接失败,返回模拟数据
const mockLoans = [
{
id: 1,
applicant_name: '张三',
loan_type: 'cattle',
loan_amount: 500000.00,
status: 'approved',
purpose: '购买西门塔尔牛30头',
created_at: '2024-01-10 09:00:00'
}
];
return res.json({
success: true,
message: '数据库连接不可用,返回模拟数据',
data: {
loans: mockLoans,
pagination: {
total: mockLoans.length,
page: parseInt(page),
limit: parseInt(limit),
pages: Math.ceil(mockLoans.length / limit)
}
}
});
}
// 构建查询条件
let whereClause = '1=1';
let queryParams = [];
if (status) {
whereClause += ' AND la.status = ?';
queryParams.push(status);
}
if (loan_type) {
whereClause += ' AND la.loan_type = ?';
queryParams.push(loan_type);
}
if (applicant_id) {
whereClause += ' AND la.applicant_id = ?';
queryParams.push(applicant_id);
}
if (search) {
whereClause += ' AND (u.real_name LIKE ? OR la.purpose LIKE ?)';
const searchTerm = `%${search}%`;
queryParams.push(searchTerm, searchTerm);
}
// 获取总数
const [countResult] = await pool.execute(
`SELECT COUNT(*) as total
FROM loan_applications la
LEFT JOIN users u ON la.applicant_id = u.id
WHERE ${whereClause}`,
queryParams
);
const total = countResult[0].total;
// 获取贷款申请列表
const [loans] = await pool.execute(
`SELECT la.*, u.real_name as applicant_name, u.phone as applicant_phone,
rv.real_name as reviewer_name
FROM loan_applications la
LEFT JOIN users u ON la.applicant_id = u.id
LEFT JOIN users rv ON la.reviewer_id = rv.id
WHERE ${whereClause}
ORDER BY la.created_at DESC
LIMIT ? OFFSET ?`,
[...queryParams, parseInt(limit), offset]
);
res.json({
success: true,
data: {
loans,
pagination: {
total,
page: parseInt(page),
limit: parseInt(limit),
pages: Math.ceil(total / limit)
}
}
});
} catch (error) {
console.error('获取贷款申请列表错误:', error);
res.status(500).json({
success: false,
message: '获取贷款申请列表失败',
code: 'GET_LOANS_ERROR'
});
}
});
// 获取贷款申请详情
router.get('/loans/:id', authenticateToken, checkPermission('loan_manage'), async (req, res) => {
try {
const loanId = req.params.id;
if (!pool) {
return res.status(500).json({
success: false,
message: '数据库连接不可用',
code: 'DB_UNAVAILABLE'
});
}
try {
await pool.execute('SELECT 1');
} catch (dbError) {
return res.status(500).json({
success: false,
message: '数据库连接不可用',
code: 'DB_UNAVAILABLE'
});
}
// 获取贷款详情
const [loans] = await pool.execute(
`SELECT la.*, u.real_name as applicant_name, u.phone as applicant_phone, u.email as applicant_email,
rv.real_name as reviewer_name
FROM loan_applications la
LEFT JOIN users u ON la.applicant_id = u.id
LEFT JOIN users rv ON la.reviewer_id = rv.id
WHERE la.id = ?`,
[loanId]
);
if (loans.length === 0) {
return res.status(404).json({
success: false,
message: '贷款申请不存在',
code: 'LOAN_NOT_FOUND'
});
}
const loan = loans[0];
// 如果有质押牛只,获取牛只信息
let cattleInfo = [];
if (loan.cattle_ids) {
try {
const cattleIds = JSON.parse(loan.cattle_ids);
if (cattleIds && cattleIds.length > 0) {
const [cattle] = await pool.execute(
`SELECT id, ear_tag, name, breed, weight, health_status
FROM cattle
WHERE id IN (${cattleIds.map(() => '?').join(',')})`,
cattleIds
);
cattleInfo = cattle;
}
} catch (parseError) {
console.warn('解析质押牛只ID失败:', parseError);
}
}
res.json({
success: true,
data: {
loan,
cattle_collateral: cattleInfo
}
});
} catch (error) {
console.error('获取贷款详情错误:', error);
res.status(500).json({
success: false,
message: '获取贷款详情失败',
code: 'GET_LOAN_DETAIL_ERROR'
});
}
});
// 创建贷款申请
router.post('/loans', authenticateToken, checkPermission('loan_manage'), async (req, res) => {
try {
const {
applicant_id,
loan_type,
cattle_ids,
loan_amount,
interest_rate,
term_months,
purpose,
repayment_method,
guarantee_type
} = req.body;
// 输入验证
if (!applicant_id || !loan_type || !loan_amount || !purpose) {
return res.status(400).json({
success: false,
message: '申请人、贷款类型、贷款金额和用途为必填项',
code: 'MISSING_REQUIRED_FIELDS'
});
}
if (!pool) {
return res.status(500).json({
success: false,
message: '数据库连接不可用',
code: 'DB_UNAVAILABLE'
});
}
try {
await pool.execute('SELECT 1');
} catch (dbError) {
return res.status(500).json({
success: false,
message: '数据库连接不可用',
code: 'DB_UNAVAILABLE'
});
}
// 验证申请人是否存在
const [users] = await pool.execute('SELECT id FROM users WHERE id = ?', [applicant_id]);
if (users.length === 0) {
return res.status(404).json({
success: false,
message: '申请人不存在',
code: 'APPLICANT_NOT_FOUND'
});
}
// 插入贷款申请
const [result] = await pool.execute(
`INSERT INTO loan_applications
(applicant_id, loan_type, cattle_ids, loan_amount, interest_rate, term_months,
purpose, repayment_method, guarantee_type, status)
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, 'submitted')`,
[
applicant_id,
loan_type,
cattle_ids ? JSON.stringify(cattle_ids) : null,
loan_amount,
interest_rate || null,
term_months || null,
purpose,
repayment_method || null,
guarantee_type || null
]
);
res.status(201).json({
success: true,
message: '贷款申请创建成功',
data: {
loan_id: result.insertId,
applicant_id,
loan_amount,
status: 'submitted'
}
});
} catch (error) {
console.error('创建贷款申请错误:', error);
res.status(500).json({
success: false,
message: '创建贷款申请失败',
code: 'CREATE_LOAN_ERROR'
});
}
});
// 审批贷款申请
router.put('/loans/:id/review', authenticateToken, checkPermission('loan_manage'), async (req, res) => {
try {
const loanId = req.params.id;
const {
status,
approved_amount,
review_notes
} = req.body;
// 输入验证
if (!status || !['approved', 'rejected'].includes(status)) {
return res.status(400).json({
success: false,
message: '审批状态必须是 approved 或 rejected',
code: 'INVALID_STATUS'
});
}
if (!pool) {
return res.status(500).json({
success: false,
message: '数据库连接不可用',
code: 'DB_UNAVAILABLE'
});
}
try {
await pool.execute('SELECT 1');
} catch (dbError) {
return res.status(500).json({
success: false,
message: '数据库连接不可用',
code: 'DB_UNAVAILABLE'
});
}
// 检查贷款申请是否存在
const [loans] = await pool.execute('SELECT id, status FROM loan_applications WHERE id = ?', [loanId]);
if (loans.length === 0) {
return res.status(404).json({
success: false,
message: '贷款申请不存在',
code: 'LOAN_NOT_FOUND'
});
}
// 检查当前状态是否允许审批
if (!['submitted', 'under_review'].includes(loans[0].status)) {
return res.status(400).json({
success: false,
message: '当前状态不允许审批',
code: 'INVALID_CURRENT_STATUS'
});
}
// 更新审批结果
await pool.execute(
`UPDATE loan_applications
SET status = ?, approved_amount = ?, review_notes = ?, reviewer_id = ?, approved_date = CURRENT_TIMESTAMP
WHERE id = ?`,
[status, approved_amount || null, review_notes || null, req.user.userId, loanId]
);
res.json({
success: true,
message: `贷款申请${status === 'approved' ? '批准' : '拒绝'}成功`,
data: {
loan_id: loanId,
status,
approved_amount: approved_amount || null
}
});
} catch (error) {
console.error('审批贷款申请错误:', error);
res.status(500).json({
success: false,
message: '审批贷款申请失败',
code: 'REVIEW_LOAN_ERROR'
});
}
});
// ======================================
// 保险管理相关接口
// ======================================
// 获取保险申请列表
router.get('/insurance', authenticateToken, checkPermission('insurance_manage'), async (req, res) => {
try {
const {
page = 1,
limit = 10,
status,
insurance_type,
applicant_id,
search
} = req.query;
const offset = (page - 1) * limit;
if (!pool) {
// 数据库不可用时返回模拟数据
const mockInsurance = [
{
id: 1,
applicant_id: 2,
applicant_name: '张三',
insurance_type: 'cattle_death',
policy_number: 'INS202401001',
insured_amount: 300000.00,
premium: 12000.00,
start_date: '2024-02-01',
end_date: '2025-01-31',
status: 'active',
created_at: '2024-01-20 10:00:00'
},
{
id: 2,
applicant_id: 3,
applicant_name: '李四',
insurance_type: 'cattle_health',
policy_number: 'INS202401002',
insured_amount: 250000.00,
premium: 8750.00,
start_date: '2024-02-15',
end_date: '2025-02-14',
status: 'underwriting',
created_at: '2024-01-25 14:30:00'
},
{
id: 3,
applicant_id: 4,
applicant_name: '王五',
insurance_type: 'cattle_theft',
policy_number: null,
insured_amount: 180000.00,
premium: 5400.00,
start_date: null,
end_date: null,
status: 'applied',
created_at: '2024-01-28 09:15:00'
}
];
return res.json({
success: true,
data: {
insurance: mockInsurance,
pagination: {
total: mockInsurance.length,
page: parseInt(page),
limit: parseInt(limit),
pages: Math.ceil(mockInsurance.length / limit)
}
}
});
}
try {
await pool.execute('SELECT 1');
} catch (dbError) {
// 数据库连接失败,返回模拟数据
const mockInsurance = [
{
id: 1,
applicant_name: '张三',
insurance_type: 'cattle_death',
insured_amount: 300000.00,
status: 'active',
created_at: '2024-01-20 10:00:00'
}
];
return res.json({
success: true,
message: '数据库连接不可用,返回模拟数据',
data: {
insurance: mockInsurance,
pagination: {
total: mockInsurance.length,
page: parseInt(page),
limit: parseInt(limit),
pages: Math.ceil(mockInsurance.length / limit)
}
}
});
}
// 实际数据库查询逻辑
let whereClause = '1=1';
let queryParams = [];
if (status) {
whereClause += ' AND ia.status = ?';
queryParams.push(status);
}
if (insurance_type) {
whereClause += ' AND ia.insurance_type = ?';
queryParams.push(insurance_type);
}
if (applicant_id) {
whereClause += ' AND ia.applicant_id = ?';
queryParams.push(applicant_id);
}
if (search) {
whereClause += ' AND (u.real_name LIKE ? OR ia.policy_number LIKE ?)';
const searchTerm = `%${search}%`;
queryParams.push(searchTerm, searchTerm);
}
// 获取总数
const [countResult] = await pool.execute(
`SELECT COUNT(*) as total
FROM insurance_applications ia
LEFT JOIN users u ON ia.applicant_id = u.id
WHERE ${whereClause}`,
queryParams
);
const total = countResult[0].total;
// 获取保险申请列表
const [insurance] = await pool.execute(
`SELECT ia.*, u.real_name as applicant_name, u.phone as applicant_phone,
uw.real_name as underwriter_name
FROM insurance_applications ia
LEFT JOIN users u ON ia.applicant_id = u.id
LEFT JOIN users uw ON ia.underwriter_id = uw.id
WHERE ${whereClause}
ORDER BY ia.created_at DESC
LIMIT ? OFFSET ?`,
[...queryParams, parseInt(limit), offset]
);
res.json({
success: true,
data: {
insurance,
pagination: {
total,
page: parseInt(page),
limit: parseInt(limit),
pages: Math.ceil(total / limit)
}
}
});
} catch (error) {
console.error('获取保险申请列表错误:', error);
res.status(500).json({
success: false,
message: '获取保险申请列表失败',
code: 'GET_INSURANCE_ERROR'
});
}
});
// 获取理赔申请列表
router.get('/claims', authenticateToken, checkPermission('insurance_manage'), async (req, res) => {
try {
const {
page = 1,
limit = 10,
status,
incident_type,
insurance_id
} = req.query;
const offset = (page - 1) * limit;
if (!pool) {
// 数据库不可用时返回模拟数据
const mockClaims = [
{
id: 1,
insurance_id: 1,
policy_number: 'INS202401001',
applicant_name: '张三',
claim_amount: 50000.00,
incident_date: '2024-01-30',
incident_type: 'illness',
description: '牛只突发疾病,经兽医诊断为传染性疾病',
status: 'under_review',
submitted_at: '2024-02-01 09:30:00'
},
{
id: 2,
insurance_id: 1,
policy_number: 'INS202401001',
applicant_name: '张三',
claim_amount: 25000.00,
incident_date: '2024-02-10',
incident_type: 'accident',
description: '牛只在放牧过程中意外受伤',
status: 'approved',
approved_amount: 22000.00,
submitted_at: '2024-02-11 14:20:00',
approved_at: '2024-02-15 10:45:00'
}
];
return res.json({
success: true,
data: {
claims: mockClaims,
pagination: {
total: mockClaims.length,
page: parseInt(page),
limit: parseInt(limit),
pages: Math.ceil(mockClaims.length / limit)
}
}
});
}
try {
await pool.execute('SELECT 1');
} catch (dbError) {
const mockClaims = [
{
id: 1,
applicant_name: '张三',
claim_amount: 50000.00,
incident_type: 'illness',
status: 'under_review'
}
];
return res.json({
success: true,
message: '数据库连接不可用,返回模拟数据',
data: {
claims: mockClaims,
pagination: {
total: mockClaims.length,
page: parseInt(page),
limit: parseInt(limit),
pages: Math.ceil(mockClaims.length / limit)
}
}
});
}
// 实际数据库查询
let whereClause = '1=1';
let queryParams = [];
if (status) {
whereClause += ' AND c.status = ?';
queryParams.push(status);
}
if (incident_type) {
whereClause += ' AND c.incident_type = ?';
queryParams.push(incident_type);
}
if (insurance_id) {
whereClause += ' AND c.insurance_id = ?';
queryParams.push(insurance_id);
}
const [countResult] = await pool.execute(
`SELECT COUNT(*) as total
FROM claims c
LEFT JOIN insurance_applications ia ON c.insurance_id = ia.id
LEFT JOIN users u ON c.applicant_id = u.id
WHERE ${whereClause}`,
queryParams
);
const total = countResult[0].total;
const [claims] = await pool.execute(
`SELECT c.*, ia.policy_number, u.real_name as applicant_name,
rv.real_name as reviewer_name
FROM claims c
LEFT JOIN insurance_applications ia ON c.insurance_id = ia.id
LEFT JOIN users u ON c.applicant_id = u.id
LEFT JOIN users rv ON c.reviewer_id = rv.id
WHERE ${whereClause}
ORDER BY c.submitted_at DESC
LIMIT ? OFFSET ?`,
[...queryParams, parseInt(limit), offset]
);
res.json({
success: true,
data: {
claims,
pagination: {
total,
page: parseInt(page),
limit: parseInt(limit),
pages: Math.ceil(total / limit)
}
}
});
} catch (error) {
console.error('获取理赔申请列表错误:', error);
res.status(500).json({
success: false,
message: '获取理赔申请列表失败',
code: 'GET_CLAIMS_ERROR'
});
}
});
// 获取金融服务统计信息
router.get('/stats/overview', authenticateToken, checkPermission('data_view'), async (req, res) => {
try {
if (!pool) {
// 数据库不可用时返回模拟数据
const mockStats = {
loans: {
total_applications: 156,
approved_loans: 89,
pending_review: 23,
total_amount: 45600000.00,
approved_amount: 32800000.00
},
insurance: {
total_policies: 234,
active_policies: 198,
total_coverage: 78500000.00,
total_claims: 45,
paid_claims: 32,
pending_claims: 8
},
risk_analysis: {
default_rate: 0.025,
claim_rate: 0.165,
average_loan_amount: 368539.32,
average_premium: 15420.50
}
};
return res.json({
success: true,
data: mockStats
});
}
try {
await pool.execute('SELECT 1');
} catch (dbError) {
// 数据库连接失败,返回模拟数据
const mockStats = {
loans: {
total_applications: 156,
approved_loans: 89,
pending_review: 23,
total_amount: 45600000.00,
approved_amount: 32800000.00
},
insurance: {
total_policies: 234,
active_policies: 198,
total_coverage: 78500000.00
}
};
return res.json({
success: true,
message: '数据库连接不可用,返回模拟数据',
data: mockStats
});
}
// 贷款统计
const [loanStats] = await pool.execute(`
SELECT
COUNT(*) as total_applications,
COUNT(CASE WHEN status = 'approved' THEN 1 END) as approved_loans,
COUNT(CASE WHEN status IN ('submitted', 'under_review') THEN 1 END) as pending_review,
SUM(loan_amount) as total_amount,
SUM(CASE WHEN status = 'approved' THEN approved_amount ELSE 0 END) as approved_amount
FROM loan_applications
`);
// 保险统计
const [insuranceStats] = await pool.execute(`
SELECT
COUNT(*) as total_policies,
COUNT(CASE WHEN status = 'active' THEN 1 END) as active_policies,
SUM(insured_amount) as total_coverage
FROM insurance_applications
`);
// 理赔统计
const [claimStats] = await pool.execute(`
SELECT
COUNT(*) as total_claims,
COUNT(CASE WHEN status = 'paid' THEN 1 END) as paid_claims,
COUNT(CASE WHEN status IN ('submitted', 'under_review') THEN 1 END) as pending_claims
FROM claims
`);
res.json({
success: true,
data: {
loans: loanStats[0],
insurance: {
...insuranceStats[0],
...claimStats[0]
},
risk_analysis: {
default_rate: 0.025, // 这里可以添加更复杂的计算逻辑
claim_rate: claimStats[0].total_claims / (insuranceStats[0].total_policies || 1),
average_loan_amount: loanStats[0].total_amount / (loanStats[0].total_applications || 1),
average_premium: 15420.50 // 可以从数据库计算
}
}
});
} catch (error) {
console.error('获取金融服务统计错误:', error);
res.status(500).json({
success: false,
message: '获取金融服务统计失败',
code: 'GET_FINANCE_STATS_ERROR'
});
}
});
module.exports = {
router,
setMiddleware
};

View File

@@ -0,0 +1,657 @@
const express = require('express');
const router = express.Router();
// 中间件将在服务器启动时设置
let authenticateToken = (req, res, next) => {
return res.status(500).json({
success: false,
message: '认证中间件未初始化',
code: 'AUTH_NOT_INITIALIZED'
});
};
let checkPermission = (permission) => {
return (req, res, next) => {
return res.status(500).json({
success: false,
message: '权限中间件未初始化',
code: 'PERMISSION_NOT_INITIALIZED'
});
};
};
let pool = null;
// 设置中间件和数据库连接(从主服务器导入)
function setMiddleware(auth, permission, dbPool) {
authenticateToken = auth;
checkPermission = permission;
pool = dbPool;
}
// ======================================
// 养殖监管相关接口
// ======================================
// 获取牧场监管信息
router.get('/farms/supervision', authenticateToken, checkPermission('government_supervision'), async (req, res) => {
try {
const {
page = 1,
limit = 10,
region,
compliance_status,
inspection_status,
search
} = req.query;
const offset = (page - 1) * limit;
if (!pool) {
// 数据库不可用时返回模拟数据
const mockFarms = [
{
id: 1,
farm_name: '锡林浩特市第一牧场',
owner_name: '张三',
owner_phone: '13900000002',
region: '锡林浩特市',
registration_number: 'REG2024001',
cattle_count: 240,
farm_area: 150.5,
compliance_status: 'compliant',
last_inspection_date: '2024-01-15',
next_inspection_date: '2024-04-15',
inspector_name: '政府检查员A',
compliance_score: 95,
violation_count: 0,
environmental_rating: 'A',
safety_rating: 'A',
notes: '管理规范,设施完善',
created_at: '2023-06-15 10:00:00'
},
{
id: 2,
farm_name: '东乌旗牧场A',
owner_name: '李四',
owner_phone: '13900000003',
region: '东乌旗',
registration_number: 'REG2024002',
cattle_count: 180,
farm_area: 120.3,
compliance_status: 'warning',
last_inspection_date: '2024-01-10',
next_inspection_date: '2024-03-10',
inspector_name: '政府检查员B',
compliance_score: 78,
violation_count: 2,
environmental_rating: 'B',
safety_rating: 'A',
notes: '存在轻微环境问题,需要改进',
created_at: '2023-08-20 14:30:00'
},
{
id: 3,
farm_name: '西乌旗生态牧场',
owner_name: '王五',
owner_phone: '13900000004',
region: '西乌旗',
registration_number: 'REG2024003',
cattle_count: 320,
farm_area: 200.8,
compliance_status: 'excellent',
last_inspection_date: '2024-01-20',
next_inspection_date: '2024-07-20',
inspector_name: '政府检查员C',
compliance_score: 98,
violation_count: 0,
environmental_rating: 'A+',
safety_rating: 'A+',
notes: '示范牧场,各项指标优秀',
created_at: '2023-05-10 09:15:00'
}
];
return res.json({
success: true,
data: {
farms: mockFarms,
pagination: {
total: mockFarms.length,
page: parseInt(page),
limit: parseInt(limit),
pages: Math.ceil(mockFarms.length / limit)
}
}
});
}
// 数据库可用时的实际查询逻辑...
res.json({
success: true,
message: '政府监管功能开发中',
data: { farms: [], pagination: { total: 0, page: parseInt(page), limit: parseInt(limit), pages: 0 } }
});
} catch (error) {
console.error('获取牧场监管信息失败:', error);
res.status(500).json({
success: false,
message: '获取牧场监管信息失败',
error: error.message
});
}
});
// 获取检查记录
router.get('/inspections', authenticateToken, checkPermission('government_supervision'), async (req, res) => {
try {
const {
page = 1,
limit = 10,
farm_id,
inspector_id,
inspection_type,
result,
start_date,
end_date
} = req.query;
const offset = (page - 1) * limit;
if (!pool) {
// 数据库不可用时返回模拟数据
const mockInspections = [
{
id: 1,
farm_id: 1,
farm_name: '锡林浩特市第一牧场',
inspector_id: 10,
inspector_name: '政府检查员A',
inspection_type: 'routine',
inspection_date: '2024-01-15',
result: 'passed',
score: 95,
violations: [],
improvements: [
'建议加强饲料储存管理',
'完善消毒记录台账'
],
next_inspection_date: '2024-04-15',
report_url: '/uploads/inspection_reports/INS001.pdf',
notes: '整体情况良好,管理规范',
created_at: '2024-01-15 14:30:00'
},
{
id: 2,
farm_id: 2,
farm_name: '东乌旗牧场A',
inspector_id: 11,
inspector_name: '政府检查员B',
inspection_type: 'follow_up',
inspection_date: '2024-01-10',
result: 'conditional_pass',
score: 78,
violations: [
{
type: 'environmental',
description: '粪污处理不够及时',
severity: 'minor',
deadline: '2024-02-10'
},
{
type: 'safety',
description: '部分围栏需要维修',
severity: 'minor',
deadline: '2024-01-25'
}
],
improvements: [
'加强粪污处理设施维护',
'定期检查围栏安全性',
'建立更完善的清洁制度'
],
next_inspection_date: '2024-03-10',
report_url: '/uploads/inspection_reports/INS002.pdf',
notes: '存在轻微问题,需要限期整改',
created_at: '2024-01-10 16:45:00'
}
];
return res.json({
success: true,
data: {
inspections: mockInspections,
pagination: {
total: mockInspections.length,
page: parseInt(page),
limit: parseInt(limit),
pages: Math.ceil(mockInspections.length / limit)
}
}
});
}
// 数据库可用时的实际查询逻辑...
res.json({
success: true,
message: '检查记录功能开发中',
data: { inspections: [], pagination: { total: 0, page: parseInt(page), limit: parseInt(limit), pages: 0 } }
});
} catch (error) {
console.error('获取检查记录失败:', error);
res.status(500).json({
success: false,
message: '获取检查记录失败',
error: error.message
});
}
});
// 创建检查记录
router.post('/inspections', authenticateToken, checkPermission('government_inspection'), async (req, res) => {
try {
const {
farm_id,
inspection_type,
inspection_date,
score,
result,
violations,
improvements,
next_inspection_date,
notes
} = req.body;
// 验证必需字段
if (!farm_id || !inspection_type || !inspection_date || !result) {
return res.status(400).json({
success: false,
message: '缺少必需的字段'
});
}
if (!pool) {
// 数据库不可用时返回模拟响应
const mockInspection = {
id: Math.floor(Math.random() * 1000) + 100,
farm_id,
inspector_id: req.user.id,
inspector_name: req.user.real_name || '检查员',
inspection_type,
inspection_date,
result,
score,
violations: violations || [],
improvements: improvements || [],
next_inspection_date,
notes,
created_at: new Date().toISOString()
};
return res.status(201).json({
success: true,
message: '检查记录创建成功(模拟数据)',
data: mockInspection
});
}
// 数据库可用时的实际创建逻辑...
res.status(201).json({
success: true,
message: '检查记录创建功能开发中'
});
} catch (error) {
console.error('创建检查记录失败:', error);
res.status(500).json({
success: false,
message: '创建检查记录失败',
error: error.message
});
}
});
// ======================================
// 质量追溯相关接口
// ======================================
// 获取产品追溯信息
router.get('/traceability/:product_id', authenticateToken, checkPermission('quality_trace'), async (req, res) => {
try {
const { product_id } = req.params;
if (!pool) {
// 数据库不可用时返回模拟数据
const mockTraceability = {
product_id,
product_name: '优质牛肉',
batch_number: 'BATCH2024001',
production_date: '2024-01-20',
expiry_date: '2024-01-27',
origin_info: {
farm_id: 1,
farm_name: '锡林浩特市第一牧场',
farmer_name: '张三',
region: '锡林浩特市',
coordinates: { lat: 43.946, lng: 116.093 }
},
cattle_info: {
cattle_id: 1,
tag_number: 'C001',
breed: '西门塔尔牛',
birth_date: '2022-01-15',
slaughter_date: '2024-01-18',
weight: 450,
health_records: [
{
date: '2023-06-15',
type: 'vaccination',
description: '口蹄疫疫苗接种',
veterinarian: '兽医A'
},
{
date: '2023-12-10',
type: 'health_check',
description: '定期健康检查',
result: '健康状况良好',
veterinarian: '兽医B'
}
]
},
processing_info: {
slaughterhouse: '锡林郭勒肉类加工厂',
slaughter_date: '2024-01-18',
processing_date: '2024-01-19',
packaging_date: '2024-01-20',
inspector: '质检员A',
quality_grade: 'A级',
certificates: [
'动物检疫合格证',
'肉品品质检验合格证',
'食品安全检测报告'
]
},
transportation_info: {
transport_company: '冷链物流A',
departure_time: '2024-01-20 08:00:00',
arrival_time: '2024-01-20 14:30:00',
temperature_records: [
{ time: '08:00', temperature: -2 },
{ time: '10:00', temperature: -1.8 },
{ time: '12:00', temperature: -2.1 },
{ time: '14:00', temperature: -1.9 }
],
driver: '司机A',
vehicle_number: '蒙H12345'
},
retail_info: {
retailer: '锡林浩特超市A',
receipt_date: '2024-01-20 15:00:00',
sale_date: '2024-01-22 10:30:00',
price: 68.00,
customer_info: '已匿名化'
},
quality_reports: [
{
test_date: '2024-01-19',
test_type: '微生物检测',
result: '合格',
lab: '第三方检测机构A'
},
{
test_date: '2024-01-19',
test_type: '重金属检测',
result: '合格',
lab: '第三方检测机构A'
}
]
};
return res.json({
success: true,
data: mockTraceability
});
}
// 数据库可用时的实际查询逻辑...
res.json({
success: true,
message: '产品追溯功能开发中',
data: { product_id, message: '开发中' }
});
} catch (error) {
console.error('获取产品追溯信息失败:', error);
res.status(500).json({
success: false,
message: '获取产品追溯信息失败',
error: error.message
});
}
});
// ======================================
// 政策法规相关接口
// ======================================
// 获取政策法规列表
router.get('/policies', authenticateToken, checkPermission('policy_view'), async (req, res) => {
try {
const {
page = 1,
limit = 10,
category,
status,
search
} = req.query;
const offset = (page - 1) * limit;
if (!pool) {
// 数据库不可用时返回模拟数据
const mockPolicies = [
{
id: 1,
title: '锡林郭勒盟畜牧业发展扶持政策',
category: 'support_policy',
content_summary: '为促进畜牧业健康发展,对符合条件的养殖户给予资金补贴和技术支持',
publish_date: '2024-01-01',
effective_date: '2024-01-01',
expiry_date: '2024-12-31',
status: 'active',
authority: '锡林郭勒盟农牧局',
document_url: '/uploads/policies/policy001.pdf',
created_at: '2024-01-01 10:00:00'
},
{
id: 2,
title: '动物疫病防控管理办法',
category: 'regulation',
content_summary: '规范动物疫病防控工作,确保畜牧业生产安全和公共卫生安全',
publish_date: '2023-12-15',
effective_date: '2024-01-01',
expiry_date: null,
status: 'active',
authority: '锡林郭勒盟兽医局',
document_url: '/uploads/policies/policy002.pdf',
created_at: '2023-12-15 14:30:00'
},
{
id: 3,
title: '草原生态保护补助奖励政策',
category: 'subsidy',
content_summary: '对实施草原禁牧、草畜平衡的牧户给予生态保护补助奖励',
publish_date: '2024-01-10',
effective_date: '2024-01-15',
expiry_date: '2024-12-31',
status: 'active',
authority: '锡林郭勒盟林草局',
document_url: '/uploads/policies/policy003.pdf',
created_at: '2024-01-10 09:15:00'
}
];
return res.json({
success: true,
data: {
policies: mockPolicies,
pagination: {
total: mockPolicies.length,
page: parseInt(page),
limit: parseInt(limit),
pages: Math.ceil(mockPolicies.length / limit)
}
}
});
}
// 数据库可用时的实际查询逻辑...
res.json({
success: true,
message: '政策法规功能开发中',
data: { policies: [], pagination: { total: 0, page: parseInt(page), limit: parseInt(limit), pages: 0 } }
});
} catch (error) {
console.error('获取政策法规列表失败:', error);
res.status(500).json({
success: false,
message: '获取政策法规列表失败',
error: error.message
});
}
});
// ======================================
// 统计报告相关接口
// ======================================
// 获取监管统计数据
router.get('/statistics', authenticateToken, checkPermission('government_statistics'), async (req, res) => {
try {
const { period = 'month', region } = req.query;
if (!pool) {
// 数据库不可用时返回模拟数据
const mockStats = {
overview: {
total_farms: 156,
total_cattle: 12850,
compliant_farms: 142,
warning_farms: 11,
violation_farms: 3,
compliance_rate: 91.0
},
regional_distribution: {
'锡林浩特市': { farms: 45, cattle: 4200, compliance_rate: 93.3 },
'东乌旗': { farms: 38, cattle: 3100, compliance_rate: 89.5 },
'西乌旗': { farms: 42, cattle: 3800, compliance_rate: 92.9 },
'阿巴嘎旗': { farms: 31, cattle: 1750, compliance_rate: 87.1 }
},
inspection_summary: {
total_inspections: 89,
passed: 76,
conditional_pass: 8,
failed: 5,
pending: 0
},
violation_categories: {
environmental: 15,
safety: 8,
health: 5,
documentation: 12
},
monthly_trend: [
{ month: '2023-11', compliance_rate: 88.5, inspections: 28 },
{ month: '2023-12', compliance_rate: 89.2, inspections: 32 },
{ month: '2024-01', compliance_rate: 91.0, inspections: 29 }
]
};
return res.json({
success: true,
data: mockStats
});
}
// 数据库可用时的实际统计查询逻辑...
res.json({
success: true,
message: '监管统计功能开发中',
data: { overview: { total_farms: 0, total_cattle: 0 } }
});
} catch (error) {
console.error('获取监管统计数据失败:', error);
res.status(500).json({
success: false,
message: '获取监管统计数据失败',
error: error.message
});
}
});
// 生成监管报告
router.post('/reports', authenticateToken, checkPermission('government_report'), async (req, res) => {
try {
const {
report_type,
period,
region,
start_date,
end_date,
format = 'pdf'
} = req.body;
// 验证必需字段
if (!report_type || !period) {
return res.status(400).json({
success: false,
message: '缺少必需的字段'
});
}
if (!pool) {
// 数据库不可用时返回模拟响应
const mockReport = {
id: Math.floor(Math.random() * 1000) + 100,
report_type,
period,
region,
start_date,
end_date,
format,
status: 'generating',
created_by: req.user.id,
created_at: new Date().toISOString(),
download_url: null,
estimated_completion: new Date(Date.now() + 5 * 60 * 1000).toISOString() // 5分钟后
};
return res.status(201).json({
success: true,
message: '报告生成任务已创建(模拟数据)',
data: mockReport
});
}
// 数据库可用时的实际报告生成逻辑...
res.status(201).json({
success: true,
message: '报告生成功能开发中'
});
} catch (error) {
console.error('生成监管报告失败:', error);
res.status(500).json({
success: false,
message: '生成监管报告失败',
error: error.message
});
}
});
// 导出模块
module.exports = {
router,
setMiddleware
};

874
backend/api/routes/mall.js Normal file
View File

@@ -0,0 +1,874 @@
const express = require('express');
const router = express.Router();
// 中间件将在服务器启动时设置
let authenticateToken = (req, res, next) => {
return res.status(500).json({
success: false,
message: '认证中间件未初始化',
code: 'AUTH_NOT_INITIALIZED'
});
};
let checkPermission = (permission) => {
return (req, res, next) => {
return res.status(500).json({
success: false,
message: '权限中间件未初始化',
code: 'PERMISSION_NOT_INITIALIZED'
});
};
};
let pool = null;
// 设置中间件和数据库连接(从主服务器导入)
function setMiddleware(auth, permission, dbPool) {
authenticateToken = auth;
checkPermission = permission;
pool = dbPool;
}
// ======================================
// 商品管理相关接口
// ======================================
// 获取商品列表
router.get('/products', async (req, res) => {
try {
const {
page = 1,
limit = 10,
category,
status,
seller_id,
price_min,
price_max,
search,
sort_by = 'created_at',
sort_order = 'desc'
} = req.query;
const offset = (page - 1) * limit;
if (!pool) {
// 数据库不可用时返回模拟数据
const mockProducts = [
{
id: 1,
name: '优质牛肉礼盒装',
category: 'beef',
description: '来自锡林浩特优质牧场的新鲜牛肉,肉质鲜美,营养丰富',
price: 268.00,
original_price: 298.00,
stock: 45,
sales_count: 128,
status: 'active',
seller_id: 2,
seller_name: '张三牧场直营店',
images: [
'/uploads/products/beef_box_1.jpg',
'/uploads/products/beef_box_2.jpg'
],
specifications: {
weight: '2kg',
packaging: '礼盒装',
storage: '冷冻保存',
shelf_life: '30天'
},
origin: '锡林浩特市第一牧场',
rating: 4.8,
review_count: 56,
created_at: '2024-01-15 10:30:00',
updated_at: '2024-01-20 14:15:00'
},
{
id: 2,
name: '有机牛奶',
category: 'dairy',
description: '纯天然有机牛奶,无添加剂,营养价值高',
price: 35.00,
original_price: 35.00,
stock: 120,
sales_count: 89,
status: 'active',
seller_id: 3,
seller_name: '草原乳业',
images: [
'/uploads/products/milk_1.jpg'
],
specifications: {
volume: '1L',
packaging: '利乐包装',
storage: '冷藏保存',
shelf_life: '7天'
},
origin: '东乌旗生态牧场',
rating: 4.6,
review_count: 32,
created_at: '2024-01-18 09:45:00',
updated_at: '2024-01-22 16:30:00'
},
{
id: 3,
name: '牛肉干',
category: 'snacks',
description: '传统工艺制作的牛肉干,口感醇香,营养丰富',
price: 68.00,
original_price: 78.00,
stock: 0,
sales_count: 245,
status: 'out_of_stock',
seller_id: 4,
seller_name: '草原食品厂',
images: [
'/uploads/products/jerky_1.jpg',
'/uploads/products/jerky_2.jpg'
],
specifications: {
weight: '500g',
packaging: '真空包装',
storage: '常温保存',
shelf_life: '180天'
},
origin: '西乌旗牧场',
rating: 4.9,
review_count: 78,
created_at: '2024-01-10 14:20:00',
updated_at: '2024-01-25 11:40:00'
}
];
// 根据查询条件过滤
let filteredProducts = mockProducts;
if (category) {
filteredProducts = filteredProducts.filter(p => p.category === category);
}
if (status) {
filteredProducts = filteredProducts.filter(p => p.status === status);
}
if (search) {
const searchLower = search.toLowerCase();
filteredProducts = filteredProducts.filter(p =>
p.name.toLowerCase().includes(searchLower) ||
p.description.toLowerCase().includes(searchLower)
);
}
return res.json({
success: true,
data: {
products: filteredProducts.slice(offset, offset + parseInt(limit)),
pagination: {
total: filteredProducts.length,
page: parseInt(page),
limit: parseInt(limit),
pages: Math.ceil(filteredProducts.length / limit)
}
}
});
}
// 数据库可用时的实际查询逻辑
try {
await pool.execute('SELECT 1');
} catch (dbError) {
// 数据库连接失败,返回模拟数据
const mockProducts = [
{
id: 1,
name: '优质牛肉礼盒装',
category: 'beef',
price: 268.00,
stock: 45,
status: 'active',
seller_name: '张三牧场直营店',
created_at: '2024-01-15 10:30:00'
}
];
return res.json({
success: true,
message: '数据库连接不可用,返回模拟数据',
data: {
products: mockProducts,
pagination: {
total: mockProducts.length,
page: parseInt(page),
limit: parseInt(limit),
pages: Math.ceil(mockProducts.length / limit)
}
}
});
}
res.json({
success: true,
message: '商品列表功能开发中',
data: { products: [], pagination: { total: 0, page: parseInt(page), limit: parseInt(limit), pages: 0 } }
});
} catch (error) {
console.error('获取商品列表失败:', error);
res.status(500).json({
success: false,
message: '获取商品列表失败',
error: error.message
});
}
});
// 获取商品详情
router.get('/products/:id', async (req, res) => {
try {
const { id } = req.params;
if (!pool) {
// 数据库不可用时返回模拟数据
const mockProduct = {
id: parseInt(id),
name: '优质牛肉礼盒装',
category: 'beef',
description: '来自锡林浩特优质牧场的新鲜牛肉,采用传统草饲方式饲养,肉质鲜美,营养丰富,是您餐桌上的不二选择。',
price: 268.00,
original_price: 298.00,
stock: 45,
sales_count: 128,
status: 'active',
seller_id: 2,
seller_name: '张三牧场直营店',
seller_rating: 4.7,
images: [
'/uploads/products/beef_box_1.jpg',
'/uploads/products/beef_box_2.jpg',
'/uploads/products/beef_box_3.jpg'
],
specifications: {
weight: '2kg',
packaging: '礼盒装',
storage: '冷冻保存',
shelf_life: '30天',
certification: ['有机认证', '质量安全认证']
},
origin_detail: {
farm_name: '锡林浩特市第一牧场',
farm_address: '锡林浩特市郊区',
cattle_breed: '西门塔尔牛',
feeding_method: '天然草饲',
slaughter_date: '2024-01-12'
},
nutritional_info: {
protein: '20.1g/100g',
fat: '15.2g/100g',
calories: '210kcal/100g',
iron: '3.2mg/100g'
},
rating: 4.8,
review_count: 56,
reviews: [
{
id: 1,
user_name: '李女士',
rating: 5,
content: '肉质非常好,很新鲜,包装也很精美,送人很有面子!',
images: ['/uploads/reviews/review_1.jpg'],
created_at: '2024-01-22 10:30:00'
},
{
id: 2,
user_name: '王先生',
rating: 5,
content: '味道正宗,口感很好,下次还会再买的',
images: [],
created_at: '2024-01-20 15:45:00'
}
],
shipping_info: {
free_shipping_threshold: 200,
shipping_fee: 0,
estimated_delivery: '2-3个工作日',
shipping_areas: ['锡林郭勒盟', '呼和浩特市', '包头市']
},
return_policy: {
return_days: 7,
return_conditions: '商品质量问题支持退换货',
return_fee: '免费'
},
created_at: '2024-01-15 10:30:00',
updated_at: '2024-01-20 14:15:00'
};
return res.json({
success: true,
data: mockProduct
});
}
// 数据库可用时的实际查询逻辑
try {
await pool.execute('SELECT 1');
} catch (dbError) {
// 数据库连接失败,返回模拟数据
return res.json({
success: true,
message: '数据库连接不可用,返回模拟数据',
data: {
id: parseInt(id),
name: '优质牛肉礼盒装',
price: 268.00,
status: 'active'
}
});
}
res.json({
success: true,
message: '商品详情功能开发中',
data: { id: parseInt(id), message: '开发中' }
});
} catch (error) {
console.error('获取商品详情失败:', error);
res.status(500).json({
success: false,
message: '获取商品详情失败',
error: error.message
});
}
});
// 创建商品(商家)
router.post('/products', authenticateToken, checkPermission('product_create'), async (req, res) => {
try {
const {
name,
category,
description,
price,
original_price,
stock,
images,
specifications,
origin
} = req.body;
// 验证必需字段
if (!name || !category || !price || !stock) {
return res.status(400).json({
success: false,
message: '缺少必需的字段'
});
}
if (!pool) {
// 数据库不可用时返回模拟响应
const mockProduct = {
id: Math.floor(Math.random() * 1000) + 100,
name,
category,
description,
price,
original_price: original_price || price,
stock,
sales_count: 0,
status: 'pending_review',
seller_id: req.user?.id || 1,
seller_name: req.user?.real_name || '商家',
images: images || [],
specifications: specifications || {},
origin,
rating: 0,
review_count: 0,
created_at: new Date().toISOString(),
updated_at: new Date().toISOString()
};
return res.status(201).json({
success: true,
message: '商品创建成功,等待审核(模拟数据)',
data: mockProduct
});
}
// 数据库可用时的实际创建逻辑
try {
await pool.execute('SELECT 1');
} catch (dbError) {
// 数据库连接失败,返回模拟数据
return res.status(201).json({
success: true,
message: '数据库连接不可用,模拟创建成功',
data: {
id: Math.floor(Math.random() * 1000) + 100,
name,
status: 'pending_review',
created_at: new Date().toISOString()
}
});
}
res.status(201).json({
success: true,
message: '商品创建功能开发中'
});
} catch (error) {
console.error('创建商品失败:', error);
res.status(500).json({
success: false,
message: '创建商品失败',
error: error.message
});
}
});
// ======================================
// 订单管理相关接口
// ======================================
// 获取订单列表
router.get('/orders', authenticateToken, checkPermission('order_view'), async (req, res) => {
try {
const {
page = 1,
limit = 10,
status,
user_id,
start_date,
end_date,
search
} = req.query;
const offset = (page - 1) * limit;
if (!pool) {
// 数据库不可用时返回模拟数据
const mockOrders = [
{
id: 1,
order_number: 'ORD202401001',
user_id: 5,
user_name: '赵六',
total_amount: 536.00,
discount_amount: 30.00,
shipping_fee: 0.00,
final_amount: 506.00,
status: 'delivered',
payment_status: 'paid',
payment_method: 'wechat_pay',
shipping_address: '呼和浩特市新城区xxx街道xxx号',
shipping_phone: '13900000005',
tracking_number: 'SF1234567890',
items: [
{
product_id: 1,
product_name: '优质牛肉礼盒装',
quantity: 2,
unit_price: 268.00,
total_price: 536.00
}
],
order_date: '2024-01-20 10:30:00',
payment_date: '2024-01-20 10:35:00',
shipping_date: '2024-01-21 08:00:00',
delivery_date: '2024-01-23 15:30:00',
created_at: '2024-01-20 10:30:00'
},
{
id: 2,
order_number: 'ORD202401002',
user_id: 6,
user_name: '钱七',
total_amount: 210.00,
discount_amount: 0.00,
shipping_fee: 15.00,
final_amount: 225.00,
status: 'shipping',
payment_status: 'paid',
payment_method: 'alipay',
shipping_address: '包头市昆都仑区xxx路xxx号',
shipping_phone: '13900000006',
tracking_number: 'YTO0987654321',
items: [
{
product_id: 2,
product_name: '有机牛奶',
quantity: 6,
unit_price: 35.00,
total_price: 210.00
}
],
order_date: '2024-01-22 14:20:00',
payment_date: '2024-01-22 14:25:00',
shipping_date: '2024-01-23 09:15:00',
delivery_date: null,
created_at: '2024-01-22 14:20:00'
}
];
return res.json({
success: true,
data: {
orders: mockOrders,
pagination: {
total: mockOrders.length,
page: parseInt(page),
limit: parseInt(limit),
pages: Math.ceil(mockOrders.length / limit)
}
}
});
}
// 数据库可用时的实际查询逻辑
try {
await pool.execute('SELECT 1');
} catch (dbError) {
// 数据库连接失败,返回模拟数据
const mockOrders = [
{
id: 1,
order_number: 'ORD202401001',
user_name: '赵六',
total_amount: 506.00,
status: 'delivered',
created_at: '2024-01-20 10:30:00'
}
];
return res.json({
success: true,
message: '数据库连接不可用,返回模拟数据',
data: {
orders: mockOrders,
pagination: {
total: mockOrders.length,
page: parseInt(page),
limit: parseInt(limit),
pages: Math.ceil(mockOrders.length / limit)
}
}
});
}
res.json({
success: true,
message: '订单列表功能开发中',
data: { orders: [], pagination: { total: 0, page: parseInt(page), limit: parseInt(limit), pages: 0 } }
});
} catch (error) {
console.error('获取订单列表失败:', error);
res.status(500).json({
success: false,
message: '获取订单列表失败',
error: error.message
});
}
});
// 创建订单
router.post('/orders', authenticateToken, async (req, res) => {
try {
const {
items,
shipping_address,
shipping_phone,
shipping_name,
payment_method,
coupon_code,
notes
} = req.body;
// 验证必需字段
if (!items || !Array.isArray(items) || items.length === 0) {
return res.status(400).json({
success: false,
message: '订单商品不能为空'
});
}
if (!shipping_address || !shipping_phone || !shipping_name) {
return res.status(400).json({
success: false,
message: '收货信息不完整'
});
}
if (!pool) {
// 数据库不可用时返回模拟响应
const mockOrder = {
id: Math.floor(Math.random() * 1000) + 100,
order_number: `ORD${new Date().getFullYear()}${String(Date.now()).slice(-8)}`,
user_id: req.user?.id || 1,
items,
total_amount: items.reduce((sum, item) => sum + (item.quantity * item.unit_price), 0),
discount_amount: 0,
shipping_fee: 0,
final_amount: items.reduce((sum, item) => sum + (item.quantity * item.unit_price), 0),
status: 'pending_payment',
payment_status: 'pending',
payment_method,
shipping_address,
shipping_phone,
shipping_name,
notes,
created_at: new Date().toISOString()
};
return res.status(201).json({
success: true,
message: '订单创建成功(模拟数据)',
data: mockOrder
});
}
// 数据库可用时的实际创建逻辑
try {
await pool.execute('SELECT 1');
} catch (dbError) {
// 数据库连接失败,返回模拟数据
return res.status(201).json({
success: true,
message: '数据库连接不可用,模拟创建成功',
data: {
id: Math.floor(Math.random() * 1000) + 100,
order_number: `ORD${new Date().getFullYear()}${String(Date.now()).slice(-8)}`,
status: 'pending_payment',
created_at: new Date().toISOString()
}
});
}
res.status(201).json({
success: true,
message: '订单创建功能开发中'
});
} catch (error) {
console.error('创建订单失败:', error);
res.status(500).json({
success: false,
message: '创建订单失败',
error: error.message
});
}
});
// ======================================
// 商品评价相关接口
// ======================================
// 获取商品评价列表
router.get('/products/:product_id/reviews', async (req, res) => {
try {
const { product_id } = req.params;
const { page = 1, limit = 10, rating } = req.query;
const offset = (page - 1) * limit;
if (!pool) {
// 数据库不可用时返回模拟数据
const mockReviews = [
{
id: 1,
product_id: parseInt(product_id),
user_id: 5,
user_name: '赵六',
user_avatar: '/uploads/avatars/user5.jpg',
order_id: 1,
rating: 5,
content: '肉质非常好,很新鲜,包装也很精美,送人很有面子!家人都很满意,下次还会购买的。',
images: [
'/uploads/reviews/review_1_1.jpg',
'/uploads/reviews/review_1_2.jpg'
],
helpful_count: 12,
reply: {
content: '感谢您的好评,我们会继续努力提供优质的产品!',
reply_date: '2024-01-23 09:15:00'
},
created_at: '2024-01-22 10:30:00'
},
{
id: 2,
product_id: parseInt(product_id),
user_id: 6,
user_name: '钱七',
user_avatar: '/uploads/avatars/user6.jpg',
order_id: 2,
rating: 4,
content: '味道正宗,口感很好,就是价格稍微有点贵',
images: [],
helpful_count: 8,
reply: null,
created_at: '2024-01-20 15:45:00'
}
];
return res.json({
success: true,
data: {
reviews: mockReviews,
pagination: {
total: mockReviews.length,
page: parseInt(page),
limit: parseInt(limit),
pages: Math.ceil(mockReviews.length / limit)
},
summary: {
average_rating: 4.8,
total_reviews: mockReviews.length,
rating_distribution: {
5: 56,
4: 12,
3: 3,
2: 1,
1: 0
}
}
}
});
}
// 数据库可用时的实际查询逻辑
try {
await pool.execute('SELECT 1');
} catch (dbError) {
// 数据库连接失败,返回模拟数据
const mockReviews = [
{
id: 1,
user_name: '赵六',
rating: 5,
content: '肉质非常好,很新鲜',
created_at: '2024-01-22 10:30:00'
}
];
return res.json({
success: true,
message: '数据库连接不可用,返回模拟数据',
data: {
reviews: mockReviews,
pagination: {
total: mockReviews.length,
page: parseInt(page),
limit: parseInt(limit),
pages: Math.ceil(mockReviews.length / limit)
}
}
});
}
res.json({
success: true,
message: '商品评价功能开发中',
data: { reviews: [], pagination: { total: 0, page: parseInt(page), limit: parseInt(limit), pages: 0 } }
});
} catch (error) {
console.error('获取商品评价失败:', error);
res.status(500).json({
success: false,
message: '获取商品评价失败',
error: error.message
});
}
});
// ======================================
// 商城统计相关接口
// ======================================
// 获取商城统计数据
router.get('/statistics', authenticateToken, checkPermission('mall_statistics'), async (req, res) => {
try {
const { period = 'month' } = req.query;
if (!pool) {
// 数据库不可用时返回模拟数据
const mockStats = {
overview: {
total_products: 156,
active_products: 142,
total_orders: 1284,
total_revenue: 2580000.00,
total_users: 8456,
active_sellers: 28
},
sales_trend: [
{ date: '2024-01-15', orders: 45, revenue: 28500.00 },
{ date: '2024-01-16', orders: 52, revenue: 31200.00 },
{ date: '2024-01-17', orders: 48, revenue: 29800.00 },
{ date: '2024-01-18', orders: 61, revenue: 38200.00 },
{ date: '2024-01-19', orders: 55, revenue: 33500.00 },
{ date: '2024-01-20', orders: 68, revenue: 42600.00 },
{ date: '2024-01-21', orders: 73, revenue: 45800.00 }
],
category_distribution: {
beef: { count: 45, revenue: 1250000.00 },
dairy: { count: 32, revenue: 680000.00 },
snacks: { count: 28, revenue: 420000.00 },
processed: { count: 35, revenue: 890000.00 },
other: { count: 16, revenue: 340000.00 }
},
top_products: [
{ id: 1, name: '优质牛肉礼盒装', sales: 245, revenue: 65660.00 },
{ id: 3, name: '牛肉干', sales: 189, revenue: 12852.00 },
{ id: 2, name: '有机牛奶', sales: 156, revenue: 5460.00 }
],
top_sellers: [
{ id: 2, name: '张三牧场直营店', orders: 128, revenue: 185600.00 },
{ id: 4, name: '草原食品厂', orders: 95, revenue: 142800.00 },
{ id: 3, name: '草原乳业', orders: 76, revenue: 98500.00 }
]
};
return res.json({
success: true,
data: mockStats
});
}
// 数据库可用时的实际统计查询逻辑
try {
await pool.execute('SELECT 1');
} catch (dbError) {
// 数据库连接失败,返回模拟数据
const mockStats = {
overview: {
total_products: 156,
total_orders: 1284,
total_revenue: 2580000.00
}
};
return res.json({
success: true,
message: '数据库连接不可用,返回模拟数据',
data: mockStats
});
}
res.json({
success: true,
message: '商城统计功能开发中',
data: { overview: { total_products: 0, total_orders: 0 } }
});
} catch (error) {
console.error('获取商城统计数据失败:', error);
res.status(500).json({
success: false,
message: '获取商城统计数据失败',
error: error.message
});
}
});
// 导出模块
module.exports = {
router,
setMiddleware
};

View File

@@ -0,0 +1,748 @@
const express = require('express');
const router = express.Router();
// 中间件将在服务器启动时设置
let authenticateToken = (req, res, next) => {
return res.status(500).json({
success: false,
message: '认证中间件未初始化',
code: 'AUTH_NOT_INITIALIZED'
});
};
let checkPermission = (permission) => {
return (req, res, next) => {
return res.status(500).json({
success: false,
message: '权限中间件未初始化',
code: 'PERMISSION_NOT_INITIALIZED'
});
};
};
let pool = null;
// 设置中间件和数据库连接(从主服务器导入)
function setMiddleware(auth, permission, dbPool) {
authenticateToken = auth;
checkPermission = permission;
pool = dbPool;
}
// ======================================
// 交易管理相关接口
// ======================================
// 获取交易记录列表
router.get('/transactions', authenticateToken, checkPermission('transaction_view'), async (req, res) => {
try {
const {
page = 1,
limit = 10,
status,
transaction_type,
buyer_id,
seller_id,
search,
start_date,
end_date
} = req.query;
const offset = (page - 1) * limit;
if (!pool) {
// 数据库不可用时返回模拟数据
const mockTransactions = [
{
id: 1,
transaction_type: 'cattle_sale',
buyer_id: 3,
seller_id: 2,
buyer_name: '李四',
seller_name: '张三',
cattle_ids: '1,2,3',
cattle_count: 3,
unit_price: 15000.00,
total_amount: 45000.00,
status: 'completed',
payment_method: 'bank_transfer',
delivery_method: 'pickup',
delivery_address: '锡林浩特市郊区牧场',
delivery_date: '2024-01-25 09:00:00',
notes: '优质西门塔尔牛,健康状况良好',
created_at: '2024-01-20 14:30:00',
updated_at: '2024-01-25 10:15:00'
},
{
id: 2,
transaction_type: 'feed_purchase',
buyer_id: 2,
seller_id: 5,
buyer_name: '张三',
seller_name: '饲料供应商A',
product_name: '优质牧草饲料',
quantity: 5000,
unit: 'kg',
unit_price: 3.50,
total_amount: 17500.00,
status: 'pending',
payment_method: 'cash',
delivery_method: 'delivery',
delivery_address: '张三牧场',
delivery_date: '2024-01-28 08:00:00',
notes: '定期饲料采购',
created_at: '2024-01-22 16:45:00',
updated_at: '2024-01-22 16:45:00'
},
{
id: 3,
transaction_type: 'equipment_sale',
buyer_id: 4,
seller_id: 6,
buyer_name: '王五',
seller_name: '设备供应商B',
product_name: '自动饮水设备',
quantity: 2,
unit: '套',
unit_price: 8500.00,
total_amount: 17000.00,
status: 'in_progress',
payment_method: 'installment',
delivery_method: 'installation',
delivery_address: '王五牧场',
delivery_date: '2024-01-30 10:00:00',
notes: '包安装调试',
created_at: '2024-01-19 11:20:00',
updated_at: '2024-01-24 15:30:00'
}
];
return res.json({
success: true,
data: {
transactions: mockTransactions,
pagination: {
total: mockTransactions.length,
page: parseInt(page),
limit: parseInt(limit),
pages: Math.ceil(mockTransactions.length / limit)
}
}
});
}
// 数据库可用时的实际查询逻辑
try {
await pool.execute('SELECT 1');
} catch (dbError) {
// 数据库连接失败,返回模拟数据
const mockTransactions = [
{
id: 1,
transaction_type: 'cattle_sale',
buyer_name: '李四',
seller_name: '张三',
total_amount: 45000.00,
status: 'completed',
created_at: '2024-01-20 14:30:00'
}
];
return res.json({
success: true,
message: '数据库连接不可用,返回模拟数据',
data: {
transactions: mockTransactions,
pagination: {
total: mockTransactions.length,
page: parseInt(page),
limit: parseInt(limit),
pages: Math.ceil(mockTransactions.length / limit)
}
}
});
}
// 构建查询条件
let whereClause = '1=1';
let queryParams = [];
if (status) {
whereClause += ' AND t.status = ?';
queryParams.push(status);
}
if (transaction_type) {
whereClause += ' AND t.transaction_type = ?';
queryParams.push(transaction_type);
}
if (buyer_id) {
whereClause += ' AND t.buyer_id = ?';
queryParams.push(buyer_id);
}
if (seller_id) {
whereClause += ' AND t.seller_id = ?';
queryParams.push(seller_id);
}
if (start_date) {
whereClause += ' AND t.created_at >= ?';
queryParams.push(start_date);
}
if (end_date) {
whereClause += ' AND t.created_at <= ?';
queryParams.push(end_date);
}
if (search) {
whereClause += ' AND (buyer.real_name LIKE ? OR seller.real_name LIKE ? OR t.notes LIKE ?)';
const searchTerm = `%${search}%`;
queryParams.push(searchTerm, searchTerm, searchTerm);
}
// 获取总数
const [countResult] = await pool.execute(
`SELECT COUNT(*) as total
FROM transactions t
LEFT JOIN users buyer ON t.buyer_id = buyer.id
LEFT JOIN users seller ON t.seller_id = seller.id
WHERE ${whereClause}`,
queryParams
);
const total = countResult[0].total;
// 获取交易记录列表
const [transactions] = await pool.execute(
`SELECT t.*,
buyer.real_name as buyer_name, buyer.phone as buyer_phone,
seller.real_name as seller_name, seller.phone as seller_phone
FROM transactions t
LEFT JOIN users buyer ON t.buyer_id = buyer.id
LEFT JOIN users seller ON t.seller_id = seller.id
WHERE ${whereClause}
ORDER BY t.created_at DESC
LIMIT ? OFFSET ?`,
[...queryParams, parseInt(limit), offset]
);
res.json({
success: true,
data: {
transactions,
pagination: {
total,
page: parseInt(page),
limit: parseInt(limit),
pages: Math.ceil(total / limit)
}
}
});
} catch (error) {
console.error('获取交易记录失败:', error);
res.status(500).json({
success: false,
message: '获取交易记录失败',
error: error.message
});
}
});
// 获取交易详情
router.get('/transactions/:id', authenticateToken, checkPermission('transaction_view'), async (req, res) => {
try {
const { id } = req.params;
if (!pool) {
// 数据库不可用时返回模拟数据
const mockTransaction = {
id: parseInt(id),
transaction_type: 'cattle_sale',
buyer_id: 3,
seller_id: 2,
buyer_name: '李四',
seller_name: '张三',
buyer_phone: '13900000003',
seller_phone: '13900000002',
cattle_ids: '1,2,3',
cattle_count: 3,
cattle_details: [
{ id: 1, tag_number: 'C001', breed: '西门塔尔牛', age_months: 24, weight: 450, price: 15000 },
{ id: 2, tag_number: 'C002', breed: '西门塔尔牛', age_months: 30, weight: 520, price: 15000 },
{ id: 3, tag_number: 'C003', breed: '安格斯牛', age_months: 28, weight: 480, price: 15000 }
],
unit_price: 15000.00,
total_amount: 45000.00,
status: 'completed',
payment_method: 'bank_transfer',
payment_status: 'paid',
delivery_method: 'pickup',
delivery_address: '锡林浩特市郊区牧场',
delivery_date: '2024-01-25 09:00:00',
delivery_status: 'delivered',
contract_id: 'CON001',
contract_url: '/uploads/contracts/CON001.pdf',
notes: '优质西门塔尔牛,健康状况良好,已完成检疫',
created_at: '2024-01-20 14:30:00',
updated_at: '2024-01-25 10:15:00'
};
return res.json({
success: true,
data: mockTransaction
});
}
// 数据库可用时的实际查询逻辑
try {
await pool.execute('SELECT 1');
} catch (dbError) {
// 数据库连接失败,返回模拟数据
return res.json({
success: true,
message: '数据库连接不可用,返回模拟数据',
data: {
id: parseInt(id),
transaction_type: 'cattle_sale',
buyer_name: '李四',
seller_name: '张三',
total_amount: 45000.00,
status: 'completed'
}
});
}
// 获取交易详情
const [transactions] = await pool.execute(
`SELECT t.*,
buyer.real_name as buyer_name, buyer.phone as buyer_phone, buyer.email as buyer_email,
seller.real_name as seller_name, seller.phone as seller_phone, seller.email as seller_email,
c.contract_number, c.contract_url
FROM transactions t
LEFT JOIN users buyer ON t.buyer_id = buyer.id
LEFT JOIN users seller ON t.seller_id = seller.id
LEFT JOIN contracts c ON t.contract_id = c.id
WHERE t.id = ?`,
[id]
);
if (transactions.length === 0) {
return res.status(404).json({
success: false,
message: '交易记录不存在'
});
}
const transaction = transactions[0];
// 如果是牛只交易,获取相关牛只信息
if (transaction.transaction_type === 'cattle_sale' && transaction.cattle_ids) {
const cattleIds = transaction.cattle_ids.split(',');
const [cattleList] = await pool.execute(
`SELECT id, tag_number, breed, age_months, weight, health_status
FROM cattle WHERE id IN (${cattleIds.map(() => '?').join(',')})`,
cattleIds
);
transaction.cattle_details = cattleList;
}
res.json({
success: true,
data: transaction
});
} catch (error) {
console.error('获取交易详情失败:', error);
res.status(500).json({
success: false,
message: '获取交易详情失败',
error: error.message
});
}
});
// 创建新交易
router.post('/transactions', authenticateToken, checkPermission('transaction_create'), async (req, res) => {
try {
const {
transaction_type,
buyer_id,
seller_id,
cattle_ids,
product_name,
quantity,
unit,
unit_price,
total_amount,
payment_method,
delivery_method,
delivery_address,
delivery_date,
notes
} = req.body;
// 验证必需字段
if (!transaction_type || !buyer_id || !seller_id || !total_amount) {
return res.status(400).json({
success: false,
message: '缺少必需的字段'
});
}
if (!pool) {
// 数据库不可用时返回模拟响应
const mockTransaction = {
id: Math.floor(Math.random() * 1000) + 100,
transaction_type,
buyer_id,
seller_id,
total_amount,
status: 'pending',
created_at: new Date().toISOString(),
updated_at: new Date().toISOString()
};
return res.status(201).json({
success: true,
message: '交易创建成功(模拟数据)',
data: mockTransaction
});
}
// 数据库可用时的实际创建逻辑
try {
await pool.execute('SELECT 1');
} catch (dbError) {
// 数据库连接失败,返回模拟数据
return res.status(201).json({
success: true,
message: '数据库连接不可用,模拟创建成功',
data: {
id: Math.floor(Math.random() * 1000) + 100,
transaction_type,
status: 'pending',
created_at: new Date().toISOString()
}
});
}
// 验证买家和卖家是否存在
const [buyerCheck] = await pool.execute('SELECT id FROM users WHERE id = ?', [buyer_id]);
const [sellerCheck] = await pool.execute('SELECT id FROM users WHERE id = ?', [seller_id]);
if (buyerCheck.length === 0) {
return res.status(400).json({
success: false,
message: '买家不存在'
});
}
if (sellerCheck.length === 0) {
return res.status(400).json({
success: false,
message: '卖家不存在'
});
}
// 创建交易记录
const [result] = await pool.execute(
`INSERT INTO transactions (
transaction_type, buyer_id, seller_id, cattle_ids, product_name,
quantity, unit, unit_price, total_amount, payment_method,
delivery_method, delivery_address, delivery_date, notes, status
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, 'pending')`,
[
transaction_type, buyer_id, seller_id, cattle_ids, product_name,
quantity, unit, unit_price, total_amount, payment_method,
delivery_method, delivery_address, delivery_date, notes
]
);
// 获取创建的交易记录
const [newTransaction] = await pool.execute(
`SELECT t.*,
buyer.real_name as buyer_name,
seller.real_name as seller_name
FROM transactions t
LEFT JOIN users buyer ON t.buyer_id = buyer.id
LEFT JOIN users seller ON t.seller_id = seller.id
WHERE t.id = ?`,
[result.insertId]
);
res.status(201).json({
success: true,
message: '交易创建成功',
data: newTransaction[0]
});
} catch (error) {
console.error('创建交易失败:', error);
res.status(500).json({
success: false,
message: '创建交易失败',
error: error.message
});
}
});
// 更新交易状态
router.put('/transactions/:id/status', authenticateToken, checkPermission('transaction_manage'), async (req, res) => {
try {
const { id } = req.params;
const { status, notes } = req.body;
if (!status) {
return res.status(400).json({
success: false,
message: '状态不能为空'
});
}
const validStatuses = ['pending', 'confirmed', 'in_progress', 'completed', 'cancelled', 'refunded'];
if (!validStatuses.includes(status)) {
return res.status(400).json({
success: false,
message: '无效的状态值'
});
}
if (!pool) {
// 数据库不可用时返回模拟响应
return res.json({
success: true,
message: '交易状态更新成功(模拟数据)',
data: {
id: parseInt(id),
status,
updated_at: new Date().toISOString()
}
});
}
// 数据库可用时的实际更新逻辑
try {
await pool.execute('SELECT 1');
} catch (dbError) {
// 数据库连接失败,返回模拟数据
return res.json({
success: true,
message: '数据库连接不可用,模拟更新成功',
data: {
id: parseInt(id),
status,
updated_at: new Date().toISOString()
}
});
}
// 检查交易是否存在
const [existingTransaction] = await pool.execute(
'SELECT id, status FROM transactions WHERE id = ?',
[id]
);
if (existingTransaction.length === 0) {
return res.status(404).json({
success: false,
message: '交易记录不存在'
});
}
// 更新交易状态
const updateData = [status, id];
let updateQuery = 'UPDATE transactions SET status = ?, updated_at = CURRENT_TIMESTAMP';
if (notes) {
updateQuery += ', notes = ?';
updateData.splice(1, 0, notes);
}
updateQuery += ' WHERE id = ?';
await pool.execute(updateQuery, updateData);
// 获取更新后的交易记录
const [updatedTransaction] = await pool.execute(
`SELECT t.*,
buyer.real_name as buyer_name,
seller.real_name as seller_name
FROM transactions t
LEFT JOIN users buyer ON t.buyer_id = buyer.id
LEFT JOIN users seller ON t.seller_id = seller.id
WHERE t.id = ?`,
[id]
);
res.json({
success: true,
message: '交易状态更新成功',
data: updatedTransaction[0]
});
} catch (error) {
console.error('更新交易状态失败:', error);
res.status(500).json({
success: false,
message: '更新交易状态失败',
error: error.message
});
}
});
// ======================================
// 合同管理相关接口
// ======================================
// 获取合同列表
router.get('/contracts', authenticateToken, checkPermission('contract_view'), async (req, res) => {
try {
const {
page = 1,
limit = 10,
status,
contract_type,
party_a_id,
party_b_id,
search
} = req.query;
const offset = (page - 1) * limit;
if (!pool) {
// 数据库不可用时返回模拟数据
const mockContracts = [
{
id: 1,
contract_number: 'CON2024001',
contract_type: 'cattle_sale',
party_a_id: 2,
party_b_id: 3,
party_a_name: '张三',
party_b_name: '李四',
contract_amount: 45000.00,
signing_date: '2024-01-20',
effective_date: '2024-01-20',
expiry_date: '2024-01-30',
status: 'active',
contract_url: '/uploads/contracts/CON2024001.pdf',
notes: '牛只买卖合同',
created_at: '2024-01-20 14:30:00'
},
{
id: 2,
contract_number: 'CON2024002',
contract_type: 'feed_supply',
party_a_id: 5,
party_b_id: 2,
party_a_name: '饲料供应商A',
party_b_name: '张三',
contract_amount: 52500.00,
signing_date: '2024-01-22',
effective_date: '2024-01-22',
expiry_date: '2024-12-31',
status: 'active',
contract_url: '/uploads/contracts/CON2024002.pdf',
notes: '饲料长期供应合同',
created_at: '2024-01-22 16:45:00'
}
];
return res.json({
success: true,
data: {
contracts: mockContracts,
pagination: {
total: mockContracts.length,
page: parseInt(page),
limit: parseInt(limit),
pages: Math.ceil(mockContracts.length / limit)
}
}
});
}
// 实际的数据库查询逻辑...
res.json({
success: true,
message: '合同管理功能开发中',
data: { contracts: [], pagination: { total: 0, page: parseInt(page), limit: parseInt(limit), pages: 0 } }
});
} catch (error) {
console.error('获取合同列表失败:', error);
res.status(500).json({
success: false,
message: '获取合同列表失败',
error: error.message
});
}
});
// ======================================
// 交易统计分析接口
// ======================================
// 获取交易统计数据
router.get('/statistics', authenticateToken, checkPermission('transaction_view'), async (req, res) => {
try {
const { period = 'month', start_date, end_date } = req.query;
if (!pool) {
// 数据库不可用时返回模拟数据
const mockStats = {
total_transactions: 156,
total_amount: 2450000.00,
completed_transactions: 134,
pending_transactions: 15,
cancelled_transactions: 7,
average_transaction_amount: 15705.13,
transaction_types: {
cattle_sale: { count: 89, amount: 1850000.00 },
feed_purchase: { count: 45, amount: 420000.00 },
equipment_sale: { count: 22, amount: 180000.00 }
},
monthly_trend: [
{ month: '2023-11', transactions: 12, amount: 195000.00 },
{ month: '2023-12', transactions: 18, amount: 285000.00 },
{ month: '2024-01', transactions: 24, amount: 385000.00 }
],
top_buyers: [
{ user_id: 3, name: '李四', transaction_count: 8, total_amount: 125000.00 },
{ user_id: 4, name: '王五', transaction_count: 6, total_amount: 98000.00 }
],
top_sellers: [
{ user_id: 2, name: '张三', transaction_count: 12, total_amount: 185000.00 },
{ user_id: 5, name: '饲料供应商A', transaction_count: 15, total_amount: 142000.00 }
]
};
return res.json({
success: true,
data: mockStats
});
}
// 实际的统计查询逻辑...
res.json({
success: true,
message: '交易统计功能开发中',
data: { total_transactions: 0, total_amount: 0 }
});
} catch (error) {
console.error('获取交易统计失败:', error);
res.status(500).json({
success: false,
message: '获取交易统计失败',
error: error.message
});
}
});
// 导出模块
module.exports = {
router,
setMiddleware
};

518
backend/api/routes/users.js Normal file
View File

@@ -0,0 +1,518 @@
const express = require('express');
const bcrypt = require('bcrypt');
const router = express.Router();
// 中间件将在服务器启动时设置
let authenticateToken = (req, res, next) => {
return res.status(500).json({
success: false,
message: '认证中间件未初始化',
code: 'AUTH_NOT_INITIALIZED'
});
};
let checkPermission = (permission) => {
return (req, res, next) => {
return res.status(500).json({
success: false,
message: '权限中间件未初始化',
code: 'PERMISSION_NOT_INITIALIZED'
});
};
};
let pool = null;
// 设置中间件和数据库连接(从主服务器导入)
function setMiddleware(auth, permission, dbPool) {
authenticateToken = auth;
checkPermission = permission;
pool = dbPool;
}
// 获取用户列表
router.get('/', authenticateToken, checkPermission('user_manage'), async (req, res) => {
try {
const { page = 1, limit = 10, user_type, status, search } = req.query;
const offset = (page - 1) * limit;
if (!pool) {
// 数据库不可用时返回模拟数据
const mockUsers = [
{
id: 1,
username: 'admin',
email: 'admin@xlxumu.com',
real_name: '系统管理员',
user_type: 'admin',
status: 1,
last_login: '2024-01-01 10:00:00',
created_at: '2024-01-01 00:00:00'
},
{
id: 2,
username: 'farmer001',
email: 'farmer001@example.com',
real_name: '张三',
user_type: 'farmer',
status: 1,
last_login: '2024-01-02 08:30:00',
created_at: '2024-01-01 01:00:00'
}
];
return res.json({
success: true,
data: {
users: mockUsers,
pagination: {
total: mockUsers.length,
page: parseInt(page),
limit: parseInt(limit),
pages: Math.ceil(mockUsers.length / limit)
}
}
});
}
// 构建查询条件
let whereClause = '1=1';
let queryParams = [];
if (user_type) {
whereClause += ' AND user_type = ?';
queryParams.push(user_type);
}
if (status !== undefined) {
whereClause += ' AND status = ?';
queryParams.push(parseInt(status));
}
if (search) {
whereClause += ' AND (username LIKE ? OR real_name LIKE ? OR email LIKE ?)';
const searchTerm = `%${search}%`;
queryParams.push(searchTerm, searchTerm, searchTerm);
}
// 获取总数
const [countResult] = await pool.execute(
`SELECT COUNT(*) as total FROM users WHERE ${whereClause}`,
queryParams
);
const total = countResult[0].total;
// 获取用户列表
const [users] = await pool.execute(
`SELECT id, username, email, phone, real_name, user_type, status, last_login, created_at
FROM users
WHERE ${whereClause}
ORDER BY created_at DESC
LIMIT ? OFFSET ?`,
[...queryParams, parseInt(limit), offset]
);
res.json({
success: true,
data: {
users,
pagination: {
total,
page: parseInt(page),
limit: parseInt(limit),
pages: Math.ceil(total / limit)
}
}
});
} catch (error) {
console.error('获取用户列表错误:', error);
res.status(500).json({
success: false,
message: '获取用户列表失败',
code: 'GET_USERS_ERROR'
});
}
});
// 获取用户详情
router.get('/:id', authenticateToken, checkPermission('user_manage'), async (req, res) => {
try {
const userId = req.params.id;
if (!pool) {
return res.status(500).json({
success: false,
message: '数据库连接不可用',
code: 'DB_UNAVAILABLE'
});
}
// 获取用户基本信息
const [users] = await pool.execute(
'SELECT id, username, email, phone, real_name, user_type, status, last_login, created_at FROM users WHERE id = ?',
[userId]
);
if (users.length === 0) {
return res.status(404).json({
success: false,
message: '用户不存在',
code: 'USER_NOT_FOUND'
});
}
// 获取用户角色
const [roles] = await pool.execute(`
SELECT r.id, r.name, r.description
FROM user_roles ur
JOIN roles r ON ur.role_id = r.id
WHERE ur.user_id = ?
`, [userId]);
res.json({
success: true,
data: {
user: users[0],
roles
}
});
} catch (error) {
console.error('获取用户详情错误:', error);
res.status(500).json({
success: false,
message: '获取用户详情失败',
code: 'GET_USER_ERROR'
});
}
});
// 创建用户
router.post('/', authenticateToken, checkPermission('user_manage'), async (req, res) => {
try {
const { username, email, phone, password, real_name, user_type, role_ids } = req.body;
// 输入验证
if (!username || !password || !user_type) {
return res.status(400).json({
success: false,
message: '用户名、密码和用户类型为必填项',
code: 'MISSING_REQUIRED_FIELDS'
});
}
if (!pool) {
return res.status(500).json({
success: false,
message: '数据库连接不可用',
code: 'DB_UNAVAILABLE'
});
}
// 检查用户名是否已存在
const [existingUsers] = await pool.execute(
'SELECT id FROM users WHERE username = ? OR email = ? OR phone = ?',
[username, email || null, phone || null]
);
if (existingUsers.length > 0) {
return res.status(409).json({
success: false,
message: '用户名、邮箱或手机号已存在',
code: 'USER_EXISTS'
});
}
// 密码加密
const saltRounds = 10;
const password_hash = await bcrypt.hash(password, saltRounds);
// 开始事务
const connection = await pool.getConnection();
await connection.beginTransaction();
try {
// 插入用户
const [userResult] = await connection.execute(
'INSERT INTO users (username, email, phone, password_hash, real_name, user_type) VALUES (?, ?, ?, ?, ?, ?)',
[username, email || null, phone || null, password_hash, real_name || null, user_type]
);
const newUserId = userResult.insertId;
// 分配角色
if (role_ids && role_ids.length > 0) {
for (const roleId of role_ids) {
await connection.execute(
'INSERT INTO user_roles (user_id, role_id) VALUES (?, ?)',
[newUserId, roleId]
);
}
}
await connection.commit();
connection.release();
res.status(201).json({
success: true,
message: '用户创建成功',
data: {
userId: newUserId,
username,
user_type
}
});
} catch (error) {
await connection.rollback();
connection.release();
throw error;
}
} catch (error) {
console.error('创建用户错误:', error);
res.status(500).json({
success: false,
message: '创建用户失败',
code: 'CREATE_USER_ERROR'
});
}
});
// 更新用户
router.put('/:id', authenticateToken, checkPermission('user_manage'), async (req, res) => {
try {
const userId = req.params.id;
const { email, phone, real_name, status, role_ids } = req.body;
if (!pool) {
return res.status(500).json({
success: false,
message: '数据库连接不可用',
code: 'DB_UNAVAILABLE'
});
}
// 检查用户是否存在
const [users] = await pool.execute('SELECT id FROM users WHERE id = ?', [userId]);
if (users.length === 0) {
return res.status(404).json({
success: false,
message: '用户不存在',
code: 'USER_NOT_FOUND'
});
}
// 检查邮箱和手机号是否被其他用户使用
if (email || phone) {
const [existingUsers] = await pool.execute(
'SELECT id FROM users WHERE (email = ? OR phone = ?) AND id != ?',
[email || null, phone || null, userId]
);
if (existingUsers.length > 0) {
return res.status(409).json({
success: false,
message: '邮箱或手机号已被其他用户使用',
code: 'CONTACT_EXISTS'
});
}
}
// 开始事务
const connection = await pool.getConnection();
await connection.beginTransaction();
try {
// 更新用户基本信息
await connection.execute(
'UPDATE users SET email = ?, phone = ?, real_name = ?, status = ? WHERE id = ?',
[email || null, phone || null, real_name || null, status !== undefined ? status : 1, userId]
);
// 更新用户角色
if (role_ids !== undefined) {
// 删除现有角色
await connection.execute('DELETE FROM user_roles WHERE user_id = ?', [userId]);
// 添加新角色
if (role_ids.length > 0) {
for (const roleId of role_ids) {
await connection.execute(
'INSERT INTO user_roles (user_id, role_id) VALUES (?, ?)',
[userId, roleId]
);
}
}
}
await connection.commit();
connection.release();
res.json({
success: true,
message: '用户更新成功'
});
} catch (error) {
await connection.rollback();
connection.release();
throw error;
}
} catch (error) {
console.error('更新用户错误:', error);
res.status(500).json({
success: false,
message: '更新用户失败',
code: 'UPDATE_USER_ERROR'
});
}
});
// 删除用户
router.delete('/:id', authenticateToken, checkPermission('user_manage'), async (req, res) => {
try {
const userId = req.params.id;
if (!pool) {
return res.status(500).json({
success: false,
message: '数据库连接不可用',
code: 'DB_UNAVAILABLE'
});
}
// 检查是否是当前用户
if (parseInt(userId) === req.user.userId) {
return res.status(400).json({
success: false,
message: '不能删除当前登录用户',
code: 'CANNOT_DELETE_SELF'
});
}
// 检查用户是否存在
const [users] = await pool.execute('SELECT id FROM users WHERE id = ?', [userId]);
if (users.length === 0) {
return res.status(404).json({
success: false,
message: '用户不存在',
code: 'USER_NOT_FOUND'
});
}
// 删除用户(级联删除用户角色关联)
await pool.execute('DELETE FROM users WHERE id = ?', [userId]);
res.json({
success: true,
message: '用户删除成功'
});
} catch (error) {
console.error('删除用户错误:', error);
res.status(500).json({
success: false,
message: '删除用户失败',
code: 'DELETE_USER_ERROR'
});
}
});
// 重置用户密码
router.post('/:id/reset-password', authenticateToken, checkPermission('user_manage'), async (req, res) => {
try {
const userId = req.params.id;
const { new_password } = req.body;
if (!new_password) {
return res.status(400).json({
success: false,
message: '新密码为必填项',
code: 'MISSING_PASSWORD'
});
}
if (!pool) {
return res.status(500).json({
success: false,
message: '数据库连接不可用',
code: 'DB_UNAVAILABLE'
});
}
// 检查用户是否存在
const [users] = await pool.execute('SELECT id FROM users WHERE id = ?', [userId]);
if (users.length === 0) {
return res.status(404).json({
success: false,
message: '用户不存在',
code: 'USER_NOT_FOUND'
});
}
// 加密新密码
const saltRounds = 10;
const password_hash = await bcrypt.hash(new_password, saltRounds);
// 更新密码
await pool.execute('UPDATE users SET password_hash = ? WHERE id = ?', [password_hash, userId]);
res.json({
success: true,
message: '密码重置成功'
});
} catch (error) {
console.error('重置密码错误:', error);
res.status(500).json({
success: false,
message: '重置密码失败',
code: 'RESET_PASSWORD_ERROR'
});
}
});
// 获取所有角色(用于分配角色)
router.get('/roles/list', authenticateToken, checkPermission('user_manage'), async (req, res) => {
try {
if (!pool) {
// 数据库不可用时返回模拟数据
const mockRoles = [
{ id: 1, name: 'admin', description: '系统管理员' },
{ id: 2, name: 'farmer', description: '养殖户' },
{ id: 3, name: 'banker', description: '银行职员' },
{ id: 4, name: 'insurer', description: '保险员' },
{ id: 5, name: 'government', description: '政府监管人员' },
{ id: 6, name: 'trader', description: '交易员' }
];
return res.json({
success: true,
data: mockRoles
});
}
const [roles] = await pool.execute('SELECT id, name, description FROM roles ORDER BY id');
res.json({
success: true,
data: roles
});
} catch (error) {
console.error('获取角色列表错误:', error);
res.status(500).json({
success: false,
message: '获取角色列表失败',
code: 'GET_ROLES_ERROR'
});
}
});
module.exports = {
router,
setMiddleware
};