healthapp
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

368 lines
11 KiB

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)
}