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.
 
 
 
 
 
 

194 lines
4.8 KiB

package logic
import (
"context"
"encoding/json"
"sort"
"time"
"healthapi/internal/model"
"healthapi/internal/svc"
"healthapi/internal/types"
"healthapi/pkg/errorx"
"github.com/zeromicro/go-zero/core/logx"
)
type SubmitAssessmentLogic struct {
logx.Logger
ctx context.Context
svcCtx *svc.ServiceContext
}
func NewSubmitAssessmentLogic(ctx context.Context, svcCtx *svc.ServiceContext) *SubmitAssessmentLogic {
return &SubmitAssessmentLogic{
Logger: logx.WithContext(ctx),
ctx: ctx,
svcCtx: svcCtx,
}
}
type constitutionScore struct {
Type string `json:"type"`
Name string `json:"name"`
Score float64 `json:"score"`
Description string `json:"description"`
}
func (l *SubmitAssessmentLogic) SubmitAssessment(req *types.SubmitAssessmentReq) (resp *types.AssessmentResult, err error) {
userID, err := GetUserIDFromCtx(l.ctx)
if err != nil {
return nil, errorx.ErrUnauthorized
}
// 获取所有问题
var questions []model.QuestionBank
l.svcCtx.DB.Find(&questions)
if len(questions) == 0 {
return nil, errorx.NewCodeError(errorx.CodeServerError, "问卷题库为空")
}
// 构建问题ID到体质类型的映射
questionTypeMap := make(map[uint]string)
typeQuestionCount := make(map[string]int)
for _, q := range questions {
questionTypeMap[q.ID] = q.ConstitutionType
typeQuestionCount[q.ConstitutionType]++
}
// 计算各体质原始分
typeScores := make(map[string]int)
for _, answer := range req.Answers {
if cType, ok := questionTypeMap[uint(answer.QuestionID)]; ok {
typeScores[cType] += answer.Score
}
}
// 计算转化分
allScores := make([]constitutionScore, 0)
for cType, rawScore := range typeScores {
questionCount := typeQuestionCount[cType]
if questionCount == 0 {
continue
}
transformedScore := float64(rawScore-questionCount) / float64(questionCount*4) * 100
if transformedScore < 0 {
transformedScore = 0
}
if transformedScore > 100 {
transformedScore = 100
}
allScores = append(allScores, constitutionScore{
Type: cType,
Name: model.ConstitutionNames[cType],
Score: transformedScore,
Description: model.ConstitutionDescriptions[cType],
})
}
// 按分数排序
sort.Slice(allScores, func(i, j int) bool {
return allScores[i].Score > allScores[j].Score
})
// 判定主要体质和次要体质
var primary constitutionScore
var secondary []constitutionScore
pingheScore := float64(0)
otherMax := float64(0)
for _, score := range allScores {
if score.Type == model.ConstitutionPinghe {
pingheScore = score.Score
} else if score.Score > otherMax {
otherMax = score.Score
}
}
if pingheScore >= 60 && otherMax < 30 {
for _, score := range allScores {
if score.Type == model.ConstitutionPinghe {
primary = score
break
}
}
} else {
for _, score := range allScores {
if score.Type == model.ConstitutionPinghe {
continue
}
if primary.Type == "" && score.Score >= 40 {
primary = score
} else if score.Score >= 30 {
secondary = append(secondary, score)
}
}
if primary.Type == "" {
for _, score := range allScores {
if score.Type != model.ConstitutionPinghe {
primary = score
break
}
}
}
}
// 获取调养建议
recommendations := make(map[string]string)
if primary.Type != "" {
if recs, ok := model.ConstitutionRecommendations[primary.Type]; ok {
for k, v := range recs {
recommendations[k] = v
}
}
}
// 保存评估结果
scoresJSON, _ := json.Marshal(allScores)
secondaryTypes := make([]string, len(secondary))
for i, s := range secondary {
secondaryTypes[i] = s.Type
}
secondaryJSON, _ := json.Marshal(secondaryTypes)
recsJSON, _ := json.Marshal(recommendations)
assessment := model.ConstitutionAssessment{
UserID: userID,
AssessedAt: time.Now(),
Scores: string(scoresJSON),
PrimaryConstitution: primary.Type,
SecondaryConstitutions: string(secondaryJSON),
Recommendations: string(recsJSON),
}
if err := l.svcCtx.DB.Create(&assessment).Error; err != nil {
return nil, errorx.ErrServerError
}
// 保存答案记录
answers := make([]model.AssessmentAnswer, len(req.Answers))
for i, a := range req.Answers {
answers[i] = model.AssessmentAnswer{
AssessmentID: assessment.ID,
QuestionID: uint(a.QuestionID),
Score: a.Score,
}
}
l.svcCtx.DB.Create(&answers)
// 构建响应
// 转换 allScores 为 map[string]float64
scoresMap := make(map[string]float64)
for _, s := range allScores {
scoresMap[s.Type] = s.Score
}
return &types.AssessmentResult{
ID: uint(assessment.ID),
AssessedAt: assessment.AssessedAt.Format(time.RFC3339),
Scores: scoresMap,
PrimaryConstitution: primary.Type,
SecondaryConstitutions: secondaryTypes,
Recommendations: recommendations,
}, nil
}