package service import ( "fmt" "time" ) // EnvSample 环境回溯样本 type EnvSample struct { Time time.Time Temp *float64 Humidity *float64 } // EnvironmentResult 环境回溯结果 type EnvironmentResult struct { HighHumidity bool TempSwing bool Summary string } // EnvironmentBacktrack 发病前环境回溯:湿度≥阈值 或 温度>30/<20 触发(规格书 3.8.3) func EnvironmentBacktrack(samples []EnvSample, humidityThreshold float64) EnvironmentResult { r := EnvironmentResult{} if len(samples) == 0 { r.Summary = "无可用环境遥测数据" return r } for _, s := range samples { if s.Humidity != nil && *s.Humidity >= humidityThreshold { r.HighHumidity = true } if s.Temp != nil && (*s.Temp > 30 || *s.Temp < 20) { r.TempSwing = true } } switch { case r.HighHumidity && r.TempSwing: r.Summary = "发病前环境存在持续高湿与温度突变,符合真菌病与核型多角体病诱发条件" case r.HighHumidity: r.Summary = fmt.Sprintf("发病前环境湿度 ≥%.0f%%,符合高湿诱病条件", humidityThreshold) case r.TempSwing: r.Summary = "发病前环境温度突变(>30℃ 或 <20℃),易诱发潜伏感染转急性" default: r.Summary = "发病前环境温湿度未见明显异常" } return r } // PastEvent 历史发病事件 type PastEvent struct { Disease string DaysAgo int } // HistoryAssociation 历史发病关联:同房间/同病种既往 90 天内有发病 → 连发性 func HistoryAssociation(past []PastEvent, disease string) bool { for _, e := range past { if e.Disease == disease && e.DaysAgo <= 90 { return true } } return false } // TransmissionInference 按病种推断传播途径(规格书 3.8.2) func TransmissionInference(disease string) (mode, source string) { switch disease { case "核型多角体病": return "食下传染为主,创伤传染次之", "多角体污染蚕座/桑叶/蚕具,环境残留或新引入" case "白僵病", "其他真菌病(绿僵病/黄僵病/曲霉病)": return "接触传染/气流扩散", "分生孢子经气流带入,或蚕房尸体产孢内源扩散" case "软化病", "浓核病/传染性软化病": return "食下传染", "桑园害虫粪便污染桑叶,或蚕座环境累积污染" case "微粒子病": return "食下传染+胚种传染", "蚕种带毒(垂直传播)或环境孢子水平传播" case "细菌性败血病": return "创伤传染", "蚕具刮伤/互相抓伤后环境细菌侵入" case "猝倒病": return "食下传染(细菌毒素)", "桑叶被细菌污染" default: return "未知", "病种不明,建议先确认病原" } } // ChecklistItem 排查清单项 type ChecklistItem struct { Key string `json:"key"` Label string `json:"label"` InternalBias bool `json:"internalBias"` } // DiseaseChecklist 分病种二级排查清单(规格书 3.8.3) func DiseaseChecklist(disease string) []ChecklistItem { switch disease { case "核型多角体病": return []ChecklistItem{ {Key: "disinfect", Label: "上批次是否发生过同种病?消毒是否彻底(含蚕具浸泡)?", InternalBias: true}, {Key: "tray_share", Label: "蚕具是否跨批次共用?", InternalBias: true}, {Key: "mulberry", Label: "桑叶来源是否变更?", InternalBias: false}, {Key: "entry", Label: "近期人员进出/蚕具借用记录是否有异常?", InternalBias: false}, } case "白僵病": return []ChecklistItem{ {Key: "vent", Label: "近期是否连续阴雨且通风不足?", InternalBias: true}, {Key: "corpse", Label: "蚕房附近是否堆放蚕沙或病蚕尸体?", InternalBias: true}, {Key: "outdoor", Label: "蚕房周边桑园昆虫是否有白僵病死亡个体?", InternalBias: false}, {Key: "filter", Label: "通风口是否有过滤防虫措施?", InternalBias: false}, } case "微粒子病": return []ChecklistItem{ {Key: "seed", Label: "蚕种来源批次与供应商是否可追溯?", InternalBias: true}, {Key: "quarantine", Label: "检疫证明与母蛾镜检结果是否齐全?", InternalBias: true}, {Key: "wild", Label: "桑园周边野外昆虫是否有微孢子虫?", InternalBias: false}, {Key: "cross", Label: "同批次蚕种在其他蚕房是否发病?", InternalBias: false}, } case "软化病", "浓核病/传染性软化病": return []ChecklistItem{ {Key: "density", Label: "蚕头密度是否过大?", InternalBias: true}, {Key: "vent", Label: "通风是否不良?", InternalBias: true}, {Key: "mulberry", Label: "桑叶是否潮湿或储运不达标?", InternalBias: true}, {Key: "pest", Label: "桑园近期害虫防治记录是否正常?", InternalBias: false}, } case "细菌性败血病": return []ChecklistItem{ {Key: "tool", Label: "蚕具是否有尖锐边缘/毛刺?", InternalBias: true}, {Key: "density", Label: "蚕头密度是否超标导致相互抓伤?", InternalBias: true}, {Key: "op", Label: "给桑操作是否粗暴?", InternalBias: true}, {Key: "disinfect", Label: "消毒是否有盲区?", InternalBias: true}, } default: return nil } } // ChecklistAnswer 清单作答 type ChecklistAnswer struct { Key string `json:"key"` Label string `json:"label"` Answer string `json:"answer"` // yes/no/unknown InternalBias bool `json:"internalBias"` } // AnalyzeChecklist 按作答统计内源/外源倾向并给出结论 func AnalyzeChecklist(answers []ChecklistAnswer) (origin string, confidence float64, conclusion string) { internal, external, unknown := 0, 0, 0 for _, a := range answers { switch a.Answer { case "yes": if a.InternalBias { internal++ } else { external++ } case "no": if a.InternalBias { external++ } else { internal++ } default: unknown++ } } total := internal + external + unknown if total == 0 { return "unknown", 0, "未填写排查清单,无法判定来源" } switch { case internal > external: origin = "internal" confidence = 0.5 + 0.3*float64(internal)/float64(total) conclusion = "倾向内源扩散(环境残留/蚕座污染),建议定向清除环境残留并升级消毒" case external > internal: origin = "external" confidence = 0.5 + 0.3*float64(external)/float64(total) conclusion = "倾向外源侵入(桑叶/气流/种源),建议封堵外部侵入途径" default: origin = "unknown" confidence = 0.5 conclusion = "内源与外源线索相当,建议结合专家会诊进一步确认" } return origin, confidence, conclusion }