This commit is contained in:
zhouwentao 2025-12-25 16:42:23 +08:00
parent 17504936d0
commit 1bc3fbc56b
10 changed files with 499 additions and 24 deletions

View File

@ -282,6 +282,38 @@ const docTemplate = `{
}
}
},
"/user//major/list": {
"get": {
"tags": [
"用户专业"
],
"summary": "获取当前用户可检索列表",
"parameters": [
{
"type": "integer",
"default": 1,
"description": "页码",
"name": "page",
"in": "query"
},
{
"type": "integer",
"default": 10,
"description": "每页数量",
"name": "size",
"in": "query"
}
],
"responses": {
"200": {
"description": "OK",
"schema": {
"$ref": "#/definitions/common.Response"
}
}
}
}
},
"/user/auth/info": {
"get": {
"tags": [
@ -347,6 +379,54 @@ const docTemplate = `{
}
}
},
"/user/score": {
"get": {
"tags": [
"用户分数"
],
"summary": "获取当前用户的激活分数",
"responses": {
"200": {
"description": "OK",
"schema": {
"$ref": "#/definitions/common.Response"
}
}
}
}
},
"/user/score/list": {
"get": {
"tags": [
"用户分数"
],
"summary": "获取当前用户的成绩列表",
"parameters": [
{
"type": "integer",
"default": 1,
"description": "页码",
"name": "page",
"in": "query"
},
{
"type": "integer",
"default": 10,
"description": "每页数量",
"name": "size",
"in": "query"
}
],
"responses": {
"200": {
"description": "OK",
"schema": {
"$ref": "#/definitions/common.Response"
}
}
}
}
},
"/user/score/save-score": {
"post": {
"tags": [
@ -379,7 +459,16 @@ const docTemplate = `{
"tags": [
"用户分数"
],
"summary": "获取当前用户的当前分数",
"summary": "获取指定 ID 的分数",
"parameters": [
{
"type": "string",
"description": "成绩ID",
"name": "id",
"in": "path",
"required": true
}
],
"responses": {
"200": {
"description": "OK",

View File

@ -276,6 +276,38 @@
}
}
},
"/user//major/list": {
"get": {
"tags": [
"用户专业"
],
"summary": "获取当前用户可检索列表",
"parameters": [
{
"type": "integer",
"default": 1,
"description": "页码",
"name": "page",
"in": "query"
},
{
"type": "integer",
"default": 10,
"description": "每页数量",
"name": "size",
"in": "query"
}
],
"responses": {
"200": {
"description": "OK",
"schema": {
"$ref": "#/definitions/common.Response"
}
}
}
}
},
"/user/auth/info": {
"get": {
"tags": [
@ -341,6 +373,54 @@
}
}
},
"/user/score": {
"get": {
"tags": [
"用户分数"
],
"summary": "获取当前用户的激活分数",
"responses": {
"200": {
"description": "OK",
"schema": {
"$ref": "#/definitions/common.Response"
}
}
}
}
},
"/user/score/list": {
"get": {
"tags": [
"用户分数"
],
"summary": "获取当前用户的成绩列表",
"parameters": [
{
"type": "integer",
"default": 1,
"description": "页码",
"name": "page",
"in": "query"
},
{
"type": "integer",
"default": 10,
"description": "每页数量",
"name": "size",
"in": "query"
}
],
"responses": {
"200": {
"description": "OK",
"schema": {
"$ref": "#/definitions/common.Response"
}
}
}
}
},
"/user/score/save-score": {
"post": {
"tags": [
@ -373,7 +453,16 @@
"tags": [
"用户分数"
],
"summary": "获取当前用户的当前分数",
"summary": "获取指定 ID 的分数",
"parameters": [
{
"type": "string",
"description": "成绩ID",
"name": "id",
"in": "path",
"required": true
}
],
"responses": {
"200": {
"description": "OK",

View File

@ -710,6 +710,27 @@ paths:
summary: Sys用户登出
tags:
- 认证
/user//major/list:
get:
parameters:
- default: 1
description: 页码
in: query
name: page
type: integer
- default: 10
description: 每页数量
in: query
name: size
type: integer
responses:
"200":
description: OK
schema:
$ref: '#/definitions/common.Response'
summary: 获取当前用户可检索列表
tags:
- 用户专业
/user/auth/info:
get:
responses:
@ -751,14 +772,51 @@ paths:
summary: 用户登出
tags:
- 认证
/user/score/{id}:
/user/score:
get:
responses:
"200":
description: OK
schema:
$ref: '#/definitions/common.Response'
summary: 获取当前用户的当前分数
summary: 获取当前用户的激活分数
tags:
- 用户分数
/user/score/{id}:
get:
parameters:
- description: 成绩ID
in: path
name: id
required: true
type: string
responses:
"200":
description: OK
schema:
$ref: '#/definitions/common.Response'
summary: 获取指定 ID 的分数
tags:
- 用户分数
/user/score/list:
get:
parameters:
- default: 1
description: 页码
in: query
name: page
type: integer
- default: 10
description: 每页数量
in: query
name: size
type: integer
responses:
"200":
description: OK
schema:
$ref: '#/definitions/common.Response'
summary: 获取当前用户的成绩列表
tags:
- 用户分数
/user/score/save-score:

View File

@ -85,6 +85,7 @@ func main() {
// 注册 User 模块路由
userController.NewUserScoreController().RegisterRoutes(api)
userController.NewAuthController().RegisterRoutes(api)
userController.NewUserMajorController().RegisterRoutes(api)
// 创建 HTTP 服务器
srv := &http.Server{

View File

@ -0,0 +1,64 @@
package controller
import (
"server/common"
user_service "server/modules/user/service"
yxDto "server/modules/yx/dto"
yx_service "server/modules/yx/service"
"strconv"
"github.com/gin-gonic/gin"
)
type UserMajorController struct {
userScoreService *user_service.UserScoreService
yxUserScoreService *yx_service.YxUserScoreService
yxCalculationMajorService *yx_service.YxCalculationMajorService
}
func NewUserMajorController() *UserMajorController {
return &UserMajorController{
yxUserScoreService: yx_service.NewYxUserScoreService(),
userScoreService: user_service.NewUserScoreService(),
yxCalculationMajorService: yx_service.NewYxCalculationMajorService(),
}
}
// RegisterRoutes 注册路由
func (ctrl *UserMajorController) RegisterRoutes(rg *gin.RouterGroup) {
group := rg.Group("/user/major")
{
// group.GET("/", ctrl.GetActive)
// group.GET("/:id", ctrl.GetByID)
group.GET("/list", ctrl.List)
}
}
// List 获取当前用户可检索列表
// @Summary 获取当前用户可检索列表
// @Tags 用户专业
// @Param page query int false "页码" default(1)
// @Param size query int false "每页数量" default(10)
// @Success 200 {object} common.Response
// @Router /user/major/list [get]
func (ctrl *UserMajorController) List(c *gin.Context) {
page, _ := strconv.Atoi(c.DefaultQuery("page", "1"))
size, _ := strconv.Atoi(c.DefaultQuery("size", "10"))
schoolMajorQuery := yxDto.SchoolMajorQuery{
Page: page,
Size: size,
LoginUserId: common.GetLoginUser(c).ID,
}
userScoreVO, err := ctrl.userScoreService.GetActiveByID(schoolMajorQuery.LoginUserId)
if err != nil {
common.Error(c, 500, err.Error())
return
}
schoolMajorQuery.UserScoreVO = userScoreVO
items, total, err := ctrl.yxCalculationMajorService.RecommendMajorList(schoolMajorQuery)
if err != nil {
common.Error(c, 500, err.Error())
return
}
common.SuccessPage(c, items, total, page, size)
}

View File

@ -0,0 +1,11 @@
package dto
import "server/modules/user/vo"
// RecommendMajorListRequest 推荐专业列表请求
type RecommendMajorListRequest struct {
Page int `json:"page"`
Size int `json:"size"`
LoginUserId string `json:"loginUserId"`
UserScoreVO vo.UserScoreVO `json:"userScoreVO"`
}

View File

@ -2,6 +2,8 @@
package service
import (
"context"
"encoding/json"
"errors"
"fmt"
"server/common"
@ -23,9 +25,16 @@ type UserScoreService struct {
mapper *mapper.YxUserScoreMapper
}
func (s *UserScoreService) GetUserScoreByUserId(id string) {
panic("unimplemented")
}
// GetActiveByID 获取当前激活的成绩
func (s *UserScoreService) GetActiveByID(userID string) (vo.UserScoreVO, error) {
var score entity.YxUserScore
scoreRedisData, err := config.RDB.Get(context.Background(), common.RedisUserScorePrefix+userID).Result()
if err != nil {
// 明确指定字段,提高可读性
err := config.DB.Model(&entity.YxUserScore{}).
Where("create_by = ? AND state = ?", userID, "1").
@ -36,8 +45,24 @@ func (s *UserScoreService) GetActiveByID(userID string) (vo.UserScoreVO, error)
}
return vo.UserScoreVO{}, fmt.Errorf("查询成绩记录失败: %w", err)
}
// 缓存到 Redis
scoreRedisSetData, err := json.Marshal(score)
if err != nil {
return vo.UserScoreVO{}, fmt.Errorf("序列化成绩记录失败: %w", err)
}
err = config.RDB.Set(context.Background(), common.RedisUserScorePrefix+userID, scoreRedisSetData, common.RedisUserScoreExpire).Err()
if err != nil {
return vo.UserScoreVO{}, fmt.Errorf("缓存成绩记录失败: %w", err)
}
} else {
if err := json.Unmarshal([]byte(scoreRedisData), &score); err != nil {
return vo.UserScoreVO{}, fmt.Errorf("解析 Redis 数据失败: %w", err)
}
// 刷新过期时间
config.RDB.Expire(context.Background(), common.RedisUserScorePrefix+userID, common.RedisUserScoreExpire)
}
return s.convertEntityToVo(&score), nil
return s.convertEntityToVo(score), nil
}
// GetByID 根据 ID 获取成绩
@ -53,7 +78,7 @@ func (s *UserScoreService) GetByID(id string) (vo.UserScoreVO, error) {
return vo.UserScoreVO{}, fmt.Errorf("查询失败: %w", err)
}
return s.convertEntityToVo(&score), nil
return s.convertEntityToVo(score), nil
}
// ListByUser 获取用户的成绩分页列表
@ -73,7 +98,7 @@ func (s *UserScoreService) ListByUser(userID string, page, size int) ([]vo.UserS
vos := make([]vo.UserScoreVO, 0, len(scores))
for i := range scores {
vos = append(vos, s.convertEntityToVo(&scores[i]))
vos = append(vos, s.convertEntityToVo(scores[i]))
}
return vos, total, nil
@ -82,6 +107,7 @@ func (s *UserScoreService) ListByUser(userID string, page, size int) ([]vo.UserS
func NewUserScoreService() *UserScoreService {
return &UserScoreService{
yxUserScoreService: service.NewYxUserScoreService(),
yxCalculationMajorService: service.NewYxCalculationMajorService(),
mapper: mapper.NewYxUserScoreMapper(),
}
}
@ -146,8 +172,8 @@ func (s *UserScoreService) SaveUserScore(req *dto.SaveScoreRequest) (vo.UserScor
}
// 私有方法DTO 转 Entity
func (s *UserScoreService) convertDtoToEntity(req *dto.SaveScoreRequest) *entity.YxUserScore {
entityItem := &entity.YxUserScore{
func (s *UserScoreService) convertDtoToEntity(req *dto.SaveScoreRequest) entity.YxUserScore {
entityItem := entity.YxUserScore{
CognitioPolyclinic: req.CognitioPolyclinic,
Subjects: strings.Join(req.SubjectList, ","),
ProfessionalCategory: req.ProfessionalCategory,
@ -185,7 +211,7 @@ func (s *UserScoreService) convertDtoToEntity(req *dto.SaveScoreRequest) *entity
}
// 私有方法Entity 转 VO
func (s *UserScoreService) convertEntityToVo(item *entity.YxUserScore) vo.UserScoreVO {
func (s *UserScoreService) convertEntityToVo(item entity.YxUserScore) vo.UserScoreVO {
voItem := vo.UserScoreVO{
ID: item.ID,
Type: item.Type,

View File

@ -1,6 +1,9 @@
package dto
import "server/modules/yx/entity"
import (
userVO "server/modules/user/vo"
"server/modules/yx/entity"
)
// SchoolMajorDTO 院校专业查询结果 DTO
type SchoolMajorDTO struct {
@ -52,8 +55,20 @@ type YxHistoryMajorEnrollDTO struct {
// SchoolMajorQuery 院校专业查询条件
type SchoolMajorQuery struct {
Page int `json:"page"`
Size int `json:"size"`
MajorType string `json:"majorType"` // 对应 major_type
Category string `json:"category"` // 对应 category
Batch string `json:"batch"` // 对应 batch
MajorTypeChildren []string `json:"majorTypeChildren"` // 对应 major_type_child in (...)
MainSubjects string `json:"mainSubjects"` // 对应 main_subjects
ScoreId string `json:"scoreId"` // 对应 score_id
TagList []string `json:"tagList"` // 对应 tags in (...)
SchoolNatureList []string `json:"schoolNatureList"` // 对应 school_nature in (...)
AddressList []string `json:"addressList"` // 对应 address in (...)
KyjxList []string `json:"kyjxList"` // 对应 kyjx in (...)
RulesEnrollProbabilityList []string `json:"rulesEnrollProbabilityList"` // 对应 rules_enroll_probability in (...)
LoginUserId string `json:"loginUserId"` // 登录用户 ID
UserScoreVO userVO.UserScoreVO `json:"userScoreVO"` // 用户成绩 VO
CalculationTableName string `json:"calculationTableName"` // 对应 calculation_table_name
}

View File

@ -2,8 +2,12 @@
package mapper
import (
"fmt"
"server/config"
"server/modules/yx/dto"
"server/modules/yx/entity"
"strings"
"sync"
"gorm.io/gorm/clause"
)
@ -22,6 +26,104 @@ func (m *YxCalculationMajorMapper) FindAll(page, size int) ([]entity.YxCalculati
return items, total, err
}
func (m *YxCalculationMajorMapper) FindRecommendList(query dto.SchoolMajorQuery) ([]entity.YxCalculationMajor, int64, error) {
var items []entity.YxCalculationMajor
var total int64
countSQL := `
SELECT COUNT(cm.id) 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
`
sql := `
SELECT
sc.school_code,
sc.school_name,
cm.major_code,
cm.major_name,
cm.major_type,
cm.major_type_child,
cm.plan_num,
cm.main_subjects,
cm.limitation,
cm.other_score_limitation,
cm.enrollment_code,
cm.tuition,
cm.detail,
cm.category,
cm.batch,
cm.rules_enroll_probability,
cm.probability_operator,
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
`
params := []interface{}{}
if query.UserScoreVO.ID != "" {
countSQL += " AND cm.score_id = ?"
sql += " AND cm.score_id = ?"
params = append(params, query.UserScoreVO.ID)
}
if query.MajorType != "" {
countSQL += " AND cm.major_type = ?"
sql += " AND cm.major_type = ?"
params = append(params, query.MajorType)
}
if query.Category != "" {
countSQL += " AND cm.category = ?"
sql += " AND cm.category = ?"
params = append(params, query.Category)
}
if len(query.MajorTypeChildren) > 0 {
placeholders := strings.Repeat("?,", len(query.MajorTypeChildren)-1) + "?"
countSQL += " AND cm.major_type_child IN (" + placeholders + ")"
sql += " AND cm.major_type_child IN (" + placeholders + ")"
for _, v := range query.MajorTypeChildren {
params = append(params, v)
}
}
if query.MainSubjects != "" {
countSQL += " AND cm.main_subjects = ?"
sql += " AND cm.main_subjects = ?"
params = append(params, query.MainSubjects)
}
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)
var wg sync.WaitGroup
var countErr, queryErr error
wg.Add(2)
// 协程1COUNT 查询
go func() {
defer wg.Done()
countErr = config.DB.Raw(countSQL, params...).Count(&total).Error
}()
// 协程2主查询
go func() {
defer wg.Done()
sql += fmt.Sprintf(" LIMIT %d OFFSET %d", query.Size, (query.Page-1)*query.Size)
queryErr = config.DB.Raw(sql, params...).Scan(&items).Error
}()
wg.Wait()
if countErr != nil || queryErr != nil {
return nil, 0, fmt.Errorf("countErr: %v, queryErr: %v", countErr, queryErr)
}
return items, total, queryErr
}
func (m *YxCalculationMajorMapper) FindByID(id string) (*entity.YxCalculationMajor, error) {
var item entity.YxCalculationMajor
err := config.DB.First(&item, "id = ?", id).Error

View File

@ -6,6 +6,7 @@ import (
"server/common"
"server/modules/user/vo"
"server/modules/yx/dto"
yxDto "server/modules/yx/dto"
"server/modules/yx/entity"
"server/modules/yx/mapper"
"strings"
@ -20,6 +21,25 @@ type YxCalculationMajorService struct {
historyScoreControlLineService *YxHistoryScoreControlLineService
}
func (s *YxCalculationMajorService) RecommendMajorList(schoolMajorQuery yxDto.SchoolMajorQuery) (any, int64, error) {
if schoolMajorQuery.UserScoreVO.ProfessionalCategory == "" {
return nil, 0, fmt.Errorf("专业类型错误")
}
if schoolMajorQuery.Batch != "" {
schoolMajorQuery.Batch = strings.ReplaceAll(schoolMajorQuery.Batch, "批", "")
}
// if len(schoolMajorQuery.MajorTypeChildren) > 0 && "高职高专" != schoolMajorQuery.Batch {
// if "表演类" == schoolMajorQuery.MajorType {
// }
// }
calculationMajors, total, err := s.mapper.FindRecommendList(schoolMajorQuery)
if err != nil {
return nil, 0, err
}
return calculationMajors, total, nil
}
func (s *YxCalculationMajorService) BatchCreateBySchoolMajorDTO(items []dto.SchoolMajorDTO, scoreID string) error {
entities := make([]entity.YxCalculationMajor, 0, len(items))
now := time.Now()