add exec history
This commit is contained in:
		
							parent
							
								
									c65851b018
								
							
						
					
					
						commit
						e2612f16b4
					
				@ -12,8 +12,8 @@ func init() {
 | 
			
		||||
// Account 空表,就是用来兼容资源增删改查公共操作的,实际列举账号等都是走各个项目api拉取
 | 
			
		||||
type Account struct {
 | 
			
		||||
	ProjectId       int
 | 
			
		||||
	Account         string    `name:"账号" json:"account"`
 | 
			
		||||
	ServerConfId    string    `name:"区服id" json:"serveId"`
 | 
			
		||||
	Account         string    `name:"账号" json:"account" where:"eq"`
 | 
			
		||||
	ServerConfId    string    `name:"区服id" json:"serveId" where:"eq"`
 | 
			
		||||
	RoleIds         []string  `gorm:"type:json;serializer:json" name:"角色id列表" json:"roleIds"`
 | 
			
		||||
	LatestLoginTime time.Time `name:"最近登录时间" json:"latest_login_time"`
 | 
			
		||||
	CreateTime      time.Time `name:"创建时间" json:"create_time"`
 | 
			
		||||
 | 
			
		||||
@ -18,7 +18,7 @@ type GlobalMail struct {
 | 
			
		||||
	Content   string            `name:"邮件内容" required:"true"`
 | 
			
		||||
	Attach    []*MailAttachItem `gorm:"type:json;serializer:json" name:"邮件附件" type:"items" desc:"搜索道具并点击添加"`
 | 
			
		||||
 | 
			
		||||
	CreatedAt time.Time `readonly:"true"`
 | 
			
		||||
	CreatedAt time.Time `readonly:"true" where:"range"`
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (lm *GlobalMail) TableName() string {
 | 
			
		||||
 | 
			
		||||
@ -12,10 +12,10 @@ func init() {
 | 
			
		||||
// Role 空表,就是用来兼容资源增删改查公共操作的,实际列举账号等都是走各个项目api拉取
 | 
			
		||||
type Role struct {
 | 
			
		||||
	ProjectId       int
 | 
			
		||||
	RoleId          string    `name:"角色ID" json:"roleId"`
 | 
			
		||||
	Account         string    `name:"账号" json:"account"`
 | 
			
		||||
	ServerConfId    string    `name:"区服id" json:"serverId"`
 | 
			
		||||
	Name            string    `name:"名称" json:"roleName"`
 | 
			
		||||
	RoleId          string    `name:"角色ID" json:"roleId" where:"eq"`
 | 
			
		||||
	Account         string    `name:"账号" json:"account" where:"eq"`
 | 
			
		||||
	ServerConfId    string    `name:"区服id" json:"serverId" where:"eq"`
 | 
			
		||||
	Name            string    `name:"名称" json:"roleName" where:"eq"`
 | 
			
		||||
	Status          string    `name:"状态" desc:"离线|在线" json:"status"`
 | 
			
		||||
	Level           int       `name:"等级" json:"roleLevel"`
 | 
			
		||||
	Profession      string    `name:"职业" json:"profession"`
 | 
			
		||||
 | 
			
		||||
@ -13,11 +13,11 @@ func init() {
 | 
			
		||||
type WhiteList struct {
 | 
			
		||||
	ID           int    `gorm:"primarykey" readonly:"true"`
 | 
			
		||||
	ProjectId    int    `gorm:"uniqueIndex:idx_whitelist"`
 | 
			
		||||
	ServerConfID string `gorm:"type:varchar(200);uniqueIndex:idx_server" name:"区服id" required:"true" choices:"GetChoiceServers"`
 | 
			
		||||
	ServerConfID string `gorm:"type:varchar(200);uniqueIndex:idx_server" name:"区服id" required:"true" choices:"GetChoiceServers" where:"eq"`
 | 
			
		||||
	Account      string `gorm:"type:varchar(128);uniqueIndex:idx_whitelist" name:"账户" required:"true"`
 | 
			
		||||
	Desc         string `name:"描述"`
 | 
			
		||||
 | 
			
		||||
	CreatedAt time.Time `readonly:"true"`
 | 
			
		||||
	CreatedAt time.Time `readonly:"true" where:"range"`
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (lm *WhiteList) TableName() string {
 | 
			
		||||
 | 
			
		||||
@ -3,6 +3,7 @@ package server
 | 
			
		||||
import (
 | 
			
		||||
	"admin/apps/game/model/dto"
 | 
			
		||||
	"admin/internal/context"
 | 
			
		||||
	stdContext "context"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
func (ctl *controller) CommonList(ctx *context.WebContext, params *dto.CommonListReq, rsp *dto.CommonListRsp) error {
 | 
			
		||||
@ -17,7 +18,11 @@ func (ctl *controller) CommonList(ctx *context.WebContext, params *dto.CommonLis
 | 
			
		||||
 | 
			
		||||
func (ctl *controller) CommonPost(ctx *context.WebContext, params *dto.CommonPostReq, rsp *dto.CommonPostRsp) error {
 | 
			
		||||
	projectId, resource := getCtxURIProjectIdAndResource(ctx)
 | 
			
		||||
	newObj, err := ctl.svc.CommonPost(ctx, projectId, resource, *params.Dto)
 | 
			
		||||
 | 
			
		||||
	ctx1 := stdContext.WithValue(ctx.Context, "user_id", ctx.Header.UserId)
 | 
			
		||||
	ctx1 = stdContext.WithValue(ctx1, "user_name", ctx.Header.UserId)
 | 
			
		||||
 | 
			
		||||
	newObj, err := ctl.svc.CommonPost(ctx1, projectId, resource, *params.Dto)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
@ -23,6 +23,8 @@ func (srv *Server) CheckToken(ctx *context.WebContext) {
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	ctx.Header.UserName = authRsp.User.NickName
 | 
			
		||||
 | 
			
		||||
	ctx.GinCtx().Set("userInfo", authRsp)
 | 
			
		||||
	return
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -6,6 +6,8 @@ import (
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
func (srv *Server) Route(engine *web.Engine) {
 | 
			
		||||
	engine.Use(srv.CheckToken)
 | 
			
		||||
 | 
			
		||||
	apiGroup := engine.Group("/api", "")
 | 
			
		||||
 | 
			
		||||
	{
 | 
			
		||||
 | 
			
		||||
@ -6,6 +6,7 @@ import (
 | 
			
		||||
	"admin/apps/game/model/dto"
 | 
			
		||||
	"admin/internal/consts"
 | 
			
		||||
	"admin/internal/errcode"
 | 
			
		||||
	"admin/internal/event"
 | 
			
		||||
	"context"
 | 
			
		||||
	"encoding/json"
 | 
			
		||||
	"gorm.io/gorm"
 | 
			
		||||
@ -59,18 +60,61 @@ func (svc *Service) CommonPost(ctx context.Context, projectId int, resourceName
 | 
			
		||||
	if resourceName != consts.ResourcesName_Project {
 | 
			
		||||
		params["ProjectId"] = projectId
 | 
			
		||||
	}
 | 
			
		||||
	return svc.resourceSvc.Create(projectId, resourceName, params)
 | 
			
		||||
 | 
			
		||||
	values, err := svc.resourceSvc.Create(projectId, resourceName, params)
 | 
			
		||||
 | 
			
		||||
	userId := ctx.Value("user_id").(int)
 | 
			
		||||
	userName := ctx.Value("user_name").(string)
 | 
			
		||||
 | 
			
		||||
	event.GetMgrInstance().Publish(event.EventTopic_UserExecute, &event.EventPayload_UserExecute{
 | 
			
		||||
		UserId:    userId,
 | 
			
		||||
		UserName:  userName,
 | 
			
		||||
		ProjectId: projectId,
 | 
			
		||||
		Resource:  resourceName,
 | 
			
		||||
		Method:    "新增",
 | 
			
		||||
		NewData:   params,
 | 
			
		||||
	})
 | 
			
		||||
 | 
			
		||||
	return values, err
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (svc *Service) CommonPut(ctx context.Context, projectId int, resourceName string, params dto.CommonDtoValues) error {
 | 
			
		||||
	if resourceName != consts.ResourcesName_Project {
 | 
			
		||||
		params["ProjectId"] = projectId
 | 
			
		||||
	}
 | 
			
		||||
	return svc.resourceSvc.Edit(projectId, resourceName, params)
 | 
			
		||||
	err := svc.resourceSvc.Edit(projectId, resourceName, params)
 | 
			
		||||
 | 
			
		||||
	userId := ctx.Value("user_id").(int)
 | 
			
		||||
	userName := ctx.Value("user_name").(string)
 | 
			
		||||
 | 
			
		||||
	event.GetMgrInstance().Publish(event.EventTopic_UserExecute, &event.EventPayload_UserExecute{
 | 
			
		||||
		UserId:    userId,
 | 
			
		||||
		UserName:  userName,
 | 
			
		||||
		ProjectId: projectId,
 | 
			
		||||
		Resource:  resourceName,
 | 
			
		||||
		Method:    "编辑",
 | 
			
		||||
		NewData:   params,
 | 
			
		||||
	})
 | 
			
		||||
 | 
			
		||||
	return err
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (svc *Service) CommonDelete(ctx context.Context, projectId int, resourceName string, id int) error {
 | 
			
		||||
	return svc.resourceSvc.Delete(projectId, resourceName, id)
 | 
			
		||||
	err := svc.resourceSvc.Delete(projectId, resourceName, id)
 | 
			
		||||
 | 
			
		||||
	userId := ctx.Value("user_id").(int)
 | 
			
		||||
	userName := ctx.Value("user_name").(string)
 | 
			
		||||
 | 
			
		||||
	event.GetMgrInstance().Publish(event.EventTopic_UserExecute, &event.EventPayload_UserExecute{
 | 
			
		||||
		UserId:    userId,
 | 
			
		||||
		UserName:  userName,
 | 
			
		||||
		ProjectId: projectId,
 | 
			
		||||
		Resource:  resourceName,
 | 
			
		||||
		Method:    "删除",
 | 
			
		||||
		NewData:   id,
 | 
			
		||||
	})
 | 
			
		||||
 | 
			
		||||
	return err
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (svc *Service) GetSupportResourcesList(permissions []string) []*api.ResourceInitInfo {
 | 
			
		||||
 | 
			
		||||
@ -24,6 +24,7 @@ type AuthReq struct {
 | 
			
		||||
 | 
			
		||||
type UserInfo struct {
 | 
			
		||||
	UserId      int      `json:"user_id"`
 | 
			
		||||
	UserName    string   `json:"user_name"`
 | 
			
		||||
	NickName    string   `json:"nick_name"`
 | 
			
		||||
	Icon        string   `json:"icon"`
 | 
			
		||||
	Character   string   `json:"character"`
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										35
									
								
								admin/apps/user/model/history.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										35
									
								
								admin/apps/user/model/history.go
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,35 @@
 | 
			
		||||
package model
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"admin/internal/db"
 | 
			
		||||
	"admin/internal/global"
 | 
			
		||||
	"time"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
func init() {
 | 
			
		||||
	db.RegisterTableModels(History{})
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// History 用户执行历史
 | 
			
		||||
type History struct {
 | 
			
		||||
	ID         int `gorm:"primarykey" readonly:"true"`
 | 
			
		||||
	UserId     int
 | 
			
		||||
	UserName   string
 | 
			
		||||
	ProjectId  int
 | 
			
		||||
	Resource   string
 | 
			
		||||
	Method     string
 | 
			
		||||
	Data       string `gorm:"type:longtext"`
 | 
			
		||||
	CreateTime time.Time
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (m *History) TableName() string {
 | 
			
		||||
	return "history"
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (m *History) GetId() int {
 | 
			
		||||
	return m.ID
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (m *History) Create() error {
 | 
			
		||||
	return global.GLOB_DB.Create(m).Error
 | 
			
		||||
}
 | 
			
		||||
@ -1,6 +1,12 @@
 | 
			
		||||
package server
 | 
			
		||||
 | 
			
		||||
import "admin/apps/user/service"
 | 
			
		||||
import (
 | 
			
		||||
	"admin/apps/user/model"
 | 
			
		||||
	"admin/apps/user/service"
 | 
			
		||||
	"admin/internal/event"
 | 
			
		||||
	"admin/lib/xlog"
 | 
			
		||||
	"encoding/json"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
type Server struct {
 | 
			
		||||
	svc *service.Service
 | 
			
		||||
@ -13,3 +19,28 @@ func New(svc *service.Service) *Server {
 | 
			
		||||
		ctl: newController(svc),
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (srv *Server) jobsSubscribe() {
 | 
			
		||||
	event.GetMgrInstance().Subscribe("user", event.EventTopic_UserExecute, srv.subscriberHandlerUserExecute)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (srv *Server) subscriberHandlerUserExecute(msg *event.Msg) {
 | 
			
		||||
	po := new(model.History)
 | 
			
		||||
	msgHistory := &event.EventPayload_UserExecute{}
 | 
			
		||||
	err := json.Unmarshal(msg.Payload, msgHistory)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		xlog.Errorf("unmarshal msg(%+v) err:%v", string(msg.Payload), err)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	po.UserId = msgHistory.UserId
 | 
			
		||||
	po.UserName = msgHistory.UserName
 | 
			
		||||
	po.ProjectId = msgHistory.ProjectId
 | 
			
		||||
	po.Resource = msgHistory.Resource
 | 
			
		||||
	po.Method = msgHistory.Method
 | 
			
		||||
	po.Data = string(msg.Payload)
 | 
			
		||||
 | 
			
		||||
	err = po.Create()
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		xlog.Errorf("create user execute(%+v) err:%v", string(msg.Payload), err)
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -40,6 +40,7 @@ func (svc *Service) Auth(ctx context.Context, req *apiUser.AuthReq) (*apiUser.Au
 | 
			
		||||
	}
 | 
			
		||||
	rsp.User = &apiUser.UserInfo{
 | 
			
		||||
		UserId:      info.User.UserId,
 | 
			
		||||
		UserName:    info.User.NickName,
 | 
			
		||||
		NickName:    info.User.NickName,
 | 
			
		||||
		Icon:        info.User.Icon,
 | 
			
		||||
		Character:   info.User.Character,
 | 
			
		||||
 | 
			
		||||
@ -9,9 +9,10 @@ import (
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
type WebHeader struct {
 | 
			
		||||
	UserId int    `json:"UserId"` // 用户id,会与下面token解析出用户id做匹配校验
 | 
			
		||||
	Token  string `json:"Token"`  // jwt token,内置一些信息
 | 
			
		||||
	Ip     string `json:"IP"`
 | 
			
		||||
	UserId   int    `json:"UserId"` // 用户id,会与下面token解析出用户id做匹配校验
 | 
			
		||||
	Token    string `json:"Token"`  // jwt token,内置一些信息
 | 
			
		||||
	Ip       string `json:"IP"`
 | 
			
		||||
	UserName string `json:"-"`
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type WebContext struct {
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										15
									
								
								admin/internal/event/event.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										15
									
								
								admin/internal/event/event.go
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,15 @@
 | 
			
		||||
package event
 | 
			
		||||
 | 
			
		||||
import "admin/lib/eventmgr"
 | 
			
		||||
 | 
			
		||||
type Msg = eventmgr.Msg
 | 
			
		||||
 | 
			
		||||
var manager *eventmgr.Mgr
 | 
			
		||||
 | 
			
		||||
func init() {
 | 
			
		||||
	manager = eventmgr.NewMgr()
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func GetMgrInstance() *eventmgr.Mgr {
 | 
			
		||||
	return manager
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										15
									
								
								admin/internal/event/topic.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										15
									
								
								admin/internal/event/topic.go
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,15 @@
 | 
			
		||||
package event
 | 
			
		||||
 | 
			
		||||
const (
 | 
			
		||||
	EventTopic_UserExecute = "user.execute"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
type EventPayload_UserExecute struct {
 | 
			
		||||
	UserId    int    `json:"user_id"`
 | 
			
		||||
	UserName  string `json:"user_name"`
 | 
			
		||||
	ProjectId int    `json:"project_id"`
 | 
			
		||||
	Resource  string `json:"resource"`
 | 
			
		||||
	Method    string `json:"method"`
 | 
			
		||||
	OldData   any    `json:"old_data"`
 | 
			
		||||
	NewData   any    `json:"new_data"`
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										66
									
								
								admin/lib/eventmgr/event.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										66
									
								
								admin/lib/eventmgr/event.go
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,66 @@
 | 
			
		||||
package eventmgr
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"admin/lib/xlog"
 | 
			
		||||
	"encoding/json"
 | 
			
		||||
	"runtime"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
type Msg struct {
 | 
			
		||||
	Event   string
 | 
			
		||||
	Payload []byte
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type subscriber struct {
 | 
			
		||||
	name    string
 | 
			
		||||
	topic   string
 | 
			
		||||
	handler func(*Msg)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type Mgr struct {
 | 
			
		||||
	subscribers []*subscriber
 | 
			
		||||
	broker      chan *Msg
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func NewMgr() *Mgr {
 | 
			
		||||
	mgr := &Mgr{
 | 
			
		||||
		subscribers: make([]*subscriber, 0),
 | 
			
		||||
		broker:      make(chan *Msg, 1024),
 | 
			
		||||
	}
 | 
			
		||||
	mgr.start()
 | 
			
		||||
	return mgr
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (m *Mgr) start() {
 | 
			
		||||
	for i := 0; i < runtime.NumCPU(); i++ {
 | 
			
		||||
		go func() {
 | 
			
		||||
			for {
 | 
			
		||||
				select {
 | 
			
		||||
				case msg := <-m.broker:
 | 
			
		||||
					for _, sub := range m.subscribers {
 | 
			
		||||
						if sub.topic == msg.Event {
 | 
			
		||||
							sub.handler(msg)
 | 
			
		||||
						}
 | 
			
		||||
					}
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
		}()
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (m *Mgr) Subscribe(name string, topic string, handler func(*Msg)) {
 | 
			
		||||
	m.subscribers = append(m.subscribers, &subscriber{name: name, topic: topic, handler: handler})
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (m *Mgr) Publish(event string, payload any) {
 | 
			
		||||
	payloadBin, err := json.Marshal(payload)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		panic(err)
 | 
			
		||||
	}
 | 
			
		||||
	msg := &Msg{Event: event, Payload: payloadBin}
 | 
			
		||||
	select {
 | 
			
		||||
	case m.broker <- msg:
 | 
			
		||||
	default:
 | 
			
		||||
		xlog.Errorf("publish event:%v broker is full", event)
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										
											BIN
										
									
								
								admin/uniugm
									
									
									
									
									
								
							
							
						
						
									
										
											BIN
										
									
								
								admin/uniugm
									
									
									
									
									
								
							
										
											Binary file not shown.
										
									
								
							@ -304,8 +304,17 @@ const handleQueryItem = (itemQueryStr) => {
 | 
			
		||||
              </el-col>
 | 
			
		||||
            </template>
 | 
			
		||||
            <template v-else>
 | 
			
		||||
              <el-input v-model="fieldDescInfo.value1"
 | 
			
		||||
                        :placeholder="(fieldDescInfo.name + fieldDescInfo.whereDesc)" style="width: 150px"></el-input>
 | 
			
		||||
              <el-col :span="calcElColSpan">
 | 
			
		||||
                <el-select v-model="fieldDescInfo.value1" :placeholder="(fieldDescInfo.multi_choice === true ? '--多选--' : '--单选--')"
 | 
			
		||||
                           style="width: 150px"
 | 
			
		||||
                           filterable v-if="(fieldDescInfo.choices.length > 0)">
 | 
			
		||||
                  <el-option v-for="choice in fieldDescInfo.choices" :key="choice.value" :label="choice.desc"
 | 
			
		||||
                             :value="choice.value"></el-option>
 | 
			
		||||
                </el-select>
 | 
			
		||||
                <el-input v-model="fieldDescInfo.value1"
 | 
			
		||||
                          :placeholder="(fieldDescInfo.name + fieldDescInfo.whereDesc)"
 | 
			
		||||
                          style="width: 150px" v-else></el-input>
 | 
			
		||||
              </el-col>
 | 
			
		||||
            </template>
 | 
			
		||||
          </template>
 | 
			
		||||
          <el-col :span="calcElColSpan">
 | 
			
		||||
 | 
			
		||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user