1
All checks were successful
ci/woodpecker/push/my-first-workflow Pipeline was successful

This commit is contained in:
昔念
2026-04-26 02:33:06 +08:00
parent 4906197c77
commit c07e521e4e
12 changed files with 265 additions and 348 deletions

View File

@@ -11,23 +11,23 @@ const (
type PeakTianxuan struct {
*BaseConfig
WeekIndex uint32 `gorm:"not null;index:idx_peak_tianxuan_week;uniqueIndex:idx_peak_tianxuan_week_pet;comment:'周序号'" json:"week_index"`
DisplayOrder uint32 `gorm:"not null;default:0;comment:'展示顺序'" json:"display_order"`
PetID uint32 `gorm:"not null;uniqueIndex:idx_peak_tianxuan_week_pet;comment:'天选精灵ID'" json:"pet_id"`
PresetName string `gorm:"type:varchar(64);not null;default:'';comment:'预设显示名'" json:"preset_name"`
Level uint32 `gorm:"not null;default:100;comment:'预设等级'" json:"level"`
Nature uint32 `gorm:"not null;default:0;comment:'预设性格'" json:"nature"`
Hp uint32 `gorm:"not null;default:0;comment:'预设当前生命'" json:"hp"`
MaxHp uint32 `gorm:"not null;default:0;comment:'预设最大生命'" json:"max_hp"`
Attack uint32 `gorm:"not null;default:0;comment:'预设攻击'" json:"attack"`
Defence uint32 `gorm:"not null;default:0;comment:'预设防御'" json:"defence"`
SpAttack uint32 `gorm:"not null;default:0;comment:'预设特攻'" json:"sp_attack"`
SpDefence uint32 `gorm:"not null;default:0;comment:'预设特防'" json:"sp_defence"`
Speed uint32 `gorm:"not null;default:0;comment:'预设速度'" json:"speed"`
SkinID uint32 `gorm:"not null;default:0;comment:'预设皮肤ID'" json:"skin_id"`
EffectIDs []uint32 `gorm:"type:jsonb;not null;default:'[]';comment:'预设特性/效果ID列表'" json:"effect_ids"`
SkillIDs []uint32 `gorm:"type:jsonb;not null;default:'[]';comment:'预设技能ID列表'" json:"skill_ids"`
VoteCount uint32 `gorm:"not null;default:0;comment:'票数统计'" json:"vote_count"`
PlayerID uint32 `gorm:"not null;index:idx_peak_tianxuan_player;uniqueIndex:idx_peak_tianxuan_player_pet;comment:'所属玩家ID'" json:"player_id"`
DisplayOrder uint32 `gorm:"not null;default:0;comment:'展示顺序'" json:"display_order"`
PetID uint32 `gorm:"not null;uniqueIndex:idx_peak_tianxuan_player_pet;comment:'天选精灵ID'" json:"pet_id"`
PresetName string `gorm:"type:varchar(64);not null;default:'';comment:'预设显示名'" json:"preset_name"`
Level uint32 `gorm:"not null;default:100;comment:'预设等级'" json:"level"`
Nature uint32 `gorm:"not null;default:0;comment:'预设性格'" json:"nature"`
Hp uint32 `gorm:"not null;default:0;comment:'预设当前生命'" json:"hp"`
MaxHp uint32 `gorm:"not null;default:0;comment:'预设最大生命'" json:"max_hp"`
Attack uint32 `gorm:"not null;default:0;comment:'预设攻击'" json:"attack"`
Defence uint32 `gorm:"not null;default:0;comment:'预设防御'" json:"defence"`
SpAttack uint32 `gorm:"not null;default:0;comment:'预设特攻'" json:"sp_attack"`
SpDefence uint32 `gorm:"not null;default:0;comment:'预设特防'" json:"sp_defence"`
Speed uint32 `gorm:"not null;default:0;comment:'预设速度'" json:"speed"`
SkinID uint32 `gorm:"not null;default:0;comment:'预设皮肤ID'" json:"skin_id"`
EffectIDs []uint32 `gorm:"type:jsonb;not null;default:'[]';comment:'预设特性/效果ID列表'" json:"effect_ids"`
SkillIDs []uint32 `gorm:"type:jsonb;not null;default:'[]';comment:'预设技能ID列表'" json:"skill_ids"`
VoteCount uint32 `gorm:"not null;default:0;comment:'票数统计'" json:"vote_count"`
}
func (*PeakTianxuan) TableName() string {

View File

@@ -2,6 +2,7 @@ package service
import (
"context"
"time"
"blazing/common/data/xmlres"
"blazing/cool"
@@ -22,20 +23,36 @@ func NewPeakTianxuanService() *PeakTianxuanService {
return &PeakTianxuanService{
&cool.Service{
Model: model.NewPeakTianxuan(),
Where: func(ctx context.Context) []g.Array {
admin := cool.GetAdmin(ctx)
return []g.Array{{"player_id", uint32(admin.UserId)}}
},
InsertParam: func(ctx context.Context) g.MapStrAny {
admin := cool.GetAdmin(ctx)
return g.MapStrAny{
"player_id": uint32(admin.UserId),
}
},
PageQueryOp: &cool.QueryOp{
KeyWordField: []string{"preset_name", "remark"},
FieldEQ: []string{"week_index", "pet_id", "is_enable"},
FieldEQ: []string{"player_id", "pet_id", "is_enable"},
Where: func(ctx context.Context) []g.Array {
admin := cool.GetAdmin(ctx)
return []g.Array{{"player_id", uint32(admin.UserId)}}
},
AddOrderby: g.MapStrStr{
"week_index": "desc",
"display_order": "asc",
"id": "desc",
},
},
ListQueryOp: &cool.QueryOp{
KeyWordField: []string{"preset_name", "remark"},
FieldEQ: []string{"week_index", "pet_id", "is_enable"},
FieldEQ: []string{"player_id", "pet_id", "is_enable"},
Where: func(ctx context.Context) []g.Array {
admin := cool.GetAdmin(ctx)
return []g.Array{{"player_id", uint32(admin.UserId)}}
},
AddOrderby: g.MapStrStr{
"week_index": "desc",
"display_order": "asc",
"id": "desc",
},
@@ -49,17 +66,20 @@ func (s *PeakTianxuanService) ModifyBefore(ctx context.Context, method string, p
return nil
}
admin := cool.GetAdmin(ctx)
param["player_id"] = uint32(admin.UserId)
var (
weekIndex = gconv.Uint32(param["week_index"])
petID = gconv.Uint32(param["pet_id"])
level = gconv.Uint32(param["level"])
hp = gconv.Uint32(param["hp"])
maxHp = gconv.Uint32(param["max_hp"])
recordID = gconv.Uint32(param["id"])
playerID = gconv.Uint32(param["player_id"])
petID = gconv.Uint32(param["pet_id"])
level = gconv.Uint32(param["level"])
hp = gconv.Uint32(param["hp"])
maxHp = gconv.Uint32(param["max_hp"])
recordID = gconv.Uint32(param["id"])
)
if weekIndex == 0 {
return gerror.New("周序号不能为空")
if playerID == 0 {
return gerror.New("配置玩家不能为空")
}
if petID == 0 {
return gerror.New("天选精灵ID不能为空")
@@ -72,7 +92,9 @@ func (s *PeakTianxuanService) ModifyBefore(ctx context.Context, method string, p
}
var currentCount int
query := cool.DBM(s.Model).Where("week_index", weekIndex).Where("pet_id", petID)
query := cool.DBM(s.Model).
Where("player_id", playerID).
Where("pet_id", petID)
if recordID > 0 {
query = query.WhereNot("id", recordID)
}
@@ -80,72 +102,67 @@ func (s *PeakTianxuanService) ModifyBefore(ctx context.Context, method string, p
return err
}
if currentCount > 0 {
return gerror.New("同一不能重复配置同一只天选精灵")
}
prevPetIDs, err := s.ListWeekPetIDs(weekIndex - 1)
if err != nil {
return err
}
if _, ok := prevPetIDs[petID]; ok {
return gerror.New("本周天选精灵不能和上一周重复")
return gerror.New("同一玩家不能重复配置同一只天选精灵")
}
return nil
}
func (s *PeakTianxuanService) LatestWeekIndex() (uint32, error) {
var result struct {
WeekIndex uint32 `json:"week_index"`
}
if err := dbm_nocache_noenable(s.Model).
Fields("COALESCE(MAX(week_index), 0) AS week_index").
Scan(&result); err != nil {
return 0, err
}
return result.WeekIndex, nil
func dateWeekIndex(t time.Time) uint32 {
year, week := t.ISOWeek()
return uint32(year*100 + week)
}
func (s *PeakTianxuanService) ListWeekPetIDs(weekIndex uint32) (map[uint32]struct{}, error) {
func currentDateWeekIndex() uint32 {
return dateWeekIndex(time.Now())
}
func prevDateWeekIndex() uint32 {
return dateWeekIndex(time.Now().AddDate(0, 0, -7))
}
func (s *PeakTianxuanService) CurrentVoteWeekIndex() (uint32, uint32, error) {
return currentDateWeekIndex(), prevDateWeekIndex(), nil
}
func (s *PeakTianxuanService) ListWeekPetIDs(weekIndex uint32, playerIDs ...uint32) (map[uint32]struct{}, error) {
ret := make(map[uint32]struct{})
if weekIndex == 0 {
return ret, nil
}
var list []model.PeakTianxuan
if err := dbm_enable(s.Model).Where("week_index", weekIndex).Scan(&list); err != nil {
var voteRows []struct {
PetID uint32 `json:"pet_id"`
}
if err := cool.DBM(model.NewPeakTianxuanVote()).
Fields("pet_id").
Where("week_index", weekIndex).
Group("pet_id").
Scan(&voteRows); err != nil {
return nil, err
}
for _, item := range list {
for _, item := range voteRows {
ret[item.PetID] = struct{}{}
}
return ret, nil
}
func (s *PeakTianxuanService) GetWeekList(weekIndex uint32) ([]model.PeakTianxuan, error) {
func (s *PeakTianxuanService) GetWeekList(weekIndex uint32, playerIDs ...uint32) ([]model.PeakTianxuan, error) {
var list []model.PeakTianxuan
if weekIndex == 0 {
return list, nil
}
err := dbm_enable(s.Model).
Where("week_index", weekIndex).
Order("display_order asc,id asc").
Scan(&list)
query := dbm_enable(s.Model)
if len(playerIDs) > 0 && playerIDs[0] > 0 {
query = query.Where("player_id", playerIDs[0])
}
err := query.Order("display_order asc,id asc").Scan(&list)
return list, err
}
func (s *PeakTianxuanService) GetCurrentWeekList() ([]model.PeakTianxuan, uint32, error) {
weekIndex, err := s.LatestWeekIndex()
if err != nil || weekIndex == 0 {
return nil, weekIndex, err
}
list, err := s.GetWeekList(weekIndex)
func (s *PeakTianxuanService) GetCurrentWeekList(playerIDs ...uint32) ([]model.PeakTianxuan, uint32, error) {
weekIndex := currentDateWeekIndex()
list, err := s.GetWeekList(0, playerIDs...)
return list, weekIndex, err
}
@@ -186,24 +203,21 @@ func (s *PeakTianxuanService) SaveVote(playerID uint32, petID uint32) (uint32, e
return 0, gerror.New("投票精灵不在候选池中")
}
currentWeekIndex, err := s.LatestWeekIndex()
voteWeekIndex, _, err := s.CurrentVoteWeekIndex()
if err != nil {
return 0, err
}
if currentWeekIndex == 0 {
currentWeekIndex = 1
}
voteModel := model.NewPeakTianxuanVote()
data := model.PeakTianxuanVote{
WeekIndex: currentWeekIndex,
WeekIndex: voteWeekIndex,
PlayerID: playerID,
PetID: normalize[0],
}
var count int
count, err = cool.DBM(voteModel).
Where("week_index", currentWeekIndex).
Where("week_index", voteWeekIndex).
Where("player_id", playerID).
Count()
if err != nil {
@@ -211,7 +225,7 @@ func (s *PeakTianxuanService) SaveVote(playerID uint32, petID uint32) (uint32, e
}
if count > 0 {
_, err = cool.DBM(voteModel).
Where("week_index", currentWeekIndex).
Where("week_index", voteWeekIndex).
Where("player_id", playerID).
Data(data).
Update()
@@ -225,8 +239,35 @@ func (s *PeakTianxuanService) SaveVote(playerID uint32, petID uint32) (uint32, e
return normalize[0], nil
}
func (s *PeakTianxuanService) BuildCurrentTianxuanPayload() ([]g.Map, uint32, error) {
list, weekIndex, err := s.GetCurrentWeekList()
func (s *PeakTianxuanService) GetPlayerVote(playerID uint32) (uint32, error) {
voteWeekIndex, prevWeekIndex, err := s.CurrentVoteWeekIndex()
if err != nil {
return 0, err
}
var vote model.PeakTianxuanVote
if err = cool.DBM(model.NewPeakTianxuanVote()).
Where("week_index", voteWeekIndex).
Where("player_id", playerID).
Scan(&vote); err != nil {
return 0, err
}
if vote.PetID > 0 || prevWeekIndex == 0 {
return vote.PetID, nil
}
// 兼容旧数据:之前投票可能写在“当前正式周”里,打开页面仍需标出玩家已选。
if err = cool.DBM(model.NewPeakTianxuanVote()).
Where("week_index", prevWeekIndex).
Where("player_id", playerID).
Scan(&vote); err != nil {
return 0, err
}
return vote.PetID, nil
}
func (s *PeakTianxuanService) BuildCurrentTianxuanPayload(playerIDs ...uint32) ([]g.Map, uint32, error) {
list, weekIndex, err := s.GetCurrentWeekList(playerIDs...)
if err != nil {
return nil, 0, err
}
@@ -241,7 +282,7 @@ func (s *PeakTianxuanService) BuildCurrentTianxuanPayload() ([]g.Map, uint32, er
}
ret = append(ret, g.Map{
"id": item.ID,
"week_index": item.WeekIndex,
"player_id": item.PlayerID,
"display_order": item.DisplayOrder,
"pet_id": item.PetID,
"petId": item.PetID,
@@ -269,37 +310,25 @@ func (s *PeakTianxuanService) BuildCurrentTianxuanPayload() ([]g.Map, uint32, er
}
func (s *PeakTianxuanService) BuildVoteCandidatePoolPayload() ([]g.Map, uint32, uint32, error) {
currentWeekIndex, err := s.LatestWeekIndex()
if err != nil {
return nil, 0, 0, err
}
prevWeekIndex := uint32(0)
if currentWeekIndex > 1 {
prevWeekIndex = currentWeekIndex - 1
}
prevWeekPetIDs, err := s.ListWeekPetIDs(prevWeekIndex)
voteWeekIndex, prevWeekIndex, err := s.CurrentVoteWeekIndex()
if err != nil {
return nil, 0, 0, err
}
currentWeekVoteMap := make(map[uint32]uint32)
if currentWeekIndex > 0 {
var voteRows []struct {
PetID uint32 `json:"pet_id"`
VoteCount uint32 `json:"vote_count"`
}
if err = cool.DBM(model.NewPeakTianxuanVote()).
Fields("pet_id, COUNT(1) AS vote_count").
Where("week_index", currentWeekIndex).
Group("pet_id").
Scan(&voteRows); err != nil {
return nil, 0, 0, err
}
for _, item := range voteRows {
currentWeekVoteMap[item.PetID] = item.VoteCount
}
var voteRows []struct {
PetID uint32 `json:"pet_id"`
VoteCount uint32 `json:"vote_count"`
}
if err = cool.DBM(model.NewPeakTianxuanVote()).
Fields("pet_id, COUNT(1) AS vote_count").
Where("week_index", voteWeekIndex).
Group("pet_id").
Scan(&voteRows); err != nil {
return nil, 0, 0, err
}
for _, item := range voteRows {
currentWeekVoteMap[item.PetID] = item.VoteCount
}
var meleeList []model.PetBaseConfig
@@ -318,9 +347,6 @@ func (s *PeakTianxuanService) BuildVoteCandidatePoolPayload() ([]g.Map, uint32,
if petID == 0 {
continue
}
if _, ok := prevWeekPetIDs[petID]; ok {
continue
}
if _, ok := unique[petID]; ok {
continue
}
@@ -354,11 +380,11 @@ func (s *PeakTianxuanService) BuildVoteCandidatePoolPayload() ([]g.Map, uint32,
})
}
return ret, currentWeekIndex, prevWeekIndex, nil
return ret, voteWeekIndex, prevWeekIndex, nil
}
func (s *PeakTianxuanService) CurrentTianxuanPetIDs() ([]uint32, error) {
list, _, err := s.GetCurrentWeekList()
func (s *PeakTianxuanService) CurrentTianxuanPetIDs(playerIDs ...uint32) ([]uint32, error) {
list, _, err := s.GetCurrentWeekList(playerIDs...)
if err != nil {
return nil, err
}
@@ -374,42 +400,30 @@ func (s *PeakTianxuanService) CurrentTianxuanPetIDs() ([]uint32, error) {
}
func (s *PeakTianxuanService) BuildWeekTianxuanPayload(weekIndex uint32) ([]g.Map, error) {
list, err := s.GetWeekList(weekIndex)
if err != nil {
var voteRows []struct {
PetID uint32 `json:"pet_id"`
VoteCount uint32 `json:"vote_count"`
}
if err := cool.DBM(model.NewPeakTianxuanVote()).
Fields("pet_id, COUNT(1) AS vote_count").
Where("week_index", weekIndex).
Group("pet_id").
Order("vote_count desc, pet_id asc").
Scan(&voteRows); err != nil {
return nil, err
}
ret := make([]g.Map, 0, len(list))
for _, item := range list {
name := item.PresetName
if name == "" {
if pet, ok := xmlres.PetMAP[int(item.PetID)]; ok {
name = pet.DefName
}
ret := make([]g.Map, 0, len(voteRows))
for _, item := range voteRows {
name := ""
if pet, ok := xmlres.PetMAP[int(item.PetID)]; ok {
name = pet.DefName
}
ret = append(ret, g.Map{
"id": item.ID,
"week_index": item.WeekIndex,
"display_order": item.DisplayOrder,
"pet_id": item.PetID,
"petId": item.PetID,
"name": name,
"preset_name": item.PresetName,
"level": item.Level,
"nature": item.Nature,
"hp": item.Hp,
"max_hp": item.MaxHp,
"attack": item.Attack,
"defence": item.Defence,
"sp_attack": item.SpAttack,
"sp_defence": item.SpDefence,
"speed": item.Speed,
"skin_id": item.SkinID,
"effect_ids": item.EffectIDs,
"skill_ids": item.SkillIDs,
"vote_count": item.VoteCount,
"is_enable": item.IsEnable,
"remark": item.Remark,
"pet_id": item.PetID,
"petId": item.PetID,
"name": name,
"vote_count": item.VoteCount,
})
}

View File

@@ -33,24 +33,29 @@ type GetPVPReq struct {
func (c *PVPController) Get(ctx context.Context, req *GetPVPReq) (res *cool.BaseRes, err error) {
res = &cool.BaseRes{}
var (
admin = cool.GetAdmin(ctx)
pvpInfo = service.NewPVPService(uint32(admin.UserId)).Get(uint32(admin.UserId))
tianxuanSv = configService.NewPeakTianxuanService()
votePool []g.Map
currentPool []g.Map
prevWeekPool []g.Map
weekIndex uint32
prevWeekIndex uint32
admin = cool.GetAdmin(ctx)
pvpInfo = service.NewPVPService(uint32(admin.UserId)).Get(uint32(admin.UserId))
tianxuanSv = configService.NewPeakTianxuanService()
votePool []g.Map
currentPool []g.Map
prevWeekPool []g.Map
playerVotePetID uint32
weekIndex uint32
prevWeekIndex uint32
)
if votePool, weekIndex, prevWeekIndex, err = tianxuanSv.BuildVoteCandidatePoolPayload(); err != nil {
return
}
if currentPool, _, err = tianxuanSv.BuildCurrentTianxuanPayload(); err != nil {
if currentPool, _, err = tianxuanSv.BuildCurrentTianxuanPayload(uint32(admin.UserId)); err != nil {
return
}
if prevWeekPool, err = tianxuanSv.BuildWeekTianxuanPayload(prevWeekIndex); err != nil {
return
}
if playerVotePetID, err = tianxuanSv.GetPlayerVote(uint32(admin.UserId)); err != nil {
return
}
markMyTianxuanVote(votePool, playerVotePetID)
res.Data = g.Map{
"id": pvpInfo.ID,
@@ -63,6 +68,7 @@ func (c *PVPController) Get(ctx context.Context, req *GetPVPReq) (res *cool.Base
"tianxuan_vote_pool": votePool,
"tianxuan_prev_week_pool": prevWeekPool,
"current_tianxuan_pool": currentPool,
"my_tianxuan_vote_pet_id": playerVotePetID,
}
return
@@ -77,9 +83,13 @@ func (c *PVPController) SaveTianxuanVote(ctx context.Context, req *SaveTianxuanV
res = &cool.BaseRes{}
var (
admin = cool.GetAdmin(ctx)
petID uint32
saved uint32
admin = cool.GetAdmin(ctx)
tianxuanSv = configService.NewPeakTianxuanService()
petID uint32
saved uint32
votePool []g.Map
weekIndex uint32
prevWeekIndex uint32
)
for _, item := range req.PetIDs {
@@ -90,13 +100,34 @@ func (c *PVPController) SaveTianxuanVote(ctx context.Context, req *SaveTianxuanV
break
}
if saved, err = configService.NewPeakTianxuanService().SaveVote(uint32(admin.UserId), petID); err != nil {
if saved, err = tianxuanSv.SaveVote(uint32(admin.UserId), petID); err != nil {
return
}
if votePool, weekIndex, prevWeekIndex, err = tianxuanSv.BuildVoteCandidatePoolPayload(); err != nil {
return
}
markMyTianxuanVote(votePool, saved)
res.Data = g.Map{
"saved_pet_id": saved,
"my_tianxuan_vote_pet_id": saved,
"required_tianxuan_vote_count": 1,
"tianxuan_week_index": weekIndex,
"tianxuan_prev_week_index": prevWeekIndex,
"tianxuan_vote_pool": votePool,
}
return
}
func markMyTianxuanVote(votePool []g.Map, petID uint32) {
if petID == 0 {
return
}
for _, item := range votePool {
if gconv.Uint32(item["pet_id"]) == petID || gconv.Uint32(item["petId"]) == petID {
item["is_voted"] = true
item["isVoted"] = true
return
}
}
}