golang-yitisheng-server/server/modules/yx/service/yx_calculation_major_servic...

446 lines
16 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

// Package service 业务逻辑层
package service
import (
"fmt"
"server/common"
calc "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 {
*common.BaseService[entity.YxCalculationMajor]
historyMajorEnrollService *YxHistoryMajorEnrollService
mapper *mapper.YxCalculationMajorMapper
historyScoreControlLineService *YxHistoryScoreControlLineService
}
func NewYxCalculationMajorService() *YxCalculationMajorService {
mapper := mapper.NewYxCalculationMajorMapper()
return &YxCalculationMajorService{
BaseService: common.NewBaseService[entity.YxCalculationMajor](),
historyMajorEnrollService: NewYxHistoryMajorEnrollService(),
mapper: mapper,
historyScoreControlLineService: NewYxHistoryScoreControlLineService(),
}
}
// RecommendMajorList 推荐专业列表
func (s *YxCalculationMajorService) RecommendMajorList(schoolMajorQuery yxDto.SchoolMajorQuery) ([]yxDto.UserMajorDTO, int64, dto.ProbabilityCountDTO, error) {
if schoolMajorQuery.UserScoreVO.ProfessionalCategory == "" {
return nil, 0, dto.ProbabilityCountDTO{}, fmt.Errorf("专业类型错误")
}
// 根据批次类型设置批次 985/211/双一流 -> 提前批, 公办本科 -> 本科A段, 民办本科 -> 本科B段, 体育类 -> 本科
if schoolMajorQuery.Batch != "" && "本科提前" == schoolMajorQuery.Batch {
return []yxDto.UserMajorDTO{}, 0, dto.ProbabilityCountDTO{}, nil
} else if schoolMajorQuery.Batch != "" && "高职高专" != schoolMajorQuery.Batch {
if schoolMajorQuery.Batch2 == "双一流" {
schoolMajorQuery.Batch = "提前批"
} else if schoolMajorQuery.Batch2 == "公办本科" {
schoolMajorQuery.Batch = "本科A段"
} else if schoolMajorQuery.Batch2 == "民办本科" {
schoolMajorQuery.Batch = "本科B段"
} else if schoolMajorQuery.MajorType == "体育类" {
schoolMajorQuery.Batch = "本科"
} else {
schoolMajorQuery.Batch = ""
}
} else {
schoolMajorQuery.Batch = "高职高专"
}
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
}
// BatchCreateBySchoolMajorDTO 根据专业 DTO 批量创建
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)
}
// GetByScoreID 根据 scoreID 获取计算专业列表
func (s *YxCalculationMajorService) GetByScoreID(scoreID string) ([]entity.YxCalculationMajor, error) {
return s.mapper.FindByScoreID(scoreID)
}
// FindListByCompositeKeys 根据复合键查找列表
func (s *YxCalculationMajorService) FindListByCompositeKeys(tableName string, keys []string, scoreId string) ([]entity.YxCalculationMajor, error) {
return s.mapper.FindListByCompositeKeys(tableName, keys, scoreId)
}
// FindDtoListByCompositeKeys 根据复合键查找 DTO 列表
func (s *YxCalculationMajorService) FindDtoListByCompositeKeys(tableName string, keys []string, scoreId string) ([]dto.SchoolMajorDTO, error) {
return s.mapper.FindDtoListByCompositeKeys(tableName, keys, scoreId)
}
// BatchCreate 批量创建(支持动态表名,使用 UUID 生成 ID
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)
}
// DeleteByScoreID 根据 scoreID 删除
func (s *YxCalculationMajorService) DeleteByScoreID(scoreID string) error {
return s.mapper.DeleteByScoreID(scoreID)
}
// DeleteByScoreIDFromTable 从指定表删除 scoreID 对应的数据
func (s *YxCalculationMajorService) DeleteByScoreIDFromTable(tableName, scoreID string) error {
return s.mapper.DeleteByScoreIDFromTable(tableName, scoreID)
}
// ListByUserQueryType 根据用户查询类型获取专业列表
func (s *YxCalculationMajorService) ListByUserQueryType(professionalCategory string, cognitioPolyclinic string,
professionalCategoryChildren []string) ([]dto.SchoolMajorDTO, error) {
// 构造查询条件
query := dto.SchoolMajorQuery{
MajorType: professionalCategory,
Category: cognitioPolyclinic,
}
// 执行院校查询
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)
}
// 执行查询院校专业的历年数据
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 {
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
}
// UserMajorDTOGetHistory 获取用户专业 DTO 的历史数据
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)
}
// 执行查询院校专业的历年数据
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 {
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
}
// CheckEnrollProbability 计算专业列表录取率
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 := "本科"
// 获取省控线 Map
historyScoreControlLineMap, err := s.historyScoreControlLineService.MapsBatchByProfessionalCategoryOfYear(common.NowYear, professionalCategory, userScoreVO.CognitioPolyclinic)
if err != nil {
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 !calc.OtherScoreJudge(professionalScore, userScoreVO, *item) {
item.EnrollProbability = common.Number0
continue
}
// 25年专业录取原则变动 (体育类特殊逻辑)
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 !calc.CrossingControlLine(rulesEnrollProbability, culturalScore, professionalScore, culturalControlLine, specialControlLine) {
item.EnrollProbability = common.Number0
continue
}
// 计算学生折合分
studentScore := calc.ConvertIntoScore(rulesEnrollProbability, culturalScore, professionalScore, probabilityOperator)
item.PrivateStudentScore = studentScore
item.StudentScore = studentScore
// 权限检查
if !calc.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 := calc.ConvertIntoScore(rulesEnrollProbability, culturalControlLine, specialControlLine, probabilityOperator)
if nowYearProvincialControlLine <= 0 {
item.EnrollProbability = common.Number0
continue
}
diffMap := calc.ComputeHistoryMajorEnrollScoreLineDifferenceWithRulesEnrollProbability(item.MajorType, rulesEnrollProbability, probabilityOperator, item.HistoryMajorEnrollMap)
historyThreeYearDiff := diffMap["scoreDifference"].(float64)
if historyThreeYearDiff == 0 {
item.EnrollProbability = common.Number0
continue
}
nowYearDiff := studentScore - nowYearProvincialControlLine
enrollProbability := calc.CommonCheckEnrollProbability(nowYearDiff, historyThreeYearDiff)
item.EnrollProbability = calc.CommonCheckEnrollProbabilityBeilv(enrollProbability)
}
}
}