更新技术实施方案和PRD文档版本历史

This commit is contained in:
2025-09-12 13:10:44 +08:00
parent 320f41f25d
commit bbc7abd69c
13 changed files with 5565 additions and 406 deletions

View File

@@ -2,59 +2,8 @@ const express = require('express')
const Joi = require('joi')
const router = express.Router()
// 模拟订单数据
let orders = [
{
id: 1,
orderNo: 'ORD20240101001',
buyerId: 2,
buyerName: '山东养殖场',
supplierId: 3,
supplierName: '河北供应商',
traderId: 1,
traderName: '北京贸易公司',
cattleBreed: '西门塔尔',
cattleCount: 50,
expectedWeight: 25000,
actualWeight: 24800,
unitPrice: 28.5,
totalAmount: 712500,
paidAmount: 200000,
remainingAmount: 512500,
status: 'shipping',
deliveryAddress: '山东省济南市某养殖场',
expectedDeliveryDate: '2024-01-15',
actualDeliveryDate: null,
notes: '优质西门塔尔牛',
createdAt: '2024-01-10T00:00:00Z',
updatedAt: '2024-01-12T00:00:00Z'
},
{
id: 2,
orderNo: 'ORD20240101002',
buyerId: 2,
buyerName: '山东养殖场',
supplierId: 4,
supplierName: '内蒙古牧场',
traderId: 1,
traderName: '北京贸易公司',
cattleBreed: '安格斯',
cattleCount: 30,
expectedWeight: 18000,
actualWeight: 18200,
unitPrice: 30.0,
totalAmount: 540000,
paidAmount: 540000,
remainingAmount: 0,
status: 'completed',
deliveryAddress: '山东省济南市某养殖场',
expectedDeliveryDate: '2024-01-08',
actualDeliveryDate: '2024-01-08',
notes: '',
createdAt: '2024-01-05T00:00:00Z',
updatedAt: '2024-01-08T00:00:00Z'
}
]
// 引入数据库模型
const { Order } = require('../models')
// 订单状态枚举
const ORDER_STATUS = {
@@ -72,8 +21,11 @@ const ORDER_STATUS = {
// 验证模式
const createOrderSchema = Joi.object({
buyerId: Joi.number().integer().positive().required(),
buyerName: Joi.string().min(1).max(100).required(),
supplierId: Joi.number().integer().positive().required(),
traderId: Joi.number().integer().positive(),
supplierName: Joi.string().min(1).max(100).required(),
traderId: Joi.number().integer().positive().allow(null),
traderName: Joi.string().min(1).max(100).allow(null, ''),
cattleBreed: Joi.string().min(1).max(50).required(),
cattleCount: Joi.number().integer().positive().required(),
expectedWeight: Joi.number().positive().required(),
@@ -84,20 +36,39 @@ const createOrderSchema = Joi.object({
})
const updateOrderSchema = Joi.object({
buyerId: Joi.number().integer().positive(),
buyerName: Joi.string().min(1).max(100),
supplierId: Joi.number().integer().positive(),
supplierName: Joi.string().min(1).max(100),
traderId: Joi.number().integer().positive().allow(null),
traderName: Joi.string().min(1).max(100).allow(null, ''),
cattleBreed: Joi.string().min(1).max(50),
cattleCount: Joi.number().integer().positive(),
expectedWeight: Joi.number().positive(),
actualWeight: Joi.number().positive(),
actualWeight: Joi.number().positive().allow(null),
unitPrice: Joi.number().positive(),
totalAmount: Joi.number().positive(),
paidAmount: Joi.number().positive(),
remainingAmount: Joi.number().positive(),
deliveryAddress: Joi.string().min(1).max(200),
expectedDeliveryDate: Joi.date().iso(),
actualDeliveryDate: Joi.date().iso(),
actualDeliveryDate: Joi.date().iso().allow(null),
notes: Joi.string().max(500).allow(''),
status: Joi.string().valid(...Object.values(ORDER_STATUS))
})
// 生成订单编号
const generateOrderNo = () => {
const date = new Date()
const year = date.getFullYear()
const month = String(date.getMonth() + 1).padStart(2, '0')
const day = String(date.getDate()).padStart(2, '0')
const random = Math.floor(100 + Math.random() * 900) // 生成3位随机数
return `ORD${year}${month}${day}${random}`
}
// 获取订单列表
router.get('/', (req, res) => {
router.get('/', async (req, res) => {
try {
const {
page = 1,
@@ -110,64 +81,63 @@ router.get('/', (req, res) => {
endDate
} = req.query
let filteredOrders = [...orders]
const where = {}
// 订单号搜索
if (orderNo) {
filteredOrders = filteredOrders.filter(order =>
order.orderNo.includes(orderNo)
)
where.orderNo = { [require('sequelize').Op.like]: `%${orderNo}%` }
}
// 买方筛选
if (buyerId) {
filteredOrders = filteredOrders.filter(order =>
order.buyerId === parseInt(buyerId)
)
where.buyerId = parseInt(buyerId)
}
// 供应商筛选
if (supplierId) {
filteredOrders = filteredOrders.filter(order =>
order.supplierId === parseInt(supplierId)
)
where.supplierId = parseInt(supplierId)
}
// 状态筛选
if (status) {
filteredOrders = filteredOrders.filter(order => order.status === status)
where.status = status
}
// 日期范围筛选
if (startDate) {
filteredOrders = filteredOrders.filter(order =>
new Date(order.createdAt) >= new Date(startDate)
)
where.created_at = {
...where.created_at,
[require('sequelize').Op.gte]: new Date(startDate)
}
}
if (endDate) {
filteredOrders = filteredOrders.filter(order =>
new Date(order.createdAt) <= new Date(endDate)
)
where.created_at = {
...where.created_at,
[require('sequelize').Op.lte]: new Date(endDate)
}
}
// 分页
const total = filteredOrders.length
const startIndex = (page - 1) * pageSize
const endIndex = startIndex + parseInt(pageSize)
const paginatedOrders = filteredOrders.slice(startIndex, endIndex)
// 查询数据库
const { count, rows } = await Order.findAndCountAll({
where,
order: [['created_at', 'DESC']],
limit: parseInt(pageSize),
offset: (parseInt(page) - 1) * parseInt(pageSize)
})
res.json({
success: true,
data: {
items: paginatedOrders,
total: total,
items: rows,
total: count,
page: parseInt(page),
pageSize: parseInt(pageSize),
totalPages: Math.ceil(total / pageSize)
totalPages: Math.ceil(count / pageSize)
}
})
} catch (error) {
console.error('获取订单列表失败:', error)
res.status(500).json({
success: false,
message: '获取订单列表失败'
@@ -176,10 +146,10 @@ router.get('/', (req, res) => {
})
// 获取订单详情
router.get('/:id', (req, res) => {
router.get('/:id', async (req, res) => {
try {
const { id } = req.params
const order = orders.find(o => o.id === parseInt(id))
const order = await Order.findByPk(id)
if (!order) {
return res.status(404).json({
@@ -193,6 +163,7 @@ router.get('/:id', (req, res) => {
data: order
})
} catch (error) {
console.error('获取订单详情失败:', error)
res.status(500).json({
success: false,
message: '获取订单详情失败'
@@ -200,8 +171,8 @@ router.get('/:id', (req, res) => {
}
})
// 创建订单
router.post('/', (req, res) => {
// 创建订单
router.post('/', async (req, res) => {
try {
// 参数验证
const { error, value } = createOrderSchema.validate(req.body)
@@ -212,61 +183,28 @@ router.post('/', (req, res) => {
details: error.details[0].message
})
}
// 计算总金额和剩余金额
const totalAmount = value.expectedWeight * value.unitPrice
const remainingAmount = totalAmount
const {
buyerId,
supplierId,
traderId,
cattleBreed,
cattleCount,
expectedWeight,
unitPrice,
deliveryAddress,
expectedDeliveryDate,
notes
} = value
// 生成订单号
const orderNo = `ORD${new Date().toISOString().slice(0, 10).replace(/-/g, '')}${String(orders.length + 1).padStart(3, '0')}`
// 计算总金额
const totalAmount = expectedWeight * unitPrice
// 创建新订单
const newOrder = {
id: Math.max(...orders.map(o => o.id)) + 1,
orderNo,
buyerId,
buyerName: '买方名称', // 实际项目中需要从数据库获取
supplierId,
supplierName: '供应商名称', // 实际项目中需要从数据库获取
traderId: traderId || null,
traderName: traderId ? '贸易商名称' : null,
cattleBreed,
cattleCount,
expectedWeight,
actualWeight: null,
unitPrice,
// 创建订单
const order = await Order.create({
...value,
orderNo: generateOrderNo(),
totalAmount,
remainingAmount,
paidAmount: 0,
remainingAmount: totalAmount,
status: ORDER_STATUS.PENDING,
deliveryAddress,
expectedDeliveryDate,
actualDeliveryDate: null,
notes: notes || '',
createdAt: new Date().toISOString(),
updatedAt: new Date().toISOString()
}
orders.push(newOrder)
status: ORDER_STATUS.PENDING
})
res.status(201).json({
success: true,
message: '订单创建成功',
data: newOrder
data: order
})
} catch (error) {
console.error('创建订单失败:', error)
res.status(500).json({
success: false,
message: '创建订单失败'
@@ -275,17 +213,9 @@ router.post('/', (req, res) => {
})
// 更新订单
router.put('/:id', (req, res) => {
router.put('/:id', async (req, res) => {
try {
const { id } = req.params
const orderIndex = orders.findIndex(o => o.id === parseInt(id))
if (orderIndex === -1) {
return res.status(404).json({
success: false,
message: '订单不存在'
})
}
// 参数验证
const { error, value } = updateOrderSchema.validate(req.body)
@@ -296,26 +226,42 @@ router.put('/:id', (req, res) => {
details: error.details[0].message
})
}
// 更新订单信息
orders[orderIndex] = {
...orders[orderIndex],
...value,
updatedAt: new Date().toISOString()
// 查找订单
const order = await Order.findByPk(id)
if (!order) {
return res.status(404).json({
success: false,
message: '订单不存在'
})
}
// 如果更新了实际重量,重新计算总金额
if (value.actualWeight && orders[orderIndex].unitPrice) {
orders[orderIndex].totalAmount = value.actualWeight * orders[orderIndex].unitPrice
orders[orderIndex].remainingAmount = orders[orderIndex].totalAmount - orders[orderIndex].paidAmount
// 如果更新了单价和重量,重新计算总金额
if (value.unitPrice && value.expectedWeight) {
value.totalAmount = value.expectedWeight * value.unitPrice
} else if (value.unitPrice) {
value.totalAmount = order.expectedWeight * value.unitPrice
} else if (value.expectedWeight) {
value.totalAmount = value.expectedWeight * order.unitPrice
}
// 如果更新了总金额或已支付金额,重新计算剩余金额
if (value.totalAmount || value.paidAmount) {
const totalAmount = value.totalAmount || order.totalAmount
const paidAmount = value.paidAmount || order.paidAmount
value.remainingAmount = totalAmount - paidAmount
}
// 更新订单
await order.update(value)
res.json({
success: true,
message: '订单更新成功',
data: orders[orderIndex]
data: order
})
} catch (error) {
console.error('更新订单失败:', error)
res.status(500).json({
success: false,
message: '更新订单失败'
@@ -324,25 +270,28 @@ router.put('/:id', (req, res) => {
})
// 删除订单
router.delete('/:id', (req, res) => {
router.delete('/:id', async (req, res) => {
try {
const { id } = req.params
const orderIndex = orders.findIndex(o => o.id === parseInt(id))
if (orderIndex === -1) {
// 查找订单
const order = await Order.findByPk(id)
if (!order) {
return res.status(404).json({
success: false,
message: '订单不存在'
})
}
orders.splice(orderIndex, 1)
// 删除订单
await order.destroy()
res.json({
success: true,
message: '订单删除成功'
})
} catch (error) {
console.error('删除订单失败:', error)
res.status(500).json({
success: false,
message: '删除订单失败'
@@ -350,188 +299,115 @@ router.delete('/:id', (req, res) => {
}
})
// 确认订单
router.put('/:id/confirm', (req, res) => {
// 更新订单状态
router.patch('/:id/status', async (req, res) => {
try {
const { id } = req.params
const orderIndex = orders.findIndex(o => o.id === parseInt(id))
const { status } = req.body
if (orderIndex === -1) {
return res.status(404).json({
success: false,
message: '订单不存在'
})
}
if (orders[orderIndex].status !== ORDER_STATUS.PENDING) {
// 验证状态
if (!status || !Object.values(ORDER_STATUS).includes(status)) {
return res.status(400).json({
success: false,
message: '只有待确认的订单才能确认'
message: '无效的订单状态'
})
}
orders[orderIndex].status = ORDER_STATUS.CONFIRMED
orders[orderIndex].updatedAt = new Date().toISOString()
res.json({
success: true,
message: '订单确认成功',
data: orders[orderIndex]
})
} catch (error) {
res.status(500).json({
success: false,
message: '确认订单失败'
})
}
})
// 取消订单
router.put('/:id/cancel', (req, res) => {
try {
const { id } = req.params
const { reason } = req.body
const orderIndex = orders.findIndex(o => o.id === parseInt(id))
if (orderIndex === -1) {
// 查找订单
const order = await Order.findByPk(id)
if (!order) {
return res.status(404).json({
success: false,
message: '订单不存在'
})
}
orders[orderIndex].status = ORDER_STATUS.CANCELLED
orders[orderIndex].notes = reason ? `取消原因: ${reason}` : '订单已取消'
orders[orderIndex].updatedAt = new Date().toISOString()
// 特殊状态处理
if (status === ORDER_STATUS.COMPLETED && !order.actualDeliveryDate) {
order.actualDeliveryDate = new Date()
}
// 更新状态
order.status = status
await order.save()
res.json({
success: true,
message: '订单取消成功',
data: orders[orderIndex]
message: '订单状态更新成功',
data: order
})
} catch (error) {
console.error('更新订单状态失败:', error)
res.status(500).json({
success: false,
message: '取消订单失败'
message: '更新订单状态失败'
})
}
})
// 订单验收
router.put('/:id/accept', (req, res) => {
// 订单支付
router.post('/:id/pay', async (req, res) => {
try {
const { id } = req.params
const { actualWeight, notes } = req.body
const orderIndex = orders.findIndex(o => o.id === parseInt(id))
const { amount } = req.body
if (orderIndex === -1) {
return res.status(404).json({
success: false,
message: '订单不存在'
})
}
if (!actualWeight || actualWeight <= 0) {
// 验证金额
if (!amount || amount <= 0) {
return res.status(400).json({
success: false,
message: '请提供有效的实际重量'
message: '支付金额必须大于0'
})
}
orders[orderIndex].status = ORDER_STATUS.ACCEPTED
orders[orderIndex].actualWeight = actualWeight
orders[orderIndex].totalAmount = actualWeight * orders[orderIndex].unitPrice
orders[orderIndex].remainingAmount = orders[orderIndex].totalAmount - orders[orderIndex].paidAmount
orders[orderIndex].actualDeliveryDate = new Date().toISOString()
if (notes) {
orders[orderIndex].notes = notes
}
orders[orderIndex].updatedAt = new Date().toISOString()
res.json({
success: true,
message: '订单验收成功',
data: orders[orderIndex]
})
} catch (error) {
res.status(500).json({
success: false,
message: '订单验收失败'
})
}
})
// 完成订单
router.put('/:id/complete', (req, res) => {
try {
const { id } = req.params
const orderIndex = orders.findIndex(o => o.id === parseInt(id))
if (orderIndex === -1) {
// 查找订单
const order = await Order.findByPk(id)
if (!order) {
return res.status(404).json({
success: false,
message: '订单不存在'
})
}
orders[orderIndex].status = ORDER_STATUS.COMPLETED
orders[orderIndex].paidAmount = orders[orderIndex].totalAmount
orders[orderIndex].remainingAmount = 0
orders[orderIndex].updatedAt = new Date().toISOString()
res.json({
success: true,
message: '订单完成成功',
data: orders[orderIndex]
})
} catch (error) {
res.status(500).json({
success: false,
message: '完成订单失败'
})
}
})
// 获取订单统计数据
router.get('/statistics', (req, res) => {
try {
const { startDate, endDate } = req.query
let filteredOrders = [...orders]
if (startDate) {
filteredOrders = filteredOrders.filter(order =>
new Date(order.createdAt) >= new Date(startDate)
)
// 检查订单状态
if (order.status === ORDER_STATUS.CANCELLED || order.status === ORDER_STATUS.REFUNDED) {
return res.status(400).json({
success: false,
message: '订单已取消或已退款,无法支付'
})
}
if (endDate) {
filteredOrders = filteredOrders.filter(order =>
new Date(order.createdAt) <= new Date(endDate)
)
// 检查支付金额是否超过剩余金额
if (amount > order.remainingAmount) {
return res.status(400).json({
success: false,
message: '支付金额不能超过剩余金额'
})
}
// 更新支付信息
order.paidAmount += amount
order.remainingAmount -= amount
const statistics = {
totalOrders: filteredOrders.length,
completedOrders: filteredOrders.filter(o => o.status === ORDER_STATUS.COMPLETED).length,
pendingOrders: filteredOrders.filter(o => o.status === ORDER_STATUS.PENDING).length,
cancelledOrders: filteredOrders.filter(o => o.status === ORDER_STATUS.CANCELLED).length,
totalAmount: filteredOrders.reduce((sum, order) => sum + order.totalAmount, 0),
totalCattle: filteredOrders.reduce((sum, order) => sum + order.cattleCount, 0),
statusDistribution: Object.values(ORDER_STATUS).reduce((acc, status) => {
acc[status] = filteredOrders.filter(o => o.status === status).length
return acc
}, {})
// 如果已全额支付,更新订单状态
if (order.remainingAmount === 0) {
order.status = ORDER_STATUS.COMPLETED
if (!order.actualDeliveryDate) {
order.actualDeliveryDate = new Date()
}
}
await order.save()
res.json({
success: true,
data: statistics
message: '支付成功',
data: order
})
} catch (error) {
console.error('订单支付失败:', error)
res.status(500).json({
success: false,
message: '获取订单统计失败'
message: '订单支付失败'
})
}
})