package handler import ( "net/http" "silk-server-go/internal/middleware" "silk-server-go/internal/model" "github.com/gin-gonic/gin" "gorm.io/gorm" ) // RegisterConsumableRoutes 注册耗材路由 func RegisterConsumableRoutes(rg *gin.RouterGroup, db *gorm.DB) { read := middleware.RequirePermission(db, "consumable:read") write := middleware.RequirePermission(db, "consumable:write") rg.GET("/consumables", read, listConsumables(db)) rg.POST("/consumables", write, createConsumable(db)) rg.PATCH("/consumables/:id", write, updateConsumable(db)) rg.DELETE("/consumables/:id", write, deleteConsumable(db)) rg.GET("/consumables/alerts", read, consumableAlerts(db)) rg.GET("/consumables/purchase-suggestions", read, purchaseSuggestions(db)) } // listConsumables 耗材列表(category 过滤) func listConsumables(db *gorm.DB) gin.HandlerFunc { return func(c *gin.Context) { q := db.Model(&model.Consumable{}) if cat := c.Query("category"); cat != "" { q = q.Where("category = ?", cat) } var list []model.Consumable q.Order("name ASC").Find(&list) c.JSON(http.StatusOK, list) } } func createConsumable(db *gorm.DB) gin.HandlerFunc { return func(c *gin.Context) { var item model.Consumable if err := c.ShouldBindJSON(&item); err != nil { c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()}) return } item.ID = "" if item.Name == "" { c.JSON(http.StatusBadRequest, gin.H{"error": "耗材名称不能为空"}) return } if item.Category == "" { item.Category = "other" } if err := db.Create(&item).Error; err != nil { c.JSON(http.StatusBadRequest, gin.H{"error": "创建失败"}) return } c.JSON(http.StatusCreated, item) } } func updateConsumable(db *gorm.DB) gin.HandlerFunc { return func(c *gin.Context) { id := c.Param("id") var item model.Consumable if db.Where("id = ?", id).First(&item).Error != nil { c.JSON(http.StatusNotFound, gin.H{"error": "consumable not found"}) return } updates, err := bindUpdates(c) if err != nil { c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()}) return } if len(updates) > 0 { db.Model(&model.Consumable{}).Where("id = ?", id).Updates(updates) } db.Where("id = ?", id).First(&item) c.JSON(http.StatusOK, item) } } func deleteConsumable(db *gorm.DB) gin.HandlerFunc { return func(c *gin.Context) { id := c.Param("id") var item model.Consumable if db.Where("id = ?", id).First(&item).Error != nil { c.JSON(http.StatusNotFound, gin.H{"error": "consumable not found"}) return } db.Where("id = ?", id).Delete(&model.Consumable{}) c.JSON(http.StatusOK, gin.H{"id": id}) } } // consumableAlerts 低库存 + 临期/过期预警(30 天窗口) func consumableAlerts(db *gorm.DB) gin.HandlerFunc { return func(c *gin.Context) { var list []model.Consumable db.Find(&list) result := make([]gin.H, 0) for _, item := range list { alertType := "" if item.LowStockAlert() { alertType = "low_stock" } if item.ExpiringAlert(30) { alertType = "expiring" } if alertType != "" { result = append(result, gin.H{ "id": item.ID, "name": item.Name, "category": item.Category, "quantity": item.Quantity, "unit": item.Unit, "minQuantity": item.MinQuantity, "expiryDate": item.ExpiryDate, "alertType": alertType, }) } } c.JSON(http.StatusOK, result) } } // purchaseSuggestions 低于安全阈值的采购建议 func purchaseSuggestions(db *gorm.DB) gin.HandlerFunc { return func(c *gin.Context) { var list []model.Consumable db.Find(&list) result := make([]gin.H, 0) for _, item := range list { if s := item.PurchaseSuggestion(); s > 0 { result = append(result, gin.H{ "id": item.ID, "name": item.Name, "category": item.Category, "quantity": item.Quantity, "unit": item.Unit, "minQuantity": item.MinQuantity, "suggest": s, }) } } c.JSON(http.StatusOK, result) } }