add gamelog
This commit is contained in:
		
							parent
							
								
									166812abf4
								
							
						
					
					
						commit
						b111e4d145
					
				@ -8,9 +8,9 @@ import (
 | 
			
		||||
	"admin/internal/model/dto"
 | 
			
		||||
	"admin/lib/xlog"
 | 
			
		||||
	"context"
 | 
			
		||||
	"github.com/ClickHouse/clickhouse-go/v2/lib/driver"
 | 
			
		||||
	"github.com/jmoiron/sqlx"
 | 
			
		||||
	"gorm.io/gorm"
 | 
			
		||||
	"strconv"
 | 
			
		||||
	"time"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
@ -19,11 +19,11 @@ type GameLogService struct {
 | 
			
		||||
	repo        repo.IGameLogRepo
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func NewGameLogSvc(db *gorm.DB, metaDb *gorm.DB, ckDb driver.Conn, clickHouseSqlx *sqlx.DB) *GameLogService {
 | 
			
		||||
	return &GameLogService{projectRepo: repo.NewProjectRepo(db), repo: repo.NewGameLogRepo(metaDb, ckDb, clickHouseSqlx)}
 | 
			
		||||
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, appId int, eventName []string, serverId int, account, roleId string,
 | 
			
		||||
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)
 | 
			
		||||
@ -33,6 +33,11 @@ func (svc *GameLogService) QueryEventList(projectId, appId int, eventName []stri
 | 
			
		||||
	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)
 | 
			
		||||
@ -40,7 +45,7 @@ func (svc *GameLogService) QueryEventList(projectId, appId int, eventName []stri
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	querier := svc.repo.NewEventListQuerier("xwl_event41", eventName, attrList)
 | 
			
		||||
	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 {
 | 
			
		||||
 | 
			
		||||
@ -5,7 +5,11 @@ import (
 | 
			
		||||
	dto2 "admin/internal/model/dto"
 | 
			
		||||
	"admin/lib/xlog"
 | 
			
		||||
	"encoding/base64"
 | 
			
		||||
	"encoding/json"
 | 
			
		||||
	"fmt"
 | 
			
		||||
	"strconv"
 | 
			
		||||
	"strings"
 | 
			
		||||
	"time"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
type GameLogHook struct {
 | 
			
		||||
@ -17,7 +21,7 @@ var removeFields = map[string]struct{}{
 | 
			
		||||
	"pub_udid":      {},
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
var alias = map[string]string{
 | 
			
		||||
var fieldsAlias = map[string]string{
 | 
			
		||||
	"pub_viplev":    "vip等级",
 | 
			
		||||
	"pub_userid":    "账号",
 | 
			
		||||
	"pub_totalcash": "总充值金额",
 | 
			
		||||
@ -61,14 +65,15 @@ func (hook *GameLogHook) Trim(projectInfo *entity.Project, eventName []string, t
 | 
			
		||||
			// 找到这个字段在去掉的列表里
 | 
			
		||||
			fieldsDescInfo = append(fieldsDescInfo[:i], fieldsDescInfo[i+1:]...)
 | 
			
		||||
			// 对应所有数据行里也删除这个值
 | 
			
		||||
			for _, row := range rows {
 | 
			
		||||
			for rowI, row := range rows {
 | 
			
		||||
				row = append(row[:i], row[i+1:]...)
 | 
			
		||||
				rows[rowI] = row
 | 
			
		||||
			}
 | 
			
		||||
		} else {
 | 
			
		||||
			// 查找要不要把value做base64解码
 | 
			
		||||
			if _, find := base64decodeFields[field.Name]; find {
 | 
			
		||||
				for _, row := range rows {
 | 
			
		||||
					newValue, err := base64.StdEncoding.DecodeString((*(row[i].(*interface{}))).(string))
 | 
			
		||||
					newValue, err := base64.StdEncoding.DecodeString(row[i].(string))
 | 
			
		||||
					if err != nil {
 | 
			
		||||
						xlog.Warnf("base64 decode field:%v value:%v error:%v", field.Name, row[i], err)
 | 
			
		||||
					} else {
 | 
			
		||||
@ -80,31 +85,206 @@ func (hook *GameLogHook) Trim(projectInfo *entity.Project, eventName []string, t
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// 查找别名
 | 
			
		||||
	for _, en := range eventName {
 | 
			
		||||
		// 查找全局eventName描述表信息,对里面没有别的字段名改为表里的名字
 | 
			
		||||
		descInfo, find := globEventList[en]
 | 
			
		||||
	//fBin, _ := json.Marshal(&fieldsDescInfo)
 | 
			
		||||
	//rBin, _ := json.Marshal(&rows)
 | 
			
		||||
	//xlog.Tracef("gamelog1 query result:%v, rows:%v", string(fBin), string(rBin))
 | 
			
		||||
 | 
			
		||||
	fieldsDescInfo, rows = (&queryResultInfo{fields: fieldsDescInfo, rows: rows}).tidyByEventDescInfo(eventName)
 | 
			
		||||
 | 
			
		||||
	//fBin, _ = json.Marshal(&fieldsDescInfo)
 | 
			
		||||
	//rBin, _ = json.Marshal(&rows)
 | 
			
		||||
	//xlog.Tracef("gamelog1 query result:%v, rows:%v", string(fBin), string(rBin))
 | 
			
		||||
 | 
			
		||||
	for i, f := range fieldsDescInfo {
 | 
			
		||||
		// 修改每一行日志别名
 | 
			
		||||
		if f.Name == "xwl_part_event" {
 | 
			
		||||
			for j := range rows {
 | 
			
		||||
				opEventName := rows[j][i].(string)
 | 
			
		||||
				descInfo, find := globEventList[opEventName]
 | 
			
		||||
				if find {
 | 
			
		||||
			for _, f := range fieldsDescInfo {
 | 
			
		||||
				find := false
 | 
			
		||||
				for _, f1 := range descInfo.fields {
 | 
			
		||||
					if f.Name == f1.Name && f1.Alias != "" {
 | 
			
		||||
						if f.Name == f.Alias {
 | 
			
		||||
							f.Alias = f1.Alias
 | 
			
		||||
					rows[j][i] = descInfo.Alias
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
		} else if f.Name == "xwl_part_date" {
 | 
			
		||||
			for j := range rows {
 | 
			
		||||
				eventDate := rows[j][i].(time.Time)
 | 
			
		||||
				//eventDate, err := time.Parse("2006-01-02T15:04:05+07:00", eventDateString)
 | 
			
		||||
				rows[j][i] = eventDate.Format(time.DateTime)
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
		// 修改每一行公共属性别名
 | 
			
		||||
		alias, find := fieldsAlias[f.Name]
 | 
			
		||||
		if find && f.Name == f.Alias {
 | 
			
		||||
			f.Alias = alias
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	fBin, _ := json.Marshal(&fieldsDescInfo)
 | 
			
		||||
	rBin, _ := json.Marshal(&rows)
 | 
			
		||||
	xlog.Tracef("gamelog2 query result:%v, rows:%v", string(fBin), string(rBin))
 | 
			
		||||
 | 
			
		||||
	i = 0
 | 
			
		||||
	for {
 | 
			
		||||
		if i >= len(fieldsDescInfo) {
 | 
			
		||||
			break
 | 
			
		||||
		}
 | 
			
		||||
		f := fieldsDescInfo[i]
 | 
			
		||||
		swapI := 2
 | 
			
		||||
		if f.Name == "pub_serverid" || f.Name == "pub_roleid" || f.Name == "pub_rolename" {
 | 
			
		||||
			pubF := fieldsDescInfo[i]
 | 
			
		||||
			for moveI := i; moveI > swapI; moveI-- {
 | 
			
		||||
				fieldsDescInfo[moveI] = fieldsDescInfo[moveI-1]
 | 
			
		||||
			}
 | 
			
		||||
			fieldsDescInfo[swapI] = pubF
 | 
			
		||||
 | 
			
		||||
			for _, row := range rows {
 | 
			
		||||
				pubValue := row[i]
 | 
			
		||||
				for moveI := i; moveI > swapI; moveI-- {
 | 
			
		||||
					row[moveI] = row[moveI-1]
 | 
			
		||||
				}
 | 
			
		||||
				row[swapI] = pubValue
 | 
			
		||||
			}
 | 
			
		||||
			swapI++
 | 
			
		||||
		}
 | 
			
		||||
		i++
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return totalCount, fieldsDescInfo, rows
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type queryResultInfo struct {
 | 
			
		||||
	fields []*dto2.GameLogFieldInfo
 | 
			
		||||
	rows   [][]any
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (info *queryResultInfo) tidyByEventDescInfo(eventNameList []string) ([]*dto2.GameLogFieldInfo, [][]any) {
 | 
			
		||||
	if len(eventNameList) == 0 {
 | 
			
		||||
		return info.fields, info.rows
 | 
			
		||||
	}
 | 
			
		||||
	if len(eventNameList) == 1 {
 | 
			
		||||
		en := eventNameList[0]
 | 
			
		||||
		enDescInfo, find := globEventList[en]
 | 
			
		||||
		if !find {
 | 
			
		||||
			panic(en)
 | 
			
		||||
		}
 | 
			
		||||
		for _, f := range info.fields {
 | 
			
		||||
			for _, df := range enDescInfo.fields {
 | 
			
		||||
				fName := removeFieldEventName(en, f.Name)
 | 
			
		||||
				if fName == df.Name && f.Name == f.Alias {
 | 
			
		||||
					f.Alias = df.Alias
 | 
			
		||||
					break
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
		return info.fields, info.rows
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// 神魔的埋点里字段名是日志名_字段名,所以如果一次游戏日志查询包含多个事件名,会查出稀疏数据,
 | 
			
		||||
	// 例如gainitem,loseitem两个日志,都会存在gainitem_itemid,loseitem_itemid,需要把对应
 | 
			
		||||
	// 为0的稀疏字段去掉
 | 
			
		||||
 | 
			
		||||
	// 具体方案:
 | 
			
		||||
	// 1.创建新的行数据,将自己日志的字段值先追加进来,然后前面补上日志名,后面补上公共字段,
 | 
			
		||||
	// 2.字段描述信息直接全部去重
 | 
			
		||||
 | 
			
		||||
	newRows := make([][]any, len(info.rows))
 | 
			
		||||
	for rowI, row := range info.rows {
 | 
			
		||||
		curRowEventName := row[0].(string)
 | 
			
		||||
		enDescInfo, find := globEventList[curRowEventName]
 | 
			
		||||
		if !find {
 | 
			
		||||
			// 不存在描述信息,先崩溃下
 | 
			
		||||
			panic(curRowEventName)
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		for _, fieldDesc := range enDescInfo.fields {
 | 
			
		||||
			for i, field := range info.fields {
 | 
			
		||||
				fName := removeFieldEventName(curRowEventName, field.Name)
 | 
			
		||||
				if fName == fieldDesc.Name {
 | 
			
		||||
					newRows[rowI] = append(newRows[rowI], row[i])
 | 
			
		||||
					break
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// 上面步骤走完,newRows每一行都是各自日志的字段值了,但是每一行长度可能不一样,例如gainitem就比loseitem多一个字段
 | 
			
		||||
	// 下面步骤会把字段描述信息通过事件名具有的所有字段去重追加,例如gainitem就是全量的字段,loseitem就是子集
 | 
			
		||||
	newFieldsDescInfo := make([]*dto2.GameLogFieldInfo, 0, len(info.fields))
 | 
			
		||||
	for _, en := range eventNameList {
 | 
			
		||||
		enDescInfo, find := globEventList[en]
 | 
			
		||||
		if !find {
 | 
			
		||||
			panic(en)
 | 
			
		||||
		}
 | 
			
		||||
		find = false
 | 
			
		||||
		for _, fd := range enDescInfo.fields {
 | 
			
		||||
			for _, newFd := range newFieldsDescInfo {
 | 
			
		||||
				if fd.Name == newFd.Name {
 | 
			
		||||
					find = true
 | 
			
		||||
					break
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
			if !find {
 | 
			
		||||
					aliasName, find1 := alias[f.Name]
 | 
			
		||||
					if find1 && f.Name == f.Alias && f.Alias != "" {
 | 
			
		||||
						f.Alias = aliasName
 | 
			
		||||
				// 追加
 | 
			
		||||
				for _, oldFd := range info.fields {
 | 
			
		||||
					fName := removeFieldEventName(en, oldFd.Name)
 | 
			
		||||
					if fName == fd.Name {
 | 
			
		||||
						newFieldInfo := &dto2.GameLogFieldInfo{
 | 
			
		||||
							Name:          fName,
 | 
			
		||||
							Alias:         oldFd.Alias,
 | 
			
		||||
							IsPublicField: oldFd.IsPublicField,
 | 
			
		||||
							FieldType:     oldFd.FieldType,
 | 
			
		||||
						}
 | 
			
		||||
						if oldFd.Name == oldFd.Alias {
 | 
			
		||||
							newFieldInfo.Alias = fd.Alias
 | 
			
		||||
						}
 | 
			
		||||
						newFieldsDescInfo = append(newFieldsDescInfo, newFieldInfo)
 | 
			
		||||
						break
 | 
			
		||||
					}
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return totalCount, fieldsDescInfo, rows
 | 
			
		||||
	// 走完上面这一步,newFieldsDescInfo就是事件列表具有的所有去重字段了
 | 
			
		||||
	allEventFieldsLen := len(newFieldsDescInfo)
 | 
			
		||||
 | 
			
		||||
	// 给newRows和newFieldsDescInfo前追加公共字段了
 | 
			
		||||
	// 追加前面的日志名、时间
 | 
			
		||||
	tmpFields := make([]*dto2.GameLogFieldInfo, 2)
 | 
			
		||||
	copy(tmpFields, info.fields[:2])
 | 
			
		||||
	newFieldsDescInfo = append(tmpFields, newFieldsDescInfo...)
 | 
			
		||||
	for i, newRow := range newRows {
 | 
			
		||||
		if len(newRow) < allEventFieldsLen {
 | 
			
		||||
			rowCols := len(newRow)
 | 
			
		||||
			for j := 0; j < allEventFieldsLen-rowCols; j++ {
 | 
			
		||||
				// 补充这一行日志没有的字段
 | 
			
		||||
				newRow = append(newRow, "\\")
 | 
			
		||||
			}
 | 
			
		||||
		} else if len(newRow) > allEventFieldsLen {
 | 
			
		||||
			panic(fmt.Sprintf("%v,%v", len(newRow), allEventFieldsLen))
 | 
			
		||||
		}
 | 
			
		||||
		tmpCols := make([]any, 2)
 | 
			
		||||
		copy(tmpCols, info.rows[i][:2])
 | 
			
		||||
		newRow = append(tmpCols, newRow...)
 | 
			
		||||
		newRows[i] = newRow
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// 给newRows和newFieldsDescInfo后追加公共字段了
 | 
			
		||||
	for i, f := range info.fields {
 | 
			
		||||
		if len(f.Name) >= 4 && f.Name[:4] == "pub_" {
 | 
			
		||||
			newFieldsDescInfo = append(newFieldsDescInfo, info.fields[i:]...)
 | 
			
		||||
			for rowI, newRow := range newRows {
 | 
			
		||||
				newRow = append(newRow, info.rows[rowI][i:]...)
 | 
			
		||||
				newRows[rowI] = newRow
 | 
			
		||||
			}
 | 
			
		||||
			break
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return newFieldsDescInfo, newRows
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// 因为推送到clickhouse的字段名都是日志名_字段名的格式,放置不同日志出现同名字段冲突,这里直接去掉一下日志名
 | 
			
		||||
func removeFieldEventName(eventName, fieldName string) string {
 | 
			
		||||
	return strings.ReplaceAll(fieldName, eventName+"_", "")
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -37,7 +37,7 @@ func init() {
 | 
			
		||||
			param, find := event["param"+strconv.Itoa(i)]
 | 
			
		||||
			if find && param != nil {
 | 
			
		||||
				fields = append(fields, &eventFieldInfo{
 | 
			
		||||
					Name:  eventName + "_" + param.(string),
 | 
			
		||||
					Name:  param.(string),
 | 
			
		||||
					Alias: event["paramDesc"+strconv.Itoa(i)].(string),
 | 
			
		||||
				})
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
@ -4,10 +4,8 @@ import (
 | 
			
		||||
	"admin/apps/game/model"
 | 
			
		||||
	"admin/internal/errcode"
 | 
			
		||||
	"admin/lib/utils"
 | 
			
		||||
	"github.com/ClickHouse/clickhouse-go/v2/lib/driver"
 | 
			
		||||
	"github.com/jmoiron/sqlx"
 | 
			
		||||
	"gorm.io/gorm"
 | 
			
		||||
	"sort"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
type IGameLogRepo interface {
 | 
			
		||||
@ -15,13 +13,12 @@ type IGameLogRepo interface {
 | 
			
		||||
	NewEventListQuerier(tableName string, eventName []string, attrList []*AttrInfo) *EventListQuerier
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func NewGameLogRepo(metaDb *gorm.DB, ckDb driver.Conn, clickHouseSqlx *sqlx.DB) IGameLogRepo {
 | 
			
		||||
	return &gameLogRepoImpl{metaDb: metaDb, db: ckDb, clickHouseSqlx: clickHouseSqlx}
 | 
			
		||||
func NewGameLogRepo(metaDb *gorm.DB, clickHouseSqlx *sqlx.DB) IGameLogRepo {
 | 
			
		||||
	return &gameLogRepoImpl{metaDb: metaDb, clickHouseSqlx: clickHouseSqlx}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type gameLogRepoImpl struct {
 | 
			
		||||
	metaDb         *gorm.DB
 | 
			
		||||
	db             driver.Conn
 | 
			
		||||
	clickHouseSqlx *sqlx.DB
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -56,64 +53,80 @@ func (impl *gameLogRepoImpl) QueryAttrListByEvent(appId int, eventName []string)
 | 
			
		||||
		return nil, errcode.New(errcode.DBError, "join tables get event list error:%v", err)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	attrList := make([]*AttrInfo, 0)
 | 
			
		||||
	normalAttrList := make([]*AttrInfo, 0)
 | 
			
		||||
	publicAttrList := make([]*AttrInfo, 0)
 | 
			
		||||
 | 
			
		||||
	var eventNameAttr *AttrInfo
 | 
			
		||||
	var timeAttr *AttrInfo
 | 
			
		||||
	for _, attr := range resultList {
 | 
			
		||||
		if len(eventName) == 0 || utils.IsInSlice(eventName, attr.EventName) {
 | 
			
		||||
			if len(attr.AttrName) >= 4 && attr.AttrName[:4] == "xwl_" {
 | 
			
		||||
				if attr.AttrName != "xwl_part_date" {
 | 
			
		||||
 | 
			
		||||
				if attr.AttrName != "xwl_part_date" && attr.AttrName != "xwl_part_event" {
 | 
			
		||||
					continue
 | 
			
		||||
				}
 | 
			
		||||
				if attr.AttrName == "xwl_part_date" {
 | 
			
		||||
					timeAttr = &AttrInfo{
 | 
			
		||||
						Name:       attr.AttrName,
 | 
			
		||||
						Alias:      "时间",
 | 
			
		||||
						DataType:   attr.AttrFieldType,
 | 
			
		||||
					IsUserAttr: attr.AttrIsPublicField != 2,
 | 
			
		||||
						IsUserAttr: true,
 | 
			
		||||
					}
 | 
			
		||||
				} else if attr.AttrName == "xwl_part_event" {
 | 
			
		||||
					eventNameAttr = &AttrInfo{
 | 
			
		||||
						Name:       attr.AttrName,
 | 
			
		||||
						Alias:      "操作类型",
 | 
			
		||||
						DataType:   attr.AttrFieldType,
 | 
			
		||||
						IsUserAttr: true,
 | 
			
		||||
					}
 | 
			
		||||
				}
 | 
			
		||||
 | 
			
		||||
				continue
 | 
			
		||||
			}
 | 
			
		||||
			attrList = append(attrList, &AttrInfo{
 | 
			
		||||
			find := false
 | 
			
		||||
			for _, oldAttr := range normalAttrList {
 | 
			
		||||
				if oldAttr.Name == attr.AttrName {
 | 
			
		||||
					find = true
 | 
			
		||||
					break
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
			if !find {
 | 
			
		||||
				for _, oldAttr := range publicAttrList {
 | 
			
		||||
					if oldAttr.Name == attr.AttrName {
 | 
			
		||||
						find = true
 | 
			
		||||
						break
 | 
			
		||||
					}
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
			if !find {
 | 
			
		||||
				var isPublicField bool
 | 
			
		||||
				if len(attr.AttrName) >= 4 {
 | 
			
		||||
					isPublicField = attr.AttrName[:4] == "pub_"
 | 
			
		||||
				}
 | 
			
		||||
				attrInfo := &AttrInfo{
 | 
			
		||||
					Name:       attr.AttrName,
 | 
			
		||||
					Alias:      attr.AttrAlias,
 | 
			
		||||
					DataType:   attr.AttrFieldType,
 | 
			
		||||
				IsUserAttr: attr.AttrIsPublicField != 2,
 | 
			
		||||
			})
 | 
			
		||||
					IsUserAttr: isPublicField,
 | 
			
		||||
				}
 | 
			
		||||
				if isPublicField {
 | 
			
		||||
					publicAttrList = append(publicAttrList, attrInfo)
 | 
			
		||||
				} else {
 | 
			
		||||
					normalAttrList = append(normalAttrList, attrInfo)
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
	sort.SliceStable(attrList, func(i, j int) bool {
 | 
			
		||||
		if attrList[i].IsUserAttr && !attrList[j].IsUserAttr {
 | 
			
		||||
			return false
 | 
			
		||||
		}
 | 
			
		||||
		if attrList[i].IsUserAttr && attrList[j].IsUserAttr {
 | 
			
		||||
			return false
 | 
			
		||||
	}
 | 
			
		||||
		if attrList[i].IsUserAttr && attrList[j].IsUserAttr {
 | 
			
		||||
			return false
 | 
			
		||||
		}
 | 
			
		||||
		return true
 | 
			
		||||
	})
 | 
			
		||||
 | 
			
		||||
	if timeAttr != nil {
 | 
			
		||||
		attrList = append([]*AttrInfo{timeAttr}, attrList...)
 | 
			
		||||
		normalAttrList = append([]*AttrInfo{timeAttr}, normalAttrList...)
 | 
			
		||||
	}
 | 
			
		||||
	if eventNameAttr != nil {
 | 
			
		||||
		normalAttrList = append([]*AttrInfo{eventNameAttr}, normalAttrList...)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	//retList := make(map[string][]*AttrInfo)
 | 
			
		||||
	//for _, attr := range resultList {
 | 
			
		||||
	//	attrList, find := retList[attr.EventName]
 | 
			
		||||
	//	if !find {
 | 
			
		||||
	//		attrList = make([]*AttrInfo, 0, 1)
 | 
			
		||||
	//	}
 | 
			
		||||
	//	attrList = append(attrList, &AttrInfo{
 | 
			
		||||
	//		Name:       attr.AttrName,
 | 
			
		||||
	//		Alias:      attr.AttrAlias,
 | 
			
		||||
	//		DataType:   attr.AttrFieldType,
 | 
			
		||||
	//		IsUserAttr: attr.AttrIsPublicField != 2,
 | 
			
		||||
	//	})
 | 
			
		||||
	//	retList[attr.EventName] = attrList
 | 
			
		||||
	//}
 | 
			
		||||
 | 
			
		||||
	return attrList, nil
 | 
			
		||||
	return append(normalAttrList, publicAttrList...), nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type AttrInfo struct {
 | 
			
		||||
@ -125,7 +138,6 @@ type AttrInfo struct {
 | 
			
		||||
 | 
			
		||||
func (impl *gameLogRepoImpl) NewEventListQuerier(tableName string, eventName []string, attrList []*AttrInfo) *EventListQuerier {
 | 
			
		||||
	querier := new(EventListQuerier)
 | 
			
		||||
	querier.db = impl.db
 | 
			
		||||
	querier.clickHouseSqlx = impl.clickHouseSqlx
 | 
			
		||||
	querier.tableName = tableName
 | 
			
		||||
	querier.eventName = eventName
 | 
			
		||||
 | 
			
		||||
@ -62,6 +62,13 @@ func (querier *EventListQuerier) Go(ctx context.Context, pageNo int, pageLen int
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if xlog.GetLogLevel() <= xlog.LogLevelDebug {
 | 
			
		||||
		argsBin, _ := json.Marshal(&sqlArgs)
 | 
			
		||||
		rowsBin, _ := json.Marshal(&rows)
 | 
			
		||||
		xlog.Debugf("query sql:%v with args:%v, rows result:%v", sql, string(argsBin), string(rowsBin))
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -85,6 +92,10 @@ func (querier *EventListQuerier) genSql(tableName string, pageNo int, pageLen in
 | 
			
		||||
	whereList := make([]string, 0)
 | 
			
		||||
	whereArgs := make([]any, 0)
 | 
			
		||||
	if len(querier.eventName) != 0 {
 | 
			
		||||
		if len(querier.eventName) == 1 {
 | 
			
		||||
			whereList = append(whereList, "`xwl_part_event`=?")
 | 
			
		||||
			whereArgs = append(whereArgs, querier.eventName[0])
 | 
			
		||||
		} else {
 | 
			
		||||
			eventNameWhereSql := make([]string, 0, len(querier.eventName))
 | 
			
		||||
			for _, v := range querier.eventName {
 | 
			
		||||
				eventNameWhereSql = append(eventNameWhereSql, "`xwl_part_event`=?")
 | 
			
		||||
@ -92,6 +103,7 @@ func (querier *EventListQuerier) genSql(tableName string, pageNo int, pageLen in
 | 
			
		||||
			}
 | 
			
		||||
			whereList = append(whereList, "("+strings.Join(eventNameWhereSql, " or ")+")")
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if querier.serverId != 0 {
 | 
			
		||||
		whereList = append(whereList, "`pub_serverid`=?")
 | 
			
		||||
@ -116,7 +128,7 @@ func (querier *EventListQuerier) genSql(tableName string, pageNo int, pageLen in
 | 
			
		||||
	limitStart := (pageNo - 1) * pageLen
 | 
			
		||||
	limitLen := pageLen
 | 
			
		||||
 | 
			
		||||
	sql += fmt.Sprintf(" limit %v,%v", limitStart, limitLen)
 | 
			
		||||
	sql += fmt.Sprintf(" order by xwl_part_date desc limit %v,%v", limitStart, limitLen)
 | 
			
		||||
 | 
			
		||||
	return sql, countSql, whereArgs
 | 
			
		||||
}
 | 
			
		||||
@ -170,6 +182,7 @@ func (querier *EventListQuerier) query(sql string, countSql string, args []any)
 | 
			
		||||
				Name:          field.Name,
 | 
			
		||||
				Alias:         field.Name,
 | 
			
		||||
				IsPublicField: false,
 | 
			
		||||
				FieldType:     field.DataType,
 | 
			
		||||
			}
 | 
			
		||||
			if field.Alias != "" {
 | 
			
		||||
				fieldDesc.Alias = field.Alias
 | 
			
		||||
@ -185,8 +198,16 @@ func (querier *EventListQuerier) query(sql string, countSql string, args []any)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return 0, nil, nil, errcode.New(errcode.DBError, "sql:%v result scan row error:%v", sql, err)
 | 
			
		||||
		}
 | 
			
		||||
		if xlog.GetLogLevel() <= xlog.LogLevelTrace {
 | 
			
		||||
			argsBin, _ := json.Marshal(&args)
 | 
			
		||||
			cacheRowBin, _ := json.Marshal(&readCacheRow)
 | 
			
		||||
			xlog.Tracef("query sql:%v with args:%+v result row:%v", sql, string(argsBin), string(cacheRowBin))
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		parsedRow := make([]any, len(readCacheRow))
 | 
			
		||||
		copy(parsedRow, readCacheRow)
 | 
			
		||||
		for i := range readCacheRow {
 | 
			
		||||
			parsedRow[i] = *(readCacheRow[i].(*interface{}))
 | 
			
		||||
		}
 | 
			
		||||
		rows = append(rows, parsedRow)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -29,6 +29,7 @@ type Project struct {
 | 
			
		||||
	DfsBucket    string    `name:"分布式存储桶名" desc:"上传服务器列表分布式存储的桶名"`
 | 
			
		||||
	DfsRegion    string    `name:"分布式存储区域" desc:"上传服务器列表分布式存储的桶区域例如ap-chengdu"`
 | 
			
		||||
	CdnPath      string    `name:"cdn地址" desc:"拉取服务器列表文件的cdn"`
 | 
			
		||||
	BiAdminAppId int       `name:"bi后台appid" desc:"用于查找所属游戏日志"`
 | 
			
		||||
	SortWeight   int       `name:"菜单排序" desc:"越大越靠前"`
 | 
			
		||||
	CreatedAt    time.Time `readonly:"true"`
 | 
			
		||||
	UpdatedAt    time.Time `readonly:"true"`
 | 
			
		||||
 | 
			
		||||
@ -3,6 +3,7 @@ package server
 | 
			
		||||
import (
 | 
			
		||||
	"admin/internal/consts"
 | 
			
		||||
	"admin/internal/context"
 | 
			
		||||
	"admin/internal/errcode"
 | 
			
		||||
	"admin/internal/model/dto"
 | 
			
		||||
	"admin/lib/httpclient"
 | 
			
		||||
	"admin/lib/xlog"
 | 
			
		||||
@ -78,11 +79,19 @@ func (ctl *controller) GameLogEventList(ctx *context.WebContext, params *dto.Gam
 | 
			
		||||
		de = time.Now().Add(time.Hour)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	eventList := strings.Split(params.EventName, ",")
 | 
			
		||||
	var eventList []string
 | 
			
		||||
	if params.EventName != "" {
 | 
			
		||||
		eventList = strings.Split(params.EventName, ",")
 | 
			
		||||
		for _, en := range eventList {
 | 
			
		||||
			if en == "" {
 | 
			
		||||
				return errcode.New(errcode.ParamsInvalid, "event name invalid:[%v]", params.EventName)
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	var err error
 | 
			
		||||
	rsp.TotalCount, rsp.FieldsDescInfo, rsp.Rows, err =
 | 
			
		||||
		ctl.svc.GameLogSvc.QueryEventList(projectId, params.AppId,
 | 
			
		||||
		ctl.svc.GameLogSvc.QueryEventList(projectId,
 | 
			
		||||
			eventList, params.ServerId, params.Account, params.RoleId, params.PageNo, params.PageLen, ds, de)
 | 
			
		||||
	return err
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -7,11 +7,12 @@ import (
 | 
			
		||||
	dbLib "admin/internal/db"
 | 
			
		||||
	"admin/internal/errcode"
 | 
			
		||||
	"admin/internal/event"
 | 
			
		||||
	"admin/internal/global"
 | 
			
		||||
	dto2 "admin/internal/model/dto"
 | 
			
		||||
	"context"
 | 
			
		||||
	"encoding/json"
 | 
			
		||||
	"fmt"
 | 
			
		||||
	"github.com/ClickHouse/clickhouse-go/v2"
 | 
			
		||||
	_ "github.com/ClickHouse/clickhouse-go/v2"
 | 
			
		||||
	"github.com/jmoiron/sqlx"
 | 
			
		||||
	"gorm.io/gorm"
 | 
			
		||||
	"log"
 | 
			
		||||
@ -28,30 +29,30 @@ type Service struct {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func New(db *gorm.DB) (*Service, error) {
 | 
			
		||||
	metaDb, err := dbLib.NewDBNoMigrate("mysql", "192.168.6.83:13306", "databi", "root", "dev123")
 | 
			
		||||
	var metaDb *gorm.DB
 | 
			
		||||
	var clickHouseSqlx *sqlx.DB
 | 
			
		||||
	var err error
 | 
			
		||||
 | 
			
		||||
	if global.GLOB_BOOT_FLAGS.BiMysqlAddr != "" {
 | 
			
		||||
		metaDb, err = dbLib.NewDBNoMigrate("mysql",
 | 
			
		||||
			global.GLOB_BOOT_FLAGS.BiMysqlAddr,
 | 
			
		||||
			global.GLOB_BOOT_FLAGS.BiMysqlDb,
 | 
			
		||||
			global.GLOB_BOOT_FLAGS.BiMysqlUser,
 | 
			
		||||
			global.GLOB_BOOT_FLAGS.BiMysqlPass)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return nil, err
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		dbSource := fmt.Sprintf(
 | 
			
		||||
		"tcp://%s:%s?username=%s&password=%s&compress=true&database=%s",
 | 
			
		||||
		"192.168.6.83", "9000", "root", "dev123", "databi")
 | 
			
		||||
 | 
			
		||||
	clickHouseSqlx, err := NewCkDb("clickhouse", dbSource, 5, 20)
 | 
			
		||||
			"tcp://%s?username=%s&password=%s&compress=true&database=%s",
 | 
			
		||||
			global.GLOB_BOOT_FLAGS.BiCkAddr,
 | 
			
		||||
			global.GLOB_BOOT_FLAGS.BiCkUser,
 | 
			
		||||
			global.GLOB_BOOT_FLAGS.BiCkPass,
 | 
			
		||||
			global.GLOB_BOOT_FLAGS.BiCkDb)
 | 
			
		||||
		clickHouseSqlx, err = NewCkDb("clickhouse", dbSource, 5, 20)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
		panic(err)
 | 
			
		||||
			return nil, err
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
	conn, err := clickhouse.Open(&clickhouse.Options{
 | 
			
		||||
		Addr: []string{"192.168.78.128:9000"},
 | 
			
		||||
		Auth: clickhouse.Auth{
 | 
			
		||||
			Database: "databi_prod",
 | 
			
		||||
			Username: "root",
 | 
			
		||||
			Password: "dev123",
 | 
			
		||||
		},
 | 
			
		||||
	})
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, errcode.New(errcode.DBError, "open clickhouse %v error:%v", "databi_prod", err)
 | 
			
		||||
		//"192.168.6.83", "9000", "root", "dev123", "databi")
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	svc := &Service{
 | 
			
		||||
@ -60,7 +61,7 @@ func New(db *gorm.DB) (*Service, error) {
 | 
			
		||||
		projectSvc:  domain.NewProjectService(db),
 | 
			
		||||
		cdkeySvc:    domain.NewCDKeyService(db),
 | 
			
		||||
		accountSvc:  domain.NewAccountService(db),
 | 
			
		||||
		GameLogSvc:  domain.NewGameLogSvc(db, metaDb, conn, clickHouseSqlx),
 | 
			
		||||
		GameLogSvc:  domain.NewGameLogSvc(db, metaDb, clickHouseSqlx),
 | 
			
		||||
	}
 | 
			
		||||
	api.RegisterGameApi(svc)
 | 
			
		||||
	//err := svc.ensureProjectsDBData()
 | 
			
		||||
 | 
			
		||||
@ -7,4 +7,12 @@ type CommonBootFlags struct {
 | 
			
		||||
	DBName      string `env:"db_name" default:"uniugm" desc:"数据库名字"`
 | 
			
		||||
	DBUser      string `env:"db_user" default:"root" desc:"数据库用户名"`
 | 
			
		||||
	DBPass      string `env:"db_pass" default:"" desc:"数据库密码"`
 | 
			
		||||
	BiCkAddr    string `env:"bi_ck_addr" desc:"clickhouse分析数据库地址"`
 | 
			
		||||
	BiCkDb      string `env:"bi_ck_db" desc:"clickhouse数据库"`
 | 
			
		||||
	BiCkUser    string `env:"bi_ck_user" desc:"clickhouse用户名"`
 | 
			
		||||
	BiCkPass    string `env:"bi_ck_pass" desc:"clickhouse密码"`
 | 
			
		||||
	BiMysqlAddr string `env:"bi_mysql_addr" desc:"mysql分析数据库地址"`
 | 
			
		||||
	BiMysqlDb   string `env:"bi_mysql_db" desc:"mysql数据库"`
 | 
			
		||||
	BiMysqlUser string `env:"bi_mysql_user" desc:"mysql用户名"`
 | 
			
		||||
	BiMysqlPass string `env:"bi_mysql_pass" desc:"mysql密码"`
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -157,4 +157,5 @@ type GameLogFieldInfo struct {
 | 
			
		||||
	Name          string `json:"name"`
 | 
			
		||||
	Alias         string `json:"alias"`
 | 
			
		||||
	IsPublicField bool   `json:"isPublicField"`
 | 
			
		||||
	FieldType     int    `json:"fieldType"`
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -137,7 +137,6 @@ type GetRoleDetailRsp struct {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type GameLogEventListReq struct {
 | 
			
		||||
	AppId     int
 | 
			
		||||
	EventName string
 | 
			
		||||
	ServerId  int
 | 
			
		||||
	Account   string
 | 
			
		||||
 | 
			
		||||
@ -5,8 +5,8 @@
 | 
			
		||||
    <link rel="icon" href="/favicon.ico">
 | 
			
		||||
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
 | 
			
		||||
    <title>Vite App</title>
 | 
			
		||||
    <script type="module" crossorigin src="/static/js/index-hOIgOejC.js"></script>
 | 
			
		||||
    <link rel="modulepreload" crossorigin href="/static/js/vendor-B2m3dX6z.js">
 | 
			
		||||
    <script type="module" crossorigin src="/static/js/index-1btxRZkB.js"></script>
 | 
			
		||||
    <link rel="modulepreload" crossorigin href="/static/js/vendor-BRRlSJxx.js">
 | 
			
		||||
    <link rel="stylesheet" crossorigin href="/static/css/vendor-DnLjZ1mj.css">
 | 
			
		||||
    <link rel="stylesheet" crossorigin href="/static/css/index-BqAGgcXq.css">
 | 
			
		||||
  </head>
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										1
									
								
								admin/ui/static/static/css/table-Dwi5aXVw.css
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								admin/ui/static/static/css/table-Dwi5aXVw.css
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1 @@
 | 
			
		||||
.roleDetailList[data-v-5a8d8958] .el-table__header-wrapper th{word-break:break-word;background-color:#f8f8f9!important;color:#515a6e;height:40px!important;font-size:13px}.roleDetailList[data-v-5a8d8958] .el-table__header .el-table-column--selection .cell{width:60px!important}.roleDetailList[data-v-5a8d8958] .el-table .fixed-width .el-button--small{padding-left:0;padding-right:0;width:20px!important}.roleDetailList[data-v-5a8d8958] .el-table__header{background:#f5f7fa!important}.roleDetailList[data-v-5a8d8958] .el-table__row td{border-color:#ebeef5}.app-content[data-v-6117fd7c]{height:calc(100vh - 100px);display:flex}.app-content .table-content[data-v-6117fd7c]{display:flex;flex-direction:column;justify-content:space-between;height:100%;overflow:auto}.app-content .table-content .table[data-v-6117fd7c]{flex:1;position:relative}.app-content .table-content .table[data-v-6117fd7c] .el-table{flex:1;position:absolute}.app-content .table-content .table[data-v-6117fd7c] .el-popper{max-width:640px;word-break:break-all}.pagination-container .el-pagination[data-v-6117fd7c]{right:0;position:absolute;height:25px;margin-bottom:50px;margin-top:0;padding:10px 30px!important;z-index:2}.pagination-container.hidden[data-v-6117fd7c]{display:none}@media (max-width: 768px){.pagination-container .el-pagination>.el-pagination__jump[data-v-6117fd7c]{display:none!important}.pagination-container .el-pagination>.el-pagination__sizes[data-v-6117fd7c]{display:none!important}}
 | 
			
		||||
							
								
								
									
										1
									
								
								admin/ui/static/static/js/Login-C5AapNRS.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								admin/ui/static/static/js/Login-C5AapNRS.js
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1 @@
 | 
			
		||||
import{r as e,ab as a,a as s,o,d as r,b as l,w as n,a0 as t,a3 as u,ac as d,W as i,v as p,$ as c,a9 as m,I as v}from"./vendor-BRRlSJxx.js";import{_ as f,u as _,r as g}from"./index-1btxRZkB.js";const y={class:"login-box"},h={class:m({container:!0,animate__animated:!0,animate__flipInX:!0})},w={class:"form-container sign-in-container"},b=f({__name:"Login",setup(m){e(void 0);const{proxy:f}=a(),b=e({user:"",password:""}),V={user:[{required:!0,trigger:"blur",message:"请输入您的账号"}],password:[{required:!0,trigger:"blur",message:"请输入您的密码"}]},x=e=>{e&&f.$refs.ruleFormRef.validate((e=>{if(!e)return console.log("error submit!"),!1;_().login(b.value.user,b.value.password).then((()=>{console.log("登录成功,推送首页。。"),g.push({path:"/welcome"})}),(e=>{})).catch((()=>{v.error("login response error")}))}))};return(e,a)=>{const m=u,v=t,f=i,_=c;return o(),s("div",y,[r("div",h,[r("div",w,[l(_,{ref:"ruleFormRef",model:b.value,"status-icon":"",rules:V,class:"form"},{default:n((()=>[l(v,{class:"form-item",prop:"username"},{default:n((()=>[l(m,{modelValue:b.value.user,"onUpdate:modelValue":a[0]||(a[0]=e=>b.value.user=e),placeholder:"用户名",autocomplete:"off",onKeyup:a[1]||(a[1]=d((e=>x(b.value)),["enter"]))},null,8,["modelValue"])])),_:1}),l(v,{class:"form-item",prop:"password"},{default:n((()=>[l(m,{modelValue:b.value.password,"onUpdate:modelValue":a[2]||(a[2]=e=>b.value.password=e),placeholder:"密码",type:"password",autocomplete:"off",onKeyup:a[3]||(a[3]=d((e=>x(b.value)),["enter"]))},null,8,["modelValue"])])),_:1}),l(f,{class:"theme-button",type:"primary",onClick:a[4]||(a[4]=e=>x(b.value)),onKeydown:a[5]||(a[5]=d((e=>{var a;13!==a.keyCode&&100!==a.keyCode||x(b.value)}),["enter"]))},{default:n((()=>a[6]||(a[6]=[p("登 陆 ")]))),_:1})])),_:1},8,["model"])]),a[7]||(a[7]=r("div",{class:"overlay_container"},[r("div",{class:"overlay"},[r("div",{class:"overlay_panel overlay_right_container"},[r("h2",{class:"container-title"},"hello friend!"),r("p",null,"输入您的个人信息,以便使用后台管理系统")])])],-1))])])}}},[["__scopeId","data-v-68d4afe9"]]);export{b as default};
 | 
			
		||||
							
								
								
									
										1
									
								
								admin/ui/static/static/js/character--9gw0-Ov.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								admin/ui/static/static/js/character--9gw0-Ov.js
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1 @@
 | 
			
		||||
import{t as e}from"./tableUser-BT_id_R-.js";import{u as r,L as t}from"./index-1btxRZkB.js";import{a as s,o as a,c as o,B as c}from"./vendor-BRRlSJxx.js";import"./resource-ebhyDeUm.js";import"./empty-DuTaDG5U.js";const m={__name:"character",setup(m){let u={meta:{desc:"character",resource:"character",resource_url:"/resource/character",methods:{get:!0,post:!0,put:!0,delete:!0}}};return"admin"!==r().userInfo.character&&(u.meta.methods={}),t.setCache("resource",u),(r,t)=>(a(),s("div",null,[(a(),o(c(e)))]))}};export{m as default};
 | 
			
		||||
							
								
								
									
										1
									
								
								admin/ui/static/static/js/empty-DuTaDG5U.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								admin/ui/static/static/js/empty-DuTaDG5U.js
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1 @@
 | 
			
		||||
import{c as o,o as r,ai as s}from"./vendor-BRRlSJxx.js";import{_ as n}from"./index-1btxRZkB.js";const e=n({},[["render",function(n,e){const t=s;return r(),o(t,{description:"没有权限!请联系管理员添加权限!"})}]]);export{e};
 | 
			
		||||
							
								
								
									
										1
									
								
								admin/ui/static/static/js/history-C3Pvxh4X.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								admin/ui/static/static/js/history-C3Pvxh4X.js
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1 @@
 | 
			
		||||
import{r as e,T as a,a as l,o as t,c as o,u,B as n,F as s,U as p,w as r,b as d,V as i,a7 as v,a3 as m,a8 as c,W as g,v as h,C as y,d as f,X as V,Y as b,Z as x,D as w,a9 as I}from"./vendor-BRRlSJxx.js";import{_ as k,u as _,a as C}from"./index-1btxRZkB.js";import{e as U}from"./empty-DuTaDG5U.js";const z={class:"table-content"},j={class:"table"},D={class:"pagination-container"},R=k({__name:"history",props:{rowInfo:{},disableConditionInput:!0},setup(k){const R=k;let S=!0;!1===R.disableConditionInput&&(S=!1);const T="admin"===_().userInfo.character,A=e(T),B=e(1),F=e(20),G=e(R.userId);R.rowInfo&&void 0!==R.rowInfo.ID&&(G.value=R.rowInfo.ID);const K=e(""),N=e(""),P=e(""),W=e(""),X=e(!1),Y=[20,50,100],Z=e(0),q=e([]),E=()=>{C(B.value,F.value,G.value,K.value,N.value,P.value,W.value).then((e=>{q.value=e.data.list,Z.value=e.data.totalCount,X.value=!0}),(e=>{}))};a((()=>{E()}));const H=()=>{G.value="",K.value="",N.value="",P.value="",W.value=""},J=e=>{Z.value<=0||F.value*B.value>Z.value&&q.value.length>=Z.value||E()},L=e=>{E()};return(e,a)=>{const k=m,_=g,C=v,R=i,T=b,M=V,O=x,Q=y,$=w;return t(),l("div",{class:I(u(S)?"app-content1":"app-content")},[u(A)?(t(),l(s,{key:1},[u(X)?(t(),o($,{key:0},{default:r((()=>[d(R,{style:{"margin-bottom":"10px"}},{default:r((()=>[d(C,null,{default:r((()=>[!1===u(S)?(t(),o(k,{key:0,modelValue:u(G),"onUpdate:modelValue":a[0]||(a[0]=e=>c(G)?G.value=e:null),placeholder:"用户id",style:{width:"150px","margin-right":"10px"}},null,8,["modelValue"])):p("",!0),!1===u(S)?(t(),o(k,{key:1,modelValue:u(K),"onUpdate:modelValue":a[1]||(a[1]=e=>c(K)?K.value=e:null),placeholder:"操作资源类型",style:{width:"150px","margin-right":"10px"}},null,8,["modelValue"])):p("",!0),!1===u(S)?(t(),o(k,{key:2,modelValue:u(N),"onUpdate:modelValue":a[2]||(a[2]=e=>c(N)?N.value=e:null),placeholder:"操作资源组",style:{width:"150px","margin-right":"10px"}},null,8,["modelValue"])):p("",!0),!1===u(S)?(t(),o(k,{key:3,modelValue:u(P),"onUpdate:modelValue":a[3]||(a[3]=e=>c(P)?P.value=e:null),placeholder:"操作对象",style:{width:"150px","margin-right":"10px"}},null,8,["modelValue"])):p("",!0),!1===u(S)?(t(),o(k,{key:4,modelValue:u(W),"onUpdate:modelValue":a[4]||(a[4]=e=>c(W)?W.value=e:null),placeholder:"操作方法",style:{width:"150px","margin-right":"10px"}},null,8,["modelValue"])):p("",!0),!1===u(S)?(t(),o(_,{key:5,onClick:E,type:"primary",style:{"margin-right":"10px"}},{default:r((()=>a[7]||(a[7]=[h("条件搜索 ")]))),_:1})):p("",!0),!1===u(S)?(t(),o(_,{key:6,onClick:H},{default:r((()=>a[8]||(a[8]=[h("清空条件")]))),_:1})):p("",!0)])),_:1})])),_:1}),d(Q,null,{default:r((()=>[f("div",z,[f("div",j,[d(M,{data:u(q),style:{width:"100%"},"table-layout":"auto",stripe:"","tooltip-effect":"light"},{default:r((()=>[d(T,{prop:"userId",label:"用户id"}),d(T,{prop:"userName",label:"用户名"}),d(T,{prop:"opResourceType",label:"操作资源类型"}),d(T,{prop:"opResourceGroup",label:"操作资源组"}),d(T,{prop:"opResourceKey",label:"操作对象"}),d(T,{prop:"method",label:"操作方法"}),d(T,{prop:"createdAt",label:"创建时间"}),d(T,{prop:"detailInfo",label:"详情数据","show-overflow-tooltip":""})])),_:1},8,["data"])]),f("div",D,[d(O,{"current-page":u(B),"onUpdate:currentPage":a[5]||(a[5]=e=>c(B)?B.value=e:null),"page-size":u(F),"onUpdate:pageSize":a[6]||(a[6]=e=>c(F)?F.value=e:null),"page-sizes":Y,layout:"total, sizes, prev, pager, next, jumper",total:u(Z),onSizeChange:J,onCurrentChange:L},null,8,["current-page","page-size","total"])])])])),_:1})])),_:1})):p("",!0)],64)):(t(),o(n(U),{key:0}))],2)}}},[["__scopeId","data-v-926d7759"]]);export{R as t};
 | 
			
		||||
							
								
								
									
										1
									
								
								admin/ui/static/static/js/history-zzIzXglC.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								admin/ui/static/static/js/history-zzIzXglC.js
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1 @@
 | 
			
		||||
import{t as s}from"./history-C3Pvxh4X.js";import{c as o,o as t,B as e}from"./vendor-BRRlSJxx.js";import"./index-1btxRZkB.js";import"./empty-DuTaDG5U.js";const i={__name:"history",setup:i=>(i,r)=>(t(),o(e(s),{disableConditionInput:false}))};export{i as default};
 | 
			
		||||
							
								
								
									
										2
									
								
								admin/ui/static/static/js/index-1btxRZkB.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										2
									
								
								admin/ui/static/static/js/index-1btxRZkB.js
									
									
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because one or more lines are too long
											
										
									
								
							
							
								
								
									
										1
									
								
								admin/ui/static/static/js/project-BRalbG0E.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								admin/ui/static/static/js/project-BRalbG0E.js
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1 @@
 | 
			
		||||
import{t as e}from"./table-BhmTKySX.js";import{L as s,u as a,c as r}from"./index-1btxRZkB.js";import{i as t,a as o,o as m,c,B as p}from"./vendor-BRRlSJxx.js";import"./resource-ebhyDeUm.js";import"./empty-DuTaDG5U.js";const i={__name:"project",setup(i){s.setCache("project",{}),t();let n=r;return"admin"!==a().userInfo.character&&(n.meta.methods={}),s.setCache("resource",n),(s,a)=>(m(),o("div",null,[(m(),c(p(e)))]))}};export{i as default};
 | 
			
		||||
							
								
								
									
										1
									
								
								admin/ui/static/static/js/project_op-DR6paW88.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								admin/ui/static/static/js/project_op-DR6paW88.js
									
									
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because one or more lines are too long
											
										
									
								
							
							
								
								
									
										1
									
								
								admin/ui/static/static/js/resource-ebhyDeUm.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								admin/ui/static/static/js/resource-ebhyDeUm.js
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1 @@
 | 
			
		||||
import{s as t}from"./index-1btxRZkB.js";function r(r,e){return t({url:r,method:"get",params:e})}function e(r,e){return t({url:r,method:"post",data:{dto:e}})}function o(r,e){return t({url:r,method:"put",data:{dto:e}})}function n(r,e){return t({url:r,method:"delete",data:e})}function u(r,e){return t({url:r+"/selection",method:"post",data:e})}function a(r){return t({url:"/project/"+r.toString()+"/items",method:"get"})}export{n as a,e as b,o as c,a as d,u as e,r};
 | 
			
		||||
							
								
								
									
										1
									
								
								admin/ui/static/static/js/table-BhmTKySX.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								admin/ui/static/static/js/table-BhmTKySX.js
									
									
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because one or more lines are too long
											
										
									
								
							
							
								
								
									
										1
									
								
								admin/ui/static/static/js/tableUser-BT_id_R-.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								admin/ui/static/static/js/tableUser-BT_id_R-.js
									
									
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because one or more lines are too long
											
										
									
								
							
							
								
								
									
										1
									
								
								admin/ui/static/static/js/user-CSxKKefZ.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								admin/ui/static/static/js/user-CSxKKefZ.js
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1 @@
 | 
			
		||||
import{t as e}from"./tableUser-BT_id_R-.js";import{u as s,L as r}from"./index-1btxRZkB.js";import{t}from"./history-C3Pvxh4X.js";import{a as o,o as a,c,B as m}from"./vendor-BRRlSJxx.js";import"./resource-ebhyDeUm.js";import"./empty-DuTaDG5U.js";const u={__name:"user",setup(u){let n={meta:{desc:"user",resource:"user",resource_url:"/resource/user",methods:{get:!0,post:!0,put:!0,delete:!0}}};"admin"!==s().userInfo.character&&(n.meta.methods={}),r.setCache("resource",n);const p=[];return p.push({key:"user:exec:history",name:"执行记录",btn_color_type:"info",btn_type:1,btn_callback_component:t}),(s,r)=>(a(),o("div",null,[(a(),c(m(e),{rowClickDialogBtns:p}))]))}};export{u as default};
 | 
			
		||||
							
								
								
									
										96
									
								
								admin/ui/static/static/js/vendor-BRRlSJxx.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										96
									
								
								admin/ui/static/static/js/vendor-BRRlSJxx.js
									
									
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because one or more lines are too long
											
										
									
								
							
							
								
								
									
										1
									
								
								admin/ui/static/static/js/welcome-DSoGychw.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								admin/ui/static/static/js/welcome-DSoGychw.js
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1 @@
 | 
			
		||||
import{a as s,o as a,d as e,b as n,v as t,t as o,u as r,aa as p,F as l}from"./vendor-BRRlSJxx.js";import{u}from"./index-1btxRZkB.js";const f={style:{"font-size":"40px"}},i={style:{color:"darkslategrey","font-size":"50px"}},m={__name:"welcome",setup(m){const c=u().userInfo;return(u,m)=>{const d=p;return a(),s(l,null,[e("span",f,[m[0]||(m[0]=t("亲爱的")),e("span",i,o(r(c).nick_name),1),m[1]||(m[1]=t("!欢迎使用本公司后台管理系统!"))]),n(d),m[2]||(m[2]=e("span",{style:{"font-size":"40px"}},"硬盘有价,数据无价,操作不规范,亲人两行泪。",-1))],64)}}};export{m as default};
 | 
			
		||||
							
								
								
									
										1
									
								
								ui/package-lock.json
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										1
									
								
								ui/package-lock.json
									
									
									
										generated
									
									
									
								
							@ -11,6 +11,7 @@
 | 
			
		||||
        "@ant-design/icons-vue": "^7.0.1",
 | 
			
		||||
        "ant-design-vue": "^4.0.0-rc.6",
 | 
			
		||||
        "axios": "^1.8.4",
 | 
			
		||||
        "dayjs": "^1.11.13",
 | 
			
		||||
        "echarts": "^5.6.0",
 | 
			
		||||
        "element-plus": "^2.9.7",
 | 
			
		||||
        "js-base64": "^3.7.7",
 | 
			
		||||
 | 
			
		||||
@ -12,6 +12,7 @@
 | 
			
		||||
    "@ant-design/icons-vue": "^7.0.1",
 | 
			
		||||
    "ant-design-vue": "^4.0.0-rc.6",
 | 
			
		||||
    "axios": "^1.8.4",
 | 
			
		||||
    "dayjs": "^1.11.13",
 | 
			
		||||
    "echarts": "^5.6.0",
 | 
			
		||||
    "element-plus": "^2.9.7",
 | 
			
		||||
    "js-base64": "^3.7.7",
 | 
			
		||||
 | 
			
		||||
@ -2,10 +2,10 @@
 | 
			
		||||
 | 
			
		||||
import {gameLogEventList} from "@/api/account.js";
 | 
			
		||||
import LocalCache from "@/stores/localCache.js";
 | 
			
		||||
import {Base64} from 'js-base64'
 | 
			
		||||
import dayjs from 'dayjs';
 | 
			
		||||
 | 
			
		||||
const props = defineProps({
 | 
			
		||||
  eventNames: [],
 | 
			
		||||
  eventName: "",
 | 
			
		||||
  serverId: "",
 | 
			
		||||
  account: "",
 | 
			
		||||
  roleId: "",
 | 
			
		||||
@ -20,49 +20,237 @@ const eventList = ref({
 | 
			
		||||
const cachedResource = LocalCache.getCache("resource");
 | 
			
		||||
const resource_url = cachedResource.meta.resource_url;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
const todayStart = new Date()
 | 
			
		||||
const todayEnd = new Date()
 | 
			
		||||
todayStart.setHours(0)
 | 
			
		||||
todayStart.setMinutes(0)
 | 
			
		||||
todayStart.setSeconds(0)
 | 
			
		||||
 | 
			
		||||
const dateTimeValue = ref([todayStart, todayEnd])
 | 
			
		||||
 | 
			
		||||
const getPageNo = ref(1)
 | 
			
		||||
const getPageLen = ref(20)
 | 
			
		||||
const getPageLen = ref(10)
 | 
			
		||||
const pageSizes = [10, 20, 50, 100, 200]
 | 
			
		||||
 | 
			
		||||
const eventNameList = props.eventName.split(",")
 | 
			
		||||
const selectedEventName = ref('')
 | 
			
		||||
const roleIdFilters = ref([])
 | 
			
		||||
 | 
			
		||||
const getEventList = () => {
 | 
			
		||||
  gameLogEventList(resource_url, {
 | 
			
		||||
  let listParams = {
 | 
			
		||||
    "AppId": 41,
 | 
			
		||||
    "EventName": props.eventNames,
 | 
			
		||||
    "EventName": props.eventName,
 | 
			
		||||
    "ServerId": props.serverId,
 | 
			
		||||
    "Account": props.account,
 | 
			
		||||
    "RoleId": props.roleId,
 | 
			
		||||
    "PageNo": getPageNo.value,
 | 
			
		||||
    "PageLen": getPageLen.value,
 | 
			
		||||
  }).then(res => {
 | 
			
		||||
  }
 | 
			
		||||
  console.log("select name:", selectedEventName.value)
 | 
			
		||||
  if (selectedEventName.value !== undefined && selectedEventName.value !== '' && selectedEventName.value !== ' ') {
 | 
			
		||||
    listParams.EventName = selectedEventName.value
 | 
			
		||||
  }
 | 
			
		||||
  if (dateTimeValue.value.length === 2) {
 | 
			
		||||
    console.log("select date time:", dateTimeValue.value)
 | 
			
		||||
    listParams.DateStart = dayjs(dateTimeValue.value[0]).format('YYYY-MM-DD HH:mm:ss')
 | 
			
		||||
    listParams.DateEnd = dayjs(dateTimeValue.value[1]).format('YYYY-MM-DD HH:mm:ss')
 | 
			
		||||
  }
 | 
			
		||||
  gameLogEventList(resource_url, listParams).then(res => {
 | 
			
		||||
    // console.log("获取账户聊天记录返回:", res.data)
 | 
			
		||||
    eventList.value = res.data
 | 
			
		||||
 | 
			
		||||
    roleIdFilters.value = []
 | 
			
		||||
    eventList.value.rows.forEach(row => {
 | 
			
		||||
      let find = false
 | 
			
		||||
      for (let i = 0; i < roleIdFilters.value.length; i++) {
 | 
			
		||||
        if (row[4] === roleIdFilters.value[i].value) {
 | 
			
		||||
          find = true
 | 
			
		||||
          break
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
      if (!find) {
 | 
			
		||||
        roleIdFilters.value.push({
 | 
			
		||||
          text: row[4],
 | 
			
		||||
          value: row[4],
 | 
			
		||||
        })
 | 
			
		||||
      }
 | 
			
		||||
    })
 | 
			
		||||
    // console.log("roleidfilter:", roleIdFilters.value)
 | 
			
		||||
  }, err => {
 | 
			
		||||
 | 
			
		||||
  })
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
const onDateTimeChange = () => {
 | 
			
		||||
  // getEventList()
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
defineExpose({
 | 
			
		||||
  getEventList
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
function b64Decode(str) {
 | 
			
		||||
  return Base64.decode(str)
 | 
			
		||||
const handlePaginationSizeChange = () => {
 | 
			
		||||
  getEventList()
 | 
			
		||||
}
 | 
			
		||||
const handlePaginationCurChange = () => {
 | 
			
		||||
  getEventList()
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
const onClickResetParams = () => {
 | 
			
		||||
  selectedEventName.value = ''
 | 
			
		||||
  dateTimeValue.value = [todayStart, todayEnd]
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
const filterRoleIdHandler = (
 | 
			
		||||
    value,
 | 
			
		||||
    row,
 | 
			
		||||
    column
 | 
			
		||||
) => {
 | 
			
		||||
  // console.log("filter:", value, row, column)
 | 
			
		||||
  return row[4] === value
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
onUnmounted(() => {
 | 
			
		||||
  console.log('用户列表组件已销毁');
 | 
			
		||||
  // 这里可以清理资源
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
const dateTimeShortcuts = [
 | 
			
		||||
  {
 | 
			
		||||
    text: '今天',
 | 
			
		||||
    value: () => {
 | 
			
		||||
      return [todayStart, todayEnd]
 | 
			
		||||
    },
 | 
			
		||||
  },
 | 
			
		||||
  {
 | 
			
		||||
    text: '昨天',
 | 
			
		||||
    value: () => {
 | 
			
		||||
      const end = new Date()
 | 
			
		||||
      end.setHours(0)
 | 
			
		||||
      end.setMinutes(0)
 | 
			
		||||
      end.setSeconds(0)
 | 
			
		||||
      const start = new Date()
 | 
			
		||||
      start.setHours(0)
 | 
			
		||||
      start.setMinutes(0)
 | 
			
		||||
      start.setSeconds(0)
 | 
			
		||||
      start.setTime(start.getTime() - 3600 * 1000 * 24 * 1)
 | 
			
		||||
      return [start, end]
 | 
			
		||||
    },
 | 
			
		||||
  },
 | 
			
		||||
  {
 | 
			
		||||
    text: '最近7天',
 | 
			
		||||
    value: () => {
 | 
			
		||||
      const end = new Date()
 | 
			
		||||
      const start = new Date()
 | 
			
		||||
      start.setTime(start.getTime() - 3600 * 1000 * 24 * 7)
 | 
			
		||||
      return [start, end]
 | 
			
		||||
    },
 | 
			
		||||
  },
 | 
			
		||||
  {
 | 
			
		||||
    text: '上周',
 | 
			
		||||
    value: () => {
 | 
			
		||||
      const end = new Date()
 | 
			
		||||
      const start = new Date()
 | 
			
		||||
      start.setTime(start.getTime() - 3600 * 1000 * 24 * 7)
 | 
			
		||||
      return [start, end]
 | 
			
		||||
    },
 | 
			
		||||
  },
 | 
			
		||||
  {
 | 
			
		||||
    text: '上个月',
 | 
			
		||||
    value: () => {
 | 
			
		||||
      const end = new Date()
 | 
			
		||||
      const start = new Date()
 | 
			
		||||
      start.setTime(start.getTime() - 3600 * 1000 * 24 * 30)
 | 
			
		||||
      return [start, end]
 | 
			
		||||
    },
 | 
			
		||||
  },
 | 
			
		||||
  {
 | 
			
		||||
    text: '最近1个月',
 | 
			
		||||
    value: () => {
 | 
			
		||||
      const end = new Date()
 | 
			
		||||
      const start = new Date()
 | 
			
		||||
      start.setTime(start.getTime() - 3600 * 1000 * 24 * 30)
 | 
			
		||||
      return [start, end]
 | 
			
		||||
    },
 | 
			
		||||
  },
 | 
			
		||||
]
 | 
			
		||||
</script>
 | 
			
		||||
 | 
			
		||||
<template>
 | 
			
		||||
  <div>
 | 
			
		||||
    <span>
 | 
			
		||||
       <el-table :data="eventList.rows" max-height="500px" style="width: 100%" table-layout="auto" border :show-header="true">
 | 
			
		||||
         <el-table-column v-for="(field, i) in eventList.fieldsDescInfo" :prop="field.name" :label="field.alias" width="100px">
 | 
			
		||||
    <el-row align="middle">
 | 
			
		||||
      <div style="margin-right: 20px">
 | 
			
		||||
        <el-select v-model="selectedEventName"
 | 
			
		||||
                   placeholder="选择事件"
 | 
			
		||||
                   clearable
 | 
			
		||||
                   style="width: 150px;margin-right: 10px">
 | 
			
		||||
          <el-option v-for="choice in eventNameList" :key="choice" :label="choice"
 | 
			
		||||
                     :value="choice"></el-option>
 | 
			
		||||
        </el-select>
 | 
			
		||||
      </div>
 | 
			
		||||
 | 
			
		||||
      <span>选择时间范围:</span>
 | 
			
		||||
      <div style="width: 400px;margin-right: 10px">
 | 
			
		||||
        <el-date-picker
 | 
			
		||||
            v-model="dateTimeValue"
 | 
			
		||||
            type="datetimerange"
 | 
			
		||||
            format="YYYY/MM/DD HH:mm:ss"
 | 
			
		||||
            range-separator="到"
 | 
			
		||||
            placeholder="选个一个时间范围"
 | 
			
		||||
            start-placeholder="开始时间"
 | 
			
		||||
            end-placeholder="结束时间"
 | 
			
		||||
            :shortcuts="dateTimeShortcuts"
 | 
			
		||||
            @change="onDateTimeChange"
 | 
			
		||||
        />
 | 
			
		||||
      </div>
 | 
			
		||||
 | 
			
		||||
      <el-button type="primary" @click="getEventList">
 | 
			
		||||
        查询
 | 
			
		||||
      </el-button>
 | 
			
		||||
 | 
			
		||||
      <el-button @click="onClickResetParams">
 | 
			
		||||
        重置
 | 
			
		||||
      </el-button>
 | 
			
		||||
 | 
			
		||||
      <div style="width:100%;height:0px;border: 1px solid #ebeef5;margin:8px 0 8px 0"/>
 | 
			
		||||
    </el-row>
 | 
			
		||||
    <el-row>
 | 
			
		||||
      <el-table :data="eventList.rows" max-height="500px" style="width: 100%" table-layout="auto" border
 | 
			
		||||
                :show-header="true">
 | 
			
		||||
        <template v-for="(field, i) in eventList.fieldsDescInfo">
 | 
			
		||||
          <el-table-column :prop="field.name" :label="field.alias" width="100px" v-if="field.name === 'pub_roleid'"
 | 
			
		||||
                           :filters="roleIdFilters" :filter-method="filterRoleIdHandler">
 | 
			
		||||
            <template #default="scope">
 | 
			
		||||
                     <span>
 | 
			
		||||
               {{scope.row[i]}}
 | 
			
		||||
                       {{ scope.row[i] }}
 | 
			
		||||
                     </span>
 | 
			
		||||
            </template>
 | 
			
		||||
          </el-table-column>
 | 
			
		||||
        </el-table>
 | 
			
		||||
          <el-table-column :prop="field.name" :label="field.alias" width="100px" v-else>
 | 
			
		||||
            <template #default="scope">
 | 
			
		||||
                     <span>
 | 
			
		||||
                       {{ scope.row[i] }}
 | 
			
		||||
                     </span>
 | 
			
		||||
            </template>
 | 
			
		||||
          </el-table-column>
 | 
			
		||||
        </template>
 | 
			
		||||
      </el-table>
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    </el-row>
 | 
			
		||||
 | 
			
		||||
    <el-row style="margin-top: 10px; margin-right: 10px" justify="end">
 | 
			
		||||
      <el-pagination
 | 
			
		||||
          v-model:current-page="getPageNo"
 | 
			
		||||
          v-model:page-size="getPageLen"
 | 
			
		||||
          :page-sizes="pageSizes"
 | 
			
		||||
          layout="total, sizes, prev, pager, next, jumper"
 | 
			
		||||
          :total="eventList.totalCount"
 | 
			
		||||
          @size-change="handlePaginationSizeChange"
 | 
			
		||||
          @current-change="handlePaginationCurChange"
 | 
			
		||||
      />
 | 
			
		||||
    </el-row>
 | 
			
		||||
  </div>
 | 
			
		||||
</template>
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -62,22 +62,28 @@ const handleClick = (tab, event) => {
 | 
			
		||||
</script>
 | 
			
		||||
 | 
			
		||||
<template>
 | 
			
		||||
  <div>
 | 
			
		||||
  <div style="width: 1000px">
 | 
			
		||||
    <el-tabs v-model="activeName" class="demo-tabs" @tab-click="handleClick" v-if="loadAccountOk">
 | 
			
		||||
      <el-tab-pane label="账号详情" name="detail">
 | 
			
		||||
        <component :is="userDetailAccount" :accountInfo="accountInfo"/>
 | 
			
		||||
      </el-tab-pane>
 | 
			
		||||
      <el-tab-pane label="充值订单记录" name="order">
 | 
			
		||||
        <component :is="userDetailOrder" :accountInfo="accountInfo"/>
 | 
			
		||||
        <component v-if="activeName === 'order'" :is="userDetailOrder" :accountInfo="accountInfo"/>
 | 
			
		||||
      </el-tab-pane>
 | 
			
		||||
      <el-tab-pane label="聊天记录" name="chat">
 | 
			
		||||
        <gamelogList ref="gamelogChatChildRef" :serverId="serverId" :account="account" :eventName="chatlog"/>
 | 
			
		||||
      <el-tab-pane key="tab-chat" label="聊天记录" name="chat">
 | 
			
		||||
        <gamelogList key="tab-chat" :ref="(el) => gamelogChatChildRef = el"
 | 
			
		||||
                     :serverId="serverId" :account="account"
 | 
			
		||||
                     eventName="chatlog"/>
 | 
			
		||||
      </el-tab-pane>
 | 
			
		||||
      <el-tab-pane label="货币变动" name="currencyChange">
 | 
			
		||||
        <gamelogList ref="gamelogCurrencyChildRef"  :serverId="serverId" :account="account" :eventName="addcoin,costcoin"/>
 | 
			
		||||
      <el-tab-pane key="tab-currency" label="货币变动" name="currencyChange">
 | 
			
		||||
        <gamelogList key="tab-currency" :ref="(el) => gamelogCurrencyChildRef = el"
 | 
			
		||||
                     :serverId="serverId" :account="account"
 | 
			
		||||
                     eventName="addcoin,costcoin"/>
 | 
			
		||||
      </el-tab-pane>
 | 
			
		||||
      <el-tab-pane label="道具变动" name="itemChange">
 | 
			
		||||
        <gamelogList ref="gamelogItemChangeChildRef"  :serverId="serverId" :account="account" :eventName="gainitem,costitem"/>
 | 
			
		||||
      <el-tab-pane key="tab-item" label="道具变动" name="itemChange">
 | 
			
		||||
        <gamelogList key="tab-item" :ref="(el) => gamelogItemChangeChildRef = el"
 | 
			
		||||
                     :serverId="serverId" :account="account"
 | 
			
		||||
                     eventName="gainitem,loseitem"/>
 | 
			
		||||
      </el-tab-pane>
 | 
			
		||||
      <!--      <el-tab-pane label="货币记录" name="currency" v-if="accountInfo !== null">货币记录子页面</el-tab-pane>-->
 | 
			
		||||
    </el-tabs>
 | 
			
		||||
 | 
			
		||||
@ -582,7 +582,7 @@ const handleGenRandAccount = () => {
 | 
			
		||||
  for (let i = 0; i < genRandAccountNum.value; i++) {
 | 
			
		||||
    let randStr = ""
 | 
			
		||||
    for (let j = 0; j < genRandAccountCharBitNum.value; j++) {
 | 
			
		||||
      randStr += randCharArray[Math.floor(Math.random() * 1000000) %randCharArray.length]
 | 
			
		||||
      randStr += randCharArray[Math.floor(Math.random() * 1000000) % randCharArray.length]
 | 
			
		||||
    }
 | 
			
		||||
    const accountName = genRandAccountPrefix.value + randStr + genRandAccountSuffix.value
 | 
			
		||||
    // console.log("rand account name:", Math.random())
 | 
			
		||||
@ -775,7 +775,7 @@ const handleGenRandAccount = () => {
 | 
			
		||||
          <template v-for="(btn, index) in rowClickBtns">
 | 
			
		||||
            <el-dialog v-model="rowClickBtnVisibleList[index]" :title="btn.name"
 | 
			
		||||
                       @close="rowClickBtnVisibleList[index]=false"
 | 
			
		||||
                       destroy-on-close>
 | 
			
		||||
                       destroy-on-close style="width: 1020px">
 | 
			
		||||
              <component :is="btn.btn_callback_component" :rowInfo="rowClickBtnSelectRow"
 | 
			
		||||
                         :fieldsDescInfo="fieldsDescInfo"/>
 | 
			
		||||
            </el-dialog>
 | 
			
		||||
@ -864,18 +864,24 @@ const handleGenRandAccount = () => {
 | 
			
		||||
                    <el-form-item :label="fieldDescInfo.name" :prop="fieldDescInfo.key">
 | 
			
		||||
                      <el-row style="margin-bottom: 10px">
 | 
			
		||||
                        <span>随机数量:</span>
 | 
			
		||||
                        <el-tooltip effect="light" placement="top-start" content="输入生成账号的数量,数量范围[1-1000],数量太大了后台短时间生成不完,注意多等几分钟会再发放账号">
 | 
			
		||||
                          <el-input type="number" v-model="genRandAccountNum" placeholder="账号数量" style="width: 90px"/>
 | 
			
		||||
                        <el-tooltip effect="light" placement="top-start"
 | 
			
		||||
                                    content="输入生成账号的数量,数量范围[1-1000],数量太大了后台短时间生成不完,注意多等几分钟会再发放账号">
 | 
			
		||||
                          <el-input type="number" v-model="genRandAccountNum" placeholder="账号数量"
 | 
			
		||||
                                    style="width: 90px"/>
 | 
			
		||||
                        </el-tooltip>
 | 
			
		||||
                        <span style="margin-left: 10px">随机模板:</span>
 | 
			
		||||
                        <el-tooltip effect="light" placement="top" content="前缀、后缀必填至少一个">
 | 
			
		||||
                          <el-input v-model="genRandAccountPrefix" placeholder="前缀" style="width: 100px;margin-right: 5px"></el-input>
 | 
			
		||||
                          <el-input v-model="genRandAccountPrefix" placeholder="前缀"
 | 
			
		||||
                                    style="width: 100px;margin-right: 5px"></el-input>
 | 
			
		||||
                        </el-tooltip>
 | 
			
		||||
                        <el-tooltip effect="light" placement="top" content="账号随机混淆字串的位数,范围[3-20],与前缀、后缀一起组成账号">
 | 
			
		||||
                          <el-input type="number" v-model="genRandAccountCharBitNum" placeholder="随机串数量" style="width: 80px;margin-right: 5px"/>
 | 
			
		||||
                        <el-tooltip effect="light" placement="top"
 | 
			
		||||
                                    content="账号随机混淆字串的位数,范围[3-20],与前缀、后缀一起组成账号">
 | 
			
		||||
                          <el-input type="number" v-model="genRandAccountCharBitNum" placeholder="随机串数量"
 | 
			
		||||
                                    style="width: 80px;margin-right: 5px"/>
 | 
			
		||||
                        </el-tooltip>
 | 
			
		||||
                        <el-tooltip effect="light" placement="top" content="前缀、后缀必填至少一个">
 | 
			
		||||
                          <el-input v-model="genRandAccountSuffix" placeholder="后缀" style="width: 100px;margin-right: 5px"></el-input>
 | 
			
		||||
                          <el-input v-model="genRandAccountSuffix" placeholder="后缀"
 | 
			
		||||
                                    style="width: 100px;margin-right: 5px"></el-input>
 | 
			
		||||
                        </el-tooltip>
 | 
			
		||||
                        <el-button type="success" @click="handleGenRandAccount">生成</el-button>
 | 
			
		||||
                      </el-row>
 | 
			
		||||
@ -927,14 +933,16 @@ const handleGenRandAccount = () => {
 | 
			
		||||
                                     :loading="loadingRemoteItems"
 | 
			
		||||
                                     value-key="value"
 | 
			
		||||
                          >
 | 
			
		||||
                          <el-option v-for="info in itemChoices" :key="info.value" :label="info.desc+'('+info.value+')'"
 | 
			
		||||
                            <el-option v-for="info in itemChoices" :key="info.value"
 | 
			
		||||
                                       :label="info.desc+'('+info.value+')'"
 | 
			
		||||
                                       :value="info"></el-option>
 | 
			
		||||
                          </el-select>
 | 
			
		||||
                        </el-tooltip>
 | 
			
		||||
                      </el-form-item>
 | 
			
		||||
 | 
			
		||||
                      <el-form-item label="数量" prop="number" label-width="40px">
 | 
			
		||||
                      <el-input type="number" v-model="selectedItemNum" placeholder="请输入数量" style="width: 100px"/>
 | 
			
		||||
                        <el-input type="number" v-model="selectedItemNum" placeholder="请输入数量"
 | 
			
		||||
                                  style="width: 100px"/>
 | 
			
		||||
                      </el-form-item>
 | 
			
		||||
 | 
			
		||||
                      <el-form-item>
 | 
			
		||||
@ -946,7 +954,8 @@ const handleGenRandAccount = () => {
 | 
			
		||||
                        <el-tooltip effect="light" content="选择礼包,点击添加到奖励列表">
 | 
			
		||||
                          <el-select placeholder="--礼包--" v-model="selectedItemBag" clearable style="width: 150px"
 | 
			
		||||
                                     value-key="name" multiple @blur="itemBagSelectChange">
 | 
			
		||||
                          <el-option v-for="bag in itemBags" :key="bag.name" :label="bag.name" :value="bag"></el-option>
 | 
			
		||||
                            <el-option v-for="bag in itemBags" :key="bag.name" :label="bag.name"
 | 
			
		||||
                                       :value="bag"></el-option>
 | 
			
		||||
                          </el-select>
 | 
			
		||||
                        </el-tooltip>
 | 
			
		||||
                      </el-form-item>
 | 
			
		||||
@ -1054,6 +1063,7 @@ const handleGenRandAccount = () => {
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      /*控制表格tooltip宽度*/
 | 
			
		||||
 | 
			
		||||
      ::v-deep(.el-popper) {
 | 
			
		||||
        max-width: 640px;
 | 
			
		||||
        word-break: break-all;
 | 
			
		||||
@ -1080,6 +1090,7 @@ const handleGenRandAccount = () => {
 | 
			
		||||
  .pagination-container .el-pagination > .el-pagination__jump {
 | 
			
		||||
    display: none !important;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  .pagination-container .el-pagination > .el-pagination__sizes {
 | 
			
		||||
    display: none !important;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user