This commit is contained in:
zhouwentao 2026-01-02 14:41:04 +08:00
parent ad15710c09
commit 0c787bc441
8 changed files with 134 additions and 18 deletions

View File

@ -27,6 +27,11 @@
- `YxVolunteerController`: 志愿控制器。
- `YxVolunteerRecordController`: 志愿明细控制器。
## server/modules/yx/service
- `YxCalculationMajorService`:
- `BatchCreateBySchoolMajorDTO(tableName string, items []dto.SchoolMajorDTO, scoreID string)`: 根据 SchoolMajorDTO 列表批量创建计算专业数据,支持动态表名。
- `BatchCreate(tableName string, items []entity.YxCalculationMajor)`: 批量创建计算专业数据,支持动态表名。
## server/modules/user/service
- `UserScoreService`:
- `GetActiveByID(userID string)`: 获取用户当前激活状态的成绩 VO。

View File

@ -8,3 +8,19 @@
- 该函数根据 `AppConfig.Log` 配置创建日志目录和文件(命名为 `sql-YYYY-MM-DD.log`)。
- 如果配置开启了控制台输出,则使用 `io.MultiWriter` 同时输出到文件和控制台。
- 验证:在测试环境下临时开启日志模式,成功生成了 `logs/sql-2025-12-25.log` 文件。
### [任务执行] 支持计算专业表的动态表名插入
- **时间戳**: 2026-01-02
- **关联任务**: 动态表名支持
- **操作目标**: 修改 `YxCalculationMajorService``YxCalculationMajorMapper` 以支持根据用户成绩中的 `CalculationTableName` 动态插入数据。
- **影响范围**:
- `server/modules/yx/mapper/yx_calculation_major_mapper.go`
- `server/modules/yx/service/yx_calculation_major_service.go`
- `server/modules/user/service/user_score_service.go`
- `server/modules/yx/controller/yx_calculation_major_controller.go`
- **修改结果**:
- `YxCalculationMajorMapper.BatchCreate` 增加 `tableName` 参数,支持 `db.Table(tableName)`
- `YxCalculationMajorService.BatchCreate``BatchCreateBySchoolMajorDTO` 增加 `tableName` 参数并透传。
- `UserScoreService.SaveUserScore` 调用 `BatchCreateBySchoolMajorDTO` 时传入 `entityItem.CalculationTableName`
- `YxCalculationMajorController.BatchCreate` 传入空字符串以使用默认表名。
- **[新增]**: 修复了 `FindRecommendList` 中表名参数传递错误的问题,改为使用 `fmt.Sprintf` 动态注入表名。

View File

@ -171,7 +171,7 @@ func (s *UserScoreService) SaveUserScore(req *dto.SaveScoreRequest) (vo.UserScor
s.yxCalculationMajorService.CheckEnrollProbability(&schoolMajorItems, userScoreVO)
// 插入到数据库
err = s.yxCalculationMajorService.BatchCreateBySchoolMajorDTO(schoolMajorItems, userScoreVO.ID)
err = s.yxCalculationMajorService.BatchCreateBySchoolMajorDTO(entityItem.CalculationTableName, schoolMajorItems, userScoreVO.ID)
if err != nil {
tx.Rollback()
return vo.UserScoreVO{}, fmt.Errorf("保存专业信息失败: %w", err)

View File

@ -16,4 +16,5 @@ type UserScoreVO struct {
ChineseScore float64 `json:"chineseScore"` // 语文成绩
Province string `json:"province"` // 高考省份
State string `json:"state"` // 状态
CalculationTableName string `json:"calculationTableName"` // 计算表名称
}

View File

@ -142,7 +142,7 @@ func (ctrl *YxCalculationMajorController) BatchCreate(c *gin.Context) {
common.Error(c, 400, "参数错误")
return
}
if err := ctrl.service.BatchCreate(items); err != nil {
if err := ctrl.service.BatchCreate("", items); err != nil {
common.Error(c, 500, err.Error())
return
}

View File

@ -29,15 +29,23 @@ func (m *YxCalculationMajorMapper) FindAll(page, size int) ([]entity.YxCalculati
func (m *YxCalculationMajorMapper) FindRecommendList(query dto.SchoolMajorQuery) ([]dto.UserMajorDTO, int64, error) {
var items []dto.UserMajorDTO
var total int64
countSQL := `
SELECT COUNT(cm.id) FROM ? cm
// 确保表名存在,防止 SQL 注入或空表名
tableName := query.UserScoreVO.CalculationTableName
if tableName == "" {
return nil, 0, fmt.Errorf("CalculationTableName is empty")
}
// 使用 Sprintf 动态插入表名
countSQL := fmt.Sprintf(`
SELECT COUNT(cm.id) FROM %s cm
LEFT JOIN yx_school_child sc ON sc.school_code = cm.school_code
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
`
`, tableName)
sql := `
sql := fmt.Sprintf(`
SELECT
cm.id,
s.school_name,
@ -67,15 +75,16 @@ func (m *YxCalculationMajorMapper) FindRecommendList(query dto.SchoolMajorQuery)
s.province as province,
s.school_nature as schoolNature,
s.institution_type as institutionType
FROM ? cm
FROM %s cm
LEFT JOIN yx_school_child sc ON sc.school_code = cm.school_code
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
`
`, tableName)
params := []interface{}{}
params = append(params, query.UserScoreVO.CalculationTableName)
// 注意:移除了 params = append(params, query.UserScoreVO.CalculationTableName) 因为表名已经通过 Sprintf 插入
if query.UserScoreVO.ID != "" {
countSQL += " AND cm.score_id = ?"
@ -124,8 +133,7 @@ func (m *YxCalculationMajorMapper) FindRecommendList(query dto.SchoolMajorQuery)
sql += " AND (cm.enroll_probability >= 93)"
}
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)
// 移除了无效的 strings.Replace
var wg sync.WaitGroup
var countErr, queryErr error
@ -178,7 +186,10 @@ func (m *YxCalculationMajorMapper) FindByScoreID(scoreID string) ([]entity.YxCal
return items, err
}
func (m *YxCalculationMajorMapper) BatchCreate(items []entity.YxCalculationMajor, batchSize int) error {
func (m *YxCalculationMajorMapper) BatchCreate(tableName string, items []entity.YxCalculationMajor, batchSize int) error {
if tableName != "" {
return config.DB.Table(tableName).CreateInBatches(items, batchSize).Error
}
return config.DB.CreateInBatches(items, batchSize).Error
}

View File

@ -21,7 +21,7 @@ type YxCalculationMajorService struct {
historyScoreControlLineService *YxHistoryScoreControlLineService
}
func (s *YxCalculationMajorService) RecommendMajorList(schoolMajorQuery yxDto.SchoolMajorQuery) (any, int64, error) {
func (s *YxCalculationMajorService) RecommendMajorList(schoolMajorQuery yxDto.SchoolMajorQuery) ([]yxDto.UserMajorDTO, int64, error) {
if schoolMajorQuery.UserScoreVO.ProfessionalCategory == "" {
return nil, 0, fmt.Errorf("专业类型错误")
}
@ -37,10 +37,17 @@ func (s *YxCalculationMajorService) RecommendMajorList(schoolMajorQuery yxDto.Sc
if err != nil {
return nil, 0, err
}
// 为专业列表添加历史数据
err = s.UserMajorDTOGetHistory(&calculationMajors)
if err != nil {
return nil, 0, err
}
return calculationMajors, total, nil
}
func (s *YxCalculationMajorService) BatchCreateBySchoolMajorDTO(items []dto.SchoolMajorDTO, scoreID string) error {
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 {
@ -93,7 +100,7 @@ func (s *YxCalculationMajorService) BatchCreateBySchoolMajorDTO(items []dto.Scho
State: item.State,
})
}
return s.BatchCreate(entities)
return s.BatchCreate(tableName, entities)
}
func NewYxCalculationMajorService() *YxCalculationMajorService {
@ -133,11 +140,11 @@ func (s *YxCalculationMajorService) GetByScoreID(scoreID string) ([]entity.YxCal
return s.mapper.FindByScoreID(scoreID)
}
func (s *YxCalculationMajorService) BatchCreate(items []entity.YxCalculationMajor) error {
func (s *YxCalculationMajorService) BatchCreate(tableName string, items []entity.YxCalculationMajor) error {
for i := range items {
items[i].ID = uuid.New().String()
}
return s.mapper.BatchCreate(items, 100)
return s.mapper.BatchCreate(tableName, items, 100)
}
func (s *YxCalculationMajorService) BatchUpdate(items []entity.YxCalculationMajor) error {
@ -184,7 +191,6 @@ func (s *YxCalculationMajorService) ListByUserQueryType(professionalCategory str
// "音乐教育",
// },
}
years := []string{"2025", "2024"}
// 执行院校查询
majorItems, err := mapper.NewYxSchoolMajorMapper().SelectSchoolMajor(query)
@ -194,6 +200,7 @@ func (s *YxCalculationMajorService) ListByUserQueryType(professionalCategory str
// 分别收集专业名称和院校代码集合(去重)
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
@ -253,6 +260,71 @@ func (s *YxCalculationMajorService) ListByUserQueryType(professionalCategory str
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
}
// 函数名 给专业列表计算录取率
// 详细描述(可选)
//

View File

@ -7,3 +7,14 @@
3. 使用 `io.MultiWriter` 支持同时输出到文件和控制台。
4. 验证日志文件生成。
- **执行结果**: SQL 日志现在会根据日期生成独立的文件(如 `logs/sql-2025-12-25.log`),且遵循全局日志配置。
## 会话 ID: 20260102-01
- **执行原因**: 用户询问如何在 `UserScoreService` 中根据 `CalculationTableName` 动态插入数据,并修复了 Mapper 中的查询 Bug。
- **执行过程**:
1. 分析 `YxCalculationMajorService` 和 Mapper发现默认使用硬编码的表名。
2. 修改 `YxCalculationMajorMapper.BatchCreate` 增加 `tableName` 参数。
3. 修改 `YxCalculationMajorService.BatchCreate``BatchCreateBySchoolMajorDTO` 增加 `tableName` 参数。
4. 更新 `UserScoreService` 调用处,传入 `entityItem.CalculationTableName`
5. 更新 `YxCalculationMajorController` 调用处,传入空字符串以保持默认行为。
6. **[修复]** 发现 `FindRecommendList` 中错误地将表名作为参数传递给 `?` 占位符。修改为使用 `fmt.Sprintf` 动态构建 SQL并移除了无效的字符串替换逻辑。
- **执行结果**: 实现了计算专业表的动态表名插入功能,并修复了推荐列表查询的 SQL 语法错误。