package controller import ( "server/common" "server/modules/user/service" yxDto "server/modules/yx/dto" "server/modules/yx/entity" yx_service "server/modules/yx/service" "time" "github.com/gin-gonic/gin" ) type UserVolunteerController struct { userScoreService *service.UserScoreService yxVolunteerService *yx_service.YxVolunteerService yxVolunteerRecordService *yx_service.YxVolunteerRecordService yxCalculationMajorService *yx_service.YxCalculationMajorService } func NewUserVolunteerController() *UserVolunteerController { return &UserVolunteerController{ userScoreService: service.NewUserScoreService(), yxVolunteerService: yx_service.NewYxVolunteerService(), yxVolunteerRecordService: yx_service.NewYxVolunteerRecordService(), yxCalculationMajorService: yx_service.NewYxCalculationMajorService(), } } func (ctrl *UserVolunteerController) RegisterRoutes(rg *gin.RouterGroup) { group := rg.Group("/user/volunteer") { group.POST("/save", ctrl.SaveVolunteer) group.GET("/detail", ctrl.GetVolunteerDetail) } } // SaveVolunteer 保存志愿明细 // @Summary 保存志愿明细 // @Tags 用户志愿 // @Param keys body []string true "Keys: schoolCode_majorCode_enrollmentCode" // @Success 200 {object} common.Response // @Router /user/volunteer/save [post] func (ctrl *UserVolunteerController) SaveVolunteer(c *gin.Context) { var keys []string if err := c.ShouldBindJSON(&keys); err != nil { common.Error(c, 500, err.Error()) return } // data deduplication seen := make(map[string]bool) var uniqueKeys []string for _, key := range keys { if !seen[key] { seen[key] = true uniqueKeys = append(uniqueKeys, key) } } keys = uniqueKeys loginUserId := common.GetLoginUser(c).ID userScoreVO, err := ctrl.userScoreService.GetActiveByID(loginUserId) if err != nil { common.Error(c, 500, err.Error()) return } if userScoreVO.CalculationTableName == "" { common.Error(c, 500, "未找到计算表名") return } // 查找当前激活的志愿表 volunteer, err := ctrl.yxVolunteerService.FindActiveByScoreId(userScoreVO.ID) if err != nil { common.Error(c, 500, "查找志愿表失败: "+err.Error()) return } if volunteer == nil || volunteer.ID == "" { common.Error(c, 500, "请先创建志愿表") return } // 查找专业信息 majors, err := ctrl.yxCalculationMajorService.FindListByCompositeKeys(userScoreVO.CalculationTableName, keys, userScoreVO.ID) if err != nil { common.Error(c, 500, "查找专业信息失败: "+err.Error()) return } // 构建 Map 用于保持顺序 majorMap := make(map[string]entity.YxCalculationMajor) for _, major := range majors { k := major.SchoolCode + "_" + major.MajorCode + "_" + major.EnrollmentCode majorMap[k] = major } var records []entity.YxVolunteerRecord for i, key := range keys { if major, ok := majorMap[key]; ok { record := entity.YxVolunteerRecord{ VolunteerID: volunteer.ID, SchoolCode: major.SchoolCode, MajorCode: major.MajorCode, EnrollmentCode: major.EnrollmentCode, Indexs: i + 1, CreateBy: loginUserId, CreateTime: time.Now(), Batch: major.Batch, EnrollProbability: major.EnrollProbability, StudentConvertedScore: major.StudentConvertedScore, CalculationMajorID: major.ID, } records = append(records, record) } } // 先删除旧数据 if err := ctrl.yxVolunteerRecordService.DeleteByVolunteerID(volunteer.ID); err != nil { common.Error(c, 500, "删除旧数据失败: "+err.Error()) return } // 批量插入新数据 if len(records) > 0 { if err := ctrl.yxVolunteerRecordService.BatchCreate(records); err != nil { common.Error(c, 500, "保存失败: "+err.Error()) return } } common.Success(c, "保存成功") } // GetVolunteerDetail 获取当前志愿单详情 // @Summary 获取当前志愿单详情 // @Tags 用户志愿 // @Success 200 {object} common.Response // @Router /user/volunteer/detail [get] func (ctrl *UserVolunteerController) GetVolunteerDetail(c *gin.Context) { loginUserId := common.GetLoginUser(c).ID userScoreVO, err := ctrl.userScoreService.GetActiveByID(loginUserId) if err != nil { common.Error(c, 500, err.Error()) return } // 查找当前激活的志愿表 volunteer, err := ctrl.yxVolunteerService.FindActiveByScoreId(userScoreVO.ID) if err != nil { common.Error(c, 500, "查找志愿表失败: "+err.Error()) return } if volunteer == nil || volunteer.ID == "" { common.Success(c, nil) // No volunteer record found return } records, err := ctrl.yxVolunteerRecordService.FindByVolunteerID(volunteer.ID) if err != nil { common.Error(c, 500, "查找志愿明细失败: "+err.Error()) return } // Fetch enriched details var enrichedMajors map[string]yxDto.SchoolMajorDTO if len(records) > 0 && userScoreVO.CalculationTableName != "" { keys := make([]string, 0, len(records)) for _, r := range records { keys = append(keys, r.SchoolCode+"_"+r.MajorCode+"_"+r.EnrollmentCode) } majors, err := ctrl.yxCalculationMajorService.FindDtoListByCompositeKeys(userScoreVO.CalculationTableName, keys, userScoreVO.ID) if err == nil { enrichedMajors = make(map[string]yxDto.SchoolMajorDTO) for _, m := range majors { // Key by composite key as ID matches record's logic (or use ID if record stores correct ID) // Record has CalculationMajorID, but DTO also has ID. Let's use ID if reliable, else composite. // FindDtoListByCompositeKeys returns items where ID should match. enrichedMajors[m.SchoolCode+"_"+m.MajorCode+"_"+m.EnrollmentCode] = m } } } // Grouping // Response structure: volunteer info + grouped items type VolunteerDetailItem struct { entity.YxVolunteerRecord SchoolName string `json:"schoolName"` MajorName string `json:"majorName"` PlanNum int `json:"planNum"` Tuition string `json:"tuition"` SchoolIcon string `json:"schoolIcon"` Province string `json:"province"` SchoolNature string `json:"schoolNature"` InstitutionType string `json:"institutionType"` MajorDetail string `json:"majorDetail"` // from detail } groupedItems := map[string][]VolunteerDetailItem{ "提前批": {}, "本科批": {}, "专科批": {}, } for _, r := range records { item := VolunteerDetailItem{ YxVolunteerRecord: r, } key := r.SchoolCode + "_" + r.MajorCode + "_" + r.EnrollmentCode if m, ok := enrichedMajors[key]; ok { item.SchoolName = m.SchoolName item.MajorName = m.MajorName item.PlanNum = m.PlanNum item.Tuition = m.Tuition // DTO doesn't have icon? Check DTO definition. // SchoolMajorDTO in step 150 sql selects school_icon. But DTO struct (step 6) might not have it. // Checking DTO definition in step 6... It does NOT have SchoolIcon. // I need to update DTO definition if I want SchoolIcon. // For now, let's omit if not in DTO or update DTO. // Wait, simple fix: update DTO struct later. For now map what matches. item.Province = m.Province item.SchoolNature = m.SchoolNature item.InstitutionType = m.InstitutionType item.MajorDetail = m.Detail } // Map batch // Batch might be "本科提前批", "本科A段" etc. Need to normalize to 3 buckets? // Or just use the batch string from record/major? // User said "志愿明细(专科批,本科批,提前批)". // If data has "本科A段", where does it go? "本科批"? // I'll assume exact match or simple containment. // If specific batches exist in data like "本科A段", "本科B段", they go to "本科批"? // Let's use simple logic: groupKey := "" if r.Batch == "提前批" || r.Batch == "本科提前批" { groupKey = "提前批" } else if r.Batch == "高职高专" || r.Batch == "专科批" { groupKey = "专科批" } else { groupKey = "本科批" } groupedItems[groupKey] = append(groupedItems[groupKey], item) } // Sort items by Indexs in each group? Records are already ordered by Indexs globally. // Within group, they should follow Indexs order naturally if iterated in order. common.Success(c, map[string]interface{}{ "volunteer": volunteer, "items": groupedItems, }) }