uniugm/admin/apps/game/domain/gamelog.go
2025-08-12 14:42:34 +08:00

227 lines
6.2 KiB
Go

package domain
import (
"admin/apps/game/domain/projects"
"admin/apps/game/domain/repo"
"admin/internal/consts"
"admin/internal/errcode"
"admin/internal/model/dto"
"admin/lib/xlog"
"context"
"github.com/jmoiron/sqlx"
"github.com/xuri/excelize/v2"
"gorm.io/gorm"
"strconv"
"time"
)
type GameLogService struct {
projectRepo repo.IProjectRepo
repo repo.IGameLogRepo
}
func NewGameLogSvc(db *gorm.DB, metaDb *gorm.DB, clickHouseSqlx *sqlx.DB) *GameLogService {
return &GameLogService{projectRepo: repo.NewProjectRepo(db), repo: repo.NewGameLogRepo(metaDb, clickHouseSqlx)}
}
func (svc *GameLogService) QueryEventList(projectId int, eventName []string, serverId int, account, roleId string,
pageNo, pageLen int, dateStart, dateEnd time.Time) (totalCount int, fieldsDescInfo []*dto.GameLogFieldInfo, rows [][]any, err error) {
_, projectEt, find, err := svc.projectRepo.GetById(projectId)
if err != nil {
return 0, nil, nil, err
}
if !find {
return 0, nil, nil, errcode.New(errcode.ServerError, "not found project %v db data", projectId)
}
appId := projectEt.Po.BiAdminAppId
if appId == 0 {
return 0, make([]*dto.GameLogFieldInfo, 0), make([][]any, 0), nil
}
var attrList []*repo.AttrInfo
attrList, err = svc.repo.QueryAttrListByEvent(appId, eventName)
if err != nil {
return
}
querier := svc.repo.NewEventListQuerier("xwl_event"+strconv.Itoa(appId), eventName, attrList)
totalCount, fieldsDescInfo, rows, err = querier.CondRoleId(serverId, roleId).CondAccount(serverId, account).
Go(context.Background(), pageNo, pageLen, dateStart, dateEnd)
if err != nil {
xlog.Warnf("event list error:%v", err)
return
}
hook := projects.GetProjectResourceHook(projectEt, consts.ResourcesName_GameLog)
if h, ok := hook.(projects.IGameLogEventListHook); ok {
totalCount, fieldsDescInfo, rows = h.Trim(projectEt, eventName, totalCount, fieldsDescInfo, rows)
}
if rows == nil {
rows = make([][]any, 0)
}
return
}
func (svc *GameLogService) QueryEventListExport(projectId int, eventName []string, serverId int, account, roleId string,
dateStart, dateEnd time.Time) (filePath string, err error) {
_, projectEt, find, err := svc.projectRepo.GetById(projectId)
if err != nil {
return "", err
}
if !find {
return "", errcode.New(errcode.ServerError, "not found project %v db data", projectId)
}
appId := projectEt.Po.BiAdminAppId
if appId == 0 {
return "", nil
}
var attrList []*repo.AttrInfo
attrList, err = svc.repo.QueryAttrListByEvent(appId, eventName)
if err != nil {
return
}
pageNo := 1
pageLen := 1000
querier := svc.repo.NewEventListQuerier("xwl_event"+strconv.Itoa(appId), eventName, attrList)
querier.CondRoleId(serverId, roleId).CondAccount(serverId, account)
queryEventLogFun := func(curPageNo, curPageLen int) (int, []*dto.GameLogFieldInfo, [][]any, error) {
a, b, c, err := querier.Go(context.Background(), curPageNo, curPageLen, dateStart, dateEnd)
if err != nil {
return 0, nil, nil, err
}
hook := projects.GetProjectResourceHook(projectEt, consts.ResourcesName_GameLog)
if h, ok := hook.(projects.IGameLogEventListHook); ok {
a, b, c = h.Trim(projectEt, eventName, a, b, c)
}
return a, b, c, nil
}
// 先读第一页看看总数
totalCount, fieldsDescInfo, tmpRows, err := queryEventLogFun(pageNo, pageLen)
if err != nil {
xlog.Warnf("event list error:%v", err)
return
}
filePath = "/tmp/" + "gamelog-" + time.Now().Format("20060102150405") + ".xlsx"
f := excelize.NewFile()
defer f.Close()
f.SetDefaultFont("Arial")
index, err := f.NewSheet("Sheet1")
if err != nil {
return "", errcode.New(errcode.ServerError, "new excel sheet error:%v", err)
}
f.SetActiveSheet(index)
sheetWriter, err := f.NewStreamWriter("Sheet1")
if err != nil {
return "", errcode.New(errcode.ServerError, "new excel sheet writer error:%v", err)
}
// 写入excel文件头
writeHeaders := make([]any, 0, len(fieldsDescInfo))
for _, field := range fieldsDescInfo {
writeHeaders = append(writeHeaders, field.Alias)
}
headerCell, _ := excelize.CoordinatesToCellName(1, 1)
err = sheetWriter.SetRow(headerCell, writeHeaders)
if err != nil {
xlog.Warnf("set row error:%v", err)
return "", errcode.New(errcode.ServerError, "set row error:%v", err)
}
xlog.Tracef("set headers %+v ok", writeHeaders)
//err = sheetWriter.Flush()
//if err != nil {
// return "", errcode.New(errcode.ServerError, "flush error:%v", err)
//}
writeQueue := make(chan [][]any, 20)
resultQueue := make(chan error, 1)
// 启动另一个协程来写文件
go func() {
curRowNum := 2
timeout := time.NewTicker(time.Second * 120)
for {
select {
case recvRows, ok := <-writeQueue:
if !ok {
return
}
for _, row := range recvRows {
rowCell, _ := excelize.CoordinatesToCellName(1, curRowNum)
err = sheetWriter.SetRow(rowCell, row)
if err != nil {
resultQueue <- errcode.New(errcode.ServerError, "set row error:%v", err)
return
}
xlog.Tracef("set row %+v ok", row)
curRowNum++
}
if curRowNum >= totalCount {
err = sheetWriter.Flush()
if err != nil {
resultQueue <- errcode.New(errcode.ServerError, "flush error:%v", err)
return
}
saveErr := f.SaveAs(filePath)
if saveErr != nil {
err = errcode.New(errcode.ServerError, "save as error:%v", err)
return
}
xlog.Infof("finish write total count %v to file:%v", curRowNum, filePath)
// 搞完了
resultQueue <- nil
return
}
case <-timeout.C:
xlog.Warnf("timeout!!")
}
}
}()
writeFileHandler := func(fields []*dto.GameLogFieldInfo, rows [][]any) {
writeQueue <- rows
}
// 写第一页数据
writeFileHandler(fieldsDescInfo, tmpRows)
if totalCount >= pageLen {
// 总数还有,分页读了
totalPageNum := totalCount/pageLen + 1
for i := 1; i <= totalPageNum; i++ {
if i == 1 {
// 第一页读过了,跳过
continue
}
totalCount, fieldsDescInfo, tmpRows, err = queryEventLogFun(pageNo, i*pageLen)
if err != nil {
xlog.Warnf("event list error:%v", err)
return
}
writeFileHandler(fieldsDescInfo, tmpRows)
}
}
err = <-resultQueue
if err != nil {
xlog.Warnf("event list write excel file:%v", err)
} else {
xlog.Infof("export file %v successfully!", filePath)
}
return
}