520 lines
18 KiB
Go
520 lines
18 KiB
Go
// 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 {
|
||
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("专业类型错误")
|
||
}
|
||
|
||
// 根据批次类型设置批次 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
|
||
}
|
||
|
||
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) FindListByCompositeKeys(tableName string, keys []string, scoreId string) ([]entity.YxCalculationMajor, error) {
|
||
return s.mapper.FindListByCompositeKeys(tableName, keys, scoreId)
|
||
}
|
||
|
||
func (s *YxCalculationMajorService) FindDtoListByCompositeKeys(tableName string, keys []string, scoreId string) ([]dto.SchoolMajorDTO, error) {
|
||
return s.mapper.FindDtoListByCompositeKeys(tableName, keys, 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)
|
||
}
|
||
|
||
func (s *YxCalculationMajorService) DeleteByScoreIDFromTable(tableName, scoreID string) error {
|
||
return s.mapper.DeleteByScoreIDFromTable(tableName, 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 !calc.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 !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)
|
||
}
|
||
}
|
||
|
||
// log time...
|
||
}
|