docs(website): 重构关于页面布局和内容

- 更新页面布局,优化导航栏和面包屑导航
- 重新组织页面内容,突出公司使命和价值观
- 添加发展历程和核心团队介绍
- 更新合作伙伴展示方式
- 调整页脚内容,增加社交媒体链接
This commit is contained in:
2025-09-10 20:09:58 +08:00
parent 59cfe620fe
commit a9209b9c75
38 changed files with 10067 additions and 1989 deletions

View File

@@ -0,0 +1,55 @@
// 数据库配置
const dbConfig = {
development: {
username: 'root',
password: 'password',
database: 'niumall_dev',
host: '127.0.0.1',
port: 3306,
dialect: 'mysql'
},
production: {
username: process.env.DB_USERNAME,
password: process.env.DB_PASSWORD,
database: process.env.DB_NAME,
host: process.env.DB_HOST,
port: process.env.DB_PORT || 3306,
dialect: 'mysql'
}
};
// JWT配置
const jwtConfig = {
secret: process.env.JWT_SECRET || 'niumall-jwt-secret',
expiresIn: process.env.JWT_EXPIRES_IN || '24h'
};
// Redis配置
const redisConfig = {
development: {
host: '127.0.0.1',
port: 6379
},
production: {
host: process.env.REDIS_HOST,
port: process.env.REDIS_PORT || 6379
}
};
// 服务器配置
const serverConfig = {
port: process.env.PORT || 3000
};
// 日志配置
const logConfig = {
level: process.env.LOG_LEVEL || 'info'
};
module.exports = {
dbConfig,
jwtConfig,
redisConfig,
serverConfig,
logConfig
};

View File

@@ -0,0 +1,36 @@
const { Sequelize } = require('sequelize');
const { dbConfig } = require('./config');
// 获取环境变量
const nodeEnv = process.env.NODE_ENV || 'development';
// 创建Sequelize实例
const sequelize = new Sequelize(
dbConfig[nodeEnv].database,
dbConfig[nodeEnv].username,
dbConfig[nodeEnv].password,
{
host: dbConfig[nodeEnv].host,
port: dbConfig[nodeEnv].port,
dialect: dbConfig[nodeEnv].dialect,
logging: nodeEnv === 'development' ? console.log : false, // 开发环境显示SQL日志
pool: {
max: 5,
min: 0,
acquire: 30000,
idle: 10000
}
}
);
// 测试数据库连接
const testConnection = async () => {
try {
await sequelize.authenticate();
console.log('数据库连接成功');
} catch (error) {
console.error('数据库连接失败:', error);
}
};
module.exports = sequelize;

View File

@@ -0,0 +1,91 @@
const jwt = require('jsonwebtoken');
const bcrypt = require('bcryptjs');
const { v4: uuidv4 } = require('uuid');
const { successResponse, errorResponse } = require('../utils/response');
const { jwtConfig } = require('../config/config');
const User = require('../models/User');
// 小程序用户登录
const miniProgramLogin = async (req, res) => {
try {
const { phone, code, miniProgramType } = req.body;
// 验证验证码(实际项目中需要对接短信服务)
if (code !== '123456') { // 临时验证码,实际项目中需要验证真实验证码
return res.status(400).json(errorResponse('验证码错误', 400));
}
// 查找用户
let user = await User.findOne({ where: { phone } });
// 如果用户不存在则创建新用户
if (!user) {
user = await User.create({
uuid: uuidv4(),
username: `user_${phone}`,
phone,
user_type: miniProgramType || 'client',
password_hash: bcrypt.hashSync(phone, 10) // 临时密码,实际项目中需要更安全的处理
});
}
// 生成JWT token
const token = jwt.sign(
{
id: user.id,
uuid: user.uuid,
username: user.username,
phone: user.phone,
userType: user.user_type
},
jwtConfig.secret,
{ expiresIn: jwtConfig.expiresIn }
);
// 返回用户信息和token
const userInfo = {
id: user.id,
username: user.username,
realName: user.real_name,
avatar: user.avatar_url,
userType: user.user_type,
phone: user.phone
};
res.json(successResponse({ token, userInfo }));
} catch (error) {
console.error('登录错误:', error);
res.status(500).json(errorResponse('服务器内部错误', 500));
}
};
// 获取当前用户信息
const getCurrentUser = async (req, res) => {
try {
const user = await User.findByPk(req.user.id);
if (!user) {
return res.status(404).json(errorResponse('用户不存在', 404));
}
const userInfo = {
id: user.id,
username: user.username,
realName: user.real_name,
avatar: user.avatar_url,
userType: user.user_type,
phone: user.phone,
email: user.email
};
res.json(successResponse(userInfo));
} catch (error) {
console.error('获取用户信息错误:', error);
res.status(500).json(errorResponse('服务器内部错误', 500));
}
};
module.exports = {
miniProgramLogin,
getCurrentUser
};

View File

@@ -0,0 +1,133 @@
const { successResponse, errorResponse, paginatedResponse } = require('../utils/response');
const Order = require('../models/Order');
// 创建订单
const createOrder = async (req, res) => {
try {
const orderData = req.body;
// 设置买家ID
orderData.buyer_id = req.user.id;
// 生成订单号
const orderNo = `ORD${Date.now()}${Math.floor(Math.random() * 1000).toString().padStart(3, '0')}`;
orderData.order_no = orderNo;
// 创建订单
const order = await Order.create(orderData);
res.status(201).json(successResponse(order, '订单创建成功'));
} catch (error) {
console.error('创建订单错误:', error);
res.status(500).json(errorResponse('服务器内部错误', 500));
}
};
// 获取订单列表
const getOrderList = async (req, res) => {
try {
const { page = 1, pageSize = 10, status, orderNo } = req.query;
// 构建查询条件
const whereConditions = {};
// 根据用户类型过滤
if (req.user.userType === 'client') {
whereConditions.buyer_id = req.user.id;
} else if (req.user.userType === 'trader') {
whereConditions.trader_id = req.user.id;
} else if (req.user.userType === 'supplier') {
whereConditions.supplier_id = req.user.id;
} else if (req.user.userType === 'driver') {
whereConditions.driver_id = req.user.id;
}
if (status) whereConditions.status = status;
if (orderNo) whereConditions.order_no = orderNo;
// 查询订单列表
const { count, rows } = await Order.findAndCountAll({
where: whereConditions,
limit: parseInt(pageSize),
offset: (parseInt(page) - 1) * parseInt(pageSize),
order: [['created_at', 'DESC']]
});
res.json(paginatedResponse(rows, count, parseInt(page), parseInt(pageSize)));
} catch (error) {
console.error('获取订单列表错误:', error);
res.status(500).json(errorResponse('服务器内部错误', 500));
}
};
// 获取订单详情
const getOrderDetail = async (req, res) => {
try {
const { id } = req.params;
const order = await Order.findByPk(id);
if (!order) {
return res.status(404).json(errorResponse('订单不存在', 404));
}
// 权限检查
if (req.user.userType === 'client' && order.buyer_id !== req.user.id) {
return res.status(403).json(errorResponse('无权限访问该订单', 403));
}
if (req.user.userType === 'trader' && order.trader_id !== req.user.id) {
return res.status(403).json(errorResponse('无权限访问该订单', 403));
}
if (req.user.userType === 'supplier' && order.supplier_id !== req.user.id) {
return res.status(403).json(errorResponse('无权限访问该订单', 403));
}
if (req.user.userType === 'driver' && order.driver_id !== req.user.id) {
return res.status(403).json(errorResponse('无权限访问该订单', 403));
}
res.json(successResponse(order));
} catch (error) {
console.error('获取订单详情错误:', error);
res.status(500).json(errorResponse('服务器内部错误', 500));
}
};
// 更新订单状态
const updateOrderStatus = async (req, res) => {
try {
const { id } = req.params;
const { status } = req.body;
const order = await Order.findByPk(id);
if (!order) {
return res.status(404).json(errorResponse('订单不存在', 404));
}
// 权限检查和状态流转验证
// 这里需要根据业务逻辑实现详细的状态流转控制
const [updatedRowsCount] = await Order.update({ status }, {
where: { id }
});
if (updatedRowsCount === 0) {
return res.status(400).json(errorResponse('订单状态更新失败', 400));
}
res.json(successResponse(null, '订单状态更新成功'));
} catch (error) {
console.error('更新订单状态错误:', error);
res.status(500).json(errorResponse('服务器内部错误', 500));
}
};
module.exports = {
createOrder,
getOrderList,
getOrderDetail,
updateOrderStatus
};

View File

@@ -0,0 +1,121 @@
const { successResponse, errorResponse, paginatedResponse } = require('../utils/response');
const Payment = require('../models/Payment');
// 创建支付
const createPayment = async (req, res) => {
try {
const { orderId, amount, paymentType, paymentMethod } = req.body;
// 生成支付单号
const paymentNo = `PAY${Date.now()}${Math.floor(Math.random() * 1000).toString().padStart(3, '0')}`;
// 创建支付记录
const payment = await Payment.create({
order_id: orderId,
user_id: req.user.id,
amount,
payment_type: paymentType,
payment_method: paymentMethod,
payment_no: paymentNo,
status: 'pending'
});
// 这里需要对接实际的支付接口(微信支付、支付宝等)
// 暂时返回模拟的支付参数
const paymentParams = {
paymentNo,
amount,
paymentType,
paymentMethod
};
res.status(201).json(successResponse({ payment, paymentParams }, '支付创建成功'));
} catch (error) {
console.error('创建支付错误:', error);
res.status(500).json(errorResponse('服务器内部错误', 500));
}
};
// 获取支付列表
const getPaymentList = async (req, res) => {
try {
const { page = 1, pageSize = 10, status } = req.query;
// 构建查询条件
const whereConditions = {
user_id: req.user.id
};
if (status) whereConditions.status = status;
// 查询支付列表
const { count, rows } = await Payment.findAndCountAll({
where: whereConditions,
limit: parseInt(pageSize),
offset: (parseInt(page) - 1) * parseInt(pageSize),
order: [['created_at', 'DESC']]
});
res.json(paginatedResponse(rows, count, parseInt(page), parseInt(pageSize)));
} catch (error) {
console.error('获取支付列表错误:', error);
res.status(500).json(errorResponse('服务器内部错误', 500));
}
};
// 获取支付详情
const getPaymentDetail = async (req, res) => {
try {
const { id } = req.params;
const payment = await Payment.findByPk(id);
if (!payment) {
return res.status(404).json(errorResponse('支付记录不存在', 404));
}
// 权限检查
if (payment.user_id !== req.user.id) {
return res.status(403).json(errorResponse('无权限访问该支付记录', 403));
}
res.json(successResponse(payment));
} catch (error) {
console.error('获取支付详情错误:', error);
res.status(500).json(errorResponse('服务器内部错误', 500));
}
};
// 更新支付状态(模拟支付回调)
const updatePaymentStatus = async (req, res) => {
try {
const { paymentNo, status, thirdPartyId } = req.body;
const [updatedRowsCount] = await Payment.update(
{
status,
third_party_id: thirdPartyId,
paid_time: status === 'paid' ? new Date() : null
},
{
where: { payment_no: paymentNo }
}
);
if (updatedRowsCount === 0) {
return res.status(404).json(errorResponse('支付记录不存在', 404));
}
res.json(successResponse(null, '支付状态更新成功'));
} catch (error) {
console.error('更新支付状态错误:', error);
res.status(500).json(errorResponse('服务器内部错误', 500));
}
};
module.exports = {
createPayment,
getPaymentList,
getPaymentDetail,
updatePaymentStatus
};

View File

@@ -0,0 +1,136 @@
const { successResponse, errorResponse, paginatedResponse } = require('../utils/response');
const User = require('../models/User');
// 获取用户列表
const getUserList = async (req, res) => {
try {
const { page = 1, pageSize = 10, userType, status } = req.query;
// 构建查询条件
const whereConditions = {};
if (userType) whereConditions.user_type = userType;
if (status) whereConditions.status = status;
// 查询用户列表
const { count, rows } = await User.findAndCountAll({
where: whereConditions,
limit: parseInt(pageSize),
offset: (parseInt(page) - 1) * parseInt(pageSize),
order: [['created_at', 'DESC']]
});
// 格式化用户数据
const users = rows.map(user => ({
id: user.id,
uuid: user.uuid,
username: user.username,
realName: user.real_name,
phone: user.phone,
email: user.email,
userType: user.user_type,
status: user.status,
avatar: user.avatar_url,
createdAt: user.created_at
}));
res.json(paginatedResponse(users, count, parseInt(page), parseInt(pageSize)));
} catch (error) {
console.error('获取用户列表错误:', error);
res.status(500).json(errorResponse('服务器内部错误', 500));
}
};
// 获取用户详情
const getUserDetail = async (req, res) => {
try {
const { id } = req.params;
const user = await User.findByPk(id);
if (!user) {
return res.status(404).json(errorResponse('用户不存在', 404));
}
const userInfo = {
id: user.id,
uuid: user.uuid,
username: user.username,
realName: user.real_name,
phone: user.phone,
email: user.email,
userType: user.user_type,
status: user.status,
avatar: user.avatar_url,
idCardFront: user.id_card_front_url,
idCardBack: user.id_card_back_url,
licenseFront: user.license_front_url,
licenseBack: user.license_back_url,
businessLicense: user.business_license_url,
createdAt: user.created_at,
updatedAt: user.updated_at
};
res.json(successResponse(userInfo));
} catch (error) {
console.error('获取用户详情错误:', error);
res.status(500).json(errorResponse('服务器内部错误', 500));
}
};
// 更新用户信息
const updateUser = async (req, res) => {
try {
const { id } = req.params;
const updateData = req.body;
// 过滤不允许更新的字段
const allowedFields = ['real_name', 'email', 'avatar_url'];
const filteredData = {};
Object.keys(updateData).forEach(key => {
if (allowedFields.includes(key)) {
filteredData[key] = updateData[key];
}
});
const [updatedRowsCount] = await User.update(filteredData, {
where: { id }
});
if (updatedRowsCount === 0) {
return res.status(404).json(errorResponse('用户不存在', 404));
}
res.json(successResponse(null, '用户信息更新成功'));
} catch (error) {
console.error('更新用户信息错误:', error);
res.status(500).json(errorResponse('服务器内部错误', 500));
}
};
// 更新用户状态
const updateUserStatus = async (req, res) => {
try {
const { id } = req.params;
const { status } = req.body;
const [updatedRowsCount] = await User.update({ status }, {
where: { id }
});
if (updatedRowsCount === 0) {
return res.status(404).json(errorResponse('用户不存在', 404));
}
res.json(successResponse(null, '用户状态更新成功'));
} catch (error) {
console.error('更新用户状态错误:', error);
res.status(500).json(errorResponse('服务器内部错误', 500));
}
};
module.exports = {
getUserList,
getUserDetail,
updateUser,
updateUserStatus
};

912
backend/src/docs/api.yaml Normal file
View File

@@ -0,0 +1,912 @@
openapi: 3.0.0
info:
title: 活牛采购智能数字化系统API
description: 活牛采购智能数字化系统后端API接口文档
version: 1.0.0
contact:
name: Niutech
email: niutech@example.com
servers:
- url: http://localhost:3000
description: 开发服务器
- url: https://api.niumall.com
description: 生产服务器
components:
securitySchemes:
bearerAuth:
type: http
scheme: bearer
bearerFormat: JWT
schemas:
User:
type: object
properties:
id:
type: integer
description: 用户ID
uuid:
type: string
description: 用户UUID
username:
type: string
description: 用户名
realName:
type: string
description: 真实姓名
phone:
type: string
description: 手机号
email:
type: string
description: 邮箱
userType:
type: string
description: 用户类型
status:
type: string
description: 用户状态
avatar:
type: string
description: 头像URL
createdAt:
type: string
format: date-time
description: 创建时间
updatedAt:
type: string
format: date-time
description: 更新时间
Order:
type: object
properties:
id:
type: integer
description: 订单ID
orderNo:
type: string
description: 订单号
buyerId:
type: integer
description: 买家ID
traderId:
type: integer
description: 贸易商ID
supplierId:
type: integer
description: 供应商ID
driverId:
type: integer
description: 司机ID
breedType:
type: string
description: 品种类型
minWeight:
type: number
description: 最小重量
maxWeight:
type: number
description: 最大重量
totalCount:
type: integer
description: 总数量
totalWeight:
type: number
description: 总重量
unitPrice:
type: number
description: 单价
totalAmount:
type: number
description: 总金额
status:
type: string
description: 订单状态
deliveryAddress:
type: string
description: 交付地址
deliveryDate:
type: string
format: date
description: 交付日期
specialRequirements:
type: string
description: 特殊要求
createdAt:
type: string
format: date-time
description: 创建时间
updatedAt:
type: string
format: date-time
description: 更新时间
Payment:
type: object
properties:
id:
type: integer
description: 支付ID
orderId:
type: integer
description: 订单ID
userId:
type: integer
description: 用户ID
amount:
type: number
description: 支付金额
paidAmount:
type: number
description: 实际支付金额
paymentType:
type: string
description: 支付类型
paymentMethod:
type: string
description: 支付方式
paymentNo:
type: string
description: 支付单号
thirdPartyId:
type: string
description: 第三方支付ID
status:
type: string
description: 支付状态
paidTime:
type: string
format: date-time
description: 支付时间
createdAt:
type: string
format: date-time
description: 创建时间
updatedAt:
type: string
format: date-time
description: 更新时间
AuthResponse:
type: object
properties:
token:
type: string
description: JWT token
userInfo:
$ref: '#/components/schemas/User'
SuccessResponse:
type: object
properties:
code:
type: integer
description: 状态码
message:
type: string
description: 消息
data:
type: object
description: 数据
ErrorResponse:
type: object
properties:
code:
type: integer
description: 状态码
message:
type: string
description: 错误消息
PaginatedResponse:
type: object
properties:
code:
type: integer
description: 状态码
message:
type: string
description: 消息
data:
type: array
items:
type: object
description: 数据列表
pagination:
type: object
properties:
page:
type: integer
description: 当前页码
pageSize:
type: integer
description: 每页数量
total:
type: integer
description: 总数量
totalPages:
type: integer
description: 总页数
paths:
/health:
get:
summary: 健康检查
description: 检查服务器健康状态
responses:
'200':
description: 服务器健康
content:
application/json:
schema:
type: object
properties:
status:
type: string
timestamp:
type: string
format: date-time
uptime:
type: number
/:
get:
summary: 根路径
description: 返回API根路径信息
responses:
'200':
description: 成功返回
content:
application/json:
schema:
type: object
properties:
message:
type: string
version:
type: string
/api/auth/mini-program/login:
post:
summary: 小程序用户登录
description: 小程序用户通过手机号和验证码登录
requestBody:
required: true
content:
application/json:
schema:
type: object
properties:
phone:
type: string
description: 手机号
code:
type: string
description: 验证码
miniProgramType:
type: string
description: 小程序类型
responses:
'200':
description: 登录成功
content:
application/json:
schema:
$ref: '#/components/schemas/AuthResponse'
'400':
description: 请求参数错误
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
'500':
description: 服务器内部错误
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
/api/auth/current:
get:
summary: 获取当前用户信息
description: 获取当前登录用户的信息
security:
- bearerAuth: []
responses:
'200':
description: 成功返回用户信息
content:
application/json:
schema:
$ref: '#/components/schemas/SuccessResponse'
'401':
description: 未授权
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
'500':
description: 服务器内部错误
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
/api/users:
get:
summary: 获取用户列表
description: 获取用户列表(管理员权限)
security:
- bearerAuth: []
parameters:
- name: page
in: query
description: 页码
schema:
type: integer
default: 1
- name: pageSize
in: query
description: 每页数量
schema:
type: integer
default: 10
- name: userType
in: query
description: 用户类型
schema:
type: string
- name: status
in: query
description: 用户状态
schema:
type: string
responses:
'200':
description: 成功返回用户列表
content:
application/json:
schema:
$ref: '#/components/schemas/PaginatedResponse'
'401':
description: 未授权
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
'403':
description: 权限不足
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
'500':
description: 服务器内部错误
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
/api/users/{id}:
get:
summary: 获取用户详情
description: 获取指定用户的信息
security:
- bearerAuth: []
parameters:
- name: id
in: path
required: true
description: 用户ID
schema:
type: integer
responses:
'200':
description: 成功返回用户信息
content:
application/json:
schema:
$ref: '#/components/schemas/SuccessResponse'
'401':
description: 未授权
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
'404':
description: 用户不存在
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
'500':
description: 服务器内部错误
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
put:
summary: 更新用户信息
description: 更新指定用户的信息
security:
- bearerAuth: []
parameters:
- name: id
in: path
required: true
description: 用户ID
schema:
type: integer
requestBody:
required: true
content:
application/json:
schema:
type: object
properties:
real_name:
type: string
description: 真实姓名
email:
type: string
description: 邮箱
avatar_url:
type: string
description: 头像URL
responses:
'200':
description: 更新成功
content:
application/json:
schema:
$ref: '#/components/schemas/SuccessResponse'
'401':
description: 未授权
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
'404':
description: 用户不存在
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
'500':
description: 服务器内部错误
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
/api/users/{id}/status:
patch:
summary: 更新用户状态
description: 更新指定用户的状态(管理员权限)
security:
- bearerAuth: []
parameters:
- name: id
in: path
required: true
description: 用户ID
schema:
type: integer
requestBody:
required: true
content:
application/json:
schema:
type: object
properties:
status:
type: string
description: 用户状态
responses:
'200':
description: 更新成功
content:
application/json:
schema:
$ref: '#/components/schemas/SuccessResponse'
'401':
description: 未授权
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
'403':
description: 权限不足
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
'404':
description: 用户不存在
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
'500':
description: 服务器内部错误
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
/api/orders:
post:
summary: 创建订单
description: 创建新的订单
security:
- bearerAuth: []
requestBody:
required: true
content:
application/json:
schema:
type: object
properties:
trader_id:
type: integer
description: 贸易商ID
supplier_id:
type: integer
description: 供应商ID
driver_id:
type: integer
description: 司机ID
breed_type:
type: string
description: 品种类型
min_weight:
type: number
description: 最小重量
max_weight:
type: number
description: 最大重量
total_count:
type: integer
description: 总数量
total_weight:
type: number
description: 总重量
unit_price:
type: number
description: 单价
total_amount:
type: number
description: 总金额
delivery_address:
type: string
description: 交付地址
delivery_date:
type: string
format: date
description: 交付日期
special_requirements:
type: string
description: 特殊要求
responses:
'201':
description: 订单创建成功
content:
application/json:
schema:
$ref: '#/components/schemas/SuccessResponse'
'401':
description: 未授权
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
'500':
description: 服务器内部错误
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
get:
summary: 获取订单列表
description: 获取订单列表
security:
- bearerAuth: []
parameters:
- name: page
in: query
description: 页码
schema:
type: integer
default: 1
- name: pageSize
in: query
description: 每页数量
schema:
type: integer
default: 10
- name: status
in: query
description: 订单状态
schema:
type: string
- name: orderNo
in: query
description: 订单号
schema:
type: string
responses:
'200':
description: 成功返回订单列表
content:
application/json:
schema:
$ref: '#/components/schemas/PaginatedResponse'
'401':
description: 未授权
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
'500':
description: 服务器内部错误
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
/api/orders/{id}:
get:
summary: 获取订单详情
description: 获取指定订单的详细信息
security:
- bearerAuth: []
parameters:
- name: id
in: path
required: true
description: 订单ID
schema:
type: integer
responses:
'200':
description: 成功返回订单信息
content:
application/json:
schema:
$ref: '#/components/schemas/SuccessResponse'
'401':
description: 未授权
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
'403':
description: 权限不足
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
'404':
description: 订单不存在
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
'500':
description: 服务器内部错误
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
/api/orders/{id}/status:
patch:
summary: 更新订单状态
description: 更新指定订单的状态
security:
- bearerAuth: []
parameters:
- name: id
in: path
required: true
description: 订单ID
schema:
type: integer
requestBody:
required: true
content:
application/json:
schema:
type: object
properties:
status:
type: string
description: 订单状态
responses:
'200':
description: 更新成功
content:
application/json:
schema:
$ref: '#/components/schemas/SuccessResponse'
'401':
description: 未授权
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
'403':
description: 权限不足
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
'404':
description: 订单不存在
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
'500':
description: 服务器内部错误
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
/api/payments:
post:
summary: 创建支付
description: 创建新的支付
security:
- bearerAuth: []
requestBody:
required: true
content:
application/json:
schema:
type: object
properties:
order_id:
type: integer
description: 订单ID
amount:
type: number
description: 支付金额
payment_type:
type: string
description: 支付类型
payment_method:
type: string
description: 支付方式
responses:
'201':
description: 支付创建成功
content:
application/json:
schema:
$ref: '#/components/schemas/SuccessResponse'
'401':
description: 未授权
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
'500':
description: 服务器内部错误
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
get:
summary: 获取支付列表
description: 获取支付列表
security:
- bearerAuth: []
parameters:
- name: page
in: query
description: 页码
schema:
type: integer
default: 1
- name: pageSize
in: query
description: 每页数量
schema:
type: integer
default: 10
- name: status
in: query
description: 支付状态
schema:
type: string
responses:
'200':
description: 成功返回支付列表
content:
application/json:
schema:
$ref: '#/components/schemas/PaginatedResponse'
'401':
description: 未授权
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
'500':
description: 服务器内部错误
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
/api/payments/{id}:
get:
summary: 获取支付详情
description: 获取指定支付的详细信息
security:
- bearerAuth: []
parameters:
- name: id
in: path
required: true
description: 支付ID
schema:
type: integer
responses:
'200':
description: 成功返回支付信息
content:
application/json:
schema:
$ref: '#/components/schemas/SuccessResponse'
'401':
description: 未授权
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
'403':
description: 权限不足
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
'404':
description: 支付记录不存在
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
'500':
description: 服务器内部错误
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
/api/payments/callback:
post:
summary: 支付回调
description: 处理第三方支付回调
requestBody:
required: true
content:
application/json:
schema:
type: object
properties:
paymentNo:
type: string
description: 支付单号
status:
type: string
description: 支付状态
thirdPartyId:
type: string
description: 第三方支付ID
responses:
'200':
description: 支付状态更新成功
content:
application/json:
schema:
$ref: '#/components/schemas/SuccessResponse'
'404':
description: 支付记录不存在
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
'500':
description: 服务器内部错误
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'

76
backend/src/main.js Normal file
View File

@@ -0,0 +1,76 @@
const express = require('express');
const cors = require('cors');
const helmet = require('helmet');
const morgan = require('morgan');
const swaggerUi = require('swagger-ui-express');
const YAML = require('yamljs');
// 数据库连接
const sequelize = require('./config/database');
// 路由
const authRoutes = require('./routes/auth');
const userRoutes = require('./routes/users');
const orderRoutes = require('./routes/orders');
const paymentRoutes = require('./routes/payments');
// 创建Express应用
const app = express();
// 中间件
app.use(helmet()); // 安全防护
app.use(cors()); // 跨域支持
app.use(morgan('combined')); // HTTP请求日志
app.use(express.json()); // JSON解析
app.use(express.urlencoded({ extended: true })); // URL编码解析
// 自定义日志中间件
const logger = require('./middleware/logger');
app.use(logger);
// 健康检查路由
const healthCheckRoutes = require('./middleware/healthCheck');
app.use('/', healthCheckRoutes);
// Swagger UI
const swaggerDocument = YAML.load('./src/docs/api.yaml');
app.use('/api-docs', swaggerUi.serve, swaggerUi.setup(swaggerDocument));
// API路由
app.use('/api/auth', authRoutes);
app.use('/api/users', userRoutes);
app.use('/api/orders', orderRoutes);
app.use('/api/payments', paymentRoutes);
// 基本路由
app.get('/', (req, res) => {
res.json({
message: '活牛采购智能数字化系统后端服务',
version: '1.0.0'
});
});
// 错误处理中间件
const errorHandler = require('./middleware/errorHandler');
app.use(errorHandler);
// 同步数据库模型
const syncDatabase = async () => {
try {
await sequelize.sync({ alter: true });
console.log('数据库模型同步成功');
} catch (error) {
console.error('数据库模型同步失败:', error);
}
};
// 启动服务器
const { serverConfig } = require('./config/config');
const PORT = serverConfig.port;
app.listen(PORT, async () => {
console.log(`服务器运行在端口 ${PORT}`);
// 同步数据库
await syncDatabase();
});
module.exports = app;

View File

@@ -0,0 +1,54 @@
const jwt = require('jsonwebtoken');
const { jwtConfig } = require('../config/config');
// 认证中间件
const authenticate = (req, res, next) => {
try {
// 从请求头获取token
const authHeader = req.headers.authorization;
if (!authHeader || !authHeader.startsWith('Bearer ')) {
return res.status(401).json({
code: 401,
message: '未提供认证token'
});
}
const token = authHeader.split(' ')[1];
// 验证token
const decoded = jwt.verify(token, jwtConfig.secret);
req.user = decoded;
next();
} catch (error) {
return res.status(401).json({
code: 401,
message: '无效的认证token'
});
}
};
// 角色权限检查中间件
const checkRole = (roles) => {
return (req, res, next) => {
if (!req.user) {
return res.status(401).json({
code: 401,
message: '未认证'
});
}
if (!roles.includes(req.user.userType)) {
return res.status(403).json({
code: 403,
message: '权限不足'
});
}
next();
};
};
module.exports = {
authenticate,
checkRole
};

View File

@@ -0,0 +1,31 @@
const { errorResponse } = require('../utils/response');
// 错误处理中间件
const errorHandler = (err, req, res, next) => {
// 记录错误日志
console.error(err.stack);
// 默认错误状态码和消息
let statusCode = 500;
let message = '服务器内部错误';
// 根据错误类型设置状态码和消息
if (err.name === 'ValidationError') {
statusCode = 400;
message = '请求参数验证失败';
} else if (err.name === 'UnauthorizedError') {
statusCode = 401;
message = '未授权访问';
} else if (err.name === 'ForbiddenError') {
statusCode = 403;
message = '访问被拒绝';
} else if (err.name === 'NotFoundError') {
statusCode = 404;
message = '资源未找到';
}
// 返回错误响应
res.status(statusCode).json(errorResponse(message, statusCode));
};
module.exports = errorHandler;

View File

@@ -0,0 +1,13 @@
const express = require('express');
const router = express.Router();
// 健康检查端点
router.get('/health', (req, res) => {
res.status(200).json({
status: 'OK',
timestamp: new Date().toISOString(),
uptime: process.uptime()
});
});
module.exports = router;

View File

@@ -0,0 +1,36 @@
const fs = require('fs');
const path = require('path');
const { logConfig } = require('../config/config');
// 创建日志目录
const logDir = path.join(__dirname, '../../logs');
if (!fs.existsSync(logDir)) {
fs.mkdirSync(logDir, { recursive: true });
}
// 创建日志文件流
const logStream = fs.createWriteStream(path.join(logDir, 'app.log'), { flags: 'a' });
// 日志中间件
const logger = (req, res, next) => {
// 只在开发环境记录详细日志
if (process.env.NODE_ENV === 'development' || logConfig.level === 'debug') {
const logEntry = {
timestamp: new Date().toISOString(),
method: req.method,
url: req.url,
ip: req.ip,
userAgent: req.get('User-Agent')
};
// 写入日志文件
logStream.write(JSON.stringify(logEntry) + '\n');
// 控制台输出
console.log(`${logEntry.timestamp} - ${logEntry.method} ${logEntry.url} - ${logEntry.ip}`);
}
next();
};
module.exports = logger;

View File

@@ -0,0 +1,83 @@
const { DataTypes } = require('sequelize');
const sequelize = require('../config/database');
// 订单模型
const Order = sequelize.define('Order', {
id: {
type: DataTypes.BIGINT,
primaryKey: true,
autoIncrement: true
},
order_no: {
type: DataTypes.STRING(50),
allowNull: false,
unique: true
},
buyer_id: {
type: DataTypes.BIGINT,
allowNull: false
},
trader_id: {
type: DataTypes.BIGINT,
allowNull: true
},
supplier_id: {
type: DataTypes.BIGINT,
allowNull: false
},
driver_id: {
type: DataTypes.BIGINT,
allowNull: true
},
breed_type: {
type: DataTypes.STRING(20),
allowNull: false
},
min_weight: {
type: DataTypes.DECIMAL(10,2),
allowNull: false
},
max_weight: {
type: DataTypes.DECIMAL(10,2),
allowNull: false
},
total_count: {
type: DataTypes.INTEGER,
allowNull: false
},
total_weight: {
type: DataTypes.DECIMAL(10,2),
allowNull: true
},
unit_price: {
type: DataTypes.DECIMAL(10,2),
allowNull: false
},
total_amount: {
type: DataTypes.DECIMAL(15,2),
allowNull: false
},
status: {
type: DataTypes.ENUM('pending', 'confirmed', 'loading', 'shipping', 'delivered', 'completed', 'cancelled'),
defaultValue: 'pending'
},
delivery_address: {
type: DataTypes.STRING(255),
allowNull: false
},
delivery_date: {
type: DataTypes.DATEONLY,
allowNull: false
},
special_requirements: {
type: DataTypes.TEXT,
allowNull: true
}
}, {
tableName: 'orders',
timestamps: true,
createdAt: 'created_at',
updatedAt: 'updated_at'
});
module.exports = Order;

View File

@@ -0,0 +1,59 @@
const { DataTypes } = require('sequelize');
const sequelize = require('../config/database');
// 支付模型
const Payment = sequelize.define('Payment', {
id: {
type: DataTypes.BIGINT,
primaryKey: true,
autoIncrement: true
},
order_id: {
type: DataTypes.BIGINT,
allowNull: false
},
user_id: {
type: DataTypes.BIGINT,
allowNull: false
},
amount: {
type: DataTypes.DECIMAL(15,2),
allowNull: false
},
paid_amount: {
type: DataTypes.DECIMAL(15,2),
allowNull: true
},
payment_type: {
type: DataTypes.ENUM('wechat', 'alipay', 'bank'),
allowNull: false
},
payment_method: {
type: DataTypes.ENUM('mini_program', 'app', 'web'),
allowNull: false
},
payment_no: {
type: DataTypes.STRING(50),
allowNull: false,
unique: true
},
third_party_id: {
type: DataTypes.STRING(100),
allowNull: true
},
status: {
type: DataTypes.ENUM('pending', 'paid', 'failed', 'refunded'),
defaultValue: 'pending'
},
paid_time: {
type: DataTypes.DATE,
allowNull: true
}
}, {
tableName: 'payments',
timestamps: true,
createdAt: 'created_at',
updatedAt: 'updated_at'
});
module.exports = Payment;

View File

@@ -0,0 +1,58 @@
const { DataTypes } = require('sequelize');
const sequelize = require('../config/database');
// 运输跟踪模型
const TransportTrack = sequelize.define('TransportTrack', {
id: {
type: DataTypes.BIGINT,
primaryKey: true,
autoIncrement: true
},
order_id: {
type: DataTypes.BIGINT,
allowNull: false
},
driver_id: {
type: DataTypes.BIGINT,
allowNull: false
},
latitude: {
type: DataTypes.DECIMAL(10,8),
allowNull: false
},
longitude: {
type: DataTypes.DECIMAL(11,8),
allowNull: false
},
speed: {
type: DataTypes.DECIMAL(5,2),
allowNull: true
},
direction: {
type: DataTypes.DECIMAL(5,2),
allowNull: true
},
cattle_status: {
type: DataTypes.STRING(20),
allowNull: true
},
temperature: {
type: DataTypes.DECIMAL(5,2),
allowNull: true
},
humidity: {
type: DataTypes.DECIMAL(5,2),
allowNull: true
},
video_url: {
type: DataTypes.STRING(255),
allowNull: true
}
}, {
tableName: 'transport_tracks',
timestamps: true,
createdAt: 'created_at',
updatedAt: false
});
module.exports = TransportTrack;

View File

@@ -0,0 +1,56 @@
const { DataTypes } = require('sequelize');
const sequelize = require('../config/database');
// 用户模型
const User = sequelize.define('User', {
id: {
type: DataTypes.BIGINT,
primaryKey: true,
autoIncrement: true
},
uuid: {
type: DataTypes.STRING(36),
allowNull: false,
unique: true
},
username: {
type: DataTypes.STRING(50),
allowNull: false,
unique: true
},
password_hash: {
type: DataTypes.STRING(255),
allowNull: false
},
phone: {
type: DataTypes.STRING(20),
allowNull: true
},
email: {
type: DataTypes.STRING(100),
allowNull: true
},
real_name: {
type: DataTypes.STRING(50),
allowNull: true
},
avatar_url: {
type: DataTypes.STRING(255),
allowNull: true
},
user_type: {
type: DataTypes.ENUM('client', 'supplier', 'driver', 'staff', 'admin'),
allowNull: false
},
status: {
type: DataTypes.ENUM('active', 'inactive', 'locked'),
defaultValue: 'active'
}
}, {
tableName: 'users',
timestamps: true,
createdAt: 'created_at',
updatedAt: 'updated_at'
});
module.exports = User;

View File

@@ -0,0 +1,12 @@
const express = require('express');
const router = express.Router();
const AuthController = require('../controllers/AuthController');
const { authenticate } = require('../middleware/auth');
// 小程序用户登录
router.post('/mini-program/login', AuthController.miniProgramLogin);
// 获取当前用户信息
router.get('/current', authenticate, AuthController.getCurrentUser);
module.exports = router;

View File

@@ -0,0 +1,18 @@
const express = require('express');
const router = express.Router();
const OrderController = require('../controllers/OrderController');
const { authenticate } = require('../middleware/auth');
// 创建订单
router.post('/', authenticate, OrderController.createOrder);
// 获取订单列表
router.get('/', authenticate, OrderController.getOrderList);
// 获取订单详情
router.get('/:id', authenticate, OrderController.getOrderDetail);
// 更新订单状态
router.patch('/:id/status', authenticate, OrderController.updateOrderStatus);
module.exports = router;

View File

@@ -0,0 +1,18 @@
const express = require('express');
const router = express.Router();
const PaymentController = require('../controllers/PaymentController');
const { authenticate } = require('../middleware/auth');
// 创建支付
router.post('/', authenticate, PaymentController.createPayment);
// 获取支付列表
router.get('/', authenticate, PaymentController.getPaymentList);
// 获取支付详情
router.get('/:id', authenticate, PaymentController.getPaymentDetail);
// 更新支付状态(模拟支付回调)
router.post('/callback', PaymentController.updatePaymentStatus);
module.exports = router;

View File

@@ -0,0 +1,18 @@
const express = require('express');
const router = express.Router();
const UserController = require('../controllers/UserController');
const { authenticate, checkRole } = require('../middleware/auth');
// 获取用户列表 (管理员)
router.get('/', authenticate, checkRole(['admin']), UserController.getUserList);
// 获取用户详情
router.get('/:id', authenticate, UserController.getUserDetail);
// 更新用户信息
router.put('/:id', authenticate, UserController.updateUser);
// 更新用户状态 (管理员)
router.patch('/:id/status', authenticate, checkRole(['admin']), UserController.updateUserStatus);
module.exports = router;

View File

@@ -0,0 +1,17 @@
const sequelize = require('../config/database');
// 同步数据库模型
const syncDatabase = async () => {
try {
await sequelize.sync({ alter: true });
console.log('数据库模型同步成功');
} catch (error) {
console.error('数据库模型同步失败:', error);
} finally {
// 关闭数据库连接
await sequelize.close();
}
};
// 执行同步
syncDatabase();

View File

@@ -0,0 +1,67 @@
const jwt = require('jsonwebtoken');
const bcrypt = require('bcryptjs');
const { v4: uuidv4 } = require('uuid');
const { jwtConfig } = require('../config/config');
const User = require('../models/User');
// 小程序用户登录服务
const miniProgramLogin = async (phone, code, miniProgramType) => {
// 验证验证码(实际项目中需要对接短信服务)
if (code !== '123456') { // 临时验证码,实际项目中需要验证真实验证码
throw new Error('验证码错误');
}
// 查找用户
let user = await User.findOne({ where: { phone } });
// 如果用户不存在则创建新用户
if (!user) {
user = await User.create({
uuid: uuidv4(),
username: `user_${phone}`,
phone,
user_type: miniProgramType || 'client',
password_hash: bcrypt.hashSync(phone, 10) // 临时密码,实际项目中需要更安全的处理
});
}
// 生成JWT token
const token = jwt.sign(
{
id: user.id,
uuid: user.uuid,
username: user.username,
phone: user.phone,
userType: user.user_type
},
jwtConfig.secret,
{ expiresIn: jwtConfig.expiresIn }
);
// 返回用户信息和token
const userInfo = {
id: user.id,
username: user.username,
realName: user.real_name,
avatar: user.avatar_url,
userType: user.user_type,
phone: user.phone
};
return { token, userInfo };
};
// 验证token服务
const verifyToken = async (token) => {
try {
const decoded = jwt.verify(token, jwtConfig.secret);
return decoded;
} catch (error) {
throw new Error('无效的token');
}
};
module.exports = {
miniProgramLogin,
verifyToken
};

View File

@@ -0,0 +1,104 @@
const Order = require('../models/Order');
// 创建订单服务
const createOrder = async (orderData, userId) => {
// 设置买家ID
orderData.buyer_id = userId;
// 生成订单号
const orderNo = `ORD${Date.now()}${Math.floor(Math.random() * 1000).toString().padStart(3, '0')}`;
orderData.order_no = orderNo;
// 创建订单
const order = await Order.create(orderData);
return order;
};
// 获取订单列表服务
const getOrderList = async (query, user) => {
const { page = 1, pageSize = 10, status, orderNo } = query;
// 构建查询条件
const whereConditions = {};
// 根据用户类型过滤
if (user.userType === 'client') {
whereConditions.buyer_id = user.id;
} else if (user.userType === 'trader') {
whereConditions.trader_id = user.id;
} else if (user.userType === 'supplier') {
whereConditions.supplier_id = user.id;
} else if (user.userType === 'driver') {
whereConditions.driver_id = user.id;
}
if (status) whereConditions.status = status;
if (orderNo) whereConditions.order_no = orderNo;
// 查询订单列表
const { count, rows } = await Order.findAndCountAll({
where: whereConditions,
limit: parseInt(pageSize),
offset: (parseInt(page) - 1) * parseInt(pageSize),
order: [['created_at', 'DESC']]
});
return { orders: rows, count, page: parseInt(page), pageSize: parseInt(pageSize) };
};
// 获取订单详情服务
const getOrderDetail = async (id, user) => {
const order = await Order.findByPk(id);
if (!order) {
throw new Error('订单不存在');
}
// 权限检查
if (user.userType === 'client' && order.buyer_id !== user.id) {
throw new Error('无权限访问该订单');
}
if (user.userType === 'trader' && order.trader_id !== user.id) {
throw new Error('无权限访问该订单');
}
if (user.userType === 'supplier' && order.supplier_id !== user.id) {
throw new Error('无权限访问该订单');
}
if (user.userType === 'driver' && order.driver_id !== user.id) {
throw new Error('无权限访问该订单');
}
return order;
};
// 更新订单状态服务
const updateOrderStatus = async (id, status, user) => {
const order = await Order.findByPk(id);
if (!order) {
throw new Error('订单不存在');
}
// 权限检查和状态流转验证
// 这里需要根据业务逻辑实现详细的状态流转控制
const [updatedRowsCount] = await Order.update({ status }, {
where: { id }
});
if (updatedRowsCount === 0) {
throw new Error('订单状态更新失败');
}
return true;
};
module.exports = {
createOrder,
getOrderList,
getOrderDetail,
updateOrderStatus
};

View File

@@ -0,0 +1,96 @@
const Payment = require('../models/Payment');
// 创建支付服务
const createPayment = async (paymentData, userId) => {
const { orderId, amount, paymentType, paymentMethod } = paymentData;
// 生成支付单号
const paymentNo = `PAY${Date.now()}${Math.floor(Math.random() * 1000).toString().padStart(3, '0')}`;
// 创建支付记录
const payment = await Payment.create({
order_id: orderId,
user_id: userId,
amount,
payment_type: paymentType,
payment_method: paymentMethod,
payment_no: paymentNo,
status: 'pending'
});
// 这里需要对接实际的支付接口(微信支付、支付宝等)
// 暂时返回模拟的支付参数
const paymentParams = {
paymentNo,
amount,
paymentType,
paymentMethod
};
return { payment, paymentParams };
};
// 获取支付列表服务
const getPaymentList = async (query, userId) => {
const { page = 1, pageSize = 10, status } = query;
// 构建查询条件
const whereConditions = {
user_id: userId
};
if (status) whereConditions.status = status;
// 查询支付列表
const { count, rows } = await Payment.findAndCountAll({
where: whereConditions,
limit: parseInt(pageSize),
offset: (parseInt(page) - 1) * parseInt(pageSize),
order: [['created_at', 'DESC']]
});
return { payments: rows, count, page: parseInt(page), pageSize: parseInt(pageSize) };
};
// 获取支付详情服务
const getPaymentDetail = async (id, userId) => {
const payment = await Payment.findByPk(id);
if (!payment) {
throw new Error('支付记录不存在');
}
// 权限检查
if (payment.user_id !== userId) {
throw new Error('无权限访问该支付记录');
}
return payment;
};
// 更新支付状态服务(模拟支付回调)
const updatePaymentStatus = async (paymentNo, status, thirdPartyId) => {
const [updatedRowsCount] = await Payment.update(
{
status,
third_party_id: thirdPartyId,
paid_time: status === 'paid' ? new Date() : null
},
{
where: { payment_no: paymentNo }
}
);
if (updatedRowsCount === 0) {
throw new Error('支付记录不存在');
}
return true;
};
module.exports = {
createPayment,
getPaymentList,
getPaymentDetail,
updatePaymentStatus
};

View File

@@ -0,0 +1,107 @@
const User = require('../models/User');
// 获取用户列表服务
const getUserList = async (query) => {
const { page = 1, pageSize = 10, userType, status } = query;
// 构建查询条件
const whereConditions = {};
if (userType) whereConditions.user_type = userType;
if (status) whereConditions.status = status;
// 查询用户列表
const { count, rows } = await User.findAndCountAll({
where: whereConditions,
limit: parseInt(pageSize),
offset: (parseInt(page) - 1) * parseInt(pageSize),
order: [['created_at', 'DESC']]
});
// 格式化用户数据
const users = rows.map(user => ({
id: user.id,
uuid: user.uuid,
username: user.username,
realName: user.real_name,
phone: user.phone,
email: user.email,
userType: user.user_type,
status: user.status,
avatar: user.avatar_url,
createdAt: user.created_at
}));
return { users, count, page: parseInt(page), pageSize: parseInt(pageSize) };
};
// 获取用户详情服务
const getUserDetail = async (id) => {
const user = await User.findByPk(id);
if (!user) {
throw new Error('用户不存在');
}
const userInfo = {
id: user.id,
uuid: user.uuid,
username: user.username,
realName: user.real_name,
phone: user.phone,
email: user.email,
userType: user.user_type,
status: user.status,
avatar: user.avatar_url,
idCardFront: user.id_card_front_url,
idCardBack: user.id_card_back_url,
licenseFront: user.license_front_url,
licenseBack: user.license_back_url,
businessLicense: user.business_license_url,
createdAt: user.created_at,
updatedAt: user.updated_at
};
return userInfo;
};
// 更新用户信息服务
const updateUser = async (id, updateData) => {
// 过滤不允许更新的字段
const allowedFields = ['real_name', 'email', 'avatar_url'];
const filteredData = {};
Object.keys(updateData).forEach(key => {
if (allowedFields.includes(key)) {
filteredData[key] = updateData[key];
}
});
const [updatedRowsCount] = await User.update(filteredData, {
where: { id }
});
if (updatedRowsCount === 0) {
throw new Error('用户不存在');
}
return true;
};
// 更新用户状态服务
const updateUserStatus = async (id, status) => {
const [updatedRowsCount] = await User.update({ status }, {
where: { id }
});
if (updatedRowsCount === 0) {
throw new Error('用户不存在');
}
return true;
};
module.exports = {
getUserList,
getUserDetail,
updateUser,
updateUserStatus
};

View File

@@ -0,0 +1,43 @@
// 统一响应格式
// 成功响应
const successResponse = (data, message = '成功', code = 200) => {
return {
code,
message,
data,
timestamp: Date.now()
};
};
// 错误响应
const errorResponse = (message = '请求失败', code = 500, data = null) => {
return {
code,
message,
data,
timestamp: Date.now()
};
};
// 分页响应
const paginatedResponse = (items, total, page, limit) => {
return {
code: 200,
message: '成功',
data: {
items,
total,
page,
limit,
totalPages: Math.ceil(total / limit)
},
timestamp: Date.now()
};
};
module.exports = {
successResponse,
errorResponse,
paginatedResponse
};