diff --git a/admin/apps/game/domain/comm_resource.go b/admin/apps/game/domain/comm_resource.go index 6f02a78..a81b0a0 100644 --- a/admin/apps/game/domain/comm_resource.go +++ b/admin/apps/game/domain/comm_resource.go @@ -22,7 +22,7 @@ func initCommonResourcesRepo(db *gorm.DB) { r(consts.ResourcesName_Account, "账号管理", repo.NewCommonResourceRepo(db, &model.Account{}), ShowMethod_Get) // 账号管理不需要在后台读写数据,都是通过项目api拉 r(consts.ResourcesName_Role, "角色管理", repo.NewCommonResourceRepo(db, &model.Role{}), ShowMethod_Get) // 角色管理不需要在后台读写数据,都是通过项目api拉 r(consts.ResourcesName_WhiteList, "白名单", repo.NewCommonResourceRepo(db, &model.WhiteList{}), ShowMethod_Get|ShowMethod_Post|ShowMethod_Delete) - r(consts.ResourcesName_Ban, "封禁管理", repo.NewCommonResourceRepo(db, &model.Ban{}), ShowMethod_Get|ShowMethod_Post|ShowMethod_Delete) + r(consts.ResourcesName_Ban, "封禁管理", repo.NewCommonResourceRepo(db, &model.Ban{}), ShowMethod_Get|ShowMethod_Post|ShowMethod_Put|ShowMethod_Delete) r(consts.ResourcesName_MailRole, "个人邮件", repo.NewCommonResourceRepo(db, &model.RoleMail{}), ShowMethod_Get|ShowMethod_Post) // 个人邮件发放就没法撤回? r(consts.ResourcesName_MailGlobal, "全服邮件", repo.NewCommonResourceRepo(db, &model.GlobalMail{}), ShowMethod_Get|ShowMethod_Post|ShowMethod_Delete) // 直接删除,别修改了,玩家收到的更乱 r(consts.ResourcesName_Notice, "公告", repo.NewCommonResourceRepo(db, &model.Notice{}), ShowMethod_Get|ShowMethod_Post|ShowMethod_Put|ShowMethod_Delete) diff --git a/admin/apps/game/domain/entity/utils.go b/admin/apps/game/domain/entity/utils.go index 1d7acf4..3585a1f 100644 --- a/admin/apps/game/domain/entity/utils.go +++ b/admin/apps/game/domain/entity/utils.go @@ -8,6 +8,7 @@ import ( "gorm.io/gorm" "reflect" "strconv" + "strings" "time" ) @@ -27,6 +28,10 @@ func poToCommonDtoNo(po any) dto.CommonDtoValues { } obj[ft.Name] = fo.Interface() + + if ft.Type.Name() == "Time" && ft.Type.PkgPath() == "time" { + obj[ft.Name] = fo.Interface().(time.Time).Format(time.DateTime) + } } return obj @@ -46,6 +51,11 @@ func getFieldTypeDtoDescInfo(projectId string, poValue reflect.Value, fieldType Required: fieldType.Tag.Get("required") == "true", Choices: make([]*dto.CommonDtoFieldChoice, 0), MultiChoice: fieldType.Tag.Get("multi_choice") == "true", + Uneditable: fieldType.Tag.Get("uneditable") == "true", + } + + if f1.Key == "CreatedAt" { + f1.Name = "创建时间" } if tagType := fieldType.Tag.Get("type"); tagType != "" { @@ -114,7 +124,9 @@ func parseStr2FieldValue(field reflect.StructField, rawValue any) (realSetValue case reflect.Struct: typeName := field.Type.Name() if typeName == "Time" { - return reflect.ValueOf(time.Now()) + xlog.Debugf("time content:%v", setValue) + t, _ := time.ParseInLocation("2006/01/02 15:04:05", setValue, time.Local) + return reflect.ValueOf(t) } if typeName == "DeletedAt" { return reflect.ValueOf(gorm.DeletedAt{}) @@ -124,29 +136,43 @@ func parseStr2FieldValue(field reflect.StructField, rawValue any) (realSetValue typeName := field.Type.String() if typeName == "[]string" { list := make([]string, 0) - if _, ok := rawValue.(string); ok { + if rawValueStr, ok := rawValue.(string); ok { + elems := strings.Split(rawValueStr, ",") + list = append(list, elems...) // 空的字符串 } else { - for _, v := range rawValue.([]interface{}) { - list = append(list, v.(string)) + if rawValueList, ok := rawValue.([]string); ok { + for _, v := range rawValueList { + list = append(list, v) + } + } else { + for _, v := range rawValue.([]interface{}) { + list = append(list, v.(string)) + } } } parsedValue = list } else if typeName == "[]*model.MailAttachItem" { items := make([]*model.MailAttachItem, 0) - for _, itemI := range rawValue.([]interface{}) { - item := &model.MailAttachItem{} - for k, vI := range itemI.(map[string]any) { - v := vI.(float64) - if k == "id" { - item.ID = int32(v) - } else if k == "num" { - item.Num = int64(v) - } else if k == "item_type" { - item.ItemType = int(v) - } + if rawValueList, ok := rawValue.([]*model.MailAttachItem); ok { + for _, item := range rawValueList { + items = append(items, item) + } + } else { + for _, itemI := range rawValue.([]interface{}) { + item := &model.MailAttachItem{} + for k, vI := range itemI.(map[string]any) { + v := vI.(float64) + if k == "id" { + item.ID = int32(v) + } else if k == "num" { + item.Num = int64(v) + } else if k == "item_type" { + item.ItemType = int(v) + } + } + items = append(items, item) } - items = append(items, item) } parsedValue = items diff --git a/admin/apps/game/domain/project.go b/admin/apps/game/domain/project.go index 65da0cd..01dee8d 100644 --- a/admin/apps/game/domain/project.go +++ b/admin/apps/game/domain/project.go @@ -15,6 +15,7 @@ type ProjectService struct { } func NewProjectService(db *gorm.DB) *ProjectService { + repo.ServerRepoInstance = repo.NewServerRepo(db) return &ProjectService{repo: repo.NewProjectRepo(db)} } diff --git a/admin/apps/game/domain/projects/projects.go b/admin/apps/game/domain/projects/projects.go index 5372baf..b5c59a5 100644 --- a/admin/apps/game/domain/projects/projects.go +++ b/admin/apps/game/domain/projects/projects.go @@ -9,10 +9,12 @@ import ( var projectsResourceHookMgr = map[string]map[string]any{ // 神魔大陆项目注册的资源钩子回调 consts.RegisteredProjectId_shenmodalu: { - consts.ResourcesName_Server: &smdl.ServerHook{}, // 查看了数据库所有数据之后,还要连alisrv获取所有进程运行情况 - consts.ResourcesName_Role: &smdl.RoleHook{}, // 所有角色走神魔大陆api直接获取 - consts.ResourcesName_Account: &smdl.AccountHook{}, // 所有角色走神魔大陆api直接获取 - consts.ResourcesName_Ban: &smdl.BanHook{}, // 所有角色走神魔大陆api直接获取 + consts.ResourcesName_Server: &smdl.ServerHook{}, // 查看了数据库所有数据之后,还要连alisrv获取所有进程运行情况 + consts.ResourcesName_Role: &smdl.RoleHook{}, // 所有角色走神魔大陆api直接获取 + consts.ResourcesName_Account: &smdl.AccountHook{}, // 所有角色走神魔大陆api直接获取 + consts.ResourcesName_Ban: &smdl.BanHook{}, // 所有角色走神魔大陆api直接获取 + consts.ResourcesName_MailGlobal: &smdl.MailGlobalHook{}, // 所有角色走神魔大陆api直接获取 + consts.ResourcesName_MailRole: &smdl.MailRoleHook{}, // 所有角色走神魔大陆api直接获取 }, } diff --git a/admin/apps/game/domain/projects/smdl/account.go b/admin/apps/game/domain/projects/smdl/account.go index 6c04d5c..8776822 100644 --- a/admin/apps/game/domain/projects/smdl/account.go +++ b/admin/apps/game/domain/projects/smdl/account.go @@ -6,6 +6,8 @@ import ( "admin/apps/game/model/dto" "admin/internal/errcode" "admin/lib/httpclient" + "admin/lib/utils" + "math" "strconv" ) @@ -24,9 +26,9 @@ func (hook *AccountHook) List(projectInfo *entity.Project, resource string, page Msg string `json:"msg"` Data struct { Data []struct { - Account string `json:"account"` - ServerId int `json:"serverId"` - RoleList []*model.Role `json:"roleList"` + Account string `json:"account"` + ServerId int `json:"serverId"` + RoleList []*Role `json:"roleList"` } `json:"data"` } `json:"data"` } @@ -43,9 +45,19 @@ func (hook *AccountHook) List(projectInfo *entity.Project, resource string, page Account: user.Account, ServerConfId: strconv.Itoa(user.ServerId), } + latestLoginTime := int64(0) + earliestCreateTime := int64(math.MaxInt64) for _, v := range user.RoleList { userPo.RoleIds = append(userPo.RoleIds, v.RoleId) + if latestLoginTime < v.LatestLoginTime { + latestLoginTime = v.LatestLoginTime + } + if earliestCreateTime > v.CreateTime { + earliestCreateTime = v.CreateTime + } } + userPo.LatestLoginTime = utils.ParseUnixTimestamp2LocalTime(latestLoginTime) + userPo.CreateTime = utils.ParseUnixTimestamp2LocalTime(earliestCreateTime) et := (&entity.CommonResource{}).FromPo(userPo) rows = append(rows, et.ToCommonDto()) } diff --git a/admin/apps/game/domain/projects/smdl/ban.go b/admin/apps/game/domain/projects/smdl/ban.go index 353740a..11f4b3c 100644 --- a/admin/apps/game/domain/projects/smdl/ban.go +++ b/admin/apps/game/domain/projects/smdl/ban.go @@ -28,13 +28,15 @@ func (hook *BanHook) Create(projectInfo *entity.Project, resource string, dtoObj params.Add("server", banInfo.ServerConfID) params.Add("roleid", roleId) - if banInfo.ExpireAt <= 0 { + expireAt := banInfo.ExpireAt.Unix() + + if expireAt <= 0 { // 解封 params.Add("forbidtime", "0") params.Add("desc", "待写原因") params.Add("desc", "你被永久封禁了") } else { - dura := banInfo.ExpireAt - time.Now().Unix() + dura := expireAt - time.Now().Unix() if dura <= 0 { // 解封 params.Add("forbidtime", "0") diff --git a/admin/apps/game/domain/projects/smdl/mail_global.go b/admin/apps/game/domain/projects/smdl/mail_global.go index 2c8df7d..e949513 100644 --- a/admin/apps/game/domain/projects/smdl/mail_global.go +++ b/admin/apps/game/domain/projects/smdl/mail_global.go @@ -2,10 +2,12 @@ package smdl import ( "admin/apps/game/domain/entity" + "admin/apps/game/domain/repo" "admin/apps/game/model" "admin/apps/game/model/dto" "admin/internal/errcode" "admin/lib/httpclient" + "admin/lib/xlog" "net/url" "strconv" "strings" @@ -45,7 +47,15 @@ func (hook *MailGlobalHook) Create(projectInfo *entity.Project, resource string, serverIdsLen := len(mailInfo.ServerIDs) switch { case serverIdsLen == 0: - // todo 所有服 + // 为空就发给所有服 + serverList, err := repo.ServerRepoInstance.List(projectInfo.ProjectPo.ProjectId) + if err != nil { + xlog.Errorf("list all server by project:%v error:%v", projectInfo.ProjectPo.ProjectId, err) + return errcode.New(errcode.ServerError, "list all server by project:%v error:%v", projectInfo.ProjectPo.ProjectId, err) + } + for _, v := range serverList { + serverIds = append(serverIds, v.ToPo().(*model.Server).ServerConfID) + } case serverIdsLen > 0: for _, v := range mailInfo.ServerIDs { serverIds = append(serverIds, v) @@ -60,8 +70,16 @@ func (hook *MailGlobalHook) Create(projectInfo *entity.Project, resource string, // 通知对应服务器 for _, serverId := range serverIds { + serverIdInt, _ := strconv.Atoi(serverId) + if serverIdInt == 0 || serverIdInt%10000 > 500 { + // 过滤掉20801 28802这些跨服 + continue + } + params.Set("server", serverId) + xlog.Debugf("通知神魔大陆区服%v添加邮件:%v", serverId, params.Encode()) + rsp := make(map[string]any) err := httpclient.Request(alisrvAddr+"/mail_global", "get", params, &rsp) if err != nil { diff --git a/admin/apps/game/domain/projects/smdl/mail_role.go b/admin/apps/game/domain/projects/smdl/mail_role.go index a91abcc..1073c77 100644 --- a/admin/apps/game/domain/projects/smdl/mail_role.go +++ b/admin/apps/game/domain/projects/smdl/mail_role.go @@ -6,6 +6,7 @@ import ( "admin/apps/game/model/dto" "admin/internal/errcode" "admin/lib/httpclient" + "admin/lib/xlog" "net/url" "strconv" "strings" @@ -49,6 +50,8 @@ func (hook *MailRoleHook) Create(projectInfo *entity.Project, resource string, d // 通知对应服务器 for _, roleId := range mailInfo.RoleIDs { + params.Set("playerid", roleId) + xlog.Debugf("发送神魔大陆个人邮件给角色:%v, 内容:%v", roleId, params.Encode()) rsp := make(map[string]any) err := httpclient.Request(alisrvAddr+"/mail_role", "get", params, &rsp) if err != nil { diff --git a/admin/apps/game/domain/projects/smdl/role.go b/admin/apps/game/domain/projects/smdl/role.go index 0dff516..c611e57 100644 --- a/admin/apps/game/domain/projects/smdl/role.go +++ b/admin/apps/game/domain/projects/smdl/role.go @@ -6,8 +6,21 @@ import ( "admin/apps/game/model/dto" "admin/internal/errcode" "admin/lib/httpclient" + "admin/lib/utils" ) +type Role struct { + RoleId string `json:"roleId"` + Account string `json:"account"` + ServerConfId string `json:"serverId"` + Name string `json:"roleName"` + Status string `json:"status"` + Level int `json:"roleLevel"` + Profession string `json:"profession"` + LatestLoginTime int64 `json:"latestLoginAt"` + CreateTime int64 `json:"createAt"` +} + type RoleHook struct { } @@ -22,7 +35,7 @@ func (hook *RoleHook) List(projectInfo *entity.Project, resource string, pageNo, Code int `json:"code"` Msg string `json:"msg"` Data struct { - Data []*model.Role `json:"data"` + Data []*Role `json:"data"` } `json:"data"` } @@ -33,7 +46,18 @@ func (hook *RoleHook) List(projectInfo *entity.Project, resource string, pageNo, } for _, role := range rsp.Data.Data { - et := (&entity.CommonResource{}).FromPo(role) + rolePo := &model.Role{ + RoleId: role.RoleId, + Account: role.Account, + ServerConfId: role.ServerConfId, + Name: role.Name, + Status: role.Status, + Level: role.Level, + Profession: role.Profession, + LatestLoginTime: utils.ParseUnixTimestamp2LocalTime(role.LatestLoginTime), + CreateTime: utils.ParseUnixTimestamp2LocalTime(role.CreateTime), + } + et := (&entity.CommonResource{}).FromPo(rolePo) rows = append(rows, et.ToCommonDto()) } diff --git a/admin/apps/game/domain/projects/smdl/server.go b/admin/apps/game/domain/projects/smdl/server.go index ce9a7a3..431256c 100644 --- a/admin/apps/game/domain/projects/smdl/server.go +++ b/admin/apps/game/domain/projects/smdl/server.go @@ -25,8 +25,9 @@ func (hook *ServerHook) List(projectInfo *entity.Project, resource string, pageN HelpText: "进程运行状态:未知、运行中、停止", Readonly: false, Required: false, - Choices: nil, + Choices: make([]*dto.CommonDtoFieldChoice, 0), MultiChoice: false, + Uneditable: true, }) type ServerInfo struct { diff --git a/admin/apps/game/domain/repo/server.go b/admin/apps/game/domain/repo/server.go new file mode 100644 index 0000000..94396ff --- /dev/null +++ b/admin/apps/game/domain/repo/server.go @@ -0,0 +1,36 @@ +package repo + +import ( + "admin/apps/game/domain/entity" + "admin/apps/game/model" + "admin/internal/errcode" + "gorm.io/gorm" +) + +var ServerRepoInstance IServerRepo + +type IServerRepo interface { + List(projectId string) ([]*entity.CommonResource, error) +} + +func NewServerRepo(db *gorm.DB) IServerRepo { + return &serverRepoImpl{db: db} +} + +type serverRepoImpl struct { + db *gorm.DB +} + +func (impl *serverRepoImpl) List(projectId string) ([]*entity.CommonResource, error) { + list := make([]*model.Server, 0) + err := impl.db.Where("project_id = ?", projectId).Find(&list).Error + if err != nil { + return nil, errcode.New(errcode.DBError, "list server error:%v", err) + } + + list1 := make([]*entity.CommonResource, 0, len(list)) + for _, v := range list { + list1 = append(list1, (&entity.CommonResource{}).FromPo(v)) + } + return list1, nil +} diff --git a/admin/apps/game/model/account.go b/admin/apps/game/model/account.go index c3e92ed..0487e67 100644 --- a/admin/apps/game/model/account.go +++ b/admin/apps/game/model/account.go @@ -2,6 +2,7 @@ package model import ( "admin/internal/db" + "time" ) func init() { @@ -10,11 +11,11 @@ func init() { // Account 空表,就是用来兼容资源增删改查公共操作的,实际列举账号等都是走各个项目api拉取 type Account struct { - Account string `name:"账号" json:"account"` - ServerConfId string `name:"区服id" json:"serveId"` - RoleIds []string `gorm:"type:json;serializer:json" name:"角色id列表" json:"roleIds"` - LatestLoginTime int64 `name:"最近登录时间" json:"latest_login_time"` - CreateTime int64 `name:"创建时间" json:"create_time"` + Account string `name:"账号" json:"account"` + ServerConfId string `name:"区服id" json:"serveId"` + 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"` } func (lm *Account) TableName() string { diff --git a/admin/apps/game/model/ban.go b/admin/apps/game/model/ban.go index f70040e..d1e3bac 100644 --- a/admin/apps/game/model/ban.go +++ b/admin/apps/game/model/ban.go @@ -3,7 +3,6 @@ package model import ( "admin/apps/game/model/dto" "admin/internal/db" - "gorm.io/gorm" "time" ) @@ -12,16 +11,15 @@ func init() { } type Ban struct { - ID int `gorm:"primarykey" readonly:"true"` - ProjectId string `gorm:"type:varchar(255);uniqueIndex:idx_ban"` - ServerConfID string `gorm:"type:varchar(200);uniqueIndex:idx_server" required:"true"` - BanType string `name:"封禁类型" required:"true" choices:"GetBanTypeChoices" multi_choice:"true"` - Value string `gorm:"type:varchar(128);uniqueIndex:idx_ban" name:"封禁账号" required:"true" desc:"填账号"` - ExpireAt int64 `name:"封禁到期时间" desc:"封禁到期时间,0表示永久封禁"` + ID int `gorm:"primarykey" readonly:"true"` + ProjectId string `gorm:"type:varchar(255);uniqueIndex:idx_ban"` + ServerConfID string `gorm:"type:varchar(200);uniqueIndex:idx_server" name:"区服id" required:"true" choices:"GetServerConfIDChoices" uneditable:"true"` + BanType string `name:"封禁类型" required:"true" choices:"GetBanTypeChoices" uneditable:"true"` + Value string `gorm:"type:varchar(128);uniqueIndex:idx_ban" name:"封禁值" required:"true" desc:"根据封禁类型填对应值,例如ip就填ip地址" uneditable:"true"` + BanReason string `name:"封禁理由" desc:"封禁理由,会推送给客户端弹窗" required:"true"` + ExpireAt time.Time `name:"封禁到期时间" desc:"封禁到期时间,0表示永久封禁"` - CreatedAt time.Time `readonly:"true"` - UpdatedAt time.Time `readonly:"true"` - DeletedAt gorm.DeletedAt `gorm:"index" readonly:"true"` + CreatedAt time.Time `readonly:"true"` } func (lm *Ban) TableName() string { @@ -32,15 +30,35 @@ func (m *Ban) GetId() int { return m.ID } +func (m *Ban) GetServerConfIDChoices(projectId string) []*dto.CommonDtoFieldChoice { + return getChoiceServers(projectId) +} + func (m *Ban) GetBanTypeChoices(projectId string) []*dto.CommonDtoFieldChoice { return []*dto.CommonDtoFieldChoice{ { - Desc: "作弊", - Value: "作弊", + Desc: "账号", + Value: "account", }, { - Desc: "广告", - Value: "广告", + Desc: "角色", + Value: "role", + }, + { + Desc: "IP", + Value: "ip", + }, + { + Desc: "账号发言", + Value: "account_chat", + }, + { + Desc: "角色发言", + Value: "role_chat", + }, + { + Desc: "设备号", + Value: "device_id", }, } } diff --git a/admin/apps/game/model/devicepush.go b/admin/apps/game/model/devicepush.go index fa0b447..5142122 100644 --- a/admin/apps/game/model/devicepush.go +++ b/admin/apps/game/model/devicepush.go @@ -2,7 +2,6 @@ package model import ( "admin/internal/db" - "gorm.io/gorm" "time" ) @@ -17,9 +16,7 @@ type DevicePush struct { Title string `name:"通知标题" desc:""` Content string `name:"通知内容"` - CreatedAt time.Time `readonly:"true"` - UpdatedAt time.Time `readonly:"true"` - DeletedAt gorm.DeletedAt `gorm:"index" readonly:"true"` + CreatedAt time.Time `readonly:"true"` } func (lm *DevicePush) TableName() string { diff --git a/admin/apps/game/model/dto/common.go b/admin/apps/game/model/dto/common.go index 8659039..e3f5247 100644 --- a/admin/apps/game/model/dto/common.go +++ b/admin/apps/game/model/dto/common.go @@ -36,6 +36,7 @@ type CommonDtoFieldDesc struct { Required bool `json:"required"` // 是否必填,不能为空 Choices []*CommonDtoFieldChoice `json:"choices"` // 可选项,用于字段做下拉框 MultiChoice bool `json:"multi_choice"` // 是否多选 + Uneditable bool `json:"uneditable"` // 不可编辑,某些数据一旦新增之后不能修改,例如封禁的值、服务器的id等 } //type CommonDtoValue struct { diff --git a/admin/apps/game/model/globalmail.go b/admin/apps/game/model/globalmail.go index b278170..46600f8 100644 --- a/admin/apps/game/model/globalmail.go +++ b/admin/apps/game/model/globalmail.go @@ -3,7 +3,6 @@ package model import ( "admin/apps/game/model/dto" "admin/internal/db" - "gorm.io/gorm" "time" ) @@ -21,9 +20,7 @@ type GlobalMail struct { Content string `name:"邮件内容" required:"true"` Attach []*MailAttachItem `gorm:"type:json;serializer:json" name:"邮件附件" type:"items" choices:"GetChoiceItems"` - CreatedAt time.Time `readonly:"true"` - UpdatedAt time.Time `readonly:"true"` - DeletedAt gorm.DeletedAt `gorm:"index" readonly:"true"` + CreatedAt time.Time `readonly:"true"` } func (lm *GlobalMail) TableName() string { diff --git a/admin/apps/game/model/imodel.go b/admin/apps/game/model/imodel.go index ad31381..17d87f0 100644 --- a/admin/apps/game/model/imodel.go +++ b/admin/apps/game/model/imodel.go @@ -11,8 +11,8 @@ type IModel interface { var GetProjectServersHandler func(projectId string) ([]*Server, error) -func getChoiceServers(args ...any) []*dto.CommonDtoFieldChoice { - servers, err := GetProjectServersHandler(args[0].(string)) +func getChoiceServers(projectId string) []*dto.CommonDtoFieldChoice { + servers, err := GetProjectServersHandler(projectId) if err != nil { panic(err) } diff --git a/admin/apps/game/model/notice.go b/admin/apps/game/model/notice.go index 451633e..9f3d836 100644 --- a/admin/apps/game/model/notice.go +++ b/admin/apps/game/model/notice.go @@ -3,7 +3,6 @@ package model import ( "admin/apps/game/model/dto" "admin/internal/db" - "gorm.io/gorm" "time" ) @@ -14,14 +13,12 @@ func init() { type Notice struct { ID int `gorm:"primarykey" readonly:"true"` ProjectId string - ServerIDs []int `gorm:"type:json;serializer:json" name:"公告生效服务器" desc:"为空表示所有服" choices:"GetChoiceServers"` - Content string `name:"公告内容" required:"true"` - StartAt int64 `name:"开始时间" required:"true"` - EndAt int64 `name:"结束时间" required:"true"` + ServerIDs []int `gorm:"type:json;serializer:json" name:"公告生效服务器" desc:"为空表示所有服" choices:"GetChoiceServers"` + Content string `name:"公告内容" required:"true"` + StartAt time.Time `name:"开始时间" required:"true"` + EndAt time.Time `name:"结束时间" required:"true"` - CreatedAt time.Time `readonly:"true"` - UpdatedAt time.Time `readonly:"true"` - DeletedAt gorm.DeletedAt `gorm:"index" readonly:"true"` + CreatedAt time.Time `readonly:"true"` } func (lm *Notice) TableName() string { diff --git a/admin/apps/game/model/project.go b/admin/apps/game/model/project.go index 45b3ac3..3462283 100644 --- a/admin/apps/game/model/project.go +++ b/admin/apps/game/model/project.go @@ -2,7 +2,6 @@ package model import ( "admin/internal/db" - "gorm.io/gorm" "time" ) @@ -14,7 +13,7 @@ func init() { type Project struct { ID int `gorm:"primarykey" readonly:"true"` ProjectId string `gorm:"type:varchar(255);unique" name:"项目id" readonly:"true"` - Name string `gorm:"primarykey" required:"true" name:"项目名" readonly:"true"` + Name string `gorm:"primarykey" required:"true" name:"项目名" readonly:"true" uneditable:"true"` Desc string `name:"项目描述"` // command_list接口服务器地址,为空代表由由项目下各个逻辑服提供command_list. // 取决于每个项目改造难度: @@ -23,9 +22,7 @@ type Project struct { // 调用各个逻辑服执行,本后台执行指令需要根据逻辑服数量调用; ApiAddr string `name:"游戏api地址" desc:"api服务器地址,例如神魔大陆就是alisrv服务器地址,用于后台调用gm"` - CreatedAt time.Time `readonly:"true"` - UpdatedAt time.Time `readonly:"true"` - DeletedAt gorm.DeletedAt `gorm:"index" readonly:"true"` + CreatedAt time.Time `readonly:"true"` } func (lm *Project) TableName() string { diff --git a/admin/apps/game/model/rewardcode.go b/admin/apps/game/model/rewardcode.go index 69cde58..dc22547 100644 --- a/admin/apps/game/model/rewardcode.go +++ b/admin/apps/game/model/rewardcode.go @@ -2,7 +2,6 @@ package model import ( "admin/internal/db" - "gorm.io/gorm" "time" ) @@ -16,9 +15,7 @@ type RewardCode struct { Group int `name:"奖励码组"` Code int `name:"奖励码"` - CreatedAt time.Time `readonly:"true"` - UpdatedAt time.Time `readonly:"true"` - DeletedAt gorm.DeletedAt `gorm:"index" readonly:"true"` + CreatedAt time.Time `readonly:"true"` } func (lm *RewardCode) TableName() string { diff --git a/admin/apps/game/model/role.go b/admin/apps/game/model/role.go index fa01014..d8aba89 100644 --- a/admin/apps/game/model/role.go +++ b/admin/apps/game/model/role.go @@ -2,6 +2,7 @@ package model import ( "admin/internal/db" + "time" ) func init() { @@ -10,15 +11,15 @@ func init() { // Role 空表,就是用来兼容资源增删改查公共操作的,实际列举账号等都是走各个项目api拉取 type Role struct { - RoleId string `name:"账号" json:"roleId"` - Account string `name:"账号" json:"account"` - ServerConfId string `name:"区服id" json:"serverId"` - Name string `name:"名称" json:"roleName"` - Status string `name:"状态" desc:"离线|在线" json:"status"` - Level int `name:"等级" json:"roleLevel"` - Profession string `name:"职业" json:"profession"` - LatestLoginTime int64 `name:"最近登录时间" json:"latestLoginAt"` - CreateTime int64 `name:"创建时间" json:"createAt"` + RoleId string `name:"角色ID" json:"roleId"` + Account string `name:"账号" json:"account"` + ServerConfId string `name:"区服id" json:"serverId"` + Name string `name:"名称" json:"roleName"` + Status string `name:"状态" desc:"离线|在线" json:"status"` + Level int `name:"等级" json:"roleLevel"` + Profession string `name:"职业" json:"profession"` + LatestLoginTime time.Time `name:"最近登录时间" json:"latestLoginAt"` + CreateTime time.Time `name:"创建时间" json:"createAt"` } func (lm *Role) TableName() string { diff --git a/admin/apps/game/model/rolemail.go b/admin/apps/game/model/rolemail.go index ae1e8ad..d2f6f90 100644 --- a/admin/apps/game/model/rolemail.go +++ b/admin/apps/game/model/rolemail.go @@ -3,7 +3,6 @@ package model import ( "admin/apps/game/model/dto" "admin/internal/db" - "gorm.io/gorm" "time" ) @@ -20,15 +19,13 @@ type MailAttachItem struct { type RoleMail struct { ID int `gorm:"primarykey" readonly:"true"` ProjectId string - RoleIDs []string `gorm:"type:json;serializer:json" name:"生效的角色id" required:"true"` - ServerID string `name:"所属区服" choices:"GetChoiceServers" multi_choice:"false"` + RoleIDs []string `gorm:"type:json;serializer:json" name:"生效的角色id" desc:"生效的角色id,逗号分隔多个" required:"true"` + ServerID string `name:"所属区服" choices:"GetChoiceServers" required:"true"` Title string `name:"邮件标题" required:"true"` Content string `name:"邮件内容" required:"true"` Attach []*MailAttachItem `gorm:"type:json;serializer:json" name:"邮件附件" type:"items" choices:"GetChoiceItems"` - CreatedAt time.Time `readonly:"true"` - UpdatedAt time.Time `readonly:"true"` - DeletedAt gorm.DeletedAt `gorm:"index" readonly:"true"` + CreatedAt time.Time `readonly:"true"` } func (lm *RoleMail) TableName() string { diff --git a/admin/apps/game/model/server.go b/admin/apps/game/model/server.go index 0daedb1..d242f26 100644 --- a/admin/apps/game/model/server.go +++ b/admin/apps/game/model/server.go @@ -2,7 +2,6 @@ package model import ( "admin/internal/db" - "gorm.io/gorm" "time" ) @@ -14,18 +13,16 @@ func init() { type Server struct { ID int `gorm:"primarykey" readonly:"true"` ProjectId string `gorm:"type:varchar(200);uniqueIndex:idx_server"` - ServerConfID string `gorm:"type:varchar(200);uniqueIndex:idx_server" required:"true"` - Desc string + ServerConfID string `gorm:"type:varchar(200);uniqueIndex:idx_server" name:"区服id" required:"true" uneditable:"true"` + Desc string `name:"描述"` // command_list接口服务器地址,为空代表由由项目统一提供command_list. // 取决于每个项目改造难度: // 为空就代表项目要实现一个自己统一对外暴露的gm调用服务对内聚合、分发指令执行,本后台执行指令只调用一次; // 不为空就代表command_list实现在各个逻辑服,由本后台系统在执行指令时聚合、分发指令 // 调用各个逻辑服执行,本后台执行指令需要根据逻辑服数量调用; - ApiAddr string + //ApiAddr string - CreatedAt time.Time `readonly:"true"` - UpdatedAt time.Time `readonly:"true"` - DeletedAt gorm.DeletedAt `gorm:"index" readonly:"true"` + CreatedAt time.Time `readonly:"true"` } func (lm *Server) TableName() string { diff --git a/admin/apps/game/model/whitelist.go b/admin/apps/game/model/whitelist.go index b57a28b..57350ca 100644 --- a/admin/apps/game/model/whitelist.go +++ b/admin/apps/game/model/whitelist.go @@ -1,8 +1,8 @@ package model import ( + "admin/apps/game/model/dto" "admin/internal/db" - "gorm.io/gorm" "time" ) @@ -13,14 +13,11 @@ func init() { type WhiteList struct { ID int `gorm:"primarykey" readonly:"true"` ProjectId string `gorm:"type:varchar(256);uniqueIndex:idx_whitelist"` - ServerConfID string `gorm:"type:varchar(200);uniqueIndex:idx_server" required:"true"` - Account string `gorm:"type:varchar(128);uniqueIndex:idx_whitelist"` - AccountType int `gorm:"uniqueIndex:idx_whitelist"` - Desc string + ServerConfID string `gorm:"type:varchar(200);uniqueIndex:idx_server" name:"区服id" required:"true" choices:"GetChoiceServers"` + Account string `gorm:"type:varchar(128);uniqueIndex:idx_whitelist" name:"账户" required:"true"` + Desc string `name:"描述"` - CreatedAt time.Time `readonly:"true"` - UpdatedAt time.Time `readonly:"true"` - DeletedAt gorm.DeletedAt `gorm:"index" readonly:"true"` + CreatedAt time.Time `readonly:"true"` } func (lm *WhiteList) TableName() string { @@ -30,3 +27,7 @@ func (lm *WhiteList) TableName() string { func (m *WhiteList) GetId() int { return m.ID } + +func (m *WhiteList) GetChoiceServers(projectId string) []*dto.CommonDtoFieldChoice { + return getChoiceServers(projectId) +} diff --git a/admin/lib/utils/time.go b/admin/lib/utils/time.go new file mode 100644 index 0000000..974d97c --- /dev/null +++ b/admin/lib/utils/time.go @@ -0,0 +1,44 @@ +package utils + +import ( + "fmt" + "time" +) + +func ParseUnixTimestamp2LocalTime(ts int64) (local time.Time) { + sec := int64(0) + nsec := int64(0) + switch { + case ts >= 1e18: // 纳秒 + sec = ts / int64(1e9) + nsec = ts % int64(1e9) + case ts >= 1e15: // 微妙 + sec = ts / int64(1e6) + nsec = ts % int64(1e6) + case ts >= 1e12: // 毫秒 + sec = ts / int64(1e3) + nsec = ts % int64(1e3) + case ts >= 1e9: // 秒 + sec = ts + nsec = 0 + default: + panic(fmt.Errorf("ts:%v invalid parse to local time")) + } + + t := time.Unix(sec, nsec) + ts2str := t.Format("2006-01-02 15:04:05.000000000") + local, _ = time.ParseInLocation("2006-01-02 15:04:05.000000000", ts2str, time.Local) + return local +} + +// GetTimeZoneLocalTime 获取指定时区的当地时间 +func GetTimeZoneLocalTime(timeZone int) time.Time { + offsetZone := time.FixedZone(time.Local.String(), timeZone*60*60) + return time.Now().In(offsetZone) +} + +// GetTimeZoneLocalTimeByTimestamp 获取指定时间戳与时区的当地时间 +func GetTimeZoneLocalTimeByTimestamp(ts int64, timeZone int) time.Time { + offsetZone := time.FixedZone(time.Local.String(), timeZone*60*60) + return time.Unix(ts, 0).Local().In(offsetZone) +} diff --git a/ui/src/assets/styles/global.scss b/ui/src/assets/styles/global.scss index 5467772..7f2d266 100644 --- a/ui/src/assets/styles/global.scss +++ b/ui/src/assets/styles/global.scss @@ -1,4 +1,29 @@ +body { + min-height: 100vh; + color: var(--color-text); + background: var(--color-background); + transition: color 0.5s, + background-color 0.5s; + line-height: 1.6; + font-family: Inter, + -apple-system, + BlinkMacSystemFont, + 'Segoe UI', + Roboto, + Oxygen, + Ubuntu, + Cantarell, + 'Fira Sans', + 'Droid Sans', + 'Helvetica Neue', + sans-serif; + font-size: 15px; + text-rendering: optimizeLegibility; + -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale; +} + .el-table { .el-table__header-wrapper, .el-table__fixed-header-wrapper { th { @@ -32,4 +57,4 @@ .el-table .el-dropdown, .el-icon-arrow-down { font-size: 12px; -} \ No newline at end of file +} diff --git a/ui/src/components/restful/table.vue b/ui/src/components/restful/table.vue index 256f2d3..5ececcb 100644 --- a/ui/src/components/restful/table.vue +++ b/ui/src/components/restful/table.vue @@ -39,11 +39,13 @@ const listData = async () => { for (let i = 0; i < fieldsDescInfo.value.length; i++) { var field = fieldsDescInfo.value[i] dialogAddForm.value[field.key] = '' + if (field.required == true) { rules.value[field.key] = [{required: true, message: field.name + "不能为空", trigger: "blur"}] } if (field.type == "items") { + dialogAddForm.value[field.key] = [] for (let j = 0; j < rows.value.length; j++) { rows.value[j].jsonValue = JSON.stringify(rows.value[j][field.key]) } @@ -71,6 +73,7 @@ const dialogEditFormRef = ref(null) const dialogAddForm = ref({ ServerIDs: [], + Attach: [], }) const dialogEditForm = ref({}) @@ -90,6 +93,7 @@ const submitAdd = async () => { }) rows.value.push(res.data.dto) dialogAddVisible.value = false + handleCloseDialog() }, (err) => { console.log("添加报错:", err) }) @@ -115,6 +119,7 @@ const submitEdit = async () => { }) dialogEditVisible.value = false rows.value[dialogEditForm.value.oldIndex] = res.data.dto + handleCloseDialog() }, (err) => { console.log("添加报错:", err) }) @@ -135,18 +140,22 @@ const handleEdit = (index, row) => { } const handleDelete = (index, row) => { - resourceDelete(resource_url, {id: row.ID}).then((res) => { - ElNotification({ - title: "删除结果通知", - message: "删除指令服务器[" + row.name + "]成功!", - type: 'success', - duration: 4000, - "show-close": true, + ElMessageBox.confirm("确定要删除吗?").then(() => { + resourceDelete(resource_url, {id: row.ID}).then((res) => { + ElNotification({ + title: "删除结果通知", + message: "删除数据[" + row.ID + "]成功!", + type: 'success', + duration: 4000, + "show-close": true, + }) + rows.value.splice(index, 1) + }, (err) => { + console.log("delet error:", err) }) - rows.value.splice(index, 1) - }, (err) => { - console.log("delet error:", err) + }).catch(() => { }) + } function addItem(fieldDescInfo) { @@ -184,6 +193,7 @@ function deleteItem(row) { } const handleCloseDialog = () => { + console.log("关闭添加/编辑弹窗") dialogAddVisible.value = false dialogEditVisible.value = false dialogAddForm.value = { @@ -213,24 +223,6 @@ const handleCloseDialog = () => {