diff --git a/backend/internal/api/handlers/order.go b/backend/internal/api/handlers/order.go index ace74ff..d157c69 100644 --- a/backend/internal/api/handlers/order.go +++ b/backend/internal/api/handlers/order.go @@ -278,11 +278,13 @@ func (h *OrderHandler) Create(c *gin.Context) { } var inventory models.Inventory - if err := utils.DB.Where("product_id = ?", cart.ProductID).First(&inventory).Error; err == nil { - if inventory.Quantity < cart.Quantity { - c.JSON(http.StatusBadRequest, gin.H{"error": "Insufficient stock for " + cart.Product.Name}) - return - } + if err := utils.DB.Where("product_id = ?", cart.ProductID).First(&inventory).Error; err != nil { + c.JSON(http.StatusBadRequest, gin.H{"error": "No inventory record for " + cart.Product.Name}) + return + } + if inventory.Quantity < cart.Quantity { + c.JSON(http.StatusBadRequest, gin.H{"error": "Insufficient stock for " + cart.Product.Name + ". Available: " + strconv.Itoa(inventory.Quantity)}) + return } subtotal += cart.Product.Price * float64(cart.Quantity) @@ -723,3 +725,52 @@ func (h *OrderHandler) ConfirmReceipt(c *gin.Context) { utils.DB.Model(&order).Update("status", models.OrderStatusCompleted) c.JSON(http.StatusOK, gin.H{"message": "Order confirmed successfully"}) } + +func (h *OrderHandler) AdminUpdateStatus(c *gin.Context) { + id, _ := strconv.Atoi(c.Param("id")) + + var order models.Order + if err := utils.DB.First(&order, id).Error; err != nil { + c.JSON(http.StatusNotFound, gin.H{"error": "Order not found"}) + return + } + + var req struct { + Status string `json:"status" binding:"required"` + TrackingNumber string `json:"tracking_number"` + } + if err := c.ShouldBindJSON(&req); err != nil { + c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()}) + return + } + + validStatuses := []string{ + models.OrderStatusPendingPayment, + models.OrderStatusPendingConfirm, + models.OrderStatusPendingShip, + models.OrderStatusShipped, + models.OrderStatusCompleted, + models.OrderStatusRefunding, + models.OrderStatusRefunded, + models.OrderStatusCancelled, + } + valid := false + for _, s := range validStatuses { + if s == req.Status { + valid = true + break + } + } + if !valid { + c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid status"}) + return + } + + updates := map[string]interface{}{"status": req.Status} + if req.TrackingNumber != "" { + updates["tracking_number"] = req.TrackingNumber + } + + utils.DB.Model(&order).Updates(updates) + c.JSON(http.StatusOK, gin.H{"message": "Order status updated successfully"}) +} diff --git a/backend/internal/api/routes/routes.go b/backend/internal/api/routes/routes.go index aa09a0a..9c25660 100644 --- a/backend/internal/api/routes/routes.go +++ b/backend/internal/api/routes/routes.go @@ -188,9 +188,10 @@ func SetupRoutes(r *gin.Engine) { adminOrders := admin.Group("/orders") { adminOrders.GET("", orderHandler.AdminList) - adminOrders.GET("/:id", orderHandler.AdminGetByID) + adminOrders.GET("/:id", orderHandler.AdminGetByID) adminOrders.GET("/export", orderHandler.Export) adminOrders.PUT("/:id/refund", orderHandler.ProcessRefund) + adminOrders.PUT("/:id/status", orderHandler.AdminUpdateStatus) } adminLotteries := admin.Group("/lotteries") diff --git a/frontend/src/api/index.ts b/frontend/src/api/index.ts index baaebdf..73d8131 100644 --- a/frontend/src/api/index.ts +++ b/frontend/src/api/index.ts @@ -152,6 +152,7 @@ export const adminApi = { getOrderById: (id: number) => api.get(`/admin/orders/${id}`), exportOrders: () => api.get('/admin/orders/export'), processRefund: (id: number, data: any) => api.put(`/admin/orders/${id}/refund`, data), + updateOrderStatus: (id: number, data: any) => api.put(`/admin/orders/${id}/status`, data), getSuppliers: () => api.get('/admin/suppliers'), createSupplier: (data: any) => api.post('/admin/suppliers', data), diff --git a/frontend/src/views/admin/Orders.vue b/frontend/src/views/admin/Orders.vue index 6794a09..a7267ad 100644 --- a/frontend/src/views/admin/Orders.vue +++ b/frontend/src/views/admin/Orders.vue @@ -48,13 +48,33 @@
状态: - {{ statusText(currentOrder.status) }} + + + + + + + + + + + + +
+
+ 快递单号: + + +
创建时间: {{ formatDate(currentOrder.created_at) }}
+
+ 保存修改 +
@@ -170,6 +190,8 @@ const paginatedOrders = computed(() => { const detailVisible = ref(false) const currentOrder = ref(null) +const editStatus = ref('') +const editTrackingNumber = ref('') const statusMap: Record = { pending_payment: '待支付', pending_confirm: '待确认', pending_ship: '待发货', @@ -201,12 +223,30 @@ async function viewDetail(row: any) { try { const res: any = await adminApi.getOrderById(row.id) currentOrder.value = res.data + editStatus.value = res.data.status + editTrackingNumber.value = res.data.tracking_number || '' detailVisible.value = true } catch { ElMessage.error('获取订单详情失败') } } +async function saveStatus() { + if (!currentOrder.value) return + try { + await adminApi.updateOrderStatus(currentOrder.value.id, { + status: editStatus.value, + tracking_number: editTrackingNumber.value + }) + ElMessage.success('订单状态已更新') + const res: any = await adminApi.getOrderById(currentOrder.value.id) + currentOrder.value = res.data + await fetchOrders() + } catch { + ElMessage.error('更新失败') + } +} + async function processRefund(id: number, status: string) { await adminApi.processRefund(id, { status }) ElMessage.success('已处理')