This commit is contained in:
zhouwentao 2026-01-02 12:19:33 +08:00
parent 9b72804e7b
commit ad15710c09
5 changed files with 176 additions and 45 deletions

View File

@ -1,6 +1,8 @@
package dto package dto
import "server/modules/user/vo" import (
"server/modules/user/vo"
)
// RecommendMajorListRequest 推荐专业列表请求 // RecommendMajorListRequest 推荐专业列表请求
type RecommendMajorListRequest struct { type RecommendMajorListRequest struct {

View File

@ -118,19 +118,26 @@ func (s *UserScoreService) SaveUserScore(req *dto.SaveScoreRequest) (vo.UserScor
if err := req.Validate(); err != nil { if err := req.Validate(); err != nil {
return vo.UserScoreVO{}, err return vo.UserScoreVO{}, err
} }
// 2. DTO 转 Entity // 2. DTO 转 Entity
entityItem := s.convertDtoToEntity(req) entityItem := s.convertDtoToEntity(req)
entityItem.CalculationTableName = "yx_calculation_major_2026"
entityItem.ID = common.GenerateStringID() // 使用新封装的 ID 生成工具 entityItem.ID = common.GenerateStringID() // 使用新封装的 ID 生成工具
entityItem.CreateTime = time.Now() entityItem.CreateTime = time.Now()
entityItem.UpdateTime = time.Now() entityItem.UpdateTime = time.Now()
// 3. 执行保存操作(可以包含事务) // 3. 执行保存操作(可以包含事务)
tx := config.DB.Begin() tx := config.DB.Begin()
defer func() { defer func() {
if r := recover(); r != nil { if r := recover(); r != nil {
fmt.Printf("【PANIC】事务执行过程中发生panic: %v", r)
// 记录详细的栈信息
fmt.Printf("【PANIC】尝试回滚事务")
tx.Rollback() tx.Rollback()
fmt.Printf("【PANIC】事务已回滚")
} }
}() }()
entityItem.ID = common.GenerateStringID() // 使用新封装的 ID 生成工具
// 标记该用户的所有旧成绩为历史状态 // 标记该用户的所有旧成绩为历史状态
if err := tx.Model(&entity.YxUserScore{}). if err := tx.Model(&entity.YxUserScore{}).
Where("create_by = ? AND state = ?", req.CreateBy, "1"). Where("create_by = ? AND state = ?", req.CreateBy, "1").
@ -138,15 +145,23 @@ func (s *UserScoreService) SaveUserScore(req *dto.SaveScoreRequest) (vo.UserScor
tx.Rollback() tx.Rollback()
return vo.UserScoreVO{}, fmt.Errorf("更新旧记录失败: %w", err) return vo.UserScoreVO{}, fmt.Errorf("更新旧记录失败: %w", err)
} }
// 保存新的成绩记录 // 保存新的成绩记录
if err := tx.Create(entityItem).Error; err != nil { if err := tx.Create(entityItem).Error; err != nil {
fmt.Errorf("保存记录失败: %w", err)
tx.Rollback() tx.Rollback()
return vo.UserScoreVO{}, fmt.Errorf("保存记录失败: %w", err) return vo.UserScoreVO{}, fmt.Errorf("保存记录失败: %w", err)
} }
userScoreVO := s.convertEntityToVo(*entityItem)
// 提交事务 - ✅ 快速释放数据库连接
// if err := tx.Commit().Error; err != nil {
// return vo.UserScoreVO{}, fmt.Errorf("提交事务失败: %w", err)
// }
userScoreVO := s.convertEntityToVo(entityItem)
// 根据成绩计算用户的专业信息 // 根据成绩计算用户的专业信息
schoolMajorItems, err := s.yxCalculationMajorService.ListByUserQueryType("美术与设计类", "文科", []string{}) schoolMajorItems, err := s.yxCalculationMajorService.ListByUserQueryType(userScoreVO.ProfessionalCategory,
userScoreVO.CognitioPolyclinic, userScoreVO.ProfessionalCategoryChildren)
if err != nil { if err != nil {
tx.Rollback() tx.Rollback()
return vo.UserScoreVO{}, fmt.Errorf("查询专业信息失败: %w", err) return vo.UserScoreVO{}, fmt.Errorf("查询专业信息失败: %w", err)
@ -172,7 +187,7 @@ func (s *UserScoreService) SaveUserScore(req *dto.SaveScoreRequest) (vo.UserScor
} }
// 私有方法DTO 转 Entity // 私有方法DTO 转 Entity
func (s *UserScoreService) convertDtoToEntity(req *dto.SaveScoreRequest) entity.YxUserScore { func (s *UserScoreService) convertDtoToEntity(req *dto.SaveScoreRequest) *entity.YxUserScore {
entityItem := entity.YxUserScore{ entityItem := entity.YxUserScore{
CognitioPolyclinic: req.CognitioPolyclinic, CognitioPolyclinic: req.CognitioPolyclinic,
Subjects: strings.Join(req.SubjectList, ","), Subjects: strings.Join(req.SubjectList, ","),
@ -207,7 +222,7 @@ func (s *UserScoreService) convertDtoToEntity(req *dto.SaveScoreRequest) entity.
entityItem.Fzby = v entityItem.Fzby = v
} }
return entityItem return &entityItem
} }
// 私有方法Entity 转 VO // 私有方法Entity 转 VO
@ -226,6 +241,7 @@ func (s *UserScoreService) convertEntityToVo(item entity.YxUserScore) vo.UserSco
ChineseScore: item.ChineseScore, ChineseScore: item.ChineseScore,
Province: item.Province, Province: item.Province,
State: item.State, State: item.State,
CalculationTableName: item.CalculationTableName,
} }
if item.Subjects == "" { if item.Subjects == "" {
voItem.SubjectList = []string{} voItem.SubjectList = []string{}

View File

@ -5,6 +5,41 @@ import (
"server/modules/yx/entity" "server/modules/yx/entity"
) )
type UserMajorDTO struct {
SchoolCode string `json:"schoolCode"`
SchoolName string `json:"schoolName"`
MajorCode string `json:"majorCode"`
MajorName string `json:"majorName"`
MajorType string `json:"majorType"`
MajorTypeChild string `json:"majorTypeChild"`
PlanNum int `json:"planNum"`
MainSubjects string `json:"mainSubjects"`
Limitation string `json:"limitation"`
ChineseScoreLimitation float64 `json:"chineseScoreLimitation"`
EnglishScoreLimitation float64 `json:"englishScoreLimitation"`
CulturalScoreLimitation float64 `json:"culturalScoreLimitation"`
ProfessionalScoreLimitation float64 `json:"professionalScoreLimitation"`
EnrollmentCode string `json:"enrollmentCode"`
Tuition string `json:"tuition"`
Detail string `json:"detail"`
Category string `json:"category"`
Batch string `json:"batch"`
RulesEnrollProbability string `json:"rulesEnrollProbability"`
ProbabilityOperator string `json:"probabilityOperator"`
// PrivateRulesEnrollProbability string `json:"privateRulesEnrollProbability"`
// PrivateProbabilityOperator string `json:"privateProbabilityOperator"`
RulesEnrollProbabilitySx string `json:"rulesEnrollProbabilitySx"`
Kslx string `json:"kslx"`
State string `json:"state"`
HistoryMajorEnrollMap map[string]YxHistoryMajorEnrollDTO `json:"historyMajorEnrollMap"`
// 计算相关字段 (非数据库直接映射)
EnrollProbability float64 `json:"enrollProbability"` // 录取率
StudentScore float64 `json:"studentScore"` // 学生折合分
// PrivateStudentScore float64 `json:"privateStudentScore"` // 学生折合分(私有)
// StudentConvertedScore float64 `json:"studentConvertedScore"` // 学生折合分(转换后)
// FirstLevelDiscipline string `json:"firstLevelDiscipline"` // 一级学科 (需确认来源)
}
// SchoolMajorDTO 院校专业查询结果 DTO // SchoolMajorDTO 院校专业查询结果 DTO
type SchoolMajorDTO struct { type SchoolMajorDTO struct {
SchoolCode string `json:"schoolCode"` SchoolCode string `json:"schoolCode"`

View File

@ -26,47 +26,57 @@ func (m *YxCalculationMajorMapper) FindAll(page, size int) ([]entity.YxCalculati
return items, total, err return items, total, err
} }
func (m *YxCalculationMajorMapper) FindRecommendList(query dto.SchoolMajorQuery) ([]entity.YxCalculationMajor, int64, error) { func (m *YxCalculationMajorMapper) FindRecommendList(query dto.SchoolMajorQuery) ([]dto.UserMajorDTO, int64, error) {
var items []entity.YxCalculationMajor var items []dto.UserMajorDTO
var total int64 var total int64
countSQL := ` countSQL := `
SELECT COUNT(cm.id) FROM yx_calculation_major cm SELECT COUNT(cm.id) FROM ? cm
LEFT JOIN (SELECT school_id,school_name,school_code FROM yx_school_child group by school_code) sc ON sc.school_code = cm.school_code LEFT JOIN yx_school_child sc ON sc.school_code = cm.school_code
LEFT JOIN yx_school s ON s.id = sc.school_id LEFT JOIN yx_school_research_teaching srt ON srt.school_id = sc.school_id
LEFT JOIN yx_school s ON s.id = sc.school_id
WHERE 1=1 AND cm.state > 0 WHERE 1=1 AND cm.state > 0
` `
sql := ` sql := `
SELECT SELECT
sc.school_code, cm.id,
sc.school_name, s.school_name,
s.school_icon,
cm.state,
cm.school_code,
cm.major_code, cm.major_code,
cm.major_name, cm.major_name,
cm.enrollment_code,
cm.tuition,
cm.detail as majorDetail,
cm.category,
cm.batch,
cm.private_student_converted_score as privateStudentScore,
cm.student_old_converted_score as studentScore,
cm.student_converted_score,
cm.enroll_probability,
cm.rules_enroll_probability_sx,
cm.rules_enroll_probability,
cm.probability_operator,
cm.major_type, cm.major_type,
cm.major_type_child, cm.major_type_child,
cm.plan_num, cm.plan_num,
cm.main_subjects, cm.main_subjects,
cm.limitation, cm.limitation,
cm.other_score_limitation, cm.other_score_limitation,
cm.enrollment_code, s.province as province,
cm.tuition, s.school_nature as schoolNature,
cm.detail, s.institution_type as institutionType
cm.category, FROM ? cm
cm.batch, LEFT JOIN yx_school_child sc ON sc.school_code = cm.school_code
cm.rules_enroll_probability, LEFT JOIN yx_school_research_teaching srt ON srt.school_id = sc.school_id
cm.probability_operator, LEFT JOIN yx_school s ON s.id = sc.school_id
cm.private_rules_enroll_probability,
cm.private_probability_operator,
cm.rules_enroll_probability_sx,
cm.kslx,
cm.state
FROM yx_calculation_major cm
LEFT JOIN (SELECT school_id,school_name,school_code FROM yx_school_child group by school_code) sc ON sc.school_code = cm.school_code
LEFT JOIN yx_school s ON s.id = sc.school_id
WHERE 1=1 AND cm.state > 0 WHERE 1=1 AND cm.state > 0
` `
params := []interface{}{} params := []interface{}{}
params = append(params, query.UserScoreVO.CalculationTableName)
if query.UserScoreVO.ID != "" { if query.UserScoreVO.ID != "" {
countSQL += " AND cm.score_id = ?" countSQL += " AND cm.score_id = ?"
sql += " AND cm.score_id = ?" sql += " AND cm.score_id = ?"
@ -98,6 +108,22 @@ func (m *YxCalculationMajorMapper) FindRecommendList(query dto.SchoolMajorQuery)
params = append(params, query.MainSubjects) params = append(params, query.MainSubjects)
} }
// 录取概率
switch query.Probability {
case "难录取":
countSQL += " AND cm.enroll_probability < 60"
sql += " AND cm.enroll_probability < 60"
case "可冲击":
countSQL += " AND (cm.enroll_probability >= 60 and cm.enroll_probability < 73)"
sql += " AND (cm.enroll_probability >= 60 and cm.enroll_probability < 73)"
case "较稳妥":
countSQL += " AND (cm.enroll_probability >= 73 and cm.enroll_probability < 93)"
sql += " AND (cm.enroll_probability >= 73 and cm.enroll_probability < 93)"
case "可保底":
countSQL += " AND (cm.enroll_probability >= 93)"
sql += " AND (cm.enroll_probability >= 93)"
}
countSQL = strings.Replace(countSQL, "yx_calculation_major", "yx_calculation_major_2025_2", -1) countSQL = strings.Replace(countSQL, "yx_calculation_major", "yx_calculation_major_2025_2", -1)
sql = strings.Replace(sql, "yx_calculation_major", "yx_calculation_major_2025_2", -1) sql = strings.Replace(sql, "yx_calculation_major", "yx_calculation_major_2025_2", -1)

View File

@ -64,11 +64,69 @@ func (m *YxSchoolMajorMapper) BatchDelete(ids []string) error {
return config.DB.Delete(&entity.YxSchoolMajor{}, "id IN ?", ids).Error return config.DB.Delete(&entity.YxSchoolMajor{}, "id IN ?", ids).Error
} }
// func (m *YxSchoolMajorMapper) SelectSchoolMajor(query dto.SchoolMajorQuery) ([]dto.SchoolMajorDTO, error) {
// var items []dto.SchoolMajorDTO
// sql := `
// SELECT
// sm.school_code,
// sc.school_name,
// sm.major_code,
// sm.major_name,
// sm.major_type,
// sm.major_type_child,
// sm.plan_num,
// sm.main_subjects,
// sm.limitation,
// sm.chinese_score_limitation,
// sm.english_score_limitation,
// sm.cultural_score_limitation,
// sm.professional_score_limitation,
// sm.enrollment_code,
// sm.tuition,
// sm.detail,
// sm.category,
// sm.batch,
// sm.rules_enroll_probability,
// sm.probability_operator,
// sm.private_rules_enroll_probability,
// sm.private_probability_operator,
// sm.rules_enroll_probability_sx,
// sm.kslx,
// sm.state
// FROM yx_school_major sm
// LEFT JOIN (SELECT school_id,school_name,school_code FROM yx_school_child group by school_code) sc ON sc.school_code = sm.school_code
// LEFT JOIN yx_school s ON s.id = sc.school_id
// WHERE 1=1 AND sm.state > 0
// `
// params := []interface{}{}
// if query.MajorType != "" {
// sql += " AND sm.major_type = ?"
// params = append(params, query.MajorType)
// }
// if query.Category != "" {
// sql += " AND sm.category = ?"
// params = append(params, query.Category)
// }
// if len(query.MajorTypeChildren) > 0 {
// sql += " AND sm.major_type_child IN ?"
// params = append(params, query.MajorTypeChildren)
// }
// if query.MainSubjects != "" {
// sql += " AND sm.main_subjects = ?"
// params = append(params, query.MainSubjects)
// }
// err := config.DB.Raw(sql, params...).Scan(&items).Error
// return items, err
// }
func (m *YxSchoolMajorMapper) SelectSchoolMajor(query dto.SchoolMajorQuery) ([]dto.SchoolMajorDTO, error) { func (m *YxSchoolMajorMapper) SelectSchoolMajor(query dto.SchoolMajorQuery) ([]dto.SchoolMajorDTO, error) {
var items []dto.SchoolMajorDTO var items []dto.SchoolMajorDTO
sql := ` queryBuilder := config.DB.Table("yx_school_major sm").
SELECT Select(`
sm.school_code, sm.school_code,
sc.school_name, sc.school_name,
sm.major_code, sm.major_code,
@ -94,30 +152,24 @@ func (m *YxSchoolMajorMapper) SelectSchoolMajor(query dto.SchoolMajorQuery) ([]d
sm.rules_enroll_probability_sx, sm.rules_enroll_probability_sx,
sm.kslx, sm.kslx,
sm.state sm.state
FROM yx_school_major sm `).
LEFT JOIN (SELECT school_id,school_name,school_code FROM yx_school_child group by school_code) sc ON sc.school_code = sm.school_code Joins("LEFT JOIN (SELECT school_id,school_name,school_code FROM yx_school_child group by school_code) sc ON sc.school_code = sm.school_code").
LEFT JOIN yx_school s ON s.id = sc.school_id Joins("LEFT JOIN yx_school s ON s.id = sc.school_id").
WHERE 1=1 AND sm.state > 0 Where("sm.state > 0")
`
params := []interface{}{}
if query.MajorType != "" { if query.MajorType != "" {
sql += " AND sm.major_type = ?" queryBuilder = queryBuilder.Where("sm.major_type = ?", query.MajorType)
params = append(params, query.MajorType)
} }
if query.Category != "" { if query.Category != "" {
sql += " AND sm.category = ?" queryBuilder = queryBuilder.Where("sm.category = ?", query.Category)
params = append(params, query.Category)
} }
if len(query.MajorTypeChildren) > 0 { if len(query.MajorTypeChildren) > 0 {
sql += " AND sm.major_type_child IN ?" queryBuilder = queryBuilder.Where("sm.major_type_child IN ?", query.MajorTypeChildren)
params = append(params, query.MajorTypeChildren)
} }
if query.MainSubjects != "" { if query.MainSubjects != "" {
sql += " AND sm.main_subjects = ?" queryBuilder = queryBuilder.Where("sm.main_subjects = ?", query.MainSubjects)
params = append(params, query.MainSubjects)
} }
err := config.DB.Raw(sql, params...).Scan(&items).Error err := queryBuilder.Scan(&items).Error
return items, err return items, err
} }