156 lines
5.3 KiB
Go
156 lines
5.3 KiB
Go
package handler
|
|
|
|
import (
|
|
"net/http"
|
|
"time"
|
|
|
|
"silk-server-go/internal/middleware"
|
|
"silk-server-go/internal/model"
|
|
"silk-server-go/internal/service"
|
|
|
|
"github.com/gin-gonic/gin"
|
|
"gorm.io/gorm"
|
|
)
|
|
|
|
// RegisterHealthRoutes 注册健康检查路由
|
|
func RegisterHealthRoutes(rg *gin.RouterGroup) {
|
|
rg.GET("/health", func(c *gin.Context) {
|
|
c.JSON(http.StatusOK, gin.H{"status": "ok"})
|
|
})
|
|
}
|
|
|
|
// RegisterHealthProfileRoutes 注册蚕房健康画像路由
|
|
func RegisterHealthProfileRoutes(rg *gin.RouterGroup, db *gorm.DB) {
|
|
rg.GET("/health-profiles/:roomId",
|
|
middleware.RequirePermission(db, "room:read"),
|
|
roomHealthProfile(db))
|
|
rg.GET("/health-profiles/:roomId/effect",
|
|
middleware.RequirePermission(db, "room:read"),
|
|
roomEffectReport(db))
|
|
}
|
|
|
|
// roomHealthProfile 单蚕房健康画像:巡检风险/检测结果/事件聚合 → 综合健康分
|
|
func roomHealthProfile(db *gorm.DB) gin.HandlerFunc {
|
|
return func(c *gin.Context) {
|
|
id := c.Param("roomId")
|
|
var room model.Room
|
|
if db.Where("id = ?", id).First(&room).Error != nil {
|
|
c.JSON(http.StatusNotFound, gin.H{"error": "room not found"})
|
|
return
|
|
}
|
|
since := time.Now().Add(-30 * 24 * time.Hour)
|
|
|
|
// 近 30 天巡检风险分布
|
|
var riskRows []struct {
|
|
RiskLevel string `gorm:"column:risk_level"`
|
|
Cnt int64 `gorm:"column:cnt"`
|
|
}
|
|
db.Table("inspection_records").
|
|
Select("risk_level, count(*) AS cnt").
|
|
Where("room_id = ? AND ai_status = 'done' AND risk_level IS NOT NULL AND created_at >= ? AND COALESCE(is_mock, false) = false", id, since).
|
|
Group("risk_level").
|
|
Scan(&riskRows)
|
|
riskCounts := map[string]int64{}
|
|
var riskLevels []string
|
|
for _, r := range riskRows {
|
|
riskCounts[r.RiskLevel] = r.Cnt
|
|
for i := int64(0); i < r.Cnt; i++ {
|
|
riskLevels = append(riskLevels, r.RiskLevel)
|
|
}
|
|
}
|
|
|
|
// 近 30 天 LAMP/分子检测结果
|
|
lampTotal, lampPositive := int64(0), int64(0)
|
|
db.Model(&model.LampTest{}).
|
|
Where("room_id = ? AND status = 'resulted' AND created_at >= ?", id, since).
|
|
Count(&lampTotal)
|
|
db.Model(&model.LampTest{}).
|
|
Where("room_id = ? AND status = 'resulted' AND result = 'positive' AND created_at >= ?", id, since).
|
|
Count(&lampPositive)
|
|
|
|
// 事件数
|
|
var consultationCount, traceCount int64
|
|
db.Model(&model.Consultation{}).Where("room_id = ?", id).Count(&consultationCount)
|
|
db.Model(&model.TraceRecord{}).Where("room_id = ?", id).Count(&traceCount)
|
|
|
|
// 当前批次
|
|
var batch *model.Batch
|
|
var latest model.Batch
|
|
if db.Where("room_id = ?", id).Order("created_at DESC").First(&latest).Error == nil {
|
|
batch = &latest
|
|
}
|
|
|
|
score, grade := service.ComputeHealthScore(service.HealthInput{
|
|
RecentRiskLevels: riskLevels,
|
|
LampPositive: int(lampPositive),
|
|
LampTotal: int(lampTotal),
|
|
ConsultationCount: int(consultationCount),
|
|
TraceCount: int(traceCount),
|
|
})
|
|
c.JSON(http.StatusOK, gin.H{
|
|
"roomId": room.ID,
|
|
"roomName": room.Name,
|
|
"score": score,
|
|
"grade": grade,
|
|
"riskDistribution": gin.H{
|
|
"green": riskCounts["green"], "yellow": riskCounts["yellow"],
|
|
"orange": riskCounts["orange"], "red": riskCounts["red"],
|
|
},
|
|
"lampResults": gin.H{"total": lampTotal, "positive": lampPositive},
|
|
"events": gin.H{"consultations": consultationCount, "traces": traceCount},
|
|
"batch": batch,
|
|
})
|
|
}
|
|
}
|
|
|
|
// roomEffectReport 处置前后窗口效果报告。
|
|
func roomEffectReport(db *gorm.DB) gin.HandlerFunc {
|
|
return func(c *gin.Context) {
|
|
roomID := c.Param("roomId")
|
|
now := time.Now()
|
|
parse := func(key string, fallback time.Time) time.Time {
|
|
raw := c.Query(key)
|
|
if raw == "" {
|
|
return fallback
|
|
}
|
|
t, err := time.Parse(time.RFC3339, raw)
|
|
if err != nil {
|
|
return fallback
|
|
}
|
|
return t
|
|
}
|
|
window := service.EffectWindow{
|
|
BeforeStart: parse("beforeStart", now.Add(-60*24*time.Hour)),
|
|
BeforeEnd: parse("beforeEnd", now.Add(-30*24*time.Hour)),
|
|
AfterStart: parse("afterStart", now.Add(-30*24*time.Hour)),
|
|
AfterEnd: parse("afterEnd", now),
|
|
}
|
|
before, after := service.EffectMetrics{}, service.EffectMetrics{}
|
|
loadEffectMetrics := func(start, end time.Time) service.EffectMetrics {
|
|
metrics := service.EffectMetrics{}
|
|
db.Table("inspection_records").
|
|
Where("room_id = ? AND ai_status = 'done' AND COALESCE(is_mock, false) = false AND risk_score IS NOT NULL AND created_at >= ? AND created_at < ?", roomID, start, end).
|
|
Pluck("risk_score", &metrics.RiskSamples)
|
|
var lampTotal int64
|
|
db.Model(&model.LampTest{}).
|
|
Where("room_id = ? AND status = 'resulted' AND created_at >= ? AND created_at < ?", roomID, start, end).
|
|
Count(&lampTotal)
|
|
metrics.LampTotal = int(lampTotal)
|
|
var lampPositive int64
|
|
db.Model(&model.LampTest{}).
|
|
Where("room_id = ? AND status = 'resulted' AND result = 'positive' AND created_at >= ? AND created_at < ?", roomID, start, end).
|
|
Count(&lampPositive)
|
|
metrics.LampPositive = int(lampPositive)
|
|
return metrics
|
|
}
|
|
before = loadEffectMetrics(window.BeforeStart, window.BeforeEnd)
|
|
after = loadEffectMetrics(window.AfterStart, window.AfterEnd)
|
|
var recurrences int64
|
|
db.Model(&model.DiseaseEvent{}).
|
|
Where("room_id = ? AND status = 'reopened' AND created_at >= ? AND created_at < ?", roomID, window.AfterStart, window.AfterEnd).
|
|
Count(&recurrences)
|
|
after.Recurrences = int(recurrences)
|
|
c.JSON(http.StatusOK, service.EvaluateControlEffect(roomID, window, before, after))
|
|
}
|
|
}
|