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