feat: 建立统一检测任务、样本链与发病事件
This commit is contained in:
@@ -0,0 +1,579 @@
|
||||
package handler
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"silk-server-go/internal/middleware"
|
||||
"silk-server-go/internal/model"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
"gorm.io/gorm"
|
||||
"gorm.io/gorm/clause"
|
||||
)
|
||||
|
||||
// RegisterDetectionTaskRoutes 注册统一检测任务、样本和发病事件路由。
|
||||
func RegisterDetectionTaskRoutes(rg *gin.RouterGroup, db *gorm.DB) {
|
||||
lampRead := middleware.RequirePermission(db, "lamp:read")
|
||||
lampWrite := middleware.RequirePermission(db, "lamp:write")
|
||||
traceRead := middleware.RequirePermission(db, "trace:read")
|
||||
traceWrite := middleware.RequirePermission(db, "trace:write")
|
||||
|
||||
rg.GET("/detection-tasks", lampRead, listDetectionTasks(db))
|
||||
rg.POST("/detection-tasks", lampWrite, createDetectionTask(db))
|
||||
rg.GET("/detection-tasks/:id", lampRead, getDetectionTask(db))
|
||||
rg.PATCH("/detection-tasks/:id", lampWrite, updateDetectionTask(db))
|
||||
rg.GET("/detection-tasks/:id/samples", lampRead, listSamples(db))
|
||||
rg.POST("/detection-tasks/:id/samples", lampWrite, createSample(db))
|
||||
rg.PATCH("/samples/:id", lampWrite, updateSample(db))
|
||||
rg.GET("/disease-events", traceRead, listDiseaseEvents(db))
|
||||
rg.POST("/disease-events", traceWrite, createDiseaseEvent(db))
|
||||
rg.PATCH("/disease-events/:id", traceWrite, updateDiseaseEvent(db))
|
||||
}
|
||||
|
||||
func listDetectionTasks(db *gorm.DB) gin.HandlerFunc {
|
||||
return func(c *gin.Context) {
|
||||
q := db.Model(&model.DetectionTask{})
|
||||
if status := c.Query("status"); status != "" {
|
||||
q = q.Where("status = ?", status)
|
||||
}
|
||||
if room := c.Query("roomId"); room != "" {
|
||||
q = q.Where("room_id = ?", room)
|
||||
}
|
||||
if sourceType := c.Query("sourceType"); sourceType != "" {
|
||||
q = q.Where("source_type = ?", sourceType)
|
||||
}
|
||||
var list []model.DetectionTask
|
||||
q.Order("created_at DESC").Limit(200).Find(&list)
|
||||
fillDetectionTaskRoomNames(db, list)
|
||||
c.JSON(http.StatusOK, list)
|
||||
}
|
||||
}
|
||||
|
||||
func getDetectionTask(db *gorm.DB) gin.HandlerFunc {
|
||||
return func(c *gin.Context) {
|
||||
var task model.DetectionTask
|
||||
if db.Where("id = ?", c.Param("id")).First(&task).Error != nil {
|
||||
c.JSON(http.StatusNotFound, gin.H{"error": "detection task not found"})
|
||||
return
|
||||
}
|
||||
fillDetectionTaskRoomNames(db, []model.DetectionTask{task})
|
||||
c.JSON(http.StatusOK, task)
|
||||
}
|
||||
}
|
||||
|
||||
func createDetectionTask(db *gorm.DB) gin.HandlerFunc {
|
||||
return func(c *gin.Context) {
|
||||
var body struct {
|
||||
SourceKey string `json:"sourceKey"`
|
||||
SourceType string `json:"sourceType"`
|
||||
SourceID string `json:"sourceId"`
|
||||
RoomID *string `json:"roomId"`
|
||||
BatchID *string `json:"batchId"`
|
||||
InspectionID *string `json:"inspectionId"`
|
||||
Disease string `json:"disease"`
|
||||
RecommendedMethod string `json:"recommendedMethod"`
|
||||
Method *string `json:"method"`
|
||||
Priority string `json:"priority"`
|
||||
Note *string `json:"note"`
|
||||
}
|
||||
if err := c.ShouldBindJSON(&body); err != nil {
|
||||
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
|
||||
return
|
||||
}
|
||||
if body.Disease == "" {
|
||||
c.JSON(http.StatusBadRequest, gin.H{"error": "病种不能为空"})
|
||||
return
|
||||
}
|
||||
if body.Method != nil && !model.ValidDetectionMethod(*body.Method) {
|
||||
c.JSON(http.StatusBadRequest, gin.H{"error": "method 仅支持 lamp/qpcr/sers/hyperspectral"})
|
||||
return
|
||||
}
|
||||
for _, id := range []*string{body.RoomID, body.BatchID, body.InspectionID} {
|
||||
if id != nil && *id != "" && !isUUID(*id) {
|
||||
c.JSON(http.StatusBadRequest, gin.H{"error": "关联 ID 不是合法的 UUID"})
|
||||
return
|
||||
}
|
||||
}
|
||||
sourceKey := body.SourceKey
|
||||
if sourceKey == "" {
|
||||
sourceKey = fmt.Sprintf("manual-%d", time.Now().UnixNano())
|
||||
}
|
||||
sourceType := body.SourceType
|
||||
if sourceType == "" {
|
||||
sourceType = "manual"
|
||||
}
|
||||
priority := body.Priority
|
||||
if priority == "" {
|
||||
priority = "routine"
|
||||
}
|
||||
task := model.DetectionTask{
|
||||
SourceKey: sourceKey,
|
||||
SourceType: sourceType,
|
||||
SourceID: body.SourceID,
|
||||
RoomID: body.RoomID,
|
||||
BatchID: body.BatchID,
|
||||
InspectionID: body.InspectionID,
|
||||
Disease: body.Disease,
|
||||
RecommendedMethod: body.RecommendedMethod,
|
||||
Method: body.Method,
|
||||
Priority: priority,
|
||||
Status: "pending",
|
||||
CreatedBy: currentUserID(c),
|
||||
Note: body.Note,
|
||||
}
|
||||
if err := db.Clauses(clause.OnConflict{
|
||||
Columns: []clause.Column{{Name: "source_key"}},
|
||||
DoNothing: true,
|
||||
}).Create(&task).Error; err != nil {
|
||||
c.JSON(http.StatusBadRequest, gin.H{"error": "创建检测任务失败"})
|
||||
return
|
||||
}
|
||||
if task.ID == "" {
|
||||
_ = db.Where("source_key = ?", sourceKey).First(&task).Error
|
||||
}
|
||||
c.JSON(http.StatusCreated, task)
|
||||
}
|
||||
}
|
||||
|
||||
func updateDetectionTask(db *gorm.DB) gin.HandlerFunc {
|
||||
return func(c *gin.Context) {
|
||||
var task model.DetectionTask
|
||||
if db.Where("id = ?", c.Param("id")).First(&task).Error != nil {
|
||||
c.JSON(http.StatusNotFound, gin.H{"error": "detection task not found"})
|
||||
return
|
||||
}
|
||||
var body struct {
|
||||
AssigneeID *string `json:"assigneeId"`
|
||||
Method *string `json:"method"`
|
||||
Status *string `json:"status"`
|
||||
Result *string `json:"result"`
|
||||
CancelledReason *string `json:"cancelledReason"`
|
||||
Note *string `json:"note"`
|
||||
}
|
||||
if err := c.ShouldBindJSON(&body); err != nil {
|
||||
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
|
||||
return
|
||||
}
|
||||
if body.Method != nil && !model.ValidDetectionMethod(*body.Method) {
|
||||
c.JSON(http.StatusBadRequest, gin.H{"error": "method 仅支持 lamp/qpcr/sers/hyperspectral"})
|
||||
return
|
||||
}
|
||||
if body.Status != nil && !model.ValidDetectionTaskTransition(task.Status, *body.Status) {
|
||||
c.JSON(http.StatusBadRequest, gin.H{"error": fmt.Sprintf("检测任务状态不能从 %s 转到 %s", task.Status, *body.Status)})
|
||||
return
|
||||
}
|
||||
if body.Status != nil && *body.Status == "assigned" && body.AssigneeID == nil && task.AssigneeID == nil {
|
||||
c.JSON(http.StatusBadRequest, gin.H{"error": "指派状态必须先分配负责人"})
|
||||
return
|
||||
}
|
||||
if body.Status != nil && *body.Status == "completed" && body.Result == nil && task.Result == nil {
|
||||
c.JSON(http.StatusBadRequest, gin.H{"error": "完成检测任务前必须录入结果"})
|
||||
return
|
||||
}
|
||||
if body.Status != nil && *body.Status == "cancelled" && (body.CancelledReason == nil || strings.TrimSpace(*body.CancelledReason) == "") {
|
||||
c.JSON(http.StatusBadRequest, gin.H{"error": "取消任务必须填写原因"})
|
||||
return
|
||||
}
|
||||
updates := map[string]interface{}{}
|
||||
if body.AssigneeID != nil {
|
||||
updates["assignee_id"] = *body.AssigneeID
|
||||
updates["assigned_at"] = time.Now()
|
||||
}
|
||||
if body.Method != nil {
|
||||
updates["method"] = *body.Method
|
||||
}
|
||||
if body.Note != nil {
|
||||
updates["note"] = *body.Note
|
||||
}
|
||||
if body.Result != nil {
|
||||
if task.Status != "review" {
|
||||
c.JSON(http.StatusBadRequest, gin.H{"error": "结果需在复核阶段录入"})
|
||||
return
|
||||
}
|
||||
updates["result"] = *body.Result
|
||||
updates["resulted_at"] = time.Now()
|
||||
}
|
||||
if body.Status != nil {
|
||||
updates["status"] = *body.Status
|
||||
if *body.Status == "cancelled" {
|
||||
updates["cancelled_reason"] = *body.CancelledReason
|
||||
}
|
||||
}
|
||||
if len(updates) > 0 {
|
||||
if err := db.Model(&model.DetectionTask{}).Where("id = ?", task.ID).Updates(updates).Error; err != nil {
|
||||
c.JSON(http.StatusBadRequest, gin.H{"error": "更新检测任务失败"})
|
||||
return
|
||||
}
|
||||
}
|
||||
db.Where("id = ?", task.ID).First(&task)
|
||||
if task.Result != nil && *task.Result == "positive" {
|
||||
_ = ensureDiseaseEventFromDetectionTask(db, task)
|
||||
}
|
||||
fillDetectionTaskRoomNames(db, []model.DetectionTask{task})
|
||||
c.JSON(http.StatusOK, task)
|
||||
}
|
||||
}
|
||||
|
||||
func listSamples(db *gorm.DB) gin.HandlerFunc {
|
||||
return func(c *gin.Context) {
|
||||
var samples []model.Sample
|
||||
db.Where("detection_task_id = ?", c.Param("id")).Order("created_at ASC").Find(&samples)
|
||||
c.JSON(http.StatusOK, samples)
|
||||
}
|
||||
}
|
||||
|
||||
func createSample(db *gorm.DB) gin.HandlerFunc {
|
||||
return func(c *gin.Context) {
|
||||
var task model.DetectionTask
|
||||
if db.Where("id = ?", c.Param("id")).First(&task).Error != nil {
|
||||
c.JSON(http.StatusNotFound, gin.H{"error": "detection task not found"})
|
||||
return
|
||||
}
|
||||
var existing model.Sample
|
||||
if db.Where("detection_task_id = ?", task.ID).First(&existing).Error == nil {
|
||||
c.JSON(http.StatusOK, existing)
|
||||
return
|
||||
}
|
||||
var body struct {
|
||||
SampleNo string `json:"sampleNo"`
|
||||
RoomID *string `json:"roomId"`
|
||||
BatchID *string `json:"batchId"`
|
||||
TrayID *string `json:"trayId"`
|
||||
Note *string `json:"note"`
|
||||
}
|
||||
if err := c.ShouldBindJSON(&body); err != nil {
|
||||
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
|
||||
return
|
||||
}
|
||||
sampleNo := body.SampleNo
|
||||
if sampleNo == "" {
|
||||
sampleNo = fmt.Sprintf("S-%s", strings.ToUpper(task.ID[:8]))
|
||||
}
|
||||
now := time.Now()
|
||||
sample := model.Sample{
|
||||
DetectionTaskID: task.ID,
|
||||
SampleNo: sampleNo,
|
||||
RoomID: body.RoomID,
|
||||
BatchID: body.BatchID,
|
||||
TrayID: body.TrayID,
|
||||
SampledBy: currentUserID(c),
|
||||
SampledAt: &now,
|
||||
State: "created",
|
||||
Note: body.Note,
|
||||
}
|
||||
if sample.RoomID == nil {
|
||||
sample.RoomID = task.RoomID
|
||||
}
|
||||
if sample.BatchID == nil {
|
||||
sample.BatchID = task.BatchID
|
||||
}
|
||||
if err := db.Create(&sample).Error; err != nil {
|
||||
c.JSON(http.StatusBadRequest, gin.H{"error": "创建样本失败"})
|
||||
return
|
||||
}
|
||||
c.JSON(http.StatusCreated, sample)
|
||||
}
|
||||
}
|
||||
|
||||
func updateSample(db *gorm.DB) gin.HandlerFunc {
|
||||
return func(c *gin.Context) {
|
||||
var sample model.Sample
|
||||
if db.Where("id = ?", c.Param("id")).First(&sample).Error != nil {
|
||||
c.JSON(http.StatusNotFound, gin.H{"error": "sample not found"})
|
||||
return
|
||||
}
|
||||
var body struct {
|
||||
State *string `json:"state"`
|
||||
Note *string `json:"note"`
|
||||
}
|
||||
if err := c.ShouldBindJSON(&body); err != nil {
|
||||
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
|
||||
return
|
||||
}
|
||||
updates := map[string]interface{}{}
|
||||
if body.Note != nil {
|
||||
updates["note"] = *body.Note
|
||||
}
|
||||
if body.State != nil {
|
||||
if !model.ValidSampleTransition(sample.State, *body.State) {
|
||||
c.JSON(http.StatusBadRequest, gin.H{"error": fmt.Sprintf("样本状态不能从 %s 转到 %s", sample.State, *body.State)})
|
||||
return
|
||||
}
|
||||
updates["state"] = *body.State
|
||||
now := time.Now()
|
||||
switch *body.State {
|
||||
case "collected":
|
||||
updates["collected_at"] = now
|
||||
case "handed_over":
|
||||
updates["handed_over_at"] = now
|
||||
updates["handed_over_by"] = currentUserID(c)
|
||||
case "received":
|
||||
updates["received_at"] = now
|
||||
updates["received_by"] = currentUserID(c)
|
||||
case "testing":
|
||||
updates["testing_started_at"] = now
|
||||
case "consumed":
|
||||
updates["consumed_at"] = now
|
||||
case "disposed":
|
||||
updates["disposed_at"] = now
|
||||
}
|
||||
}
|
||||
if len(updates) > 0 {
|
||||
if err := db.Model(&model.Sample{}).Where("id = ?", sample.ID).Updates(updates).Error; err != nil {
|
||||
c.JSON(http.StatusBadRequest, gin.H{"error": "更新样本失败"})
|
||||
return
|
||||
}
|
||||
}
|
||||
db.Where("id = ?", sample.ID).First(&sample)
|
||||
c.JSON(http.StatusOK, sample)
|
||||
}
|
||||
}
|
||||
|
||||
func listDiseaseEvents(db *gorm.DB) gin.HandlerFunc {
|
||||
return func(c *gin.Context) {
|
||||
q := db.Model(&model.DiseaseEvent{})
|
||||
if status := c.Query("status"); status != "" {
|
||||
q = q.Where("status = ?", status)
|
||||
}
|
||||
if room := c.Query("roomId"); room != "" {
|
||||
q = q.Where("room_id = ?", room)
|
||||
}
|
||||
var list []model.DiseaseEvent
|
||||
q.Order("created_at DESC").Limit(200).Find(&list)
|
||||
fillDiseaseEventRoomNames(db, list)
|
||||
c.JSON(http.StatusOK, list)
|
||||
}
|
||||
}
|
||||
|
||||
func createDiseaseEvent(db *gorm.DB) gin.HandlerFunc {
|
||||
return func(c *gin.Context) {
|
||||
var body struct {
|
||||
SourceKey string `json:"sourceKey"`
|
||||
RoomID *string `json:"roomId"`
|
||||
BatchID *string `json:"batchId"`
|
||||
DetectionTaskID *string `json:"detectionTaskId"`
|
||||
LampTestID *string `json:"lampTestId"`
|
||||
ConsultationID *string `json:"consultationId"`
|
||||
InspectionID *string `json:"inspectionId"`
|
||||
Disease string `json:"disease"`
|
||||
Status string `json:"status"`
|
||||
Evidence json.RawMessage `json:"evidence"`
|
||||
LossSummary *string `json:"lossSummary"`
|
||||
Measure *string `json:"measure"`
|
||||
Note *string `json:"note"`
|
||||
}
|
||||
if err := c.ShouldBindJSON(&body); err != nil {
|
||||
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
|
||||
return
|
||||
}
|
||||
if body.Disease == "" {
|
||||
c.JSON(http.StatusBadRequest, gin.H{"error": "病种不能为空"})
|
||||
return
|
||||
}
|
||||
for _, id := range []*string{body.RoomID, body.BatchID, body.DetectionTaskID, body.LampTestID, body.ConsultationID, body.InspectionID} {
|
||||
if id != nil && *id != "" && !isUUID(*id) {
|
||||
c.JSON(http.StatusBadRequest, gin.H{"error": "关联 ID 不是合法的 UUID"})
|
||||
return
|
||||
}
|
||||
}
|
||||
if body.Status == "" {
|
||||
body.Status = "suspected"
|
||||
}
|
||||
event := model.DiseaseEvent{
|
||||
SourceKey: body.SourceKey,
|
||||
RoomID: body.RoomID,
|
||||
BatchID: body.BatchID,
|
||||
DetectionTaskID: body.DetectionTaskID,
|
||||
LampTestID: body.LampTestID,
|
||||
ConsultationID: body.ConsultationID,
|
||||
InspectionID: body.InspectionID,
|
||||
Disease: body.Disease,
|
||||
Status: body.Status,
|
||||
Evidence: body.Evidence,
|
||||
LossSummary: body.LossSummary,
|
||||
Measure: body.Measure,
|
||||
Note: body.Note,
|
||||
}
|
||||
if event.SourceKey == "" {
|
||||
event.SourceKey = fmt.Sprintf("manual-%d", time.Now().UnixNano())
|
||||
}
|
||||
if err := model.ValidateDiseaseEventEvidence(event); err != nil {
|
||||
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
|
||||
return
|
||||
}
|
||||
if event.Status == "confirmed" {
|
||||
now := time.Now()
|
||||
event.ConfirmedAt = &now
|
||||
event.ConfirmedBy = currentUserID(c)
|
||||
}
|
||||
if err := db.Clauses(clause.OnConflict{
|
||||
Columns: []clause.Column{{Name: "source_key"}},
|
||||
DoNothing: true,
|
||||
}).Create(&event).Error; err != nil {
|
||||
c.JSON(http.StatusBadRequest, gin.H{"error": "创建发病事件失败"})
|
||||
return
|
||||
}
|
||||
if event.ID == "" {
|
||||
_ = db.Where("source_key = ?", event.SourceKey).First(&event).Error
|
||||
}
|
||||
if event.Status == "confirmed" {
|
||||
_ = ensureTraceForDiseaseEvent(db, event)
|
||||
}
|
||||
c.JSON(http.StatusCreated, event)
|
||||
}
|
||||
}
|
||||
|
||||
func updateDiseaseEvent(db *gorm.DB) gin.HandlerFunc {
|
||||
return func(c *gin.Context) {
|
||||
var event model.DiseaseEvent
|
||||
if db.Where("id = ?", c.Param("id")).First(&event).Error != nil {
|
||||
c.JSON(http.StatusNotFound, gin.H{"error": "disease event not found"})
|
||||
return
|
||||
}
|
||||
var body struct {
|
||||
Status *string `json:"status"`
|
||||
Evidence json.RawMessage `json:"evidence"`
|
||||
LossSummary *string `json:"lossSummary"`
|
||||
Measure *string `json:"measure"`
|
||||
Note *string `json:"note"`
|
||||
}
|
||||
if err := c.ShouldBindJSON(&body); err != nil {
|
||||
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
|
||||
return
|
||||
}
|
||||
updates := map[string]interface{}{}
|
||||
if body.Status != nil {
|
||||
if !model.ValidDiseaseEventTransition(event.Status, *body.Status) {
|
||||
c.JSON(http.StatusBadRequest, gin.H{"error": fmt.Sprintf("发病事件状态不能从 %s 转到 %s", event.Status, *body.Status)})
|
||||
return
|
||||
}
|
||||
updates["status"] = *body.Status
|
||||
if *body.Status == "confirmed" {
|
||||
if len(body.Evidence) == 0 && len(event.Evidence) == 0 {
|
||||
c.JSON(http.StatusBadRequest, gin.H{"error": "确诊发病事件必须提供证据"})
|
||||
return
|
||||
}
|
||||
now := time.Now()
|
||||
updates["confirmed_at"] = now
|
||||
updates["confirmed_by"] = currentUserID(c)
|
||||
}
|
||||
}
|
||||
if len(body.Evidence) > 0 {
|
||||
updates["evidence"] = body.Evidence
|
||||
}
|
||||
if body.LossSummary != nil {
|
||||
updates["loss_summary"] = *body.LossSummary
|
||||
}
|
||||
if body.Measure != nil {
|
||||
updates["measure"] = *body.Measure
|
||||
}
|
||||
if body.Note != nil {
|
||||
updates["note"] = *body.Note
|
||||
}
|
||||
if len(updates) > 0 {
|
||||
if err := db.Model(&model.DiseaseEvent{}).Where("id = ?", event.ID).Updates(updates).Error; err != nil {
|
||||
c.JSON(http.StatusBadRequest, gin.H{"error": "更新发病事件失败"})
|
||||
return
|
||||
}
|
||||
}
|
||||
db.Where("id = ?", event.ID).First(&event)
|
||||
if event.Status == "confirmed" {
|
||||
_ = ensureTraceForDiseaseEvent(db, event)
|
||||
}
|
||||
c.JSON(http.StatusOK, event)
|
||||
}
|
||||
}
|
||||
|
||||
func fillDetectionTaskRoomNames(db *gorm.DB, list []model.DetectionTask) {
|
||||
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 name, ok := names[*list[i].RoomID]; ok {
|
||||
list[i].RoomName = &name
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func fillDiseaseEventRoomNames(db *gorm.DB, list []model.DiseaseEvent) {
|
||||
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 name, ok := names[*list[i].RoomID]; ok {
|
||||
list[i].RoomName = &name
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ensureTraceForDiseaseEvent 确诊后自动创建关联溯源记录,重复调用不重复创建。
|
||||
func ensureTraceForDiseaseEvent(db *gorm.DB, event model.DiseaseEvent) error {
|
||||
if event.Status != "confirmed" {
|
||||
return nil
|
||||
}
|
||||
var count int64
|
||||
if err := db.Model(&model.TraceRecord{}).Where("disease_event_id = ?", event.ID).Count(&count).Error; err != nil {
|
||||
return err
|
||||
}
|
||||
if count > 0 {
|
||||
return nil
|
||||
}
|
||||
trace := model.TraceRecord{
|
||||
DiseaseEventID: &event.ID,
|
||||
RoomID: event.RoomID,
|
||||
LampTestID: event.LampTestID,
|
||||
Disease: event.Disease,
|
||||
Status: "pending",
|
||||
}
|
||||
return db.Create(&trace).Error
|
||||
}
|
||||
|
||||
func ensureDiseaseEventFromDetectionTask(db *gorm.DB, task model.DetectionTask) error {
|
||||
if task.Result == nil || *task.Result != "positive" {
|
||||
return nil
|
||||
}
|
||||
now := time.Now()
|
||||
evidence, _ := json.Marshal(map[string]interface{}{
|
||||
"result": *task.Result,
|
||||
"method": task.Method,
|
||||
"detectionTaskId": task.ID,
|
||||
"resultedAt": task.ResultedAt,
|
||||
})
|
||||
sourceKey := "detection-task-" + task.ID
|
||||
event := model.DiseaseEvent{
|
||||
SourceKey: sourceKey,
|
||||
RoomID: task.RoomID,
|
||||
BatchID: task.BatchID,
|
||||
DetectionTaskID: &task.ID,
|
||||
InspectionID: task.InspectionID,
|
||||
Disease: task.Disease,
|
||||
Status: "confirmed",
|
||||
Evidence: evidence,
|
||||
ConfirmedAt: &now,
|
||||
ConfirmedBy: task.AssigneeID,
|
||||
}
|
||||
if err := db.Clauses(clause.OnConflict{
|
||||
Columns: []clause.Column{{Name: "source_key"}},
|
||||
DoNothing: true,
|
||||
}).Create(&event).Error; err != nil {
|
||||
return err
|
||||
}
|
||||
if event.ID == "" {
|
||||
_ = db.Where("source_key = ?", sourceKey).First(&event).Error
|
||||
}
|
||||
return ensureTraceForDiseaseEvent(db, event)
|
||||
}
|
||||
Reference in New Issue
Block a user