package service import ( "errors" "time" "health-ai/internal/model" "health-ai/internal/repository/impl" ) type SurveyService struct { healthRepo *impl.HealthRepository userRepo *impl.UserRepositoryImpl } func NewSurveyService() *SurveyService { return &SurveyService{ healthRepo: impl.NewHealthRepository(), userRepo: impl.NewUserRepository(), } } // ================= 请求结构体 ================= // BasicInfoRequest 基础信息请求 type BasicInfoRequest struct { Name string `json:"name" binding:"required"` BirthDate string `json:"birth_date"` // 格式: 2006-01-02 Gender string `json:"gender" binding:"required,oneof=male female"` Height float64 `json:"height" binding:"required,gt=0"` Weight float64 `json:"weight" binding:"required,gt=0"` BloodType string `json:"blood_type"` Occupation string `json:"occupation"` MaritalStatus string `json:"marital_status"` Region string `json:"region"` } // LifestyleRequest 生活习惯请求 type LifestyleRequest struct { SleepTime string `json:"sleep_time"` // 格式: HH:MM WakeTime string `json:"wake_time"` // 格式: HH:MM SleepQuality string `json:"sleep_quality"` // good, normal, poor MealRegularity string `json:"meal_regularity"` // regular, irregular DietPreference string `json:"diet_preference"` DailyWaterML int `json:"daily_water_ml"` ExerciseFrequency string `json:"exercise_frequency"` // never, sometimes, often, daily ExerciseType string `json:"exercise_type"` ExerciseDurationMin int `json:"exercise_duration_min"` IsSmoker bool `json:"is_smoker"` AlcoholFrequency string `json:"alcohol_frequency"` // never, sometimes, often } // MedicalHistoryRequest 病史请求 type MedicalHistoryRequest struct { DiseaseName string `json:"disease_name" binding:"required"` DiseaseType string `json:"disease_type"` // chronic, surgery, other DiagnosedDate string `json:"diagnosed_date"` Status string `json:"status"` // cured, treating, controlled Notes string `json:"notes"` } // FamilyHistoryRequest 家族病史请求 type FamilyHistoryRequest struct { Relation string `json:"relation" binding:"required"` // father, mother, grandparent DiseaseName string `json:"disease_name" binding:"required"` Notes string `json:"notes"` } // AllergyRequest 过敏信息请求 type AllergyRequest struct { AllergyType string `json:"allergy_type" binding:"required"` // drug, food, other Allergen string `json:"allergen" binding:"required"` Severity string `json:"severity"` // mild, moderate, severe ReactionDesc string `json:"reaction_desc"` } // BatchMedicalHistoryRequest 批量病史请求 type BatchMedicalHistoryRequest struct { Histories []MedicalHistoryRequest `json:"histories"` } // BatchFamilyHistoryRequest 批量家族病史请求 type BatchFamilyHistoryRequest struct { Histories []FamilyHistoryRequest `json:"histories"` } // BatchAllergyRequest 批量过敏信息请求 type BatchAllergyRequest struct { Allergies []AllergyRequest `json:"allergies"` } // ================= 响应结构体 ================= // SurveyStatusResponse 调查状态响应 type SurveyStatusResponse struct { BasicInfo bool `json:"basic_info"` Lifestyle bool `json:"lifestyle"` MedicalHistory bool `json:"medical_history"` FamilyHistory bool `json:"family_history"` Allergy bool `json:"allergy"` AllCompleted bool `json:"all_completed"` } // ================= Service 方法 ================= // GetStatus 获取调查完成状态 func (s *SurveyService) GetStatus(userID uint) (*SurveyStatusResponse, error) { status := &SurveyStatusResponse{ BasicInfo: false, Lifestyle: false, MedicalHistory: false, FamilyHistory: false, Allergy: false, AllCompleted: false, } // 检查基础信息 profile, err := s.healthRepo.GetProfileByUserID(userID) if err == nil && profile.ID > 0 { status.BasicInfo = true // 病史、家族史、过敏史可以为空,只要有profile就算完成 status.MedicalHistory = true status.FamilyHistory = true status.Allergy = true } // 检查生活习惯 lifestyle, err := s.healthRepo.GetLifestyleByUserID(userID) if err == nil && lifestyle.ID > 0 { status.Lifestyle = true } // 检查是否全部完成 status.AllCompleted = status.BasicInfo && status.Lifestyle return status, nil } // SubmitBasicInfo 提交基础信息 func (s *SurveyService) SubmitBasicInfo(userID uint, req *BasicInfoRequest) error { // 计算 BMI heightM := req.Height / 100 bmi := req.Weight / (heightM * heightM) profile := &model.HealthProfile{ UserID: userID, Name: req.Name, Gender: req.Gender, Height: req.Height, Weight: req.Weight, BMI: bmi, BloodType: req.BloodType, Occupation: req.Occupation, MaritalStatus: req.MaritalStatus, Region: req.Region, } // 解析出生日期 if req.BirthDate != "" { birthDate, err := time.Parse("2006-01-02", req.BirthDate) if err == nil { profile.BirthDate = &birthDate } } // 检查是否已存在 existing, _ := s.healthRepo.GetProfileByUserID(userID) if existing.ID > 0 { profile.ID = existing.ID profile.CreatedAt = existing.CreatedAt return s.healthRepo.UpdateProfile(profile) } return s.healthRepo.CreateProfile(profile) } // SubmitLifestyle 提交生活习惯 func (s *SurveyService) SubmitLifestyle(userID uint, req *LifestyleRequest) error { lifestyle := &model.LifestyleInfo{ UserID: userID, SleepTime: req.SleepTime, WakeTime: req.WakeTime, SleepQuality: req.SleepQuality, MealRegularity: req.MealRegularity, DietPreference: req.DietPreference, DailyWaterML: req.DailyWaterML, ExerciseFrequency: req.ExerciseFrequency, ExerciseType: req.ExerciseType, ExerciseDurationMin: req.ExerciseDurationMin, IsSmoker: req.IsSmoker, AlcoholFrequency: req.AlcoholFrequency, } existing, _ := s.healthRepo.GetLifestyleByUserID(userID) if existing.ID > 0 { lifestyle.ID = existing.ID lifestyle.CreatedAt = existing.CreatedAt return s.healthRepo.UpdateLifestyle(lifestyle) } return s.healthRepo.CreateLifestyle(lifestyle) } // SubmitMedicalHistory 提交单条病史 func (s *SurveyService) SubmitMedicalHistory(userID uint, req *MedicalHistoryRequest) error { profile, err := s.healthRepo.GetProfileByUserID(userID) if err != nil { return errors.New("请先填写基础信息") } history := &model.MedicalHistory{ HealthProfileID: profile.ID, DiseaseName: req.DiseaseName, DiseaseType: req.DiseaseType, DiagnosedDate: req.DiagnosedDate, Status: req.Status, Notes: req.Notes, } return s.healthRepo.CreateMedicalHistory(history) } // SubmitBatchMedicalHistory 批量提交病史(覆盖式) func (s *SurveyService) SubmitBatchMedicalHistory(userID uint, req *BatchMedicalHistoryRequest) error { profile, err := s.healthRepo.GetProfileByUserID(userID) if err != nil { return errors.New("请先填写基础信息") } // 清除旧数据 if err := s.healthRepo.ClearMedicalHistories(profile.ID); err != nil { return err } // 创建新数据 if len(req.Histories) == 0 { return nil } histories := make([]model.MedicalHistory, len(req.Histories)) for i, h := range req.Histories { histories[i] = model.MedicalHistory{ HealthProfileID: profile.ID, DiseaseName: h.DiseaseName, DiseaseType: h.DiseaseType, DiagnosedDate: h.DiagnosedDate, Status: h.Status, Notes: h.Notes, } } return s.healthRepo.BatchCreateMedicalHistories(histories) } // SubmitFamilyHistory 提交单条家族病史 func (s *SurveyService) SubmitFamilyHistory(userID uint, req *FamilyHistoryRequest) error { profile, err := s.healthRepo.GetProfileByUserID(userID) if err != nil { return errors.New("请先填写基础信息") } history := &model.FamilyHistory{ HealthProfileID: profile.ID, Relation: req.Relation, DiseaseName: req.DiseaseName, Notes: req.Notes, } return s.healthRepo.CreateFamilyHistory(history) } // SubmitBatchFamilyHistory 批量提交家族病史(覆盖式) func (s *SurveyService) SubmitBatchFamilyHistory(userID uint, req *BatchFamilyHistoryRequest) error { profile, err := s.healthRepo.GetProfileByUserID(userID) if err != nil { return errors.New("请先填写基础信息") } // 清除旧数据 if err := s.healthRepo.ClearFamilyHistories(profile.ID); err != nil { return err } // 创建新数据 if len(req.Histories) == 0 { return nil } histories := make([]model.FamilyHistory, len(req.Histories)) for i, h := range req.Histories { histories[i] = model.FamilyHistory{ HealthProfileID: profile.ID, Relation: h.Relation, DiseaseName: h.DiseaseName, Notes: h.Notes, } } return s.healthRepo.BatchCreateFamilyHistories(histories) } // SubmitAllergy 提交单条过敏信息 func (s *SurveyService) SubmitAllergy(userID uint, req *AllergyRequest) error { profile, err := s.healthRepo.GetProfileByUserID(userID) if err != nil { return errors.New("请先填写基础信息") } record := &model.AllergyRecord{ HealthProfileID: profile.ID, AllergyType: req.AllergyType, Allergen: req.Allergen, Severity: req.Severity, ReactionDesc: req.ReactionDesc, } return s.healthRepo.CreateAllergyRecord(record) } // SubmitBatchAllergy 批量提交过敏信息(覆盖式) func (s *SurveyService) SubmitBatchAllergy(userID uint, req *BatchAllergyRequest) error { profile, err := s.healthRepo.GetProfileByUserID(userID) if err != nil { return errors.New("请先填写基础信息") } // 清除旧数据 if err := s.healthRepo.ClearAllergyRecords(profile.ID); err != nil { return err } // 创建新数据 if len(req.Allergies) == 0 { return nil } records := make([]model.AllergyRecord, len(req.Allergies)) for i, a := range req.Allergies { records[i] = model.AllergyRecord{ HealthProfileID: profile.ID, AllergyType: a.AllergyType, Allergen: a.Allergen, Severity: a.Severity, ReactionDesc: a.ReactionDesc, } } return s.healthRepo.BatchCreateAllergyRecords(records) } // MarkSurveyCompleted 标记调查完成 func (s *SurveyService) MarkSurveyCompleted(userID uint) error { return s.userRepo.UpdateSurveyStatus(userID, true) } // CompleteSurvey 完成调查(检查并标记) func (s *SurveyService) CompleteSurvey(userID uint) error { status, err := s.GetStatus(userID) if err != nil { return err } if !status.BasicInfo || !status.Lifestyle { return errors.New("请先完成基础信息和生活习惯的填写") } return s.MarkSurveyCompleted(userID) }