feat(cron): 添加角色配装信息刷新任务并优化神器数据同步功能
- 新增每5天执行一次的角色配装信息刷新任务 - 重构神器数据同步功能,优化数据处理和保存逻辑- 添加神器图片URL获取和上传逻辑 - 更新相关测试用例
This commit is contained in:
@@ -180,6 +180,13 @@ func (l *Logic) registerDefaultJobs(ctx context.Context) error {
|
||||
// return err
|
||||
//}
|
||||
|
||||
// 每5天执行一次角色配装信息刷新任务
|
||||
if err := l.AddJob(ctx, "hero_set_refresh_5days", "0 0 0 */5 * *", func() {
|
||||
l.refreshHeroSetContent(ctx)
|
||||
}); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -196,7 +203,7 @@ func (l *Logic) syncDataFromThirdParty(ctx context.Context) {
|
||||
g.Log().Info(ctx, "Data sync completed")
|
||||
}
|
||||
|
||||
// syncHeroData 同步英雄数据
|
||||
//同步英雄数据
|
||||
func (l *Logic) syncHeroData(ctx context.Context) {
|
||||
g.Log().Info(ctx, "Starting hero data sync...")
|
||||
|
||||
@@ -284,3 +291,13 @@ func (l *Logic) refreshOssPresignUrlCacheJob(ctx context.Context) {
|
||||
g.Log().Info(ctx, "OSS presigned URL cache refresh completed")
|
||||
}
|
||||
}
|
||||
|
||||
// 新增:定时刷新角色配装信息
|
||||
func (l *Logic) refreshHeroSetContent(ctx context.Context) {
|
||||
g.Log().Info(ctx, "Starting hero set content refresh...")
|
||||
if err := l.sync.RefreshAllHeroSetContent(ctx); err != nil {
|
||||
g.Log().Error(ctx, "Hero set content refresh failed:", err)
|
||||
return
|
||||
}
|
||||
g.Log().Info(ctx, "Hero set content refresh completed")
|
||||
}
|
||||
|
||||
@@ -15,6 +15,7 @@ import (
|
||||
"github.com/gogf/gf/v2/net/gclient"
|
||||
"github.com/gogf/gf/v2/os/gtime"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
@@ -132,10 +133,9 @@ func (t *ThirdPartyDataSync) FetchHeroBuildsFromAPI(ctx context.Context, heroNam
|
||||
// 从API获取神器数据
|
||||
func (t *ThirdPartyDataSync) fetchArtifactDataFromAPI(ctx context.Context) (string, error) {
|
||||
// 示例API地址
|
||||
apiURL := "https://static.smilegatemegaport.com/gameRecord/epic7/epic7_artifact.json?_=1729322698936"
|
||||
apiURL := consts.ArtifactDataURL
|
||||
|
||||
headers := map[string]string{
|
||||
//"User-Agent": "EpicGameBot/1.0",
|
||||
"Accept": "application/json",
|
||||
}
|
||||
|
||||
@@ -282,27 +282,76 @@ func (t *ThirdPartyDataSync) processAndSaveHeroData(ctx context.Context, data []
|
||||
|
||||
// processAndSaveArtifactData 处理并保存神器数据
|
||||
func (t *ThirdPartyDataSync) processAndSaveArtifactData(ctx context.Context, data string) error {
|
||||
// 使用 gjson 解析
|
||||
j := gjson.New(data)
|
||||
zhcn := j.Get("zh-CN")
|
||||
// 检查json对象本身和其内部值,并使用 .Var().IsSlice() 这种更可靠的方式判断是否为数组
|
||||
if !zhcn.IsSlice() {
|
||||
return fmt.Errorf("神器数据格式错误,期望是一个JSON数组")
|
||||
// 1. 解析json为map
|
||||
var artifactMap map[string]struct {
|
||||
Name string `json:"name"`
|
||||
Rarity int `json:"rarity"`
|
||||
Role string `json:"role"`
|
||||
Stats struct {
|
||||
Attack int `json:"attack"`
|
||||
Health int `json:"health"`
|
||||
Defense int `json:"defense"`
|
||||
} `json:"stats"`
|
||||
Code string `json:"code"`
|
||||
}
|
||||
if err := json.Unmarshal([]byte(data), &artifactMap); err != nil {
|
||||
return fmt.Errorf("解析神器数据失败: %v", err)
|
||||
}
|
||||
g.Log().Info(ctx, "解析到", len(artifactMap), "个神器数据")
|
||||
|
||||
// 2. 查询数据库所有神器,构建map
|
||||
var dbArtifacts []*entity.EpicArtifactInfo
|
||||
err := dao.EpicArtifactInfo.Ctx(ctx).Scan(&dbArtifacts)
|
||||
if err != nil {
|
||||
return fmt.Errorf("查询数据库神器失败: %v", err)
|
||||
}
|
||||
artifactDbMap := make(map[string]*entity.EpicArtifactInfo, len(dbArtifacts))
|
||||
for _, a := range dbArtifacts {
|
||||
artifactDbMap[a.ArtifactCode] = a
|
||||
}
|
||||
|
||||
var artifacts []*dto.ThirdPartyArtifactDTO
|
||||
if err := zhcn.Scan(&artifacts); err != nil {
|
||||
return fmt.Errorf("解析神器数据到DTO失败: %v", err)
|
||||
}
|
||||
|
||||
// 批量处理数据
|
||||
for _, artifact := range artifacts {
|
||||
if err := t.saveArtifactData(ctx, artifact); err != nil {
|
||||
g.Log().Error(ctx, "保存神器数据失败:", err)
|
||||
continue
|
||||
for _, art := range artifactMap {
|
||||
var dbArt *entity.EpicArtifactInfo
|
||||
if v, ok := artifactDbMap[art.Code]; ok {
|
||||
dbArt = v
|
||||
}
|
||||
customImgUrl := getArtifactImageUrl(ctx, art.Code, dbArt)
|
||||
artifact := &entity.EpicArtifactInfo{
|
||||
ArtifactName: i18n.GetZh(ctx, art.Name),
|
||||
ArtifactNameEn: art.Name,
|
||||
ArtifactCode: art.Code,
|
||||
Rarity: strconv.Itoa(art.Rarity),
|
||||
Role: art.Role,
|
||||
StatsAttack: art.Stats.Attack,
|
||||
StatsHealth: art.Stats.Health,
|
||||
StatsDefense: art.Stats.Defense,
|
||||
ImageUrl: customImgUrl,
|
||||
Updater: "sync",
|
||||
UpdateTime: gtime.Now(),
|
||||
Deleted: false,
|
||||
}
|
||||
if dbArt != nil {
|
||||
artifact.Id = dbArt.Id
|
||||
_, err := dao.EpicArtifactInfo.Ctx(ctx).
|
||||
Where(dao.EpicArtifactInfo.Columns().ArtifactCode, art.Code).
|
||||
Data(artifact).
|
||||
Update()
|
||||
if err != nil {
|
||||
g.Log().Error(ctx, "更新神器失败:", art.Name, err)
|
||||
continue
|
||||
}
|
||||
g.Log().Info(ctx, "更新神器:", art.Name)
|
||||
} else {
|
||||
artifact.Creator = "sync"
|
||||
artifact.CreateTime = gtime.Now()
|
||||
_, err := dao.EpicArtifactInfo.Ctx(ctx).Data(artifact).Insert()
|
||||
if err != nil {
|
||||
g.Log().Error(ctx, "插入神器失败:", art.Name, err)
|
||||
continue
|
||||
}
|
||||
g.Log().Info(ctx, "插入神器:", art.Name)
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -443,7 +492,7 @@ func (t *ThirdPartyDataSync) RefreshHeroSetContentByHeroInfo(ctx context.Context
|
||||
}
|
||||
}
|
||||
|
||||
// RefreshAllHeroSetContent 刷新所有角色配装字段
|
||||
//刷新所有角色配装字段
|
||||
func (t *ThirdPartyDataSync) RefreshAllHeroSetContent(ctx context.Context) error {
|
||||
g.Log().Info(ctx, "开始批量刷新所有角色配装字段...")
|
||||
|
||||
@@ -477,3 +526,20 @@ func (t *ThirdPartyDataSync) RefreshAllHeroSetContent(ctx context.Context) error
|
||||
g.Log().Info(ctx, "所有角色配装字段刷新完成")
|
||||
return nil
|
||||
}
|
||||
|
||||
// 获取神器图片URL,已上传则复用,否则上传
|
||||
func getArtifactImageUrl(ctx context.Context, artCode string, dbArt *entity.EpicArtifactInfo) string {
|
||||
if dbArt != nil && dbArt.ImageUrl != "" && strings.HasPrefix(dbArt.ImageUrl, consts.S3CustomDomain) {
|
||||
return dbArt.ImageUrl
|
||||
}
|
||||
ossObjectKey := fmt.Sprintf("epic/artifact/images/%s.png", artCode)
|
||||
ossUrl, err := util.DownloadAndUploadToOSS(ctx, "", ossObjectKey)
|
||||
if err != nil || ossUrl == "" {
|
||||
return ""
|
||||
}
|
||||
prefix := consts.S3Endpoint + "/" + consts.S3Bucket
|
||||
if strings.HasPrefix(ossUrl, prefix) {
|
||||
return consts.S3CustomDomain + ossUrl[len(prefix):]
|
||||
}
|
||||
return ossUrl
|
||||
}
|
||||
|
||||
@@ -49,8 +49,8 @@ func TestSyncHeroData(t *testing.T) {
|
||||
* 测试同步神器数据
|
||||
*/
|
||||
func TestSyncArtifactData_Success(t *testing.T) {
|
||||
_ = i18n.RefreshI18n(context.Background())
|
||||
sync := NewThirdPartyDataSync()
|
||||
|
||||
err := sync.SyncArtifactData(context.Background())
|
||||
if err != nil {
|
||||
t.Errorf("expected success, but got error: %v", err)
|
||||
|
||||
Reference in New Issue
Block a user