Files
silk/server-go/internal/handler/consultation.go
T

254 lines
7.3 KiB
Go

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(&lt).Error == nil {
lamp = &lt
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)
}
}