updates
This commit is contained in:
parent
523f323cd8
commit
17504936d0
|
|
@ -1,7 +1,6 @@
|
|||
package common
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strconv"
|
||||
"sync"
|
||||
"time"
|
||||
|
|
@ -9,7 +8,7 @@ import (
|
|||
|
||||
// IDGenerator 简单的 ID 生成器(类似 Snowflake)
|
||||
type IDGenerator struct {
|
||||
mu sync.Mutex
|
||||
mu sync.RWMutex
|
||||
lastTime int64
|
||||
sequence int64
|
||||
machineID int64
|
||||
|
|
@ -24,14 +23,44 @@ var (
|
|||
func GetIDGenerator() *IDGenerator {
|
||||
once.Do(func() {
|
||||
defaultGenerator = &IDGenerator{
|
||||
machineID: 1, // 默认机器 ID,实际可从配置读取
|
||||
machineID: 1,
|
||||
}
|
||||
})
|
||||
return defaultGenerator
|
||||
}
|
||||
|
||||
// Lazy initialize on first access
|
||||
func getInstance() *IDGenerator {
|
||||
if defaultGenerator == nil {
|
||||
once.Do(func() {
|
||||
defaultGenerator = &IDGenerator{
|
||||
machineID: 1,
|
||||
}
|
||||
})
|
||||
}
|
||||
return defaultGenerator
|
||||
}
|
||||
|
||||
// GenerateStringID 全局辅助函数:生成 string 类型 ID
|
||||
func GenerateStringID() string {
|
||||
gen := getInstance()
|
||||
if gen == nil {
|
||||
// Fallback: create new instance if singleton fails
|
||||
gen = &IDGenerator{machineID: 1}
|
||||
}
|
||||
return gen.NextIDStr()
|
||||
}
|
||||
|
||||
// GenerateLongID 全局辅助函数:生成 long 类型 ID
|
||||
func GenerateLongID() int64 {
|
||||
gen := getInstance()
|
||||
if gen == nil {
|
||||
gen = &IDGenerator{machineID: 1}
|
||||
}
|
||||
return gen.NextID()
|
||||
}
|
||||
|
||||
// NextID 生成下一个 64 位整数 ID
|
||||
// 格式:时间戳(毫秒) + 机器ID + 序列号
|
||||
func (g *IDGenerator) NextID() int64 {
|
||||
g.mu.Lock()
|
||||
defer g.mu.Unlock()
|
||||
|
|
@ -39,9 +68,8 @@ func (g *IDGenerator) NextID() int64 {
|
|||
now := time.Now().UnixMilli()
|
||||
|
||||
if now == g.lastTime {
|
||||
g.sequence = (g.sequence + 1) & 4095 // 12位序列号
|
||||
g.sequence = (g.sequence + 1) & 4095
|
||||
if g.sequence == 0 {
|
||||
// 序列号溢出,等待下一毫秒
|
||||
for now <= g.lastTime {
|
||||
now = time.Now().UnixMilli()
|
||||
}
|
||||
|
|
@ -51,53 +79,11 @@ func (g *IDGenerator) NextID() int64 {
|
|||
}
|
||||
|
||||
g.lastTime = now
|
||||
|
||||
// 简单的位运算组合 ID
|
||||
// 时间戳(41位) | 机器ID(10位) | 序列号(12位)
|
||||
// 这里为了简单,直接返回时间戳+序列号的组合
|
||||
// 如果需要严格的 long 类型且包含时间戳信息:
|
||||
return now*10000 + g.sequence
|
||||
}
|
||||
|
||||
// NextIDStr 生成字符串类型的 ID
|
||||
func (g *IDGenerator) NextIDStr() string {
|
||||
return strconv.FormatInt(g.NextID(), 10)
|
||||
}
|
||||
|
||||
// GenerateLongID 全局辅助函数:生成 long 类型 ID
|
||||
func GenerateLongID() int64 {
|
||||
return GetIDGenerator().NextID()
|
||||
}
|
||||
|
||||
// GenerateStringID 全局辅助函数:生成 string 类型 ID
|
||||
func GenerateStringID() string {
|
||||
return GetIDGenerator().NextIDStr()
|
||||
}
|
||||
|
||||
// FormatTimestampToLong 将指定时间转为 long 格式 (yyyyMMddHHmmss)
|
||||
func FormatTimestampToLong(t time.Time) int64 {
|
||||
s := t.Format("20060102150405")
|
||||
id, _ := strconv.ParseInt(s, 10, 64)
|
||||
return id
|
||||
}
|
||||
|
||||
// GenerateTimestampLongID 生成当前时间的 long 格式 ID (yyyyMMddHHmmss + 3位随机/序列)
|
||||
func (g *IDGenerator) GenerateTimestampLongID() int64 {
|
||||
g.mu.Lock()
|
||||
defer g.mu.Unlock()
|
||||
|
||||
now := time.Now()
|
||||
timestampStr := now.Format("20060102150405")
|
||||
|
||||
nowMs := now.UnixMilli()
|
||||
if nowMs/1000 == g.lastTime/1000 {
|
||||
g.sequence = (g.sequence + 1) & 999
|
||||
} else {
|
||||
g.sequence = 0
|
||||
}
|
||||
g.lastTime = nowMs
|
||||
|
||||
idStr := fmt.Sprintf("%s%03d", timestampStr, g.sequence)
|
||||
id, _ := strconv.ParseInt(idStr, 10, 64)
|
||||
return id
|
||||
id := g.NextID()
|
||||
return strconv.FormatInt(id, 10)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -19,11 +19,12 @@ import (
|
|||
|
||||
type UserScoreService struct {
|
||||
yxUserScoreService *service.YxUserScoreService
|
||||
yxCalculationMajorService *service.YxCalculationMajorService
|
||||
mapper *mapper.YxUserScoreMapper
|
||||
}
|
||||
|
||||
// GetActiveByID 获取当前激活的成绩
|
||||
func (s *UserScoreService) GetActiveByID(userID string) (*vo.UserScoreVO, error) {
|
||||
func (s *UserScoreService) GetActiveByID(userID string) (vo.UserScoreVO, error) {
|
||||
var score entity.YxUserScore
|
||||
// 明确指定字段,提高可读性
|
||||
err := config.DB.Model(&entity.YxUserScore{}).
|
||||
|
|
@ -31,32 +32,32 @@ func (s *UserScoreService) GetActiveByID(userID string) (*vo.UserScoreVO, error)
|
|||
First(&score).Error
|
||||
if err != nil {
|
||||
if errors.Is(err, gorm.ErrRecordNotFound) {
|
||||
return nil, fmt.Errorf("未找到激活的成绩记录")
|
||||
return vo.UserScoreVO{}, fmt.Errorf("未找到激活的成绩记录")
|
||||
}
|
||||
return nil, fmt.Errorf("查询成绩记录失败: %w", err)
|
||||
return vo.UserScoreVO{}, fmt.Errorf("查询成绩记录失败: %w", err)
|
||||
}
|
||||
|
||||
return s.convertEntityToVo(&score), nil
|
||||
}
|
||||
|
||||
// GetByID 根据 ID 获取成绩
|
||||
func (s *UserScoreService) GetByID(id string) (*vo.UserScoreVO, error) {
|
||||
func (s *UserScoreService) GetByID(id string) (vo.UserScoreVO, error) {
|
||||
var score entity.YxUserScore
|
||||
err := config.DB.Model(&entity.YxUserScore{}).
|
||||
Where("id = ?", id).
|
||||
First(&score).Error
|
||||
if err != nil {
|
||||
if errors.Is(err, gorm.ErrRecordNotFound) {
|
||||
return nil, fmt.Errorf("记录不存在")
|
||||
return vo.UserScoreVO{}, fmt.Errorf("记录不存在")
|
||||
}
|
||||
return nil, fmt.Errorf("查询失败: %w", err)
|
||||
return vo.UserScoreVO{}, fmt.Errorf("查询失败: %w", err)
|
||||
}
|
||||
|
||||
return s.convertEntityToVo(&score), nil
|
||||
}
|
||||
|
||||
// ListByUser 获取用户的成绩分页列表
|
||||
func (s *UserScoreService) ListByUser(userID string, page, size int) ([]*vo.UserScoreVO, int64, error) {
|
||||
func (s *UserScoreService) ListByUser(userID string, page, size int) ([]vo.UserScoreVO, int64, error) {
|
||||
var scores []entity.YxUserScore
|
||||
var total int64
|
||||
|
||||
|
|
@ -70,7 +71,7 @@ func (s *UserScoreService) ListByUser(userID string, page, size int) ([]*vo.User
|
|||
return nil, 0, fmt.Errorf("查询成绩列表失败: %w", err)
|
||||
}
|
||||
|
||||
vos := make([]*vo.UserScoreVO, 0, len(scores))
|
||||
vos := make([]vo.UserScoreVO, 0, len(scores))
|
||||
for i := range scores {
|
||||
vos = append(vos, s.convertEntityToVo(&scores[i]))
|
||||
}
|
||||
|
|
@ -86,10 +87,10 @@ func NewUserScoreService() *UserScoreService {
|
|||
}
|
||||
|
||||
// SaveUserScore 保存用户成绩并返回 VO
|
||||
func (s *UserScoreService) SaveUserScore(req *dto.SaveScoreRequest) (*vo.UserScoreVO, error) {
|
||||
func (s *UserScoreService) SaveUserScore(req *dto.SaveScoreRequest) (vo.UserScoreVO, error) {
|
||||
// 1. 业务验证
|
||||
if err := req.Validate(); err != nil {
|
||||
return nil, err
|
||||
return vo.UserScoreVO{}, err
|
||||
}
|
||||
// 2. DTO 转 Entity
|
||||
entityItem := s.convertDtoToEntity(req)
|
||||
|
|
@ -109,19 +110,39 @@ func (s *UserScoreService) SaveUserScore(req *dto.SaveScoreRequest) (*vo.UserSco
|
|||
Where("create_by = ? AND state = ?", req.CreateBy, "1").
|
||||
Updates(map[string]interface{}{"state": "2"}).Error; err != nil {
|
||||
tx.Rollback()
|
||||
return nil, fmt.Errorf("更新旧记录失败: %w", err)
|
||||
return vo.UserScoreVO{}, fmt.Errorf("更新旧记录失败: %w", err)
|
||||
}
|
||||
// 保存新的成绩记录
|
||||
if err := tx.Create(entityItem).Error; err != nil {
|
||||
tx.Rollback()
|
||||
return nil, fmt.Errorf("保存记录失败: %w", err)
|
||||
}
|
||||
// 根据成绩计算用户的专业信息
|
||||
if err := tx.Commit().Error; err != nil {
|
||||
return nil, fmt.Errorf("提交事务失败: %w", err)
|
||||
return vo.UserScoreVO{}, fmt.Errorf("保存记录失败: %w", err)
|
||||
}
|
||||
|
||||
return s.convertEntityToVo(entityItem), nil
|
||||
userScoreVO := s.convertEntityToVo(entityItem)
|
||||
// 根据成绩计算用户的专业信息
|
||||
schoolMajorItems, err := s.yxCalculationMajorService.ListByUserQueryType("美术与设计类", "文科", []string{})
|
||||
if err != nil {
|
||||
tx.Rollback()
|
||||
return vo.UserScoreVO{}, fmt.Errorf("查询专业信息失败: %w", err)
|
||||
}
|
||||
|
||||
// 检查录取概率
|
||||
s.yxCalculationMajorService.CheckEnrollProbability(&schoolMajorItems, userScoreVO)
|
||||
|
||||
// 插入到数据库
|
||||
err = s.yxCalculationMajorService.BatchCreateBySchoolMajorDTO(schoolMajorItems, userScoreVO.ID)
|
||||
if err != nil {
|
||||
tx.Rollback()
|
||||
return vo.UserScoreVO{}, fmt.Errorf("保存专业信息失败: %w", err)
|
||||
}
|
||||
|
||||
// 提交事务
|
||||
if err := tx.Commit().Error; err != nil {
|
||||
tx.Rollback()
|
||||
return vo.UserScoreVO{}, fmt.Errorf("提交事务失败: %w", err)
|
||||
}
|
||||
|
||||
return userScoreVO, nil
|
||||
}
|
||||
|
||||
// 私有方法:DTO 转 Entity
|
||||
|
|
@ -164,8 +185,8 @@ func (s *UserScoreService) convertDtoToEntity(req *dto.SaveScoreRequest) *entity
|
|||
}
|
||||
|
||||
// 私有方法:Entity 转 VO
|
||||
func (s *UserScoreService) convertEntityToVo(item *entity.YxUserScore) *vo.UserScoreVO {
|
||||
voItem := &vo.UserScoreVO{
|
||||
func (s *UserScoreService) convertEntityToVo(item *entity.YxUserScore) vo.UserScoreVO {
|
||||
voItem := vo.UserScoreVO{
|
||||
ID: item.ID,
|
||||
Type: item.Type,
|
||||
EducationalLevel: item.EducationalLevel,
|
||||
|
|
|
|||
|
|
@ -64,12 +64,8 @@ func ComputeHistoryMajorEnrollScoreLineDifferenceWithRulesEnrollProbability(majo
|
|||
// 特殊逻辑:高职高专(非体育类)需计算分差率(分差/省控线)
|
||||
// Java: boolean isVocationalCollege = "高职高专".equals(enrollData.getBatch());
|
||||
// boolean isSportsMajor = "体育类".equals(enrollData.getMajorType());
|
||||
isSportsMajor := "体育类" == majorType
|
||||
if isSportsMajor {
|
||||
if "2024" == enrollData.Year && "专过文排" != enrollData.EnrollmentCode && "文过专排" != enrollData.EnrollmentCode { // enrollment_code 对应 rulesEnrollProbability? No.
|
||||
// Java uses rulesEnrollProbability field in entity.
|
||||
// Go entity YxHistoryMajorEnroll doesn't have RulesEnrollProbability field?
|
||||
// Let's check entity definition again.
|
||||
if "体育类" == majorType {
|
||||
if "2024" == enrollData.Year && "专过文排" != enrollData.EnrollmentCode && "文过专排" != enrollData.EnrollmentCode {
|
||||
currentDiff = currentDiff * common.Number7p5
|
||||
} else if "2024" == enrollData.Year && "文过专排" == enrollData.EnrollmentCode { // Placeholder
|
||||
currentDiff = currentDiff * common.Number5
|
||||
|
|
|
|||
|
|
@ -2,11 +2,14 @@
|
|||
package service
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"server/common"
|
||||
"server/modules/user/vo"
|
||||
"server/modules/yx/dto"
|
||||
"server/modules/yx/entity"
|
||||
"server/modules/yx/mapper"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/google/uuid"
|
||||
)
|
||||
|
|
@ -17,6 +20,62 @@ type YxCalculationMajorService struct {
|
|||
historyScoreControlLineService *YxHistoryScoreControlLineService
|
||||
}
|
||||
|
||||
func (s *YxCalculationMajorService) BatchCreateBySchoolMajorDTO(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(entities)
|
||||
}
|
||||
|
||||
func NewYxCalculationMajorService() *YxCalculationMajorService {
|
||||
return &YxCalculationMajorService{
|
||||
historyMajorEnrollService: NewYxHistoryMajorEnrollService(),
|
||||
|
|
|
|||
|
|
@ -58,6 +58,14 @@ func TestSchoolMajorQuery(t *testing.T) {
|
|||
cs.CheckEnrollProbability(&items, userScoreVO)
|
||||
elapsed := time.Now().UnixMilli() - startTime.UnixMilli()
|
||||
common.LogInfo("CheckEnrollProbability elapsed: %v", elapsed)
|
||||
|
||||
// 插入到数据库
|
||||
// err = cs.BatchCreateBySchoolMajorDTO(items)
|
||||
if err != nil {
|
||||
t.Fatalf("插入数据库失败: %v", err)
|
||||
}
|
||||
t.Logf("成功插入 %d 条记录到数据库", len(items))
|
||||
|
||||
// 打印前几条结果
|
||||
// for i, item := range items {
|
||||
// if i >= 3 {
|
||||
|
|
@ -76,6 +84,6 @@ func TestIDGenerator(t *testing.T) {
|
|||
idStr := common.GenerateStringID()
|
||||
t.Logf("生成的 String ID: %s", idStr)
|
||||
|
||||
idTimestamp := common.GetIDGenerator().GenerateTimestampLongID()
|
||||
t.Logf("生成的 Timestamp Long ID: %d", idTimestamp)
|
||||
// idTimestamp := common.GetIDGenerator().GenerateTimestampLongID()
|
||||
// t.Logf("生成的 Timestamp Long ID: %d", idTimestamp)
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue