package handler import ( "encoding/json" "net/http" "time" "silk-server-go/internal/middleware" "silk-server-go/internal/model" "github.com/gin-gonic/gin" "gorm.io/gorm" ) // RegisterConsultationRoutes 注册专家会诊路由 func RegisterConsultationRoutes(rg *gin.RouterGroup, db *gorm.DB) { read := middleware.RequirePermission(db, "consultation:read") write := middleware.RequirePermission(db, "consultation:write") rg.GET("/consultations", read, listConsultations(db)) rg.GET("/consultations/:id", read, getConsultation(db)) rg.POST("/consultations", write, createConsultation(db)) rg.PATCH("/consultations/:id", write, updateConsultation(db)) rg.POST("/consultations/:id/resolve", write, resolveConsultation(db)) rg.POST("/consultations/:id/archive", write, archiveConsultation(db)) } // listConsultations 会诊单列表(status 过滤) func listConsultations(db *gorm.DB) gin.HandlerFunc { return func(c *gin.Context) { q := db.Model(&model.Consultation{}) if status := c.Query("status"); status != "" { q = q.Where("status = ?", status) } var list []model.Consultation q.Order("created_at DESC").Find(&list) fillConsultationRoomNames(db, list) c.JSON(http.StatusOK, list) } } func fillConsultationRoomNames(db *gorm.DB, list []model.Consultation) { var rooms []model.Room db.Select("id", "name").Find(&rooms) names := make(map[string]string, len(rooms)) for _, r := range rooms { names[r.ID] = r.Name } for i := range list { if list[i].RoomID != nil { if n, ok := names[*list[i].RoomID]; ok { list[i].RoomName = &n } } } } // getConsultation 会诊单详情 func getConsultation(db *gorm.DB) gin.HandlerFunc { return func(c *gin.Context) { var t model.Consultation if db.Where("id = ?", c.Param("id")).First(&t).Error != nil { c.JSON(http.StatusNotFound, gin.H{"error": "consultation not found"}) return } fillConsultationRoomNames(db, []model.Consultation{t}) c.JSON(http.StatusOK, t) } } // createConsultation 新建会诊单(可关联 LAMP 任务,自动打包病例快照) func createConsultation(db *gorm.DB) gin.HandlerFunc { return func(c *gin.Context) { var body struct { Title string `json:"title"` Summary *string `json:"summary"` RoomID *string `json:"roomId"` BatchID *string `json:"batchId"` LampTestID *string `json:"lampTestId"` } if err := c.ShouldBindJSON(&body); err != nil { c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()}) return } for _, id := range []*string{body.RoomID, body.BatchID, body.LampTestID} { if id != nil && *id != "" && !isUUID(*id) { c.JSON(http.StatusBadRequest, gin.H{"error": "关联 ID 不是合法的 UUID"}) return } } rec := model.Consultation{ RoomID: body.RoomID, BatchID: body.BatchID, LampTestID: body.LampTestID, Summary: body.Summary, Status: "pending", } if body.Title != "" { rec.Title = body.Title } else { rec.Title = "LAMP 交叉验证会诊" if body.Summary != nil { rec.Title = "专家会诊:" + *body.Summary } } // 病例快照 var lamp *model.LampTest if body.LampTestID != nil && *body.LampTestID != "" { var lt model.LampTest if db.Where("id = ?", *body.LampTestID).First(<).Error == nil { lamp = < if rec.RoomID == nil { rec.RoomID = lt.RoomID } if rec.BatchID == nil { rec.BatchID = lt.BatchID } } } snapshot := buildConsultationSnapshot(db, rec.RoomID, rec.BatchID, lamp) raw, _ := json.Marshal(snapshot) rec.Snapshot = raw if err := db.Create(&rec).Error; err != nil { c.JSON(http.StatusBadRequest, gin.H{"error": "创建失败"}) return } c.JSON(http.StatusCreated, rec) } } // buildConsultationSnapshot 打包病例快照(房间/巡检/LAMP/批次/天气) func buildConsultationSnapshot(db *gorm.DB, roomID, batchID *string, lamp *model.LampTest) model.ConsultationSnapshot { s := model.ConsultationSnapshot{CreatedAt: time.Now()} if roomID != nil { var room model.Room if db.Where("id = ?", *roomID).First(&room).Error == nil { s.RoomName = room.Name } var insp model.InspectionRecord if db.Where("room_id = ?", *roomID).Order("created_at DESC").First(&insp).Error == nil { s.Inspection = &insp } var alerts []model.WeatherAlert db.Order("created_at DESC").Limit(3).Find(&alerts) s.WeatherAlerts = alerts } if lamp != nil { s.LampTest = lamp } if batchID != nil { var b model.Batch if db.Where("id = ?", *batchID).First(&b).Error == nil { s.Batch = &b } } else if lamp != nil && lamp.BatchID != nil { var b model.Batch if db.Where("id = ?", *lamp.BatchID).First(&b).Error == nil { s.Batch = &b } } return s } // updateConsultation 更新会诊单(标题/摘要/状态流转) func updateConsultation(db *gorm.DB) gin.HandlerFunc { return func(c *gin.Context) { id := c.Param("id") var t model.Consultation if db.Where("id = ?", id).First(&t).Error != nil { c.JSON(http.StatusNotFound, gin.H{"error": "consultation not found"}) return } updates, err := bindUpdates(c) if err != nil { c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()}) return } if s, ok := updates["status"]; ok { to, _ := s.(string) if !model.ValidConsultationTransition(t.Status, to) { c.JSON(http.StatusBadRequest, gin.H{"error": "非法的会诊状态流转"}) return } } if len(updates) > 0 { db.Model(&model.Consultation{}).Where("id = ?", id).Updates(updates) } db.Where("id = ?", id).First(&t) c.JSON(http.StatusOK, t) } } // resolveConsultation 专家出会诊意见与防控方案 func resolveConsultation(db *gorm.DB) gin.HandlerFunc { return func(c *gin.Context) { id := c.Param("id") var t model.Consultation if db.Where("id = ?", id).First(&t).Error != nil { c.JSON(http.StatusNotFound, gin.H{"error": "consultation not found"}) return } if !model.ValidConsultationTransition(t.Status, "resolved") { c.JSON(http.StatusBadRequest, gin.H{"error": "当前状态不能出方案"}) return } var body struct { Opinion string `json:"opinion"` Plan string `json:"plan"` } if err := c.ShouldBindJSON(&body); err != nil { c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()}) return } if body.Plan == "" { c.JSON(http.StatusBadRequest, gin.H{"error": "防控方案不能为空"}) return } now := time.Now() updates := map[string]interface{}{ "status": "resolved", "expert_id": currentUserID(c), "opinion": body.Opinion, "plan": body.Plan, "resolved_at": now, } db.Model(&model.Consultation{}).Where("id = ?", id).Updates(updates) db.Where("id = ?", id).First(&t) c.JSON(http.StatusOK, t) } } // archiveConsultation 归档 func archiveConsultation(db *gorm.DB) gin.HandlerFunc { return func(c *gin.Context) { id := c.Param("id") var t model.Consultation if db.Where("id = ?", id).First(&t).Error != nil { c.JSON(http.StatusNotFound, gin.H{"error": "consultation not found"}) return } if !model.ValidConsultationTransition(t.Status, "archived") { c.JSON(http.StatusBadRequest, gin.H{"error": "仅已出方案的会诊可归档"}) return } now := time.Now() db.Model(&model.Consultation{}).Where("id = ?", id). Updates(map[string]interface{}{"status": "archived", "archived_at": now}) db.Where("id = ?", id).First(&t) c.JSON(http.StatusOK, t) } }