diff --git a/admin/apps/game/boot.go b/admin/apps/game/boot.go index d5bf3e5..fe90095 100644 --- a/admin/apps/game/boot.go +++ b/admin/apps/game/boot.go @@ -8,9 +8,12 @@ import ( ) func initFun(app *node.Application) error { - svc := service.New(global.GLOB_DB) // 初始化应用服务 - srv := server.New(svc) // 初始化http服务 - srv.Route(global.GLOB_API_ENGINE) // 初始化http服务路由 + svc, err := service.New(global.GLOB_DB) // 初始化应用服务 + if err != nil { + panic(err) + } + srv := server.New(svc) // 初始化http服务 + srv.Route(global.GLOB_API_ENGINE) // 初始化http服务路由 return nil } diff --git a/admin/apps/game/domain/comm_resource.go b/admin/apps/game/domain/comm_resource.go new file mode 100644 index 0000000..066cf9b --- /dev/null +++ b/admin/apps/game/domain/comm_resource.go @@ -0,0 +1,180 @@ +package domain + +import ( + "admin/apps/game/domain/entity" + "admin/apps/game/domain/projects" + "admin/apps/game/domain/repo" + "admin/apps/game/model" + "admin/apps/game/model/dto" + "admin/internal/consts" + "admin/internal/errcode" + "fmt" + "gorm.io/gorm" +) + +type CommonResourceService struct { + projectRepo repo.IProjectRepo +} + +func initCommonResourcesRepo(db *gorm.DB) { + commResourcesRepo = []*resourceRepoInfo{ + {consts.ResourcesName_Project, "项目管理", repo.NewCommonResourceRepo(db, &model.Project{})}, + {consts.ResourcesName_Server, "服务器管理", repo.NewCommonResourceRepo(db, &model.Server{})}, + {consts.ResourcesName_WhiteList, "白名单", repo.NewCommonResourceRepo(db, &model.WhiteList{})}, + {consts.ResourcesName_Ban, "封禁管理", repo.NewCommonResourceRepo(db, &model.Ban{})}, + {consts.ResourcesName_MailRole, "个人邮件", repo.NewCommonResourceRepo(db, &model.RoleMail{})}, + {consts.ResourcesName_MailGlobal, "全服邮件", repo.NewCommonResourceRepo(db, &model.GlobalMail{})}, + {consts.ResourcesName_Notice, "公告", repo.NewCommonResourceRepo(db, &model.Notice{})}, + {consts.ResourcesName_RewardCode, "奖励码", repo.NewCommonResourceRepo(db, &model.RewardCode{})}, + {consts.ResourcesName_DevicePush, "设备推送", repo.NewCommonResourceRepo(db, &model.DevicePush{})}, + } +} + +func NewCommonResourceService(db *gorm.DB) *CommonResourceService { + initCommonResourcesRepo(db) + svc := &CommonResourceService{ + projectRepo: repo.NewProjectRepo(db), + } + return svc +} + +func (svc *CommonResourceService) List(projectId string, resource string, pageNo, pageLen int, extraQuery string, args ...any) ([]*dto.CommonDtoFieldDesc, []dto.CommonDtoValues, error) { + projectEt, find, err := svc.projectRepo.GetByProjectId(projectId) + if err != nil { + return nil, nil, err + } + if !find { + return nil, nil, errcode.New(errcode.ServerError, "not found project %v db data", projectId) + } + + fieldsDescInfo, etList, err := findCommResourceRepo(resource).List(projectId, pageNo, pageLen, extraQuery, args...) + if err != nil { + return nil, nil, err + } + retList := make([]dto.CommonDtoValues, 0, len(etList)) + for _, v := range etList { + retList = append(retList, v.ToCommonDto()) + } + + // 执行各个项目特定的钩子方法 + if hook, ok := projects.GetProjectResourceHook(projectId, resource).(projects.IPostResourceOpListHook); ok { + return hook.List(projectEt, resource, pageNo, pageLen, fieldsDescInfo, retList, extraQuery, args...) + } + + return fieldsDescInfo, retList, nil +} + +func (svc *CommonResourceService) GetById(projectId string, resource string, id int) ([]*dto.CommonDtoFieldDesc, dto.CommonDtoValues, *entity.CommonResource, bool, error) { + fieldsDescInfo, et, find, err := findCommResourceRepo(resource).GetById(projectId, id) + if err != nil { + return nil, nil, nil, false, err + } + + return fieldsDescInfo, et.ToCommonDto(), et, find, nil +} + +func (svc *CommonResourceService) Create(projectId string, resource string, dtoObj dto.CommonDtoValues) (dto.CommonDtoValues, error) { + projectEt, find, err := svc.projectRepo.GetByProjectId(projectId) + if err != nil { + return nil, err + } + if !find { + return nil, errcode.New(errcode.ServerError, "not found project %v db data", projectId) + } + + et, err := findCommResourceRepo(resource).Create(projectId, dtoObj) + if err != nil { + return nil, err + } + + // 返回新的实体,插入数据库之后会填入数据库id,所以要返给前端刷新id数据 + + // 执行各个项目特定的钩子方法 + if hook, ok := projects.GetProjectResourceHook(projectId, resource).(projects.IPostResourceOpCreateHook); ok { + dtoObj := et.ToCommonDto() + err = hook.Create(projectEt, resource, dtoObj) + if err != nil { + return nil, err + } + return dtoObj, nil + } + + return et.ToCommonDto(), err +} + +func (svc *CommonResourceService) Edit(projectId string, resource string, dtoObj dto.CommonDtoValues) error { + projectEt, find, err := svc.projectRepo.GetByProjectId(projectId) + if err != nil { + return err + } + if !find { + return errcode.New(errcode.ServerError, "not found project %v db data", projectId) + } + + err = findCommResourceRepo(resource).Edit(projectId, dtoObj) + if err != nil { + return err + } + + // 执行各个项目特定的钩子方法 + if hook, ok := projects.GetProjectResourceHook(projectId, resource).(projects.IPostResourceOpEditHook); ok { + err = hook.Edit(projectEt, resource, dtoObj) + if err != nil { + return err + } + return nil + } + + return nil +} + +func (svc *CommonResourceService) Delete(projectId string, resource string, id int) error { + projectEt, find, err := svc.projectRepo.GetByProjectId(projectId) + if err != nil { + return err + } + if !find { + return errcode.New(errcode.ServerError, "not found project %v db data", projectId) + } + + err = findCommResourceRepo(resource).Delete(projectId, id) + if err != nil { + return err + } + + // 执行各个项目特定的钩子方法 + if hook, ok := projects.GetProjectResourceHook(projectId, resource).(projects.IPostResourceOpDeleteHook); ok { + err = hook.Delete(projectEt, resource, id) + if err != nil { + return err + } + return nil + } + return nil +} + +func (svc *CommonResourceService) GetSupportResourcesList() [][2]string { + list := make([][2]string, 0, len(commResourcesRepo)) + for _, v := range commResourcesRepo { + list = append(list, [2]string{v.resource, v.desc}) + } + return list +} + +type resourceRepoInfo struct { + resource string + desc string + repo repo.ICommonResourceRepo +} + +var commResourcesRepo = make([]*resourceRepoInfo, 0) + +func findCommResourceRepo(resource string) repo.ICommonResourceRepo { + for _, v := range commResourcesRepo { + if v.resource == resource { + return v.repo + } + } + panic(fmt.Errorf("not found resource:%v", resource)) + return nil +} diff --git a/admin/apps/game/domain/entity/comm_resouce.go b/admin/apps/game/domain/entity/comm_resouce.go new file mode 100644 index 0000000..cc1d325 --- /dev/null +++ b/admin/apps/game/domain/entity/comm_resouce.go @@ -0,0 +1,68 @@ +package entity + +import ( + "admin/apps/game/model" + "admin/apps/game/model/dto" + "reflect" +) + +type CommonResource struct { + ProjectEt *Project + Po model.IModel +} + +func (et *CommonResource) FromPo(po model.IModel) *CommonResource { + et.Po = po + return et +} + +func (et *CommonResource) FromDto(dto dto.CommonDtoValues) *CommonResource { + po := et.Po + + //to := reflect.TypeOf(Po) + vo := reflect.ValueOf(po).Elem() + to := reflect.TypeOf(po).Elem() + + for k, v := range dto { + fo := vo.FieldByName(k) + ft, find := to.FieldByName(k) + if !find { + continue + } + fo.Set(parseStr2FieldValue(ft, v)) + } + + return et +} + +func (et *CommonResource) ToPo() model.IModel { + return et.Po +} + +func (et *CommonResource) ToCommonDto() dto.CommonDtoValues { + return poToCommonDtoNo(et.Po) +} + +func (et *CommonResource) GetDtoFieldsDescInfo(projectId string) []*dto.CommonDtoFieldDesc { + + ptrVo := reflect.ValueOf(et.Po) + + to := reflect.TypeOf(et.Po).Elem() + vo := ptrVo.Elem() + + obj := make([]*dto.CommonDtoFieldDesc, 0, to.NumField()) + + for i := 0; i < vo.NumField(); i++ { + ft := to.Field(i) + //fo := vo.Field(i) + + if ft.Name == "ProjectId" { + continue + } + + f1 := getFieldTypeDtoDescInfo(projectId, ptrVo, ft) + obj = append(obj, f1) + } + + return obj +} diff --git a/admin/apps/game/domain/entity/project.go b/admin/apps/game/domain/entity/project.go index 1a6e577..5113430 100644 --- a/admin/apps/game/domain/entity/project.go +++ b/admin/apps/game/domain/entity/project.go @@ -1,94 +1,24 @@ package entity -import ( - "admin/apps/game/model" - "admin/apps/game/model/dto" - "math/rand" - "reflect" -) - -var ProjectDtoFieldsDescInfo = DefaultProject().GetDtoFieldsDescInfo() +import "admin/apps/game/model" type Project struct { - Id int - po *model.Project + *CommonResource + ProjectPo *model.Project } -func DefaultProject() *Project { +func (commEt *CommonResource) ToProjectEntity() *Project { + po := commEt.ToPo().(*model.Project) return &Project{ - po: &model.Project{}, + CommonResource: commEt, + ProjectPo: po, } } -func FromProjectPo(po *model.Project) *Project { - return &Project{ - Id: po.ID, - po: po, - } +func (project *Project) GetProjectPo() *model.Project { + return project.ProjectPo } -func FromProjectDto(dto dto.CommonDtoValues) *Project { - et := DefaultProject() - po := et.po - - //to := reflect.TypeOf(po) - vo := reflect.ValueOf(po).Elem() - to := reflect.TypeOf(po).Elem() - - for k, v := range dto { - fo := vo.FieldByName(k) - ft, _ := to.FieldByName(k) - fo.Set(parseStr2FieldValue(ft, v)) - } - - et.Id = po.ID - - return et -} - -func (et *Project) ToPo() *model.Project { - return et.po -} - -func (et *Project) ToCommonDto() dto.CommonDtoValues { - obj := make(dto.CommonDtoValues) - - to := reflect.TypeOf(et.po).Elem() - vo := reflect.ValueOf(et.po).Elem() - for i := 0; i < vo.NumField(); i++ { - ft := to.Field(i) - fo := vo.Field(i) - - obj[ft.Name] = fo.Interface() - } - - return obj -} - -func (et *Project) GetDtoFieldsDescInfo() []*dto.CommonDtoFieldDesc { - - to := reflect.TypeOf(et.po).Elem() - vo := reflect.ValueOf(et.po).Elem() - - obj := make([]*dto.CommonDtoFieldDesc, 0, to.NumField()) - - for i := 0; i < vo.NumField(); i++ { - ft := to.Field(i) - //fo := vo.Field(i) - - f1 := &dto.CommonDtoFieldDesc{ - Name: ft.Name, - Key: ft.Name, - Type: ft.Type.Name(), - HelpText: ft.Tag.Get("desc"), - Editable: true, - Require: rand.Int()%2 == 0, - Choices: make([]*dto.CommonDtoFieldChoice, 0), - MultiChoice: false, - } - - obj = append(obj, f1) - } - - return obj +func (project *Project) GetApiAddr() string { + return project.ProjectPo.ApiAddr } diff --git a/admin/apps/game/domain/entity/server.go b/admin/apps/game/domain/entity/server.go deleted file mode 100644 index b158cc7..0000000 --- a/admin/apps/game/domain/entity/server.go +++ /dev/null @@ -1,91 +0,0 @@ -package entity - -import ( - "admin/apps/game/model" - "admin/apps/game/model/dto" - "reflect" -) - -var ServerDtoFieldsDescInfo = DefaultServer().GetDtoFieldsDescInfo() - -type Server struct { - Id int - po *model.Server -} - -func DefaultServer() *Server { - return &Server{ - po: &model.Server{}, - } -} - -func FromServerPo(po *model.Server) *Server { - return &Server{ - Id: po.ID, - po: po, - } -} - -func FromServerDto(dto dto.CommonDtoValues) *Server { - et := DefaultServer() - po := et.po - - //to := reflect.TypeOf(po) - vo := reflect.ValueOf(po) - - for k, v := range dto { - fo := vo.FieldByName(k) - fo.Set(reflect.ValueOf(v)) - } - - et.Id = po.ID - - return et -} - -func (et *Server) ToPo() *model.Server { - return et.po -} - -func (et *Server) ToCommonDto() dto.CommonDtoValues { - obj := make(dto.CommonDtoValues) - - to := reflect.TypeOf(et.po).Elem() - vo := reflect.ValueOf(et.po).Elem() - for i := 0; i < vo.NumField(); i++ { - ft := to.Field(i) - fo := vo.Field(i) - - obj[ft.Name] = fo.Interface() - } - - return obj -} - -func (et *Server) GetDtoFieldsDescInfo() []*dto.CommonDtoFieldDesc { - - to := reflect.TypeOf(et.po).Elem() - vo := reflect.ValueOf(et.po).Elem() - - obj := make([]*dto.CommonDtoFieldDesc, 0, to.NumField()) - - for i := 0; i < vo.NumField(); i++ { - ft := to.Field(i) - //fo := vo.Field(i) - - f1 := &dto.CommonDtoFieldDesc{ - Name: ft.Name, - Key: ft.Name, - Type: ft.Type.Name(), - HelpText: ft.Tag.Get("desc"), - Editable: true, - Require: true, - Choices: make([]*dto.CommonDtoFieldChoice, 0), - MultiChoice: false, - } - - obj = append(obj, f1) - } - - return obj -} diff --git a/admin/apps/game/domain/entity/utils.go b/admin/apps/game/domain/entity/utils.go index cc1c8e3..1d7acf4 100644 --- a/admin/apps/game/domain/entity/utils.go +++ b/admin/apps/game/domain/entity/utils.go @@ -1,6 +1,9 @@ package entity import ( + "admin/apps/game/model" + "admin/apps/game/model/dto" + "admin/lib/xlog" "fmt" "gorm.io/gorm" "reflect" @@ -8,6 +11,62 @@ import ( "time" ) +func poToCommonDtoNo(po any) dto.CommonDtoValues { + obj := make(dto.CommonDtoValues) + + to := reflect.TypeOf(po).Elem() + vo := reflect.ValueOf(po).Elem() + for i := 0; i < vo.NumField(); i++ { + ft := to.Field(i) + fo := vo.Field(i) + + if ft.Name == "ProjectId" { + if _, ok := po.(*model.Project); !ok { + continue + } + } + + obj[ft.Name] = fo.Interface() + } + + return obj +} + +func getFieldTypeDtoDescInfo(projectId string, poValue reflect.Value, fieldType reflect.StructField) *dto.CommonDtoFieldDesc { + name := fieldType.Tag.Get("name") + if name == "" { + name = fieldType.Name + } + f1 := &dto.CommonDtoFieldDesc{ + Name: name, + Key: fieldType.Name, + Type: fieldType.Type.Name(), + HelpText: fieldType.Tag.Get("desc"), + Readonly: fieldType.Tag.Get("readonly") == "true", + Required: fieldType.Tag.Get("required") == "true", + Choices: make([]*dto.CommonDtoFieldChoice, 0), + MultiChoice: fieldType.Tag.Get("multi_choice") == "true", + } + + if tagType := fieldType.Tag.Get("type"); tagType != "" { + f1.Type = tagType + } + + cf := fieldType.Tag.Get("choices") + if cf != "" { + method := poValue.MethodByName(cf) + if !method.IsValid() { + xlog.Warnf("po %v choices %v function not found in model", poValue.Type().Name(), cf) + } else { + rets := method.Call([]reflect.Value{reflect.ValueOf(projectId)}) + f1.Choices = rets[0].Interface().([]*dto.CommonDtoFieldChoice) + } + + } + + return f1 +} + func parseStr2FieldValue(field reflect.StructField, rawValue any) (realSetValue reflect.Value) { setValue := fmt.Sprintf("%v", rawValue) var parsedValue any @@ -61,6 +120,37 @@ func parseStr2FieldValue(field reflect.StructField, rawValue any) (realSetValue return reflect.ValueOf(gorm.DeletedAt{}) } fallthrough + case reflect.Slice: + typeName := field.Type.String() + if typeName == "[]string" { + list := make([]string, 0) + if _, ok := rawValue.(string); ok { + // 空的字符串 + } 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) + } + } + items = append(items, item) + } + + parsedValue = items + } default: panic(fmt.Errorf("暂时不支持的前后端交互字段类型:%v, 类型名:%v", field.Type.Kind(), field.Type.Name())) } diff --git a/admin/apps/game/domain/iresource.go b/admin/apps/game/domain/iresource.go new file mode 100644 index 0000000..9acd6b7 --- /dev/null +++ b/admin/apps/game/domain/iresource.go @@ -0,0 +1,19 @@ +package domain + +import ( + "admin/apps/game/model/dto" +) + +type IRestfulEntity interface { + ToCommonDto() dto.CommonDtoValues +} + +type IRestfulResourceSvc interface { + List(pageNo, pageLen int, whereValues ...string) ([]*dto.CommonDtoFieldDesc, []IRestfulEntity, error) + Post(obj dto.CommonDtoValues) (IRestfulEntity, error) + Put(obj dto.CommonDtoValues) (IRestfulEntity, error) + Delete(id int) error +} + +type IResourceOpPostHook interface { +} diff --git a/admin/apps/game/domain/irestfull.go b/admin/apps/game/domain/irestfull.go deleted file mode 100644 index c02d018..0000000 --- a/admin/apps/game/domain/irestfull.go +++ /dev/null @@ -1,31 +0,0 @@ -package domain - -import ( - "admin/apps/game/model/dto" - "admin/internal/errcode" -) - -type IRestfulEntity interface { - ToCommonDto() dto.CommonDtoValues -} - -type IRestfulResourceSvc interface { - List(pageNo, pageLen int) ([]*dto.CommonDtoFieldDesc, []IRestfulEntity, error) - Post(obj dto.CommonDtoValues) (IRestfulEntity, error) - Put(obj dto.CommonDtoValues) (IRestfulEntity, error) - Delete(id int) error -} - -var restfulResourceSvcMgr = make(map[string]IRestfulResourceSvc) - -func registerRestfulSvc(name string, svc IRestfulResourceSvc) { - restfulResourceSvcMgr[name] = svc -} - -func FindRestfulResourceSvc(name string) (IRestfulResourceSvc, error) { - svc, find := restfulResourceSvcMgr[name] - if !find { - return nil, errcode.New(errcode.ServerError, "not found %v restful svc", name) - } - return svc, nil -} diff --git a/admin/apps/game/domain/project.go b/admin/apps/game/domain/project.go index 1fd16dd..77b3222 100644 --- a/admin/apps/game/domain/project.go +++ b/admin/apps/game/domain/project.go @@ -1,48 +1,65 @@ package domain import ( - "admin/apps/game/domain/entity" + "admin/apps/game/domain/projects" "admin/apps/game/domain/repo" - "admin/apps/game/model/dto" + "admin/apps/game/model" + "admin/lib/xlog" "gorm.io/gorm" + "time" ) -type ProjectSvc struct { - proRepo repo.IProjectRepo +type ProjectService struct { + repo repo.IProjectRepo } -func NewProjectSvc(db *gorm.DB) *ProjectSvc { - svc := &ProjectSvc{ - proRepo: repo.NewProjectRepo(db), - } - registerRestfulSvc("project", svc) - return svc +func NewProjectService(db *gorm.DB) *ProjectService { + return &ProjectService{repo: repo.NewProjectRepo(db)} } -func (svc *ProjectSvc) List(pageNo, pageLen int) ([]*dto.CommonDtoFieldDesc, []IRestfulEntity, error) { - entityList, err := svc.proRepo.List(pageNo, pageLen) +func (svc *ProjectService) EnsureProjectsDBData() error { + _, err := svc.repo.EnsureProjectsDBData() + go svc.startProjectBackGroundWorker() + return err +} + +func (svc *ProjectService) GetProjectInvokeApiAddr(projectId string, serverIds []int) ([]string, error) { + et, _, err := svc.repo.GetByProjectId(projectId) if err != nil { - return nil, nil, err + return nil, err } - iList := make([]IRestfulEntity, 0, len(entityList)) - for _, v := range entityList { - iList = append(iList, v) + return []string{et.ToPo().(*model.Project).ApiAddr}, nil +} + +func (svc *ProjectService) startProjectBackGroundWorker() { + for { + allProjects, err := svc.repo.List() + if err != nil { + xlog.Warnf("list all projects error:%v", err) + time.Sleep(time.Second * 60) + continue + } + for _, p := range allProjects { + apiAddr := p.GetApiAddr() + if apiAddr == "" { + continue + } + + po := p.ToPo().(*model.Project) + handler := projects.GetProjectValueChoicesGetHook(po.ProjectId) + if handler != nil { + itemsChoices, err := handler.GetItems(p) + if err != nil { + xlog.Warnf("get project %v items error:%v", po.ProjectId, err) + } else { + if len(itemsChoices) > 100 { + itemsChoices = itemsChoices[:100] + } + model.ProjectsAllItems[po.ProjectId] = itemsChoices + } + } + } + + time.Sleep(time.Second * 60) } - return entity.ProjectDtoFieldsDescInfo, iList, nil -} - -func (svc *ProjectSvc) Post(obj dto.CommonDtoValues) (IRestfulEntity, error) { - et := entity.FromProjectDto(obj) - err := svc.proRepo.Create(et) - return et, err -} - -func (svc *ProjectSvc) Put(obj dto.CommonDtoValues) (IRestfulEntity, error) { - et := entity.FromProjectDto(obj) - err := svc.proRepo.Edit(et) - return et, err -} - -func (svc *ProjectSvc) Delete(id int) error { - return svc.proRepo.Delete(id) } diff --git a/admin/apps/game/domain/projects/ihook.go b/admin/apps/game/domain/projects/ihook.go new file mode 100644 index 0000000..1c6a68e --- /dev/null +++ b/admin/apps/game/domain/projects/ihook.go @@ -0,0 +1,28 @@ +package projects + +import ( + "admin/apps/game/domain/entity" + "admin/apps/game/model/dto" +) + +type IPostResourceOpListHook interface { + List(projectInfo *entity.Project, resource string, pageNo, pageLen int, fields []*dto.CommonDtoFieldDesc, rows []dto.CommonDtoValues, extraQuery string, args ...any) ( + []*dto.CommonDtoFieldDesc, []dto.CommonDtoValues, error) +} + +type IPostResourceOpCreateHook interface { + Create(projectInfo *entity.Project, resource string, dtoObj dto.CommonDtoValues) error +} + +type IPostResourceOpEditHook interface { + Edit(projectInfo *entity.Project, resource string, dtoObj dto.CommonDtoValues) error +} + +type IPostResourceOpDeleteHook interface { + Delete(projectInfo *entity.Project, resource string, id int) error +} + +type IGetAllValueChoicesHook interface { + // 获取所有道具,可以用于前端页面做下拉选择等 + GetItems(projectInfo *entity.Project) ([]*dto.CommonDtoFieldChoice, error) +} diff --git a/admin/apps/game/domain/projects/projects.go b/admin/apps/game/domain/projects/projects.go new file mode 100644 index 0000000..d89d0ad --- /dev/null +++ b/admin/apps/game/domain/projects/projects.go @@ -0,0 +1,30 @@ +package projects + +import ( + "admin/apps/game/domain/projects/smdl" + "admin/internal/consts" +) + +// 注册各个项目所有gm资源操作后的回调,例如后台添加了白名单,可以在回调里加上通知项目内的服务 +var projectsResourceHookMgr = map[string]map[string]any{ + consts.RegisteredProjectId_shenmodalu: map[string]any{ + consts.ResourcesName_Server: &smdl.ServerHook{}, // 查看了数据库所有数据之后,还要连alisrv获取所有进程运行情况 + }, +} + +// 注册各个项目所有增删改字段可选项的钩子 +var projectsValueChoicesGetHook = map[string]IGetAllValueChoicesHook{ + consts.RegisteredProjectId_shenmodalu: &smdl.Items{}, +} + +func GetProjectResourceHook(projectId, resource string) any { + project, find := projectsResourceHookMgr[projectId] + if !find { + return nil + } + return project[resource] +} + +func GetProjectValueChoicesGetHook(projectId string) IGetAllValueChoicesHook { + return projectsValueChoicesGetHook[projectId] +} diff --git a/admin/apps/game/domain/projects/smdl/items.go b/admin/apps/game/domain/projects/smdl/items.go new file mode 100644 index 0000000..b9aa1e4 --- /dev/null +++ b/admin/apps/game/domain/projects/smdl/items.go @@ -0,0 +1,32 @@ +package smdl + +import ( + "admin/apps/game/domain/entity" + "admin/apps/game/model/dto" + "admin/internal/errcode" + "admin/lib/httpclient" +) + +type Items struct { +} + +func (items *Items) GetItems(projectInfo *entity.Project) ([]*dto.CommonDtoFieldChoice, error) { + alisrvAddr := projectInfo.GetApiAddr() + if alisrvAddr == "" { + return nil, errcode.New(errcode.ServerError, "项目%v没有配置api服务器地址", projectInfo.ProjectPo.Name) + } + + type RspData struct { + Code int `json:"code"` + Msg string `json:"msg"` + Data struct { + List []*dto.CommonDtoFieldChoice `json:"list"` + } `json:"data"` + } + rsp := &RspData{} + err := httpclient.Request(alisrvAddr+"/items", "get", nil, rsp) + if err != nil { + return nil, err + } + return rsp.Data.List, nil +} diff --git a/admin/apps/game/domain/projects/smdl/server.go b/admin/apps/game/domain/projects/smdl/server.go new file mode 100644 index 0000000..ce9a7a3 --- /dev/null +++ b/admin/apps/game/domain/projects/smdl/server.go @@ -0,0 +1,69 @@ +package smdl + +import ( + "admin/apps/game/domain/entity" + "admin/apps/game/model" + "admin/apps/game/model/dto" + "admin/internal/errcode" + "admin/lib/httpclient" +) + +type ServerHook struct { +} + +func (hook *ServerHook) List(projectInfo *entity.Project, resource string, pageNo, pageLen int, fields []*dto.CommonDtoFieldDesc, rows []dto.CommonDtoValues, extraQuery string, args ...any) ( + []*dto.CommonDtoFieldDesc, []dto.CommonDtoValues, error) { + alisrvAddr := projectInfo.GetApiAddr() + if alisrvAddr == "" { + return nil, nil, errcode.New(errcode.ServerError, "项目%v没有配置api服务器地址", projectInfo.ProjectPo.Name) + } + + fields = append(fields, &dto.CommonDtoFieldDesc{ + Name: "进程运行状态", + Key: "RunningStatus", + Type: "string", + HelpText: "进程运行状态:未知、运行中、停止", + Readonly: false, + Required: false, + Choices: nil, + MultiChoice: false, + }) + + type ServerInfo struct { + ServerId string `json:"serverId"` + ServerName string `json:"serverName"` + } + + type RspData struct { + Code int `json:"code"` + Msg string `json:"msg"` + Data struct { + List []*ServerInfo `json:"list"` + } `json:"data"` + } + + rsp := &RspData{} + err := httpclient.Request(alisrvAddr+"/"+resource, "get", nil, rsp) + if err != nil { + return nil, nil, err + } + + for _, row := range rows { + findRunning := false + for _, curRunning := range rsp.Data.List { + et := (&entity.CommonResource{}).FromPo(&model.Server{}).FromDto(row) + if et.ToPo().(*model.Server).ServerConfID == curRunning.ServerId { + // 运行中,给描述信息添加运行信息 + findRunning = true + break + } + } + if findRunning { + row["RunningStatus"] = "运行中" + } else { + row["RunningStatus"] = "未知" + } + } + + return fields, rows, nil +} diff --git a/admin/apps/game/domain/repo/comm_resource.go b/admin/apps/game/domain/repo/comm_resource.go new file mode 100644 index 0000000..9116829 --- /dev/null +++ b/admin/apps/game/domain/repo/comm_resource.go @@ -0,0 +1,102 @@ +package repo + +import ( + "admin/apps/game/domain/entity" + "admin/apps/game/model" + "admin/apps/game/model/dto" + "admin/internal/errcode" + "errors" + "gorm.io/gorm" + "reflect" +) + +type ICommonResourceRepo interface { + List(projectId string, pageNo, pageLen int, extraQuery string, args ...any) ([]*dto.CommonDtoFieldDesc, []*entity.CommonResource, error) + GetById(projectId string, id int) ([]*dto.CommonDtoFieldDesc, *entity.CommonResource, bool, error) + Create(projectId string, et dto.CommonDtoValues) (*entity.CommonResource, error) + Edit(projectId string, et dto.CommonDtoValues) error + Delete(projectId string, id int) error +} + +func NewCommonResourceRepo(db *gorm.DB, poTemplate model.IModel) ICommonResourceRepo { + return newCommonResourceRepoImpl(db, poTemplate) +} + +type commonResourceRepoImpl struct { + db *gorm.DB + poTemplate model.IModel + fieldsDescInfoFun func(projectId string) []*dto.CommonDtoFieldDesc +} + +func newCommonResourceRepoImpl(db *gorm.DB, poTemplate model.IModel) *commonResourceRepoImpl { + fieldsInfo := (&entity.CommonResource{}).FromPo(poTemplate).GetDtoFieldsDescInfo + return &commonResourceRepoImpl{db: db, poTemplate: poTemplate, fieldsDescInfoFun: fieldsInfo} +} + +func (repo *commonResourceRepoImpl) List(projectId string, pageNo, pageLen int, extraQuery string, args ...any) ([]*dto.CommonDtoFieldDesc, []*entity.CommonResource, error) { + listType := reflect.New(reflect.SliceOf(reflect.TypeOf(repo.poTemplate))) + var err error + if extraQuery == "" { + err = repo.db.Find(listType.Interface()).Error + } else { + err = repo.db.Where(extraQuery, args...).Find(listType.Interface()).Error + } + if err != nil { + return nil, nil, errcode.New(errcode.DBError, "list resource %v error:%v", repo.poTemplate.TableName(), err) + } + + listType1 := listType.Elem() + listLen := listType1.Len() + + entityList := make([]*entity.CommonResource, 0, listLen) + for i := 0; i < listType1.Len(); i++ { + po := listType1.Index(i).Interface().(model.IModel) + et := &entity.CommonResource{} + et.FromPo(po) + entityList = append(entityList, et) + } + + return repo.fieldsDescInfoFun(projectId), entityList, nil +} + +func (repo *commonResourceRepoImpl) GetById(projectId string, id int) ([]*dto.CommonDtoFieldDesc, *entity.CommonResource, bool, error) { + po := repo.newEmptyPo() + err := repo.db.Where("id = ?", id).Find(po).Error + if err != nil { + if errors.Is(err, gorm.ErrRecordNotFound) { + return repo.fieldsDescInfoFun(projectId), (&entity.CommonResource{}).FromPo(repo.newEmptyPo()), false, nil + } + return nil, nil, false, errcode.New(errcode.DBError, "get resource:%v by id:%v error:%v", repo.poTemplate.TableName(), id, err) + } + return repo.fieldsDescInfoFun(projectId), (&entity.CommonResource{}).FromPo(po), true, nil +} + +func (repo *commonResourceRepoImpl) Create(projectId string, dtoObj dto.CommonDtoValues) (*entity.CommonResource, error) { + et := (&entity.CommonResource{}).FromPo(repo.newEmptyPo()).FromDto(dtoObj) + err := repo.db.Create(et.Po).Error + if err != nil { + return et, errcode.New(errcode.DBError, "create resource:%v obj:%+v error:%v", repo.poTemplate.TableName(), et, err) + } + return et, nil +} + +func (repo *commonResourceRepoImpl) Edit(projectId string, dtoObj dto.CommonDtoValues) error { + et := (&entity.CommonResource{}).FromPo(repo.newEmptyPo()).FromDto(dtoObj) + err := repo.db.Where("id=?", et.Po.GetId()).Updates(et.Po).Error + if err != nil { + return errcode.New(errcode.DBError, "edit resource:%v obj:%+v error:%v", repo.poTemplate.TableName(), et, err) + } + return nil +} + +func (repo *commonResourceRepoImpl) Delete(projectId string, id int) error { + err := repo.db.Where("id=?", id).Unscoped().Delete(repo.poTemplate).Error + if err != nil { + return errcode.New(errcode.DBError, "delete resource:%v obj:%+v error:%v", repo.poTemplate.TableName(), id, err) + } + return nil +} + +func (repo *commonResourceRepoImpl) newEmptyPo() model.IModel { + return reflect.New(reflect.TypeOf(repo.poTemplate).Elem()).Interface().(model.IModel) +} diff --git a/admin/apps/game/domain/repo/project.go b/admin/apps/game/domain/repo/project.go index 9e789cf..aa5684c 100644 --- a/admin/apps/game/domain/repo/project.go +++ b/admin/apps/game/domain/repo/project.go @@ -3,75 +3,79 @@ package repo import ( "admin/apps/game/domain/entity" "admin/apps/game/model" + "admin/internal/consts" "admin/internal/errcode" + "errors" "gorm.io/gorm" ) type IProjectRepo interface { - List(pageNo, pageLen int) ([]*entity.Project, error) - Create(et *entity.Project) error - Edit(et *entity.Project) error - Delete(id int) error + EnsureProjectsDBData() ([]*model.Project, error) + List() ([]*entity.Project, error) + GetByProjectId(id string) (*entity.Project, bool, error) } func NewProjectRepo(db *gorm.DB) IProjectRepo { - return newProjectRepoImpl(db) + model.GetProjectServersHandler = func(projectId string) ([]*model.Server, error) { + servers := make([]*model.Server, 0) + err := db.Where("project_id=?", projectId).Find(&servers).Error + return servers, err + } + return &projectRepoImpl{db: db} } type projectRepoImpl struct { db *gorm.DB } -func newProjectRepoImpl(db *gorm.DB) *projectRepoImpl { - return &projectRepoImpl{db: db} +func (impl *projectRepoImpl) EnsureProjectsDBData() ([]*model.Project, error) { + var curProjects []*model.Project + err := impl.db.Find(&curProjects).Error + if err != nil { + return nil, errcode.New(errcode.DBError, "find all projects error:%v", err) + } + for k, v := range consts.RegisteredProjects { + find := false + for _, cur := range curProjects { + if k == cur.ProjectId { + find = true + break + } + } + if !find { + po := &model.Project{ProjectId: k, Name: v.Name} + err := impl.db.Create(po).Error + if err != nil { + return nil, errcode.New(errcode.DBError, "create project:%v error:%v", k, err) + } + curProjects = append(curProjects, po) + } + } + return curProjects, nil } -func (repo *projectRepoImpl) List(pageNo, pageLen int) ([]*entity.Project, error) { +func (impl *projectRepoImpl) List() ([]*entity.Project, error) { list := make([]*model.Project, 0) - err := repo.db.Find(&list).Error + err := impl.db.Find(&list).Error if err != nil { - return nil, errcode.New(errcode.DBError, "find project error:%v", err) + return nil, errcode.New(errcode.DBError, "list project error:%v", err) } - - // debug - //list = append(list, &model.Project{ - // ID: 123, - // Name: "神魔大陆", - // Desc: "神魔大陆服务器", - // ApiAddr: "http://192.168.1.1:8081", - //}) - - entityList := make([]*entity.Project, 0, len(list)) - for _, Project := range list { - entityList = append(entityList, entity.FromProjectPo(Project)) + + list1 := make([]*entity.Project, 0, len(list)) + for _, v := range list { + list1 = append(list1, (&entity.CommonResource{}).FromPo(v).ToProjectEntity()) } - - return entityList, nil + return list1, nil } -func (repo *projectRepoImpl) Create(et *entity.Project) error { - po := et.ToPo() - err := repo.db.Create(po).Error +func (impl *projectRepoImpl) GetByProjectId(id string) (*entity.Project, bool, error) { + po := &model.Project{} + err := impl.db.Where("project_id=?", id).Find(po).Error if err != nil { - return errcode.New(errcode.DBError, "create obj:%+v error:%v", et, err) + if errors.Is(err, gorm.ErrRecordNotFound) { + return (&entity.CommonResource{}).FromPo(po).ToProjectEntity(), false, nil + } } - et.Id = po.ID - return nil -} -func (repo *projectRepoImpl) Edit(et *entity.Project) error { - po := et.ToPo() - err := repo.db.Where("id=?", et.Id).Updates(po).Error - if err != nil { - return errcode.New(errcode.DBError, "edit obj:%+v error:%v", et, err) - } - return nil -} - -func (repo *projectRepoImpl) Delete(id int) error { - err := repo.db.Where("id=?", id).Unscoped().Delete(&model.Project{}).Error - if err != nil { - return errcode.New(errcode.DBError, "delete obj:%+v error:%v", id, err) - } - return nil + return (&entity.CommonResource{}).FromPo(po).ToProjectEntity(), true, nil } diff --git a/admin/apps/game/domain/repo/server.go b/admin/apps/game/domain/repo/server.go deleted file mode 100644 index 38327e7..0000000 --- a/admin/apps/game/domain/repo/server.go +++ /dev/null @@ -1,69 +0,0 @@ -package repo - -import ( - "admin/apps/game/domain/entity" - "admin/apps/game/model" - "admin/internal/errcode" - "gorm.io/gorm" -) - -type IServerRepo interface { - List(pageNo, pageLen int) ([]*entity.Server, error) - Create(et *entity.Server) error - Edit(et *entity.Server) error - Delete(id int) error -} - -func NewServerRepo(db *gorm.DB) IServerRepo { - return newServerRepoImpl(db) -} - -type ServerRepoImpl struct { - db *gorm.DB -} - -func newServerRepoImpl(db *gorm.DB) *ServerRepoImpl { - return &ServerRepoImpl{db: db} -} - -func (repo *ServerRepoImpl) List(pageNo, pageLen int) ([]*entity.Server, error) { - list := make([]*model.Server, 0) - err := repo.db.Find(&list).Error - if err != nil { - return nil, errcode.New(errcode.DBError, "find Server error:%v", err) - } - - entityList := make([]*entity.Server, 0, len(list)) - for _, Server := range list { - entityList = append(entityList, entity.FromServerPo(Server)) - } - - return entityList, nil -} - -func (repo *ServerRepoImpl) Create(et *entity.Server) error { - po := et.ToPo() - err := repo.db.Create(po).Error - if err != nil { - return errcode.New(errcode.DBError, "create obj:%+v error:%v", et, err) - } - et.Id = po.ID - return nil -} - -func (repo *ServerRepoImpl) Edit(et *entity.Server) error { - po := et.ToPo() - err := repo.db.Where("id=?", et.Id).Updates(po).Error - if err != nil { - return errcode.New(errcode.DBError, "edit obj:%+v error:%v", et, err) - } - return nil -} - -func (repo *ServerRepoImpl) Delete(id int) error { - err := repo.db.Where("id=?", id).Unscoped().Delete(&model.Server{}).Error - if err != nil { - return errcode.New(errcode.DBError, "delete obj:%+v error:%v", id, err) - } - return nil -} diff --git a/admin/apps/game/domain/server.go b/admin/apps/game/domain/server.go deleted file mode 100644 index 03aecd5..0000000 --- a/admin/apps/game/domain/server.go +++ /dev/null @@ -1,48 +0,0 @@ -package domain - -import ( - "admin/apps/game/domain/entity" - "admin/apps/game/domain/repo" - "admin/apps/game/model/dto" - "gorm.io/gorm" -) - -type ServerSvc struct { - serverRepo repo.IServerRepo -} - -func NewServerSvc(db *gorm.DB) *ServerSvc { - svc := &ServerSvc{ - serverRepo: repo.NewServerRepo(db), - } - registerRestfulSvc("server", svc) - return svc -} - -func (svc *ServerSvc) List(pageNo, pageLen int) ([]*dto.CommonDtoFieldDesc, []IRestfulEntity, error) { - entityList, err := svc.serverRepo.List(pageNo, pageLen) - if err != nil { - return nil, nil, err - } - iList := make([]IRestfulEntity, 0, len(entityList)) - for _, v := range entityList { - iList = append(iList, v) - } - return entity.ServerDtoFieldsDescInfo, iList, nil -} - -func (svc *ServerSvc) Post(obj dto.CommonDtoValues) (IRestfulEntity, error) { - et := entity.FromServerDto(obj) - err := svc.serverRepo.Create(et) - return et, err -} - -func (svc *ServerSvc) Put(obj dto.CommonDtoValues) (IRestfulEntity, error) { - et := entity.FromServerDto(obj) - err := svc.serverRepo.Edit(et) - return et, err -} - -func (svc *ServerSvc) Delete(id int) error { - return svc.serverRepo.Delete(id) -} diff --git a/admin/apps/game/model/ban.go b/admin/apps/game/model/ban.go new file mode 100644 index 0000000..40099d5 --- /dev/null +++ b/admin/apps/game/model/ban.go @@ -0,0 +1,38 @@ +package model + +import ( + "admin/internal/db" + "gorm.io/gorm" + "time" +) + +func init() { + db.RegisterTableModels(Ban{}) +} + +type Ban struct { + ID int `gorm:"primarykey" readonly:"true"` + ProjectId string `gorm:"type:varchar(255);uniqueIndex:idx_ban"` + BanType string `name:"封禁类型" required:"true" choices:"GetBanTypeChoices" multi_choice:"true"` + Value string `gorm:"type:varchar(128);uniqueIndex:idx_ban" name:"封禁账号" required:"true" desc:"填账号"` + ExpireSeconds int `name:"封禁秒数" desc:"封禁到期秒数,为0表示永久封禁"` + + CreatedAt time.Time `readonly:"true"` + UpdatedAt time.Time `readonly:"true"` + DeletedAt gorm.DeletedAt `gorm:"index" readonly:"true"` +} + +func (lm *Ban) TableName() string { + return "ban" +} + +func (m *Ban) GetId() int { + return m.ID +} + +func (m *Ban) GetBanTypeChoices() []string { + return []string{ + "作弊", + "广告", + } +} diff --git a/admin/apps/game/model/devicepush.go b/admin/apps/game/model/devicepush.go new file mode 100644 index 0000000..fa0b447 --- /dev/null +++ b/admin/apps/game/model/devicepush.go @@ -0,0 +1,31 @@ +package model + +import ( + "admin/internal/db" + "gorm.io/gorm" + "time" +) + +func init() { + db.RegisterTableModels(DevicePush{}) +} + +type DevicePush struct { + ID int `gorm:"primarykey" readonly:"true"` + ProjectId string + Account string `name:"账号" desc:"给账号所属的设备做推送"` + Title string `name:"通知标题" desc:""` + Content string `name:"通知内容"` + + CreatedAt time.Time `readonly:"true"` + UpdatedAt time.Time `readonly:"true"` + DeletedAt gorm.DeletedAt `gorm:"index" readonly:"true"` +} + +func (lm *DevicePush) TableName() string { + return "device_push" +} + +func (m *DevicePush) GetId() int { + return m.ID +} diff --git a/admin/apps/game/model/dto/common.go b/admin/apps/game/model/dto/common.go index a296593..2ac5a05 100644 --- a/admin/apps/game/model/dto/common.go +++ b/admin/apps/game/model/dto/common.go @@ -1,5 +1,11 @@ package dto +type WebRspData struct { + Code int `json:"code"` + Msg string `json:"msg"` + Data any `json:"data"` +} + type CommonDtoFieldChoice struct { Desc string `json:"desc"` Value any `json:"value"` @@ -14,8 +20,8 @@ type CommonDtoFieldDesc struct { // 支持自定义类型和自定义类型的数组 Type string `json:"type"` HelpText string `json:"help_text"` - Editable bool `json:"editable"` // 是否可编辑,例如id就不可编辑,新增时也不需要填写 - Require bool `json:"require"` // 是否必填,不能为空 + Readonly bool `json:"readonly"` // 是否只读,就只展示在表格中 + Required bool `json:"required"` // 是否必填,不能为空 Choices []*CommonDtoFieldChoice `json:"choices"` // 可选项,用于字段做下拉框 MultiChoice bool `json:"multi_choice"` // 是否多选 } @@ -36,3 +42,9 @@ type PathInfo struct { Path string `json:"path"` Method string `json:"method"` } + +type ResourceInfo struct { + Resource string `json:"resource"` + Desc string `json:"desc"` + Methods []string `json:"methods"` // get|post|put|delete // 资源支持的方法,某些功能比如白名单,只有增删 +} diff --git a/admin/apps/game/model/dto/msg.go b/admin/apps/game/model/dto/msg.go index d4179cf..4e3d91d 100644 --- a/admin/apps/game/model/dto/msg.go +++ b/admin/apps/game/model/dto/msg.go @@ -6,8 +6,11 @@ type NilReq struct { type NilRsp = NilReq type CommonListReq struct { - PageNo int `json:"page_no"` - PageLen int `json:"page_len"` + PageNo int `json:"page_no"` + PageLen int `json:"page_len"` + WhereValue1 string `json:"where_value1"` + WhereValue2 string `json:"where_value2"` + WhereValue3 string `json:"where_value3"` } type CommonPostReq struct { @@ -43,3 +46,7 @@ type CommandListReq struct { type CommandListRsp struct { List []*PathInfo `json:"list"` } + +type ResourceListRsp struct { + List []*ResourceInfo `json:"list"` +} diff --git a/admin/apps/game/model/globalmail.go b/admin/apps/game/model/globalmail.go new file mode 100644 index 0000000..b278170 --- /dev/null +++ b/admin/apps/game/model/globalmail.go @@ -0,0 +1,43 @@ +package model + +import ( + "admin/apps/game/model/dto" + "admin/internal/db" + "gorm.io/gorm" + "time" +) + +func init() { + db.RegisterTableModels(GlobalMail{}) +} + +var ProjectsAllItems = make(map[string][]*dto.CommonDtoFieldChoice) + +type GlobalMail struct { + ID int `gorm:"primarykey" readonly:"true"` + ProjectId string + ServerIDs []string `gorm:"type:json;serializer:json" name:"区服" type:"[]string" choices:"GetChoiceServers" multi_choice:"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"` +} + +func (lm *GlobalMail) TableName() string { + return "mail_global" +} + +func (m *GlobalMail) GetId() int { + return m.ID +} + +func (m *GlobalMail) GetChoiceServers(projectId string) []*dto.CommonDtoFieldChoice { + return getChoiceServers(projectId) +} + +func (m *GlobalMail) GetChoiceItems(projectId string) []*dto.CommonDtoFieldChoice { + return ProjectsAllItems[projectId] +} diff --git a/admin/apps/game/model/imodel.go b/admin/apps/game/model/imodel.go new file mode 100644 index 0000000..ad31381 --- /dev/null +++ b/admin/apps/game/model/imodel.go @@ -0,0 +1,28 @@ +package model + +import ( + "admin/apps/game/model/dto" +) + +type IModel interface { + TableName() string + GetId() int +} + +var GetProjectServersHandler func(projectId string) ([]*Server, error) + +func getChoiceServers(args ...any) []*dto.CommonDtoFieldChoice { + servers, err := GetProjectServersHandler(args[0].(string)) + if err != nil { + panic(err) + } + + serverChoices := make([]*dto.CommonDtoFieldChoice, 0, len(servers)) + for _, s := range servers { + serverChoices = append(serverChoices, &dto.CommonDtoFieldChoice{ + Desc: s.Desc, + Value: s.ServerConfID, + }) + } + return serverChoices +} diff --git a/admin/apps/game/model/notice.go b/admin/apps/game/model/notice.go new file mode 100644 index 0000000..451633e --- /dev/null +++ b/admin/apps/game/model/notice.go @@ -0,0 +1,37 @@ +package model + +import ( + "admin/apps/game/model/dto" + "admin/internal/db" + "gorm.io/gorm" + "time" +) + +func init() { + db.RegisterTableModels(Notice{}) +} + +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"` + + CreatedAt time.Time `readonly:"true"` + UpdatedAt time.Time `readonly:"true"` + DeletedAt gorm.DeletedAt `gorm:"index" readonly:"true"` +} + +func (lm *Notice) TableName() string { + return "notice" +} + +func (m *Notice) GetId() int { + return m.ID +} + +func (m *Notice) GetChoiceServers(args ...any) []*dto.CommonDtoFieldChoice { + return getChoiceServers(args[0].(string)) +} diff --git a/admin/apps/game/model/project.go b/admin/apps/game/model/project.go index a9644e5..45b3ac3 100644 --- a/admin/apps/game/model/project.go +++ b/admin/apps/game/model/project.go @@ -12,17 +12,26 @@ func init() { // Project 游戏项目,例如神谕、神魔大陆 type Project struct { - ID int `gorm:"primarykey"` - Name string `gorm:"primarykey"` - Desc string + 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"` + Desc string `name:"项目描述"` // command_list接口服务器地址,为空代表由由项目下各个逻辑服提供command_list. // 取决于每个项目改造难度: // 不为空就代表项目要实现一个自己统一对外暴露的gm调用服务对内聚合、分发指令执行,本后台执行指令只调用一次; // 为空就代表command_list实现在各个逻辑服,由本后台系统在执行指令时聚合、分发指令 // 调用各个逻辑服执行,本后台执行指令需要根据逻辑服数量调用; - ApiAddr string // + ApiAddr string `name:"游戏api地址" desc:"api服务器地址,例如神魔大陆就是alisrv服务器地址,用于后台调用gm"` - CreatedAt time.Time - UpdatedAt time.Time - DeletedAt gorm.DeletedAt `gorm:"index"` + CreatedAt time.Time `readonly:"true"` + UpdatedAt time.Time `readonly:"true"` + DeletedAt gorm.DeletedAt `gorm:"index" readonly:"true"` +} + +func (lm *Project) TableName() string { + return "project" +} + +func (m *Project) GetId() int { + return m.ID } diff --git a/admin/apps/game/model/rewardcode.go b/admin/apps/game/model/rewardcode.go new file mode 100644 index 0000000..69cde58 --- /dev/null +++ b/admin/apps/game/model/rewardcode.go @@ -0,0 +1,30 @@ +package model + +import ( + "admin/internal/db" + "gorm.io/gorm" + "time" +) + +func init() { + db.RegisterTableModels(RewardCode{}) +} + +type RewardCode struct { + ID int `gorm:"primarykey" readonly:"true"` + ProjectId string + Group int `name:"奖励码组"` + Code int `name:"奖励码"` + + CreatedAt time.Time `readonly:"true"` + UpdatedAt time.Time `readonly:"true"` + DeletedAt gorm.DeletedAt `gorm:"index" readonly:"true"` +} + +func (lm *RewardCode) TableName() string { + return "reward_code" +} + +func (m *RewardCode) GetId() int { + return m.ID +} diff --git a/admin/apps/game/model/rolemail.go b/admin/apps/game/model/rolemail.go new file mode 100644 index 0000000..ae1e8ad --- /dev/null +++ b/admin/apps/game/model/rolemail.go @@ -0,0 +1,48 @@ +package model + +import ( + "admin/apps/game/model/dto" + "admin/internal/db" + "gorm.io/gorm" + "time" +) + +func init() { + db.RegisterTableModels(RoleMail{}) +} + +type MailAttachItem struct { + ID int32 `json:"id"` + Num int64 `json:"num"` + ItemType int `json:"item_type"` +} + +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"` + 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"` +} + +func (lm *RoleMail) TableName() string { + return "mail_role" +} + +func (m *RoleMail) GetId() int { + return m.ID +} + +func (m *RoleMail) GetChoiceServers(projectId string) []*dto.CommonDtoFieldChoice { + return getChoiceServers(projectId) +} + +func (m *RoleMail) GetChoiceItems(projectId string) []*dto.CommonDtoFieldChoice { + return ProjectsAllItems[projectId] +} diff --git a/admin/apps/game/model/server.go b/admin/apps/game/model/server.go index fe876c7..0daedb1 100644 --- a/admin/apps/game/model/server.go +++ b/admin/apps/game/model/server.go @@ -12,8 +12,9 @@ func init() { // Server 逻辑服 type Server struct { - ID int `gorm:"primarykey"` - ServerConfID string `gorm:"primarykey"` + 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 // command_list接口服务器地址,为空代表由由项目统一提供command_list. // 取决于每个项目改造难度: @@ -22,7 +23,15 @@ type Server struct { // 调用各个逻辑服执行,本后台执行指令需要根据逻辑服数量调用; ApiAddr string - CreatedAt time.Time - UpdatedAt time.Time - DeletedAt gorm.DeletedAt `gorm:"index"` + CreatedAt time.Time `readonly:"true"` + UpdatedAt time.Time `readonly:"true"` + DeletedAt gorm.DeletedAt `gorm:"index" readonly:"true"` +} + +func (lm *Server) TableName() string { + return "server" +} + +func (m *Server) GetId() int { + return m.ID } diff --git a/admin/apps/game/model/whitelist.go b/admin/apps/game/model/whitelist.go new file mode 100644 index 0000000..31be9b4 --- /dev/null +++ b/admin/apps/game/model/whitelist.go @@ -0,0 +1,31 @@ +package model + +import ( + "admin/internal/db" + "gorm.io/gorm" + "time" +) + +func init() { + db.RegisterTableModels(WhiteList{}) +} + +type WhiteList struct { + ID int `gorm:"primarykey" readonly:"true"` + ProjectId string `gorm:"type:varchar(256);uniqueIndex:idx_whitelist"` + Account string `gorm:"type:varchar(128);uniqueIndex:idx_whitelist"` + AccountType int `gorm:"uniqueIndex:idx_whitelist"` + Desc string + + CreatedAt time.Time `readonly:"true"` + UpdatedAt time.Time `readonly:"true"` + DeletedAt gorm.DeletedAt `gorm:"index" readonly:"true"` +} + +func (lm *WhiteList) TableName() string { + return "whitelist" +} + +func (m *WhiteList) GetId() int { + return m.ID +} diff --git a/admin/apps/game/server/ctl_common_rest.go b/admin/apps/game/server/ctl_common_rest.go index 1e292d3..1bc08b5 100644 --- a/admin/apps/game/server/ctl_common_rest.go +++ b/admin/apps/game/server/ctl_common_rest.go @@ -5,8 +5,9 @@ import ( "admin/internal/context" ) -func (ctl *controller) CommonList(ctx *context.WebContext, restfulResourceName string, params *dto.CommonListReq, rsp *dto.CommonListRsp) error { - list, err := ctl.svc.CommonList(ctx, restfulResourceName, params) +func (ctl *controller) CommonList(ctx *context.WebContext, params *dto.CommonListReq, rsp *dto.CommonListRsp) error { + projectId, resource := getCtxURIProjectIdAndResource(ctx) + list, err := ctl.svc.CommonList(ctx, projectId, resource, params) if err != nil { return err } @@ -14,8 +15,9 @@ func (ctl *controller) CommonList(ctx *context.WebContext, restfulResourceName s return nil } -func (ctl *controller) CommonPost(ctx *context.WebContext, restfulResourceName string, params *dto.CommonPostReq, rsp *dto.CommonPostRsp) error { - newObj, err := ctl.svc.CommonPost(ctx, restfulResourceName, *params.Dto) +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) if err != nil { return err } @@ -23,17 +25,19 @@ func (ctl *controller) CommonPost(ctx *context.WebContext, restfulResourceName s return nil } -func (ctl *controller) CommonPut(ctx *context.WebContext, restfulResourceName string, params *dto.CommonPutReq, rsp *dto.CommonPutRsp) error { - newObj, err := ctl.svc.CommonPut(ctx, restfulResourceName, *params.Dto) +func (ctl *controller) CommonPut(ctx *context.WebContext, params *dto.CommonPutReq, rsp *dto.CommonPutRsp) error { + projectId, resource := getCtxURIProjectIdAndResource(ctx) + err := ctl.svc.CommonPut(ctx, projectId, resource, *params.Dto) if err != nil { return err } - rsp.Dto = &newObj + rsp.Dto = params.Dto return nil } -func (ctl *controller) CommonDelete(ctx *context.WebContext, restfulResourceName string, params *dto.CommonDeleteReq, rsp *dto.CommonDeleteRsp) error { - err := ctl.svc.CommonDelete(ctx, restfulResourceName, params.Id) +func (ctl *controller) CommonDelete(ctx *context.WebContext, params *dto.CommonDeleteReq, rsp *dto.CommonDeleteRsp) error { + projectId, resource := getCtxURIProjectIdAndResource(ctx) + err := ctl.svc.CommonDelete(ctx, projectId, resource, params.Id) if err != nil { return err } diff --git a/admin/apps/game/server/ctl_game.go b/admin/apps/game/server/ctl_game.go index bdb08aa..85ee4a7 100644 --- a/admin/apps/game/server/ctl_game.go +++ b/admin/apps/game/server/ctl_game.go @@ -2,9 +2,11 @@ package server import ( "admin/apps/game/model/dto" + "admin/internal/consts" "admin/internal/context" "admin/lib/httpclient" "admin/lib/xlog" + "strings" ) func (ctl *controller) CommandList(ctx *context.WebContext, params *dto.CommandListReq, rsp *dto.CommandListRsp) error { @@ -26,6 +28,67 @@ func (ctl *controller) CommandList(ctx *context.WebContext, params *dto.CommandL return nil } +func (ctl *controller) ProjectResourceList(ctx *context.WebContext, params *dto.CommonListReq, rsp *dto.CommonListRsp) error { + projectId := getCtxURIProjectId(ctx) + resource := getCtxURIResource(ctx) + + apiAddr, err := ctl.svc.GetProjectInvokeApiAddr(projectId, nil) + if err != nil { + return err + } + + url := apiAddr[0] + "/api/" + resource + + listRsp := make(map[string]any) + err = httpclient.Request(url, "get", nil, &listRsp) + if err != nil { + return err + } + + xlog.Debugf("receive project %v resource %v list", "projectId", resource) + return nil +} + +func (ctl *controller) ProjectResourcePost(ctx *context.WebContext, params *dto.CommonPostReq, rsp *dto.CommonPostRsp) error { + + return nil +} + +func (ctl *controller) ProjectResourcePut(ctx *context.WebContext, params *dto.CommonPutReq, rsp *dto.CommonPutRsp) error { + + return nil +} + +func (ctl *controller) ProjectResourceDelete(ctx *context.WebContext, params *dto.CommonDeleteReq, rsp *dto.CommonDeleteRsp) error { + + return nil +} + +func (ctl *controller) getProjectResourceCommandApiAddr(ctx *context.WebContext) ([]string, error) { + projectId := getCtxURIProjectId(ctx) + //resouce := getCtxURIResource(ctx) + return ctl.svc.GetProjectInvokeApiAddr(projectId, nil) +} + +func getCtxURIProjectIdAndResource(ctx *context.WebContext) (string, string) { + return getCtxURIProjectId(ctx), getCtxURIResource(ctx) +} + +func getCtxURIResource(ctx *context.WebContext) string { + resource := ctx.GinCtx().Param("resource") + if resource == "" { + if strings.HasPrefix(ctx.GinCtx().Request.RequestURI, "/api/"+consts.ResourcesName_Project) { + return consts.ResourcesName_Project + } + } + return resource +} + +func getCtxURIProjectId(ctx *context.WebContext) string { + projectId := ctx.GinCtx().Param("projectId") + return projectId +} + func (ctl *controller) apiRequest() { } diff --git a/admin/apps/game/server/route.go b/admin/apps/game/server/route.go index 4ba5076..47a54b7 100644 --- a/admin/apps/game/server/route.go +++ b/admin/apps/game/server/route.go @@ -2,58 +2,41 @@ package server import ( "admin/apps/game/model/dto" + "admin/internal/consts" "admin/internal/context" - "admin/internal/global" "admin/lib/web" ) func (srv *Server) Route(engine *web.Engine) { apiGroup := engine.Group("/api", "") - srv.proRoute(apiGroup) - srv.serverRoute(apiGroup) { - apiGroup.Get("/project/commandlist", "调用对应游戏服api获取命令列表", global.WebPathPermit_Read, srv.ctl.CommandList) + // 注册项目增删改查接口 + projectGroup := apiGroup.Group("/"+consts.ResourcesName_Project, "项目") + projectGroup.Get("", "查看列表", consts.WebPathPermit_Read, srv.ctl.CommonList) + projectGroup.Post("", "新增", consts.WebPathPermit_Read, srv.ctl.CommonPost) + projectGroup.Put("", "编辑", consts.WebPathPermit_Read, srv.ctl.CommonPut) + projectGroup.Delete("", "删除", consts.WebPathPermit_Read, srv.ctl.CommonDelete) + + // 注册项目之下其它所有资源通用增删改查接口 + { + resourceUnderProjectGroup := projectGroup.Group("/:projectId/:resource", "") + resourceUnderProjectGroup.Get("", "查看列表", consts.WebPathPermit_Read, srv.ctl.CommonList) + resourceUnderProjectGroup.Post("", "新增", consts.WebPathPermit_Read, srv.ctl.CommonPost) + resourceUnderProjectGroup.Put("", "编辑", consts.WebPathPermit_Read, srv.ctl.CommonPut) + resourceUnderProjectGroup.Delete("", "删除", consts.WebPathPermit_Read, srv.ctl.CommonDelete) + } + + projectGroup.Get("/resourcelist", "获取支持的资源列表,用于客户端生成前端操作菜单", consts.WebPathPermit_Read, srv.getResourceList) } } -func (srv *Server) proRoute(engine *web.RoutesGroup) { - resourceName := "project" - srv.registerResourceRouter(resourceName, engine.Group("/"+resourceName, "")) -} - -func (srv *Server) serverRoute(engine *web.RoutesGroup) { - resourceName := "server" - srv.registerResourceRouter(resourceName, engine.Group("/"+resourceName, "")) -} - -func (srv *Server) registerResourceRouter(resourceName string, group *web.RoutesGroup) { - group.Get("", "获取列表", global.WebPathPermit_Read, commonHandlerList(srv.ctl, resourceName)) - group.Post("", "新增", global.WebPathPermit_Read, commonHandlerPost(srv.ctl, resourceName)) - group.Put("", "修改", global.WebPathPermit_Read, commonHandlerPut(srv.ctl, resourceName)) - group.Delete("", "删除", global.WebPathPermit_Read, commonHandlerDelete(srv.ctl, resourceName)) -} - -func commonHandlerList(ctl *controller, resourceName string) func(ctx *context.WebContext, params *dto.CommonListReq, rsp *dto.CommonListRsp) error { - return func(ctx *context.WebContext, params *dto.CommonListReq, rsp *dto.CommonListRsp) error { - return ctl.CommonList(ctx, resourceName, params, rsp) - } -} - -func commonHandlerPost(ctl *controller, resourceName string) func(ctx *context.WebContext, params *dto.CommonPostReq, rsp *dto.CommonPostRsp) error { - return func(ctx *context.WebContext, params *dto.CommonPostReq, rsp *dto.CommonPostRsp) error { - return ctl.CommonPost(ctx, resourceName, params, rsp) - } -} - -func commonHandlerPut(ctl *controller, resourceName string) func(ctx *context.WebContext, params *dto.CommonPutReq, rsp *dto.CommonPutRsp) error { - return func(ctx *context.WebContext, params *dto.CommonPutReq, rsp *dto.CommonPutRsp) error { - return ctl.CommonPut(ctx, resourceName, params, rsp) - } -} - -func commonHandlerDelete(ctl *controller, resourceName string) func(ctx *context.WebContext, params *dto.CommonDeleteReq, rsp *dto.CommonDeleteRsp) error { - return func(ctx *context.WebContext, params *dto.CommonDeleteReq, rsp *dto.CommonDeleteRsp) error { - return ctl.CommonDelete(ctx, resourceName, params, rsp) +func (srv *Server) getResourceList(ctx *context.WebContext, params *dto.NilReq, rsp *dto.ResourceListRsp) error { + for _, v := range srv.ctl.svc.GetSupportResourcesList() { + if v[0] == consts.ResourcesName_Project { + continue + } + rsp.List = append(rsp.List, &dto.ResourceInfo{Resource: v[0], Desc: v[1], Methods: []string{"get", "post", "put", "delete"}}) } + return nil } diff --git a/admin/apps/game/service/service.go b/admin/apps/game/service/service.go index b953b40..3b91a24 100644 --- a/admin/apps/game/service/service.go +++ b/admin/apps/game/service/service.go @@ -3,66 +3,63 @@ package service import ( "admin/apps/game/domain" "admin/apps/game/model/dto" + "admin/internal/consts" "context" "gorm.io/gorm" ) type Service struct { - db *gorm.DB - projectSvc *domain.ProjectSvc - serverSvc *domain.ServerSvc + db *gorm.DB + resourceSvc *domain.CommonResourceService + projectSvc *domain.ProjectService } -func New(db *gorm.DB) *Service { - return &Service{ - db: db, - projectSvc: domain.NewProjectSvc(db), - serverSvc: domain.NewServerSvc(db), +func New(db *gorm.DB) (*Service, error) { + svc := &Service{ + db: db, + resourceSvc: domain.NewCommonResourceService(db), + projectSvc: domain.NewProjectService(db), } + err := svc.ensureProjectsDBData() + if err != nil { + return nil, err + } + return svc, nil } -func (svc *Service) CommonList(ctx context.Context, resourceName string, params *dto.CommonListReq) (*dto.CommonDtoList, error) { - restfulDomainSvc, err := domain.FindRestfulResourceSvc(resourceName) - if err != nil { - return nil, err +func (svc *Service) CommonList(ctx context.Context, projectId string, resourceName string, params *dto.CommonListReq) (*dto.CommonDtoList, error) { + var ( + query string + args []any + ) + switch resourceName { + case consts.ResourcesName_Project: + default: + query = "project_id = ?" + args = append(args, projectId) } - dtoFieldsDescInfo, list, err := restfulDomainSvc.List(params.PageNo, params.PageLen) - if err != nil { - return nil, err - } - retList := make([]dto.CommonDtoValues, 0, len(list)) - for _, v := range list { - retList = append(retList, v.ToCommonDto()) - } - return &dto.CommonDtoList{FieldsDesc: dtoFieldsDescInfo, Rows: retList}, nil + fieldsDescInfo, rows, err := svc.resourceSvc.List(projectId, resourceName, params.PageNo, params.PageLen, query, args) + return &dto.CommonDtoList{FieldsDesc: fieldsDescInfo, Rows: rows}, err } -func (svc *Service) CommonPost(ctx context.Context, resourceName string, params dto.CommonDtoValues) (dto.CommonDtoValues, error) { - restfulDomainSvc, err := domain.FindRestfulResourceSvc(resourceName) - if err != nil { - return nil, err +func (svc *Service) CommonPost(ctx context.Context, projectId string, resourceName string, params dto.CommonDtoValues) (dto.CommonDtoValues, error) { + if resourceName != consts.ResourcesName_Project { + params["ProjectId"] = projectId } - et, err := restfulDomainSvc.Post(params) - if err != nil { - return nil, err - } - return et.ToCommonDto(), nil + return svc.resourceSvc.Create(projectId, resourceName, params) } -func (svc *Service) CommonPut(ctx context.Context, resourceName string, params dto.CommonDtoValues) (dto.CommonDtoValues, error) { - restfulDomainSvc, err := domain.FindRestfulResourceSvc(resourceName) - if err != nil { - return nil, err + +func (svc *Service) CommonPut(ctx context.Context, projectId string, resourceName string, params dto.CommonDtoValues) error { + if resourceName != consts.ResourcesName_Project { + params["ProjectId"] = projectId } - et, err := restfulDomainSvc.Put(params) - if err != nil { - return nil, err - } - return et.ToCommonDto(), nil + return svc.resourceSvc.Edit(projectId, resourceName, params) } -func (svc *Service) CommonDelete(ctx context.Context, resourceName string, id int) error { - restfulDomainSvc, err := domain.FindRestfulResourceSvc(resourceName) - if err != nil { - return err - } - return restfulDomainSvc.Delete(id) + +func (svc *Service) CommonDelete(ctx context.Context, projectId string, resourceName string, id int) error { + return svc.resourceSvc.Delete(projectId, resourceName, id) +} + +func (svc *Service) GetSupportResourcesList() [][2]string { + return svc.resourceSvc.GetSupportResourcesList() } diff --git a/admin/apps/game/service/service_project.go b/admin/apps/game/service/service_project.go new file mode 100644 index 0000000..e0a8ed3 --- /dev/null +++ b/admin/apps/game/service/service_project.go @@ -0,0 +1,9 @@ +package service + +func (svc *Service) ensureProjectsDBData() error { + return svc.projectSvc.EnsureProjectsDBData() +} + +func (svc *Service) GetProjectInvokeApiAddr(projectId string, serverIds []int) ([]string, error) { + return svc.projectSvc.GetProjectInvokeApiAddr(projectId, serverIds) +} diff --git a/admin/apps/mockpro/internal/model/account.go b/admin/apps/mockpro/internal/model/account.go index 524e052..48f10b6 100644 --- a/admin/apps/mockpro/internal/model/account.go +++ b/admin/apps/mockpro/internal/model/account.go @@ -18,3 +18,7 @@ type Account struct { UpdatedAt time.Time DeletedAt gorm.DeletedAt `gorm:"index"` } + +func (lm *Account) TableName() string { + return "mock_account" +} diff --git a/admin/apps/mockpro/internal/model/ban.go b/admin/apps/mockpro/internal/model/ban.go index 0701e4a..e6d292e 100644 --- a/admin/apps/mockpro/internal/model/ban.go +++ b/admin/apps/mockpro/internal/model/ban.go @@ -20,3 +20,7 @@ type Ban struct { UpdatedAt time.Time DeletedAt gorm.DeletedAt `gorm:"index"` } + +func (lm *Ban) TableName() string { + return "mock_ban" +} diff --git a/admin/apps/mockpro/internal/model/devicepush.go b/admin/apps/mockpro/internal/model/devicepush.go index fc53060..33fe357 100644 --- a/admin/apps/mockpro/internal/model/devicepush.go +++ b/admin/apps/mockpro/internal/model/devicepush.go @@ -20,3 +20,7 @@ type DevicePush struct { UpdatedAt time.Time DeletedAt gorm.DeletedAt `gorm:"index"` } + +func (lm *DevicePush) TableName() string { + return "mock_devicepush" +} diff --git a/admin/apps/mockpro/internal/model/globalmail.go b/admin/apps/mockpro/internal/model/globalmail.go index 422ee08..a5b3fe5 100644 --- a/admin/apps/mockpro/internal/model/globalmail.go +++ b/admin/apps/mockpro/internal/model/globalmail.go @@ -21,3 +21,7 @@ type GlobalMail struct { UpdatedAt time.Time DeletedAt gorm.DeletedAt `gorm:"index"` } + +func (lm *GlobalMail) TableName() string { + return "mock_mailglobal" +} diff --git a/admin/apps/mockpro/internal/model/notice.go b/admin/apps/mockpro/internal/model/notice.go index 83e43bf..ade239d 100644 --- a/admin/apps/mockpro/internal/model/notice.go +++ b/admin/apps/mockpro/internal/model/notice.go @@ -21,3 +21,7 @@ type Notice struct { UpdatedAt time.Time DeletedAt gorm.DeletedAt `gorm:"index"` } + +func (lm *Notice) TableName() string { + return "mock_notice" +} diff --git a/admin/apps/mockpro/internal/model/order.go b/admin/apps/mockpro/internal/model/order.go index 9274538..21a988e 100644 --- a/admin/apps/mockpro/internal/model/order.go +++ b/admin/apps/mockpro/internal/model/order.go @@ -22,3 +22,7 @@ type Order struct { UpdatedAt time.Time DeletedAt gorm.DeletedAt `gorm:"index"` } + +func (lm *Order) TableName() string { + return "mock_order" +} diff --git a/admin/apps/mockpro/internal/model/rewardcode.go b/admin/apps/mockpro/internal/model/rewardcode.go index 393a8fb..f823095 100644 --- a/admin/apps/mockpro/internal/model/rewardcode.go +++ b/admin/apps/mockpro/internal/model/rewardcode.go @@ -19,3 +19,7 @@ type RewardCode struct { UpdatedAt time.Time DeletedAt gorm.DeletedAt `gorm:"index"` } + +func (lm *RewardCode) TableName() string { + return "mock_rewardcode" +} diff --git a/admin/apps/mockpro/internal/model/role.go b/admin/apps/mockpro/internal/model/role.go index 7af6a99..b86183a 100644 --- a/admin/apps/mockpro/internal/model/role.go +++ b/admin/apps/mockpro/internal/model/role.go @@ -20,3 +20,7 @@ type Role struct { UpdatedAt time.Time DeletedAt gorm.DeletedAt `gorm:"index"` } + +func (lm *Role) TableName() string { + return "mock_role" +} diff --git a/admin/apps/mockpro/internal/model/rolemail.go b/admin/apps/mockpro/internal/model/rolemail.go index 3e946a2..2b65467 100644 --- a/admin/apps/mockpro/internal/model/rolemail.go +++ b/admin/apps/mockpro/internal/model/rolemail.go @@ -28,3 +28,7 @@ type RoleMail struct { UpdatedAt time.Time DeletedAt gorm.DeletedAt `gorm:"index"` } + +func (lm *RoleMail) TableName() string { + return "mock_mailrole" +} diff --git a/admin/apps/mockpro/internal/model/whitelist.go b/admin/apps/mockpro/internal/model/whitelist.go index 14bda69..09cb741 100644 --- a/admin/apps/mockpro/internal/model/whitelist.go +++ b/admin/apps/mockpro/internal/model/whitelist.go @@ -20,3 +20,7 @@ type WhiteList struct { UpdatedAt time.Time DeletedAt gorm.DeletedAt `gorm:"index"` } + +func (lm *WhiteList) TableName() string { + return "mock_whitelist" +} diff --git a/admin/apps/mockpro/server/route.go b/admin/apps/mockpro/server/route.go index 257a79e..03afda2 100644 --- a/admin/apps/mockpro/server/route.go +++ b/admin/apps/mockpro/server/route.go @@ -2,7 +2,7 @@ package server import ( "admin/apps/mockpro/internal/model/dto" - "admin/internal/global" + "admin/internal/consts" "admin/lib/web" ) @@ -20,7 +20,7 @@ func (srv *Server) Route(engine *web.Engine) { srv.rewardcode(apiGroup) srv.devicepush(apiGroup) } - apiGroup.Get("/commandlist", "获取项目所有gm指令描述", global.WebPathPermit_Read, srv.commandlist) + apiGroup.Get("/commandlist", "获取项目所有gm指令描述", consts.WebPathPermit_Read, srv.commandlist) } func (srv *Server) whitelist(engine *web.RoutesGroup) { @@ -74,10 +74,10 @@ func (srv *Server) devicepush(engine *web.RoutesGroup) { } func (srv *Server) registerResourceRouter(resourceName string, group *web.RoutesGroup) { - group.Get("", "获取列表", global.WebPathPermit_Read, commonHandlerList(srv.ctl, resourceName)) - group.Post("", "新增", global.WebPathPermit_Read, commonHandlerPost(srv.ctl, resourceName)) - group.Put("", "修改", global.WebPathPermit_Read, commonHandlerPut(srv.ctl, resourceName)) - group.Delete("", "删除", global.WebPathPermit_Read, commonHandlerDelete(srv.ctl, resourceName)) + group.Get("", "获取列表", consts.WebPathPermit_Read, commonHandlerList(srv.ctl, resourceName)) + group.Post("", "新增", consts.WebPathPermit_Read, commonHandlerPost(srv.ctl, resourceName)) + group.Put("", "修改", consts.WebPathPermit_Read, commonHandlerPut(srv.ctl, resourceName)) + group.Delete("", "删除", consts.WebPathPermit_Read, commonHandlerDelete(srv.ctl, resourceName)) } func commonHandlerList(ctl *controller, resourceName string) func(ctx *WebContext, params *dto.CommonListReq, rsp *dto.CommonListRsp) error { diff --git a/admin/apps/mockpro/server/route_desc.go b/admin/apps/mockpro/server/route_desc.go index fbdcd38..cadf65f 100644 --- a/admin/apps/mockpro/server/route_desc.go +++ b/admin/apps/mockpro/server/route_desc.go @@ -3,6 +3,7 @@ package server import ( "admin/apps/mockpro/internal/model/dto" "admin/lib/web" + "path/filepath" ) type PathInfo struct { @@ -10,6 +11,7 @@ type PathInfo struct { Method string `json:"method"` } type ResourceInfo struct { + Path string `json:"path"` Desc string `json:"desc"` Paths []*PathInfo `json:"paths"` } @@ -19,7 +21,7 @@ type CmdListRsp struct { func (srv *Server) commandlist(ctx *WebContext, req *dto.NilReq, rsp *CmdListRsp) error { paths := make([]*ResourceInfo, 0) - srv.engine.TravelPaths(func(path string, parentDesc string, method string, handlers ...web.HandlerFunc) { + srv.engine.TravelPaths(func(parentPath, parentDesc string, path string, method string, handlers ...web.HandlerFunc) { find := false for _, v := range paths { if v.Desc == parentDesc { @@ -33,6 +35,7 @@ func (srv *Server) commandlist(ctx *WebContext, req *dto.NilReq, rsp *CmdListRsp } if !find { paths = append(paths, &ResourceInfo{ + Path: filepath.Base(parentPath), Desc: parentDesc, Paths: []*PathInfo{ &PathInfo{ diff --git a/admin/internal/consts/consts.go b/admin/internal/consts/consts.go new file mode 100644 index 0000000..df1ab26 --- /dev/null +++ b/admin/internal/consts/consts.go @@ -0,0 +1,35 @@ +package consts + +const ( + RegisteredProjectId_shenmodalu = "smdl" + RegisteredProjectId_shenyu = "sy" + RegisteredProjectId_mt = "mt" +) + +var ( + RegisteredProjects = map[string]struct { + ID string + Name string + }{ + RegisteredProjectId_shenmodalu: {ID: RegisteredProjectId_shenmodalu, Name: "神魔大陆"}, + RegisteredProjectId_shenyu: {ID: RegisteredProjectId_shenyu, Name: "神谕"}, + RegisteredProjectId_mt: {ID: RegisteredProjectId_mt, Name: "MT"}, + } +) + +const ( + ResourcesName_Project = "project" + ResourcesName_Server = "server" + ResourcesName_WhiteList = "whitelist" + ResourcesName_Ban = "ban" + ResourcesName_MailRole = "mail_role" + ResourcesName_MailGlobal = "mail_global" + ResourcesName_Notice = "notice" + ResourcesName_RewardCode = "reward_code" + ResourcesName_DevicePush = "device_push" +) + +const ( + WebPathPermit_Read = 1 + WebPathPermit_Write = 2 +) diff --git a/admin/internal/context/ctx_web.go b/admin/internal/context/ctx_web.go index 1ebfa59..0d7d0d5 100644 --- a/admin/internal/context/ctx_web.go +++ b/admin/internal/context/ctx_web.go @@ -18,6 +18,10 @@ func NewWebContext(rawCtx *gin.Context) web.IContext { return &WebContext{rawCtx: rawCtx} } +func (ctx *WebContext) GinCtx() *gin.Context { + return ctx.rawCtx +} + func (ctx *WebContext) Ok(data any) { if ctx.alreadySetRsp { return @@ -44,7 +48,7 @@ func (ctx *WebContext) Fail(err error) { "msg": msg, "data": "", }) - + ctx.alreadySetRsp = true } diff --git a/admin/internal/db/db.go b/admin/internal/db/db.go index 6a4a445..2c6e94f 100644 --- a/admin/internal/db/db.go +++ b/admin/internal/db/db.go @@ -136,7 +136,7 @@ func autoMigrate(db *gorm.DB, tables ...interface{}) error { // 初始化表 if err := db.AutoMigrate(tables...); err != nil { - return errcode.New(errcode.DBError, "failed to init tables", err) + return errcode.New(errcode.DBError, "failed to init tables:%v", err) } return nil } diff --git a/admin/internal/global/consts.go b/admin/internal/global/consts.go deleted file mode 100644 index 3d58b45..0000000 --- a/admin/internal/global/consts.go +++ /dev/null @@ -1,6 +0,0 @@ -package global - -const ( - WebPathPermit_Read = 1 - WebPathPermit_Write = 2 -) diff --git a/admin/lib/httpclient/client.go b/admin/lib/httpclient/client.go index 6330346..2cdbacb 100644 --- a/admin/lib/httpclient/client.go +++ b/admin/lib/httpclient/client.go @@ -53,7 +53,9 @@ func Request(addr string, method string, body interface{}, resData interface{}) return errcode.New(errcode.ServerError, "数据解析失败:%v", err) } - xlog.Debugf("request url:%v, rsp:%v", removeUrl, string(resBody)) + if len(resBody) < 256 { + xlog.Debugf("request url:%v, rsp:%v", removeUrl, string(resBody)) + } if err = json.Unmarshal(resBody, resData); err != nil { return errcode.New(errcode.ServerError, "数据(%v)格式错误:%v", string(resBody), err) diff --git a/admin/lib/web/desc.go b/admin/lib/web/desc.go index ef6cacb..d10ceab 100644 --- a/admin/lib/web/desc.go +++ b/admin/lib/web/desc.go @@ -39,7 +39,7 @@ func (n *routesNode) addMethod(method string, desc string, permit int, handlers return n } -func (n *routesNode) travel(parentPath string, parentDesc string, travelFun func(parentDesc string, path string, method string, handlers ...HandlerFunc)) { +func (n *routesNode) travel(parentPath string, parentDesc string, travelFun func(parentPath, parentDesc string, path string, method string, handlers ...HandlerFunc)) { curPath := parentPath + n.path curNodeDesc := "" if len(n.methods) > 0 { @@ -48,7 +48,7 @@ func (n *routesNode) travel(parentPath string, parentDesc string, travelFun func curNodeDesc = method.desc continue } - travelFun(curPath, parentDesc, method.method, method.handlers) + travelFun(parentPath, parentDesc, curPath, method.method, method.handlers) } } for _, c := range n.child { diff --git a/admin/lib/web/engine.go b/admin/lib/web/engine.go index 44196ab..47fe26a 100644 --- a/admin/lib/web/engine.go +++ b/admin/lib/web/engine.go @@ -27,7 +27,7 @@ func (e *Engine) Run(addr string) error { return e.rawEngine.Run(addr) } -func (e *Engine) TravelPaths(travelFun func(path string, parentDesc string, method string, handlers ...HandlerFunc)) { +func (e *Engine) TravelPaths(travelFun func(parentPath, parentDesc, path string, method string, handlers ...HandlerFunc)) { for _, c := range e.RoutesGroup.node.child { c.travel("", "", travelFun) } diff --git a/admin/lib/web/routes_group.go b/admin/lib/web/routes_group.go index bbe5ba5..e675c94 100644 --- a/admin/lib/web/routes_group.go +++ b/admin/lib/web/routes_group.go @@ -93,6 +93,10 @@ func getGinHandlerFunWithRequest(newContextFun func(ctx *gin.Context) IContext, rspTo := handlerTo.In(2) rsp := reflect.New(rspTo.Elem()).Interface() rets := reflect.ValueOf(handler).Call([]reflect.Value{reflect.ValueOf(ctx), reflect.ValueOf(params), reflect.ValueOf(rsp)}) + if len(rets) != 1 { + ctx.HandleError(rawCtx.Request.RequestURI, fmt.Errorf("register handler must return error type")) + return + } errInt := rets[0] if errInt.Interface() == nil { ctx.HandleSuccess(rsp) diff --git a/ui/src/api/game_api.js b/ui/src/api/game_api.js index cc55a09..ef6c4df 100644 --- a/ui/src/api/game_api.js +++ b/ui/src/api/game_api.js @@ -1,9 +1,16 @@ import request from '@/utils/request' export function gameApiRequest(url, method, data) { + if (method === "get") { + return request({ + url: url, + method: method, + params: data + }) + } return request({ url: url, method: method, - params: data + data: data }) } diff --git a/ui/src/api/resource.js b/ui/src/api/resource.js index 14b524a..295e85c 100644 --- a/ui/src/api/resource.js +++ b/ui/src/api/resource.js @@ -1,10 +1,17 @@ import request from '@/utils/request' +class InternalResource { + list(url, params) { + this.name = name + } +} + + export function resourceList(url, params) { return request({ url: url, method: 'get', - data: params + params: params }) } diff --git a/ui/src/components/project/op.vue b/ui/src/components/project/op.vue new file mode 100644 index 0000000..b892bbf --- /dev/null +++ b/ui/src/components/project/op.vue @@ -0,0 +1,63 @@ + + + + + \ No newline at end of file diff --git a/ui/src/components/restful/table.vue b/ui/src/components/restful/table.vue index cad8e6e..cd57f78 100644 --- a/ui/src/components/restful/table.vue +++ b/ui/src/components/restful/table.vue @@ -2,23 +2,38 @@ import {ElNotification} from "element-plus"; import {resourceDelete, resourceList, resourcePost, resourcePut} from "@/api/resource.js"; import {ref, toRaw} from "vue"; +import {useRoute} from 'vue-router'; const props = defineProps({ // rows: {}, - resource_url: '', + resource_url: String, row_click_handler: null, }) +const route = useRoute(); + const listRsp = ref({fields_desc: [], rows: []}) -const getListOk = ref(false) -const resource_url = props.resource_url +const listDataOK = ref(false) +const resource_url = props.resource_url !== undefined && props.resource_url !== "" ? props.resource_url : route.query.resource_url; const fieldsDescInfo = ref([]) const rows = ref([]) const rules = ref({}) +const item = ref({ + id: 0, + number: 1, +}) + +console.log("table resource:", resource_url) + const listData = async () => { try { - const rspData = await resourceList(resource_url, {page_no: 0, page_len: 100}); + let listParams = { + page_no: 0, + page_len: 100, + } + console.log("list params:", listParams) + const rspData = await resourceList(resource_url, listParams); listRsp.value = rspData; if (listRsp.value.code !== 200) throw new Error("请求失败,错误码:", listRsp.code); fieldsDescInfo.value = listRsp.value.data.fields_desc @@ -28,9 +43,15 @@ const listData = async () => { for (let i = 0; i < fieldsDescInfo.value.length; i++) { var field = fieldsDescInfo.value[i] dialogAddForm.value[field.key] = '' - if (field.require == true) { + if (field.required == true) { rules.value[field.key] = [{required: true, message: field.name + "不能为空", trigger: "blur"}] } + + if (field.type == "items") { + for (let j = 0; j < rows.value.length; j++) { + rows.value[j].jsonValue = JSON.stringify(rows.value[j][field.key]) + } + } } console.log('await list rsp:', listRsp.value) @@ -38,7 +59,7 @@ const listData = async () => { console.log("await rows:", toRaw(rows.value)) console.log("await rules:", toRaw(rules.value)) - getListOk.value = true + listDataOK.value = true } catch (err) { console.log(err) } finally { @@ -55,7 +76,9 @@ const dialogEditVisible = ref(false) const dialogAddFormRef = ref(null) const dialogEditFormRef = ref(null) -const dialogAddForm = ref({}) +const dialogAddForm = ref({ + ServerIDs: [], +}) const dialogEditForm = ref({}) @@ -63,6 +86,7 @@ const submitAdd = async () => { try { await dialogAddFormRef.value.validate(valid => { if (valid) { + console.log("commit add form:", dialogAddForm.value) resourcePost(resource_url, dialogAddForm.value).then((res) => { ElNotification({ title: "添加结果通知", @@ -71,7 +95,7 @@ const submitAdd = async () => { duration: 4000, "show-close": true, }) - rows.value.push(dialogAddForm.value) + rows.value.push(res.data.dto) dialogAddVisible.value = false }, (err) => { console.log("添加报错:", err) @@ -109,7 +133,7 @@ const submitEdit = async () => { } } -const handleEdit = (oper, index, row) => { +const handleEdit = (index, row) => { dialogEditForm.value.oldData = row dialogEditForm.value.oldIndex = index dialogEditForm.value = row @@ -117,7 +141,7 @@ const handleEdit = (oper, index, row) => { dialogEditVisible.value = true } -const handleDelete = (oper, index, row) => { +const handleDelete = (index, row) => { resourceDelete(resource_url, {id: row.ID}).then((res) => { ElNotification({ title: "删除结果通知", @@ -139,24 +163,63 @@ const tableRowClick = (index, row) => { } } +function addItem(fieldDescInfo) { + if (item.value.id == null || item.value.id == '' || item.value.id < 0) { + ElMessage('请选择道具!') + return; + } + if (item.value.num == null || item.value.num == '' || item.value.num <= 0) { + ElMessage('请输入有效道具数量!') + return; + } + + let d = {id: item.value.id, num: Number(item.value.num)}; + + for (let i = 0; i < fieldDescInfo.choices.length; i++) { + const field = fieldDescInfo.choices[i] + if (field.value === item.value.id) { + d.item_type = field.type + break + } + } + + console.log("add item:", d) + + if (typeof dialogAddForm.value.Attach === typeof "") { + dialogAddForm.value.Attach = []; + } + dialogAddForm.value.Attach.push(d); +} + +function deleteItem(row) { + // 移除该对象 + let number = form.value.Attach.findIndex(item => item === row); + dialogAddForm.value.Attach.splice(number, 1); +} + const handleCloseDialog = () => { dialogAddVisible.value = false dialogEditVisible.value = false - dialogAddForm.value = {} + dialogAddForm.value = { + Attach: [], + } dialogEditForm.value = {} }