// Package service 业务逻辑层 package service import ( "fmt" "server/common" "server/modules/user/vo" "server/modules/yx/dto" yxDto "server/modules/yx/dto" "server/modules/yx/entity" "server/modules/yx/mapper" "strings" "time" "github.com/google/uuid" ) type YxCalculationMajorService struct { historyMajorEnrollService *YxHistoryMajorEnrollService mapper *mapper.YxCalculationMajorMapper historyScoreControlLineService *YxHistoryScoreControlLineService } func (s *YxCalculationMajorService) RecommendMajorList(schoolMajorQuery yxDto.SchoolMajorQuery) ([]yxDto.UserMajorDTO, int64, dto.ProbabilityCountDTO, error) { if schoolMajorQuery.UserScoreVO.ProfessionalCategory == "" { return nil, 0, dto.ProbabilityCountDTO{}, fmt.Errorf("专业类型错误") } if schoolMajorQuery.Batch != "" { schoolMajorQuery.Batch = strings.ReplaceAll(schoolMajorQuery.Batch, "批", "") } // if len(schoolMajorQuery.MajorTypeChildren) > 0 && "高职高专" != schoolMajorQuery.Batch { // if "表演类" == schoolMajorQuery.MajorType { // } // } calculationMajors, total, probCount, err := s.mapper.FindRecommendList(schoolMajorQuery) if err != nil { return nil, 0, dto.ProbabilityCountDTO{}, err } // 为专业列表添加历史数据 startTime := time.Now() err = s.UserMajorDTOGetHistory(&calculationMajors) endTime := time.Now() // 执行时长 queryCostTime := endTime.Sub(startTime) fmt.Printf(" 历史数据查询耗时:%v\n", queryCostTime) if err != nil { return nil, 0, dto.ProbabilityCountDTO{}, err } return calculationMajors, total, probCount, nil } func (s *YxCalculationMajorService) BatchCreateBySchoolMajorDTO(tableName string, items []dto.SchoolMajorDTO, scoreID string) error { entities := make([]entity.YxCalculationMajor, 0, len(items)) now := time.Now() for _, item := range items { // 构建 OtherScoreLimitation var otherScoreLimitation strings.Builder if item.ChineseScoreLimitation > 0 { otherScoreLimitation.WriteString(fmt.Sprintf("语文成绩不低于%.1f分,", item.ChineseScoreLimitation)) } if item.EnglishScoreLimitation > 0 { otherScoreLimitation.WriteString(fmt.Sprintf("外语成绩不低于%.1f分,", item.EnglishScoreLimitation)) } if item.CulturalScoreLimitation > 0 { otherScoreLimitation.WriteString(fmt.Sprintf("文化成绩不低于%.1f分,", item.CulturalScoreLimitation)) } if item.ProfessionalScoreLimitation > 0 { otherScoreLimitation.WriteString(fmt.Sprintf("专业成绩不低于%.1f分,", item.ProfessionalScoreLimitation)) } otherScoreLimitationStr := otherScoreLimitation.String() if len(otherScoreLimitationStr) > 0 { otherScoreLimitationStr = otherScoreLimitationStr[:len(otherScoreLimitationStr)-1] } entities = append(entities, entity.YxCalculationMajor{ ScoreID: scoreID, SchoolCode: item.SchoolCode, MajorCode: item.MajorCode, MajorName: item.MajorName, EnrollmentCode: item.EnrollmentCode, Tuition: item.Tuition, Detail: item.Detail, Category: item.Category, RulesEnrollProbability: item.RulesEnrollProbability, Batch: item.Batch, StudentOldConvertedScore: item.StudentScore, StudentConvertedScore: item.StudentConvertedScore, EnrollProbability: item.EnrollProbability, ProbabilityOperator: item.ProbabilityOperator, CreateTime: now, MajorType: item.MajorType, MajorTypeChild: item.MajorTypeChild, PlanNum: item.PlanNum, MainSubjects: item.MainSubjects, Limitation: item.Limitation, OtherScoreLimitation: otherScoreLimitationStr, RulesEnrollProbabilitySx: item.RulesEnrollProbabilitySx, Kslx: item.Kslx, PrivateStudentConvertedScore: item.PrivateStudentScore, PrivateRulesEnrollProbability: item.PrivateRulesEnrollProbability, PrivateProbabilityOperator: item.PrivateProbabilityOperator, State: item.State, }) } return s.BatchCreate(tableName, entities) } func NewYxCalculationMajorService() *YxCalculationMajorService { return &YxCalculationMajorService{ historyMajorEnrollService: NewYxHistoryMajorEnrollService(), mapper: mapper.NewYxCalculationMajorMapper(), historyScoreControlLineService: NewYxHistoryScoreControlLineService(), } } func (s *YxCalculationMajorService) List(page, size int) ([]entity.YxCalculationMajor, int64, error) { return s.mapper.FindAll(page, size) } func (s *YxCalculationMajorService) GetByID(id string) (*entity.YxCalculationMajor, error) { return s.mapper.FindByID(id) } func (s *YxCalculationMajorService) Create(item *entity.YxCalculationMajor) error { item.ID = uuid.New().String() return s.mapper.Create(item) } func (s *YxCalculationMajorService) Update(item *entity.YxCalculationMajor) error { return s.mapper.Update(item) } func (s *YxCalculationMajorService) UpdateFields(id string, fields map[string]interface{}) error { return s.mapper.UpdateFields(id, fields) } func (s *YxCalculationMajorService) Delete(id string) error { return s.mapper.Delete(id) } func (s *YxCalculationMajorService) GetByScoreID(scoreID string) ([]entity.YxCalculationMajor, error) { return s.mapper.FindByScoreID(scoreID) } func (s *YxCalculationMajorService) BatchCreate(tableName string, items []entity.YxCalculationMajor) error { for i := range items { items[i].ID = uuid.New().String() } return s.mapper.BatchCreate(tableName, items, 100) } func (s *YxCalculationMajorService) BatchUpdate(items []entity.YxCalculationMajor) error { return s.mapper.BatchUpdate(items) } func (s *YxCalculationMajorService) BatchUpsert(items []entity.YxCalculationMajor, updateColumns []string) error { for i := range items { if items[i].ID == "" { items[i].ID = uuid.New().String() } } return s.mapper.BatchUpsert(items, updateColumns) } func (s *YxCalculationMajorService) BatchDelete(ids []string) error { return s.mapper.BatchDelete(ids) } func (s *YxCalculationMajorService) DeleteByScoreID(scoreID string) error { return s.mapper.DeleteByScoreID(scoreID) } // 函数名 根据用户查询类型获取专业列表 // 详细描述(可选) // // 参数说明: // // professionalCategory - 专业分类 // cognitioPolyclinic - 文理文科 // professionalCategoryChildren - 专业分类子项 // // 返回值说明: // // 返回值类型 - 返回值描述 func (s *YxCalculationMajorService) ListByUserQueryType(professionalCategory string, cognitioPolyclinic string, professionalCategoryChildren []string) ([]dto.SchoolMajorDTO, error) { // 构造查询条件 query := dto.SchoolMajorQuery{ MajorType: professionalCategory, Category: cognitioPolyclinic, // MainSubjects: "器乐", // MajorTypeChildren: []string{ // "音乐教育", // }, } // 执行院校查询 majorItems, err := mapper.NewYxSchoolMajorMapper().SelectSchoolMajor(query) if err != nil { return nil, err } // 分别收集专业名称和院校代码集合(去重) majorNameSet := make(map[string]bool) schoolCodeSet := make(map[string]bool) years := common.OldYearList for _, dto := range majorItems { majorNameSet[dto.MajorName] = true schoolCodeSet[dto.SchoolCode] = true } // 转换为切片用于查询 majorNames := make([]string, 0, len(majorNameSet)) schoolCodes := make([]string, 0, len(schoolCodeSet)) for name := range majorNameSet { majorNames = append(majorNames, name) } for code := range schoolCodeSet { schoolCodes = append(schoolCodes, code) } // 执行查询院校专业的历年数据 - 类似Java中的in查询 historyItems, err := s.historyMajorEnrollService.ListBySchoolCodesAndMajorNames( schoolCodes, majorNames, query.Category, // 文科/理科 query.MajorType, // 专业类型 years, // 年份 ) if err != nil { return nil, err } // 构建历史数据映射:schoolCode_majorName_batch_year -> historyItem allHistoryMajorEnrollMap := make(map[string]entity.YxHistoryMajorEnroll) for _, historyItem := range historyItems { key := historyItem.SchoolCode + "_" + historyItem.MajorName + "_" + historyItem.Batch + "_" + historyItem.Year allHistoryMajorEnrollMap[key] = historyItem } // 将历史数据填充到每个专业数据中 for i, majorItem := range majorItems { // 为每个majorItem创建独立的历史数据映射 historyMap := make(map[string]dto.YxHistoryMajorEnrollDTO) for _, year := range years { key := majorItem.SchoolCode + "_" + majorItem.MajorName + "_" + majorItem.Batch + "_" + year if historyItem, ok := allHistoryMajorEnrollMap[key]; ok { // 类型转换:entity -> dto dtoItem := dto.YxHistoryMajorEnrollDTO{ Year: historyItem.Year, EnrollmentCode: historyItem.EnrollmentCode, RulesEnrollProbability: historyItem.RulesEnrollProbability, ProbabilityOperator: historyItem.ProbabilityOperator, AdmissionLine: historyItem.AdmissionLine, ControlLine: historyItem.ControlLine, // 复制其他需要的字段 } historyMap[year] = dtoItem } } majorItems[i].HistoryMajorEnrollMap = historyMap } return majorItems, nil } func (s *YxCalculationMajorService) UserMajorDTOGetHistory(userMajorDTOList *[]dto.UserMajorDTO) error { if len(*userMajorDTOList) > 0 { // 分别收集专业名称和院校代码集合(去重) majorNameSet := make(map[string]bool) schoolCodeSet := make(map[string]bool) years := common.OldYearList for _, dto := range *userMajorDTOList { majorNameSet[dto.MajorName] = true schoolCodeSet[dto.SchoolCode] = true } // 转换为切片用于查询 majorNames := make([]string, 0, len(majorNameSet)) schoolCodes := make([]string, 0, len(schoolCodeSet)) for name := range majorNameSet { majorNames = append(majorNames, name) } for code := range schoolCodeSet { schoolCodes = append(schoolCodes, code) } // 执行查询院校专业的历年数据 - 类似Java中的in查询 historyItems, err := s.historyMajorEnrollService.ListBySchoolCodesAndMajorNames( schoolCodes, majorNames, (*userMajorDTOList)[0].Category, // 文科/理科 (*userMajorDTOList)[0].MajorType, // 专业类型 years, // 年份 ) if err != nil { return nil } // 构建历史数据映射:schoolCode_majorName_batch_year -> historyItem allHistoryMajorEnrollMap := make(map[string]entity.YxHistoryMajorEnroll) for _, historyItem := range historyItems { key := historyItem.SchoolCode + "_" + historyItem.MajorName + "_" + historyItem.Batch + "_" + historyItem.Year allHistoryMajorEnrollMap[key] = historyItem } // 将历史数据填充到每个专业数据中 for i, majorItem := range *userMajorDTOList { // 为每个majorItem创建独立的历史数据映射 historyMap := make(map[string]dto.YxHistoryMajorEnrollDTO) for _, year := range years { key := majorItem.SchoolCode + "_" + majorItem.MajorName + "_" + majorItem.Batch + "_" + year if historyItem, ok := allHistoryMajorEnrollMap[key]; ok { // 类型转换:entity -> dto dtoItem := dto.YxHistoryMajorEnrollDTO{ Year: historyItem.Year, EnrollmentCode: historyItem.EnrollmentCode, RulesEnrollProbability: historyItem.RulesEnrollProbability, ProbabilityOperator: historyItem.ProbabilityOperator, AdmissionLine: historyItem.AdmissionLine, ControlLine: historyItem.ControlLine, // 复制其他需要的字段 } historyMap[year] = dtoItem } } (*userMajorDTOList)[i].HistoryMajorEnrollMap = historyMap } } return nil } // 函数名 给专业列表计算录取率 // 详细描述(可选) // // 参数说明: // // schoolMajorDTOList - 专业列表 // professionalCategory - 专业分类 // cognitioPolyclinic - 文理文科 // professionalCategoryChildren - 专业分类子项 // // 返回值说明: // // 返回值类型 - 返回值描述 func (s *YxCalculationMajorService) CheckEnrollProbability(schoolMajorDTOList *[]dto.SchoolMajorDTO, userScoreVO vo.UserScoreVO) error { professionalCategory := userScoreVO.ProfessionalCategory if "表演类" == professionalCategory { // TODO: biaoyanService } else if "音乐类" == professionalCategory { // TODO: musicService } else { s.betaRecommendMajorListSetEnrollProbability(schoolMajorDTOList, userScoreVO) } return nil } // betaRecommendMajorListSetEnrollProbability 美术与设计类,书法类,体育类 按这个走 获取录取率 func (s *YxCalculationMajorService) betaRecommendMajorListSetEnrollProbability(recommendMajorList *[]dto.SchoolMajorDTO, userScoreVO vo.UserScoreVO) { if recommendMajorList == nil || len(*recommendMajorList) == 0 { return } professionalCategory := userScoreVO.ProfessionalCategory nowBatch := "本科" // TODO 默认为本科,需根据实际情况获取,Java中是从 userScore 获取,这里 VO 中似乎没有 Batch? 假设为本科或从 VO 获取 // userScoreVO.Batch? 检查 VO 定义 // 假设 userScoreVO 没有 Batch,需要确认。Entity YxUserScore 有 Batch。VO 可能需要补充。 // 暂时假设为 "本科" 或 "" // 获取省控线 Map historyScoreControlLineMap, err := s.historyScoreControlLineService.MapsBatchByProfessionalCategoryOfYear(common.NowYear, professionalCategory, userScoreVO.CognitioPolyclinic) if err != nil { // Log error return } culturalScore := userScoreVO.CulturalScore professionalScore := userScoreVO.ProfessionalScore for i := range *recommendMajorList { item := &(*recommendMajorList)[i] rulesEnrollProbability := item.PrivateRulesEnrollProbability probabilityOperator := item.PrivateProbabilityOperator // 获取对应批次的省控线 controlLineData, ok := historyScoreControlLineMap[item.Batch] if !ok { // 尝试默认批次 if val, okDefault := historyScoreControlLineMap["本科"]; okDefault { controlLineData = val } else { continue // 没有省控线无法计算 } } culturalControlLine := controlLineData.CulturalScore specialControlLine := controlLineData.SpecialScore if rulesEnrollProbability == "" { continue } // 补全 probabilityOperator 逻辑 if rulesEnrollProbability == "文过专排" && probabilityOperator == "" { probabilityOperator = "文*0+专*1" } else if rulesEnrollProbability == "专过文排" && probabilityOperator == "" { probabilityOperator = "文*1+专*0" } if probabilityOperator == "" { item.EnrollProbability = common.Number5 continue } // 判断其他录取要求 if !OtherScoreJudge(professionalScore, userScoreVO, *item) { item.EnrollProbability = common.Number0 continue } // 25年专业录取原则变动 (体育类特殊逻辑,硬编码 ID 列表) if item.MajorType == "体育类" { specialSchoolCodes := []string{"6530", "6085", "6110", "6065", "6050"} isSpecial := false for _, code := range specialSchoolCodes { if item.SchoolCode == code { isSpecial = true break } } if isSpecial { item.EnrollProbability = common.Number0 continue } } // 判断是否过省控线 if !CrossingControlLine(rulesEnrollProbability, culturalScore, professionalScore, culturalControlLine, specialControlLine) { item.EnrollProbability = common.Number0 continue } // 计算学生折合分 studentScore := ConvertIntoScore(rulesEnrollProbability, culturalScore, professionalScore, probabilityOperator) item.PrivateStudentScore = studentScore item.StudentScore = studentScore // 展示用 // 权限检查 if !HasComputeEnrollProbabilityPermissions(nowBatch, item.Batch) { item.EnrollProbability = common.Number0 continue } // 录取方式计算 if common.CulturalControlLineGuoMain == rulesEnrollProbability { if len(item.HistoryMajorEnrollList) == 0 { item.EnrollProbability = common.Number0 continue } item.EnrollProbability = (studentScore * item.HistoryMajorEnrollList[0].AdmissionLine) * common.Number0p75 if studentScore >= item.HistoryMajorEnrollList[0].AdmissionLine { item.EnrollProbability *= common.Number0p5 } continue } else { // 当前年省控线 折合后 nowYearProvincialControlLine := ConvertIntoScore(rulesEnrollProbability, culturalControlLine, specialControlLine, probabilityOperator) if nowYearProvincialControlLine <= 0 { item.EnrollProbability = common.Number0 continue } // 历年分差 diffMap := ComputeHistoryMajorEnrollScoreLineDifferenceWithRulesEnrollProbability(item.MajorType, rulesEnrollProbability, probabilityOperator, item.HistoryMajorEnrollMap) historyThreeYearDiff := diffMap["scoreDifference"].(float64) if historyThreeYearDiff == 0 { item.EnrollProbability = common.Number0 continue } // 当前年线差 nowYearDiff := studentScore - nowYearProvincialControlLine // 计算录取率 enrollProbability := CommonCheckEnrollProbability(nowYearDiff, historyThreeYearDiff) item.EnrollProbability = CommonCheckEnrollProbabilityBeilv(enrollProbability) } } // log time... }