optimize
This commit is contained in:
parent
dafa58a5d0
commit
f815590b7c
@ -8,14 +8,14 @@ import (
|
||||
)
|
||||
|
||||
func initFun(app *node.Application) error {
|
||||
svc := service.NewCmdServerSvc(global.GLOB_DB) // 初始化应用服务
|
||||
srv := server.New(svc) // 初始化http服务
|
||||
srv.Route(global.GLOB_API_ENGINE) // 初始化http服务路由
|
||||
svc := service.New(global.GLOB_DB) // 初始化应用服务
|
||||
srv := server.New(svc) // 初始化http服务
|
||||
srv.Route(global.GLOB_API_ENGINE) // 初始化http服务路由
|
||||
return nil
|
||||
}
|
||||
|
||||
func New() *node.ApplicationDescInfo {
|
||||
app := node.NewApplicationDescInfo("user", initFun)
|
||||
app := node.NewApplicationDescInfo("game", initFun)
|
||||
return app
|
||||
}
|
||||
|
||||
|
@ -3,6 +3,7 @@ package entity
|
||||
import (
|
||||
"admin/apps/game/model"
|
||||
"admin/apps/game/model/dto"
|
||||
"math/rand"
|
||||
"reflect"
|
||||
)
|
||||
|
||||
@ -31,13 +32,17 @@ func FromProjectDto(dto dto.CommonDtoValues) *Project {
|
||||
po := et.po
|
||||
|
||||
//to := reflect.TypeOf(po)
|
||||
vo := reflect.ValueOf(po)
|
||||
vo := reflect.ValueOf(po).Elem()
|
||||
to := reflect.TypeOf(po).Elem()
|
||||
|
||||
for k, v := range dto {
|
||||
fo := vo.FieldByName(k)
|
||||
fo.Set(reflect.ValueOf(v))
|
||||
ft, _ := to.FieldByName(k)
|
||||
fo.Set(parseStr2FieldValue(ft, v))
|
||||
}
|
||||
|
||||
et.Id = po.ID
|
||||
|
||||
return et
|
||||
}
|
||||
|
||||
@ -77,7 +82,7 @@ func (et *Project) GetDtoFieldsDescInfo() []*dto.CommonDtoFieldDesc {
|
||||
Type: ft.Type.Name(),
|
||||
HelpText: ft.Tag.Get("desc"),
|
||||
Editable: true,
|
||||
Require: true,
|
||||
Require: rand.Int()%2 == 0,
|
||||
Choices: make([]*dto.CommonDtoFieldChoice, 0),
|
||||
MultiChoice: false,
|
||||
}
|
||||
|
@ -38,6 +38,8 @@ func FromServerDto(dto dto.CommonDtoValues) *Server {
|
||||
fo.Set(reflect.ValueOf(v))
|
||||
}
|
||||
|
||||
et.Id = po.ID
|
||||
|
||||
return et
|
||||
}
|
||||
|
||||
|
68
admin/apps/game/domain/entity/utils.go
Normal file
68
admin/apps/game/domain/entity/utils.go
Normal file
@ -0,0 +1,68 @@
|
||||
package entity
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"gorm.io/gorm"
|
||||
"reflect"
|
||||
"strconv"
|
||||
"time"
|
||||
)
|
||||
|
||||
func parseStr2FieldValue(field reflect.StructField, rawValue any) (realSetValue reflect.Value) {
|
||||
setValue := fmt.Sprintf("%v", rawValue)
|
||||
var parsedValue any
|
||||
switch field.Type.Kind() {
|
||||
case reflect.Int:
|
||||
v, _ := strconv.Atoi(setValue)
|
||||
parsedValue = int(v)
|
||||
case reflect.Int32:
|
||||
v, _ := strconv.Atoi(setValue)
|
||||
parsedValue = int32(v)
|
||||
case reflect.Int8:
|
||||
v, _ := strconv.Atoi(setValue)
|
||||
parsedValue = int8(v)
|
||||
case reflect.Int16:
|
||||
v, _ := strconv.Atoi(setValue)
|
||||
parsedValue = int16(v)
|
||||
case reflect.Int64:
|
||||
v, _ := strconv.Atoi(setValue)
|
||||
parsedValue = int64(v)
|
||||
case reflect.Uint:
|
||||
v, _ := strconv.Atoi(setValue)
|
||||
parsedValue = uint(v)
|
||||
case reflect.Uint8:
|
||||
v, _ := strconv.Atoi(setValue)
|
||||
parsedValue = uint(v)
|
||||
case reflect.Uint16:
|
||||
v, _ := strconv.Atoi(setValue)
|
||||
parsedValue = uint16(v)
|
||||
case reflect.Uint32:
|
||||
v, _ := strconv.Atoi(setValue)
|
||||
parsedValue = uint32(v)
|
||||
case reflect.Uint64:
|
||||
v, _ := strconv.Atoi(setValue)
|
||||
parsedValue = uint64(v)
|
||||
case reflect.Bool:
|
||||
parsedValue = setValue == "true"
|
||||
case reflect.String:
|
||||
parsedValue = setValue
|
||||
case reflect.Float32:
|
||||
v, _ := strconv.ParseFloat(setValue, 10)
|
||||
parsedValue = float32(v)
|
||||
case reflect.Float64:
|
||||
v, _ := strconv.ParseFloat(setValue, 10)
|
||||
parsedValue = float64(v)
|
||||
case reflect.Struct:
|
||||
typeName := field.Type.Name()
|
||||
if typeName == "Time" {
|
||||
return reflect.ValueOf(time.Now())
|
||||
}
|
||||
if typeName == "DeletedAt" {
|
||||
return reflect.ValueOf(gorm.DeletedAt{})
|
||||
}
|
||||
fallthrough
|
||||
default:
|
||||
panic(fmt.Errorf("暂时不支持的前后端交互字段类型:%v, 类型名:%v", field.Type.Kind(), field.Type.Name()))
|
||||
}
|
||||
return reflect.ValueOf(parsedValue)
|
||||
}
|
@ -34,12 +34,12 @@ func (repo *projectRepoImpl) List(pageNo, pageLen int) ([]*entity.Project, error
|
||||
}
|
||||
|
||||
// debug
|
||||
list = append(list, &model.Project{
|
||||
ID: 123,
|
||||
Name: "神魔大陆",
|
||||
Desc: "神魔大陆服务器",
|
||||
ApiAddr: "http://192.168.1.1:8081",
|
||||
})
|
||||
//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 {
|
||||
|
@ -31,3 +31,8 @@ type CommonDtoList struct {
|
||||
FieldsDesc []*CommonDtoFieldDesc `json:"fields_desc"` // 数据字段描述信息
|
||||
Rows []CommonDtoValues `json:"rows"` // 数据行
|
||||
}
|
||||
|
||||
type PathInfo struct {
|
||||
Path string `json:"path"`
|
||||
Method string `json:"method"`
|
||||
}
|
||||
|
45
admin/apps/game/model/dto/msg.go
Normal file
45
admin/apps/game/model/dto/msg.go
Normal file
@ -0,0 +1,45 @@
|
||||
package dto
|
||||
|
||||
type NilReq struct {
|
||||
}
|
||||
|
||||
type NilRsp = NilReq
|
||||
|
||||
type CommonListReq struct {
|
||||
PageNo int `json:"page_no"`
|
||||
PageLen int `json:"page_len"`
|
||||
}
|
||||
|
||||
type CommonPostReq struct {
|
||||
Dto *CommonDtoValues `json:"dto"`
|
||||
}
|
||||
|
||||
type CommonPutReq struct {
|
||||
Dto *CommonDtoValues `json:"dto"`
|
||||
}
|
||||
|
||||
type CommonDeleteReq struct {
|
||||
Id int `json:"id"`
|
||||
}
|
||||
|
||||
type CommonListRsp = CommonDtoList
|
||||
|
||||
type CommonPostRsp struct {
|
||||
Dto *CommonDtoValues `json:"dto"`
|
||||
}
|
||||
|
||||
type CommonPutRsp struct {
|
||||
Dto *CommonDtoValues `json:"dto"`
|
||||
}
|
||||
|
||||
type CommonDeleteRsp struct {
|
||||
Id int `json:"id"`
|
||||
}
|
||||
|
||||
type CommandListReq struct {
|
||||
Addr string `json:"addr"`
|
||||
}
|
||||
|
||||
type CommandListRsp struct {
|
||||
List []*PathInfo `json:"list"`
|
||||
}
|
@ -1,3 +0,0 @@
|
||||
package dto
|
||||
|
||||
type CommonListRsp = CommonDtoList
|
@ -5,38 +5,37 @@ import (
|
||||
"admin/internal/context"
|
||||
)
|
||||
|
||||
func (ctl *controller) CommonList(ctx *context.WebContext, restfulResourceName string, params *dto.CommonListReq) {
|
||||
func (ctl *controller) CommonList(ctx *context.WebContext, restfulResourceName string, params *dto.CommonListReq, rsp *dto.CommonListRsp) error {
|
||||
list, err := ctl.svc.CommonList(ctx, restfulResourceName, params)
|
||||
if err != nil {
|
||||
ctx.Fail(err)
|
||||
return
|
||||
return err
|
||||
}
|
||||
ctx.Ok(list)
|
||||
*rsp = *list
|
||||
return nil
|
||||
}
|
||||
|
||||
func (ctl *controller) CommonPost(ctx *context.WebContext, restfulResourceName string, params *dto.CommonDtoValues) {
|
||||
newObj, err := ctl.svc.CommonPost(ctx, restfulResourceName, *params)
|
||||
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)
|
||||
if err != nil {
|
||||
ctx.Fail(err)
|
||||
return
|
||||
return err
|
||||
}
|
||||
ctx.Ok(newObj)
|
||||
rsp.Dto = &newObj
|
||||
return nil
|
||||
}
|
||||
|
||||
func (ctl *controller) CommonPut(ctx *context.WebContext, restfulResourceName string, params *dto.CommonDtoValues) {
|
||||
newObj, err := ctl.svc.CommonPut(ctx, restfulResourceName, *params)
|
||||
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)
|
||||
if err != nil {
|
||||
ctx.Fail(err)
|
||||
return
|
||||
return err
|
||||
}
|
||||
ctx.Ok(newObj)
|
||||
rsp.Dto = &newObj
|
||||
return nil
|
||||
}
|
||||
|
||||
func (ctl *controller) CommonDelete(ctx *context.WebContext, restfulResourceName string, id int) {
|
||||
err := ctl.svc.CommonDelete(ctx, restfulResourceName, id)
|
||||
func (ctl *controller) CommonDelete(ctx *context.WebContext, restfulResourceName string, params *dto.CommonDeleteReq, rsp *dto.CommonDeleteRsp) error {
|
||||
err := ctl.svc.CommonDelete(ctx, restfulResourceName, params.Id)
|
||||
if err != nil {
|
||||
ctx.Fail(err)
|
||||
return
|
||||
return err
|
||||
}
|
||||
ctx.Ok(nil)
|
||||
return nil
|
||||
}
|
||||
|
31
admin/apps/game/server/ctl_game.go
Normal file
31
admin/apps/game/server/ctl_game.go
Normal file
@ -0,0 +1,31 @@
|
||||
package server
|
||||
|
||||
import (
|
||||
"admin/apps/game/model/dto"
|
||||
"admin/internal/context"
|
||||
"admin/lib/httpclient"
|
||||
"admin/lib/xlog"
|
||||
)
|
||||
|
||||
func (ctl *controller) CommandList(ctx *context.WebContext, params *dto.CommandListReq, rsp *dto.CommandListRsp) error {
|
||||
|
||||
url := params.Addr + "/api/commandlist"
|
||||
|
||||
xlog.Debugf("request url:%v command list", url)
|
||||
|
||||
cmdListRsp := make(map[string]any)
|
||||
err := httpclient.Request(url, "get", nil, &cmdListRsp)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
xlog.Debugf("command list rsp:%+v", cmdListRsp)
|
||||
|
||||
ctx.Ok(cmdListRsp)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (ctl *controller) apiRequest() {
|
||||
|
||||
}
|
@ -3,55 +3,57 @@ package server
|
||||
import (
|
||||
"admin/apps/game/model/dto"
|
||||
"admin/internal/context"
|
||||
"admin/internal/global"
|
||||
"admin/lib/web"
|
||||
)
|
||||
|
||||
func (srv *Server) Route(engine *web.Engine) {
|
||||
apiGroup := engine.Group("/api")
|
||||
apiGroup := engine.Group("/api", "")
|
||||
srv.proRoute(apiGroup)
|
||||
srv.serverRoute(apiGroup)
|
||||
|
||||
{
|
||||
apiGroup.Get("/project/commandlist", "调用对应游戏服api获取命令列表", global.WebPathPermit_Read, srv.ctl.CommandList)
|
||||
}
|
||||
}
|
||||
|
||||
func (srv *Server) proRoute(engine *web.Group) {
|
||||
func (srv *Server) proRoute(engine *web.RoutesGroup) {
|
||||
resourceName := "project"
|
||||
proGroup := engine.Group("/" + resourceName)
|
||||
|
||||
proGroup.Get("", "获取项目列表", web.AccessMode_Read, dto.CommonListReq{}, commonHandlerList(srv.ctl, resourceName))
|
||||
proGroup.Post("", "新增项目", web.AccessMode_Read, dto.CommonPostReq{}, commonHandlerList(srv.ctl, resourceName))
|
||||
proGroup.Put("", "修改项目", web.AccessMode_Read, dto.CommonPutReq{}, commonHandlerList(srv.ctl, resourceName))
|
||||
proGroup.Delete("", "删除项目", web.AccessMode_Read, dto.CommonDeleteReq{}, commonHandlerList(srv.ctl, resourceName))
|
||||
srv.registerResourceRouter(resourceName, engine.Group("/"+resourceName, ""))
|
||||
}
|
||||
|
||||
func (srv *Server) serverRoute(engine *web.Group) {
|
||||
func (srv *Server) serverRoute(engine *web.RoutesGroup) {
|
||||
resourceName := "server"
|
||||
proGroup := engine.Group("/" + resourceName)
|
||||
|
||||
proGroup.Get("", "获取服务器列表", web.AccessMode_Read, dto.CommonListReq{}, commonHandlerList(srv.ctl, resourceName))
|
||||
proGroup.Post("", "新增服务器", web.AccessMode_Read, dto.CommonPostReq{}, commonHandlerList(srv.ctl, resourceName))
|
||||
proGroup.Put("", "修改服务器", web.AccessMode_Read, dto.CommonPutReq{}, commonHandlerList(srv.ctl, resourceName))
|
||||
proGroup.Delete("", "删除服务器", web.AccessMode_Read, dto.CommonDeleteReq{}, commonHandlerList(srv.ctl, resourceName))
|
||||
srv.registerResourceRouter(resourceName, engine.Group("/"+resourceName, ""))
|
||||
}
|
||||
|
||||
func commonHandlerList(ctl *controller, resourceName string) func(ctx *context.WebContext, params *dto.CommonListReq) {
|
||||
return func(ctx *context.WebContext, params *dto.CommonListReq) {
|
||||
ctl.CommonList(ctx, resourceName, params)
|
||||
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) {
|
||||
return func(ctx *context.WebContext, params *dto.CommonPostReq) {
|
||||
ctl.CommonPost(ctx, resourceName, params.Dto)
|
||||
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) {
|
||||
return func(ctx *context.WebContext, params *dto.CommonPutReq) {
|
||||
ctl.CommonPut(ctx, resourceName, params.Dto)
|
||||
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) {
|
||||
return func(ctx *context.WebContext, params *dto.CommonDeleteReq) {
|
||||
ctl.CommonDelete(ctx, resourceName, params.Id)
|
||||
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)
|
||||
}
|
||||
}
|
||||
|
@ -13,7 +13,7 @@ type Service struct {
|
||||
serverSvc *domain.ServerSvc
|
||||
}
|
||||
|
||||
func NewCmdServerSvc(db *gorm.DB) *Service {
|
||||
func New(db *gorm.DB) *Service {
|
||||
return &Service{
|
||||
db: db,
|
||||
projectSvc: domain.NewProjectSvc(db),
|
||||
|
28
admin/apps/mockpro/boot.go
Normal file
28
admin/apps/mockpro/boot.go
Normal file
@ -0,0 +1,28 @@
|
||||
package mockpro
|
||||
|
||||
import (
|
||||
internalGlobal "admin/apps/mockpro/internal/global"
|
||||
"admin/apps/mockpro/server"
|
||||
"admin/apps/mockpro/service"
|
||||
"admin/internal/global"
|
||||
"admin/lib/node"
|
||||
)
|
||||
|
||||
func initFun(app *node.Application) error {
|
||||
internalGlobal.GLOB_DB = global.GLOB_DB
|
||||
svc := service.New(global.GLOB_DB)
|
||||
server.New(svc) // 初始化http服务
|
||||
return nil
|
||||
}
|
||||
|
||||
func New() *node.ApplicationDescInfo {
|
||||
app := node.NewApplicationDescInfo("mock_project", initFun).
|
||||
WithOptions(node.WithAppBootFlag(internalGlobal.GLOB_BOOT_FLAGS))
|
||||
return app
|
||||
}
|
||||
|
||||
func must(err error) {
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}
|
48
admin/apps/mockpro/domain/ban.go
Normal file
48
admin/apps/mockpro/domain/ban.go
Normal file
@ -0,0 +1,48 @@
|
||||
package domain
|
||||
|
||||
import (
|
||||
"admin/apps/mockpro/domain/entity"
|
||||
"admin/apps/mockpro/domain/repo"
|
||||
"admin/apps/mockpro/internal/model/dto"
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
|
||||
type BanSvc struct {
|
||||
BanRepo repo.IBanRepo
|
||||
}
|
||||
|
||||
func NewBanSvc(db *gorm.DB) *BanSvc {
|
||||
svc := &BanSvc{
|
||||
BanRepo: repo.NewBanRepo(db),
|
||||
}
|
||||
registerRestfulSvc("ban", svc)
|
||||
return svc
|
||||
}
|
||||
|
||||
func (svc *BanSvc) List(pageNo, pageLen int) ([]*dto.CommonDtoFieldDesc, []IRestfulEntity, error) {
|
||||
entityList, err := svc.BanRepo.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.BanDtoFieldsDescInfo, iList, nil
|
||||
}
|
||||
|
||||
func (svc *BanSvc) Post(obj dto.CommonDtoValues) (IRestfulEntity, error) {
|
||||
et := entity.FromBanDto(obj)
|
||||
err := svc.BanRepo.Create(et)
|
||||
return et, err
|
||||
}
|
||||
|
||||
func (svc *BanSvc) Put(obj dto.CommonDtoValues) (IRestfulEntity, error) {
|
||||
et := entity.FromBanDto(obj)
|
||||
err := svc.BanRepo.Edit(et)
|
||||
return et, err
|
||||
}
|
||||
|
||||
func (svc *BanSvc) Delete(id int) error {
|
||||
return svc.BanRepo.Delete(id)
|
||||
}
|
89
admin/apps/mockpro/domain/entity/server.go
Normal file
89
admin/apps/mockpro/domain/entity/server.go
Normal file
@ -0,0 +1,89 @@
|
||||
package entity
|
||||
|
||||
import (
|
||||
"admin/apps/mockpro/internal/model"
|
||||
"admin/apps/mockpro/internal/model/dto"
|
||||
"reflect"
|
||||
)
|
||||
|
||||
var BanDtoFieldsDescInfo = DefaultBan().GetDtoFieldsDescInfo()
|
||||
|
||||
type Ban struct {
|
||||
Id int
|
||||
po *model.Ban
|
||||
}
|
||||
|
||||
func DefaultBan() *Ban {
|
||||
return &Ban{
|
||||
po: &model.Ban{},
|
||||
}
|
||||
}
|
||||
|
||||
func FromBanPo(po *model.Ban) *Ban {
|
||||
return &Ban{
|
||||
Id: po.ID,
|
||||
po: po,
|
||||
}
|
||||
}
|
||||
|
||||
func FromBanDto(dto dto.CommonDtoValues) *Ban {
|
||||
et := DefaultBan()
|
||||
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))
|
||||
}
|
||||
|
||||
return et
|
||||
}
|
||||
|
||||
func (et *Ban) ToPo() *model.Ban {
|
||||
return et.po
|
||||
}
|
||||
|
||||
func (et *Ban) 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 *Ban) 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
|
||||
}
|
89
admin/apps/mockpro/domain/entity/whitelist.go
Normal file
89
admin/apps/mockpro/domain/entity/whitelist.go
Normal file
@ -0,0 +1,89 @@
|
||||
package entity
|
||||
|
||||
import (
|
||||
"admin/apps/mockpro/internal/model"
|
||||
"admin/apps/mockpro/internal/model/dto"
|
||||
"reflect"
|
||||
)
|
||||
|
||||
var WhiteListDtoFieldsDescInfo = DefaultWhiteList().GetDtoFieldsDescInfo()
|
||||
|
||||
type WhiteList struct {
|
||||
Id int
|
||||
po *model.WhiteList
|
||||
}
|
||||
|
||||
func DefaultWhiteList() *WhiteList {
|
||||
return &WhiteList{
|
||||
po: &model.WhiteList{},
|
||||
}
|
||||
}
|
||||
|
||||
func FromWhiteListPo(po *model.WhiteList) *WhiteList {
|
||||
return &WhiteList{
|
||||
Id: po.ID,
|
||||
po: po,
|
||||
}
|
||||
}
|
||||
|
||||
func FromWhiteListDto(dto dto.CommonDtoValues) *WhiteList {
|
||||
et := DefaultWhiteList()
|
||||
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))
|
||||
}
|
||||
|
||||
return et
|
||||
}
|
||||
|
||||
func (et *WhiteList) ToPo() *model.WhiteList {
|
||||
return et.po
|
||||
}
|
||||
|
||||
func (et *WhiteList) 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 *WhiteList) 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
|
||||
}
|
31
admin/apps/mockpro/domain/irestfull.go
Normal file
31
admin/apps/mockpro/domain/irestfull.go
Normal file
@ -0,0 +1,31 @@
|
||||
package domain
|
||||
|
||||
import (
|
||||
"admin/apps/mockpro/internal/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
|
||||
}
|
69
admin/apps/mockpro/domain/repo/ban.go
Normal file
69
admin/apps/mockpro/domain/repo/ban.go
Normal file
@ -0,0 +1,69 @@
|
||||
package repo
|
||||
|
||||
import (
|
||||
"admin/apps/mockpro/domain/entity"
|
||||
"admin/apps/mockpro/internal/model"
|
||||
"admin/internal/errcode"
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
|
||||
type IBanRepo interface {
|
||||
List(pageNo, pageLen int) ([]*entity.Ban, error)
|
||||
Create(et *entity.Ban) error
|
||||
Edit(et *entity.Ban) error
|
||||
Delete(id int) error
|
||||
}
|
||||
|
||||
func NewBanRepo(db *gorm.DB) IBanRepo {
|
||||
return newBanRepoImpl(db)
|
||||
}
|
||||
|
||||
type BanRepoImpl struct {
|
||||
db *gorm.DB
|
||||
}
|
||||
|
||||
func newBanRepoImpl(db *gorm.DB) *BanRepoImpl {
|
||||
return &BanRepoImpl{db: db}
|
||||
}
|
||||
|
||||
func (repo *BanRepoImpl) List(pageNo, pageLen int) ([]*entity.Ban, error) {
|
||||
list := make([]*model.Ban, 0)
|
||||
err := repo.db.Find(&list).Error
|
||||
if err != nil {
|
||||
return nil, errcode.New(errcode.DBError, "find Ban error:%v", err)
|
||||
}
|
||||
|
||||
entityList := make([]*entity.Ban, 0, len(list))
|
||||
for _, Ban := range list {
|
||||
entityList = append(entityList, entity.FromBanPo(Ban))
|
||||
}
|
||||
|
||||
return entityList, nil
|
||||
}
|
||||
|
||||
func (repo *BanRepoImpl) Create(et *entity.Ban) 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 *BanRepoImpl) Edit(et *entity.Ban) 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 *BanRepoImpl) Delete(id int) error {
|
||||
err := repo.db.Where("id=?", id).Unscoped().Delete(&model.Ban{}).Error
|
||||
if err != nil {
|
||||
return errcode.New(errcode.DBError, "delete obj:%+v error:%v", id, err)
|
||||
}
|
||||
return nil
|
||||
}
|
69
admin/apps/mockpro/domain/repo/whitelist.go
Normal file
69
admin/apps/mockpro/domain/repo/whitelist.go
Normal file
@ -0,0 +1,69 @@
|
||||
package repo
|
||||
|
||||
import (
|
||||
"admin/apps/mockpro/domain/entity"
|
||||
"admin/apps/mockpro/internal/model"
|
||||
"admin/internal/errcode"
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
|
||||
type IWhiteListRepo interface {
|
||||
List(pageNo, pageLen int) ([]*entity.WhiteList, error)
|
||||
Create(et *entity.WhiteList) error
|
||||
Edit(et *entity.WhiteList) error
|
||||
Delete(id int) error
|
||||
}
|
||||
|
||||
func NewWhiteListRepo(db *gorm.DB) IWhiteListRepo {
|
||||
return newWhiteListRepoImpl(db)
|
||||
}
|
||||
|
||||
type WhiteListRepoImpl struct {
|
||||
db *gorm.DB
|
||||
}
|
||||
|
||||
func newWhiteListRepoImpl(db *gorm.DB) *WhiteListRepoImpl {
|
||||
return &WhiteListRepoImpl{db: db}
|
||||
}
|
||||
|
||||
func (repo *WhiteListRepoImpl) List(pageNo, pageLen int) ([]*entity.WhiteList, error) {
|
||||
list := make([]*model.WhiteList, 0)
|
||||
err := repo.db.Find(&list).Error
|
||||
if err != nil {
|
||||
return nil, errcode.New(errcode.DBError, "find WhiteList error:%v", err)
|
||||
}
|
||||
|
||||
entityList := make([]*entity.WhiteList, 0, len(list))
|
||||
for _, WhiteList := range list {
|
||||
entityList = append(entityList, entity.FromWhiteListPo(WhiteList))
|
||||
}
|
||||
|
||||
return entityList, nil
|
||||
}
|
||||
|
||||
func (repo *WhiteListRepoImpl) Create(et *entity.WhiteList) 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 *WhiteListRepoImpl) Edit(et *entity.WhiteList) 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 *WhiteListRepoImpl) Delete(id int) error {
|
||||
err := repo.db.Where("id=?", id).Unscoped().Delete(&model.WhiteList{}).Error
|
||||
if err != nil {
|
||||
return errcode.New(errcode.DBError, "delete obj:%+v error:%v", id, err)
|
||||
}
|
||||
return nil
|
||||
}
|
48
admin/apps/mockpro/domain/whitelist.go
Normal file
48
admin/apps/mockpro/domain/whitelist.go
Normal file
@ -0,0 +1,48 @@
|
||||
package domain
|
||||
|
||||
import (
|
||||
"admin/apps/mockpro/domain/entity"
|
||||
"admin/apps/mockpro/domain/repo"
|
||||
"admin/apps/mockpro/internal/model/dto"
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
|
||||
type WhiteListSvc struct {
|
||||
proRepo repo.IWhiteListRepo
|
||||
}
|
||||
|
||||
func NewWhiteListSvc(db *gorm.DB) *WhiteListSvc {
|
||||
svc := &WhiteListSvc{
|
||||
proRepo: repo.NewWhiteListRepo(db),
|
||||
}
|
||||
registerRestfulSvc("whitelist", svc)
|
||||
return svc
|
||||
}
|
||||
|
||||
func (svc *WhiteListSvc) List(pageNo, pageLen int) ([]*dto.CommonDtoFieldDesc, []IRestfulEntity, error) {
|
||||
entityList, err := svc.proRepo.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.WhiteListDtoFieldsDescInfo, iList, nil
|
||||
}
|
||||
|
||||
func (svc *WhiteListSvc) Post(obj dto.CommonDtoValues) (IRestfulEntity, error) {
|
||||
et := entity.FromWhiteListDto(obj)
|
||||
err := svc.proRepo.Create(et)
|
||||
return et, err
|
||||
}
|
||||
|
||||
func (svc *WhiteListSvc) Put(obj dto.CommonDtoValues) (IRestfulEntity, error) {
|
||||
et := entity.FromWhiteListDto(obj)
|
||||
err := svc.proRepo.Edit(et)
|
||||
return et, err
|
||||
}
|
||||
|
||||
func (svc *WhiteListSvc) Delete(id int) error {
|
||||
return svc.proRepo.Delete(id)
|
||||
}
|
5
admin/apps/mockpro/internal/config/flags.go
Normal file
5
admin/apps/mockpro/internal/config/flags.go
Normal file
@ -0,0 +1,5 @@
|
||||
package config
|
||||
|
||||
type MockBootFlags struct {
|
||||
ApiPort string `env:"mock_api_port" default:"8654" desc:"api端口,客户端请求的地址端口"`
|
||||
}
|
11
admin/apps/mockpro/internal/global/var.go
Normal file
11
admin/apps/mockpro/internal/global/var.go
Normal file
@ -0,0 +1,11 @@
|
||||
package global
|
||||
|
||||
import (
|
||||
"admin/apps/mockpro/internal/config"
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
|
||||
var (
|
||||
GLOB_BOOT_FLAGS = &config.MockBootFlags{}
|
||||
GLOB_DB *gorm.DB
|
||||
)
|
20
admin/apps/mockpro/internal/model/account.go
Normal file
20
admin/apps/mockpro/internal/model/account.go
Normal file
@ -0,0 +1,20 @@
|
||||
package model
|
||||
|
||||
import (
|
||||
"admin/internal/db"
|
||||
"gorm.io/gorm"
|
||||
"time"
|
||||
)
|
||||
|
||||
func init() {
|
||||
db.RegisterTableModels(Account{})
|
||||
}
|
||||
|
||||
type Account struct {
|
||||
ID int `gorm:"primarykey"`
|
||||
Account string `gorm:"primarykey"`
|
||||
|
||||
CreatedAt time.Time
|
||||
UpdatedAt time.Time
|
||||
DeletedAt gorm.DeletedAt `gorm:"index"`
|
||||
}
|
22
admin/apps/mockpro/internal/model/ban.go
Normal file
22
admin/apps/mockpro/internal/model/ban.go
Normal file
@ -0,0 +1,22 @@
|
||||
package model
|
||||
|
||||
import (
|
||||
"admin/internal/db"
|
||||
"gorm.io/gorm"
|
||||
"time"
|
||||
)
|
||||
|
||||
func init() {
|
||||
db.RegisterTableModels(Ban{})
|
||||
}
|
||||
|
||||
type Ban struct {
|
||||
ID int `gorm:"primarykey"`
|
||||
BanType string
|
||||
Value string
|
||||
ExpireSeconds int
|
||||
|
||||
CreatedAt time.Time
|
||||
UpdatedAt time.Time
|
||||
DeletedAt gorm.DeletedAt `gorm:"index"`
|
||||
}
|
22
admin/apps/mockpro/internal/model/devicepush.go
Normal file
22
admin/apps/mockpro/internal/model/devicepush.go
Normal file
@ -0,0 +1,22 @@
|
||||
package model
|
||||
|
||||
import (
|
||||
"admin/internal/db"
|
||||
"gorm.io/gorm"
|
||||
"time"
|
||||
)
|
||||
|
||||
func init() {
|
||||
db.RegisterTableModels(DevicePush{})
|
||||
}
|
||||
|
||||
type DevicePush struct {
|
||||
ID int `gorm:"primarykey"`
|
||||
Account string
|
||||
Title string
|
||||
Content string
|
||||
|
||||
CreatedAt time.Time
|
||||
UpdatedAt time.Time
|
||||
DeletedAt gorm.DeletedAt `gorm:"index"`
|
||||
}
|
33
admin/apps/mockpro/internal/model/dto/common.go
Normal file
33
admin/apps/mockpro/internal/model/dto/common.go
Normal file
@ -0,0 +1,33 @@
|
||||
package dto
|
||||
|
||||
type CommonDtoFieldChoice struct {
|
||||
Desc string `json:"desc"`
|
||||
Value any `json:"value"`
|
||||
// 描述选项的类型,例如添加物品时,可以添加道具、翅膀、宠物等,他们可能不一定都设计为道具
|
||||
Type int `json:"type"`
|
||||
}
|
||||
|
||||
type CommonDtoFieldDesc struct {
|
||||
Name string `json:"name"`
|
||||
Key string `json:"key"`
|
||||
// 字段类型,基础类型支持int float string bool []<基础类行>,
|
||||
// 支持自定义类型和自定义类型的数组
|
||||
Type string `json:"type"`
|
||||
HelpText string `json:"help_text"`
|
||||
Editable bool `json:"editable"` // 是否可编辑,例如id就不可编辑,新增时也不需要填写
|
||||
Require bool `json:"require"` // 是否必填,不能为空
|
||||
Choices []*CommonDtoFieldChoice `json:"choices"` // 可选项,用于字段做下拉框
|
||||
MultiChoice bool `json:"multi_choice"` // 是否多选
|
||||
}
|
||||
|
||||
//type CommonDtoValue struct {
|
||||
// FieldName string `json:"field_name"`
|
||||
// Value any `json:"value"`
|
||||
//}
|
||||
|
||||
type CommonDtoValues map[string]any
|
||||
|
||||
type CommonDtoList struct {
|
||||
FieldsDesc []*CommonDtoFieldDesc `json:"fields_desc"` // 数据字段描述信息
|
||||
Rows []CommonDtoValues `json:"rows"` // 数据行
|
||||
}
|
@ -1,5 +1,11 @@
|
||||
package dto
|
||||
|
||||
type NilReq struct {
|
||||
}
|
||||
|
||||
type NilRsp struct {
|
||||
}
|
||||
|
||||
type CommonListReq struct {
|
||||
PageNo int `json:"page_no"`
|
||||
PageLen int `json:"page_len"`
|
||||
@ -16,3 +22,17 @@ type CommonPutReq struct {
|
||||
type CommonDeleteReq struct {
|
||||
Id int `json:"id"`
|
||||
}
|
||||
|
||||
type CommonListRsp = CommonDtoList
|
||||
|
||||
type CommonPostRsp struct {
|
||||
Dto *CommonDtoValues `json:"dto"`
|
||||
}
|
||||
|
||||
type CommonPutRsp struct {
|
||||
Dto *CommonDtoValues `json:"dto"`
|
||||
}
|
||||
|
||||
type CommonDeleteRsp struct {
|
||||
Id int `json:"id"`
|
||||
}
|
23
admin/apps/mockpro/internal/model/globalmail.go
Normal file
23
admin/apps/mockpro/internal/model/globalmail.go
Normal file
@ -0,0 +1,23 @@
|
||||
package model
|
||||
|
||||
import (
|
||||
"admin/internal/db"
|
||||
"gorm.io/gorm"
|
||||
"time"
|
||||
)
|
||||
|
||||
func init() {
|
||||
db.RegisterTableModels(GlobalMail{})
|
||||
}
|
||||
|
||||
type GlobalMail struct {
|
||||
ID int `gorm:"primarykey"`
|
||||
ServerIDs []int `gorm:"type:json;serializer:json"`
|
||||
Title string
|
||||
Content string
|
||||
Attach []*MailAttachItem `gorm:"type:json;serializer:json"`
|
||||
|
||||
CreatedAt time.Time
|
||||
UpdatedAt time.Time
|
||||
DeletedAt gorm.DeletedAt `gorm:"index"`
|
||||
}
|
23
admin/apps/mockpro/internal/model/notice.go
Normal file
23
admin/apps/mockpro/internal/model/notice.go
Normal file
@ -0,0 +1,23 @@
|
||||
package model
|
||||
|
||||
import (
|
||||
"admin/internal/db"
|
||||
"gorm.io/gorm"
|
||||
"time"
|
||||
)
|
||||
|
||||
func init() {
|
||||
db.RegisterTableModels(Notice{})
|
||||
}
|
||||
|
||||
type Notice struct {
|
||||
ID int `gorm:"primarykey"`
|
||||
ServerIDs []int `gorm:"type:json;serializer:json"`
|
||||
Content string
|
||||
StartAt int64
|
||||
EndAt int64
|
||||
|
||||
CreatedAt time.Time
|
||||
UpdatedAt time.Time
|
||||
DeletedAt gorm.DeletedAt `gorm:"index"`
|
||||
}
|
24
admin/apps/mockpro/internal/model/order.go
Normal file
24
admin/apps/mockpro/internal/model/order.go
Normal file
@ -0,0 +1,24 @@
|
||||
package model
|
||||
|
||||
import (
|
||||
"admin/internal/db"
|
||||
"gorm.io/gorm"
|
||||
"time"
|
||||
)
|
||||
|
||||
func init() {
|
||||
db.RegisterTableModels(Order{})
|
||||
}
|
||||
|
||||
type Order struct {
|
||||
ID int `gorm:"primarykey"`
|
||||
RoleID string
|
||||
Account string
|
||||
Price int
|
||||
Currency int
|
||||
GoodID int
|
||||
|
||||
CreatedAt time.Time
|
||||
UpdatedAt time.Time
|
||||
DeletedAt gorm.DeletedAt `gorm:"index"`
|
||||
}
|
21
admin/apps/mockpro/internal/model/rewardcode.go
Normal file
21
admin/apps/mockpro/internal/model/rewardcode.go
Normal file
@ -0,0 +1,21 @@
|
||||
package model
|
||||
|
||||
import (
|
||||
"admin/internal/db"
|
||||
"gorm.io/gorm"
|
||||
"time"
|
||||
)
|
||||
|
||||
func init() {
|
||||
db.RegisterTableModels(RewardCode{})
|
||||
}
|
||||
|
||||
type RewardCode struct {
|
||||
ID int `gorm:"primarykey"`
|
||||
Group int
|
||||
Code int
|
||||
|
||||
CreatedAt time.Time
|
||||
UpdatedAt time.Time
|
||||
DeletedAt gorm.DeletedAt `gorm:"index"`
|
||||
}
|
22
admin/apps/mockpro/internal/model/role.go
Normal file
22
admin/apps/mockpro/internal/model/role.go
Normal file
@ -0,0 +1,22 @@
|
||||
package model
|
||||
|
||||
import (
|
||||
"admin/internal/db"
|
||||
"gorm.io/gorm"
|
||||
"time"
|
||||
)
|
||||
|
||||
func init() {
|
||||
db.RegisterTableModels(Role{})
|
||||
}
|
||||
|
||||
type Role struct {
|
||||
ID int `gorm:"primarykey"`
|
||||
RoleID string
|
||||
Name string
|
||||
Account string `gorm:"primarykey"`
|
||||
|
||||
CreatedAt time.Time
|
||||
UpdatedAt time.Time
|
||||
DeletedAt gorm.DeletedAt `gorm:"index"`
|
||||
}
|
30
admin/apps/mockpro/internal/model/rolemail.go
Normal file
30
admin/apps/mockpro/internal/model/rolemail.go
Normal file
@ -0,0 +1,30 @@
|
||||
package model
|
||||
|
||||
import (
|
||||
"admin/internal/db"
|
||||
"gorm.io/gorm"
|
||||
"time"
|
||||
)
|
||||
|
||||
func init() {
|
||||
db.RegisterTableModels(RoleMail{})
|
||||
}
|
||||
|
||||
type MailAttachItem struct {
|
||||
ID int32
|
||||
Num int64
|
||||
ItemType int
|
||||
}
|
||||
|
||||
type RoleMail struct {
|
||||
ID int `gorm:"primarykey"`
|
||||
RoleIDs string
|
||||
ServerID int
|
||||
Title string
|
||||
Content string
|
||||
Attach []*MailAttachItem `gorm:"type:json;serializer:json"`
|
||||
|
||||
CreatedAt time.Time
|
||||
UpdatedAt time.Time
|
||||
DeletedAt gorm.DeletedAt `gorm:"index"`
|
||||
}
|
22
admin/apps/mockpro/internal/model/whitelist.go
Normal file
22
admin/apps/mockpro/internal/model/whitelist.go
Normal file
@ -0,0 +1,22 @@
|
||||
package model
|
||||
|
||||
import (
|
||||
"admin/internal/db"
|
||||
"gorm.io/gorm"
|
||||
"time"
|
||||
)
|
||||
|
||||
func init() {
|
||||
db.RegisterTableModels(WhiteList{})
|
||||
}
|
||||
|
||||
type WhiteList struct {
|
||||
ID int `gorm:"primarykey"`
|
||||
Account string `gorm:"primarykey"`
|
||||
AccountType int
|
||||
Desc string
|
||||
|
||||
CreatedAt time.Time
|
||||
UpdatedAt time.Time
|
||||
DeletedAt gorm.DeletedAt `gorm:"index"`
|
||||
}
|
11
admin/apps/mockpro/server/ctl.go
Normal file
11
admin/apps/mockpro/server/ctl.go
Normal file
@ -0,0 +1,11 @@
|
||||
package server
|
||||
|
||||
import "admin/apps/mockpro/service"
|
||||
|
||||
type controller struct {
|
||||
svc *service.Service
|
||||
}
|
||||
|
||||
func newController(svc *service.Service) *controller {
|
||||
return &controller{svc: svc}
|
||||
}
|
40
admin/apps/mockpro/server/ctl_mock.go
Normal file
40
admin/apps/mockpro/server/ctl_mock.go
Normal file
@ -0,0 +1,40 @@
|
||||
package server
|
||||
|
||||
import (
|
||||
dto2 "admin/apps/mockpro/internal/model/dto"
|
||||
)
|
||||
|
||||
func (ctl *controller) CommonList(ctx *WebContext, restfulResourceName string, params *dto2.CommonListReq, rsp *dto2.CommonListRsp) error {
|
||||
list, err := ctl.svc.CommonList(ctx, restfulResourceName, params)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
*rsp = *list
|
||||
return nil
|
||||
}
|
||||
|
||||
func (ctl *controller) CommonPost(ctx *WebContext, restfulResourceName string, params *dto2.CommonPostReq, rsp *dto2.CommonPostRsp) error {
|
||||
newObj, err := ctl.svc.CommonPost(ctx, restfulResourceName, *params.Dto)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
rsp.Dto = &newObj
|
||||
return nil
|
||||
}
|
||||
|
||||
func (ctl *controller) CommonPut(ctx *WebContext, restfulResourceName string, params *dto2.CommonPutReq, rsp *dto2.CommonPutRsp) error {
|
||||
newObj, err := ctl.svc.CommonPut(ctx, restfulResourceName, *params.Dto)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
rsp.Dto = &newObj
|
||||
return nil
|
||||
}
|
||||
|
||||
func (ctl *controller) CommonDelete(ctx *WebContext, restfulResourceName string, params *dto2.CommonDeleteReq, rsp *dto2.CommonDeleteRsp) error {
|
||||
err := ctl.svc.CommonDelete(ctx, restfulResourceName, params.Id)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
43
admin/apps/mockpro/server/ctx_web.go
Normal file
43
admin/apps/mockpro/server/ctx_web.go
Normal file
@ -0,0 +1,43 @@
|
||||
package server
|
||||
|
||||
import (
|
||||
"admin/internal/errcode"
|
||||
"admin/lib/web"
|
||||
"context"
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
type WebContext struct {
|
||||
context.Context
|
||||
rawCtx *gin.Context
|
||||
}
|
||||
|
||||
func NewWebContext(rawCtx *gin.Context) web.IContext {
|
||||
return &WebContext{rawCtx: rawCtx}
|
||||
}
|
||||
|
||||
func (ctx *WebContext) Ok(data any) {
|
||||
ctx.rawCtx.JSON(200, map[string]any{
|
||||
"code": 200,
|
||||
"msg": "",
|
||||
"data": data,
|
||||
})
|
||||
}
|
||||
|
||||
func (ctx *WebContext) Fail(err error) {
|
||||
code, stack, msg := errcode.ParseError(err)
|
||||
ctx.rawCtx.JSON(200, map[string]any{
|
||||
"code": code,
|
||||
"stack": stack,
|
||||
"msg": msg,
|
||||
"data": "",
|
||||
})
|
||||
}
|
||||
|
||||
func (ctx *WebContext) HandleError(path string, err error) {
|
||||
ctx.Fail(err)
|
||||
}
|
||||
|
||||
func (ctx *WebContext) HandleSuccess(rspData any) {
|
||||
ctx.Ok(rspData)
|
||||
}
|
105
admin/apps/mockpro/server/route.go
Normal file
105
admin/apps/mockpro/server/route.go
Normal file
@ -0,0 +1,105 @@
|
||||
package server
|
||||
|
||||
import (
|
||||
"admin/apps/mockpro/internal/model/dto"
|
||||
"admin/internal/global"
|
||||
"admin/lib/web"
|
||||
)
|
||||
|
||||
func (srv *Server) Route(engine *web.Engine) {
|
||||
apiGroup := engine.Group("/api", "")
|
||||
{
|
||||
srv.whitelist(apiGroup)
|
||||
srv.ban(apiGroup)
|
||||
srv.rolemail(apiGroup)
|
||||
srv.globalmail(apiGroup)
|
||||
srv.account(apiGroup)
|
||||
srv.role(apiGroup)
|
||||
srv.order(apiGroup)
|
||||
srv.notice(apiGroup)
|
||||
srv.rewardcode(apiGroup)
|
||||
srv.devicepush(apiGroup)
|
||||
}
|
||||
apiGroup.Get("/commandlist", "获取项目所有gm指令描述", global.WebPathPermit_Read, srv.commandlist)
|
||||
}
|
||||
|
||||
func (srv *Server) whitelist(engine *web.RoutesGroup) {
|
||||
resourceName := "whitelist"
|
||||
srv.registerResourceRouter(resourceName, engine.Group("/"+resourceName, "白名单管理"))
|
||||
}
|
||||
|
||||
func (srv *Server) ban(engine *web.RoutesGroup) {
|
||||
resourceName := "ban"
|
||||
srv.registerResourceRouter(resourceName, engine.Group("/"+resourceName, "封禁管理"))
|
||||
}
|
||||
|
||||
func (srv *Server) rolemail(engine *web.RoutesGroup) {
|
||||
resourceName := "rolemail"
|
||||
srv.registerResourceRouter(resourceName, engine.Group("/"+resourceName, "个人邮件"))
|
||||
}
|
||||
|
||||
func (srv *Server) globalmail(engine *web.RoutesGroup) {
|
||||
resourceName := "globalmail"
|
||||
srv.registerResourceRouter(resourceName, engine.Group("/"+resourceName, "全服邮件"))
|
||||
}
|
||||
|
||||
func (srv *Server) account(engine *web.RoutesGroup) {
|
||||
resourceName := "account"
|
||||
srv.registerResourceRouter(resourceName, engine.Group("/"+resourceName, "账号管理"))
|
||||
}
|
||||
|
||||
func (srv *Server) role(engine *web.RoutesGroup) {
|
||||
resourceName := "role"
|
||||
srv.registerResourceRouter(resourceName, engine.Group("/"+resourceName, "角色管理"))
|
||||
}
|
||||
|
||||
func (srv *Server) order(engine *web.RoutesGroup) {
|
||||
resourceName := "order"
|
||||
srv.registerResourceRouter(resourceName, engine.Group("/"+resourceName, "订单管理"))
|
||||
}
|
||||
|
||||
func (srv *Server) notice(engine *web.RoutesGroup) {
|
||||
resourceName := "notice"
|
||||
srv.registerResourceRouter(resourceName, engine.Group("/"+resourceName, "公告管理"))
|
||||
}
|
||||
|
||||
func (srv *Server) rewardcode(engine *web.RoutesGroup) {
|
||||
resourceName := "rewardcode"
|
||||
srv.registerResourceRouter(resourceName, engine.Group("/"+resourceName, "奖励码"))
|
||||
}
|
||||
|
||||
func (srv *Server) devicepush(engine *web.RoutesGroup) {
|
||||
resourceName := "devicepush"
|
||||
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 *WebContext, params *dto.CommonListReq, rsp *dto.CommonListRsp) error {
|
||||
return func(ctx *WebContext, params *dto.CommonListReq, rsp *dto.CommonListRsp) error {
|
||||
return ctl.CommonList(ctx, resourceName, params, rsp)
|
||||
}
|
||||
}
|
||||
|
||||
func commonHandlerPost(ctl *controller, resourceName string) func(ctx *WebContext, params *dto.CommonPostReq, rsp *dto.CommonPostRsp) error {
|
||||
return func(ctx *WebContext, params *dto.CommonPostReq, rsp *dto.CommonPostRsp) error {
|
||||
return ctl.CommonPost(ctx, resourceName, params, rsp)
|
||||
}
|
||||
}
|
||||
|
||||
func commonHandlerPut(ctl *controller, resourceName string) func(ctx *WebContext, params *dto.CommonPutReq, rsp *dto.CommonPutRsp) error {
|
||||
return func(ctx *WebContext, params *dto.CommonPutReq, rsp *dto.CommonPutRsp) error {
|
||||
return ctl.CommonPut(ctx, resourceName, params, rsp)
|
||||
}
|
||||
}
|
||||
|
||||
func commonHandlerDelete(ctl *controller, resourceName string) func(ctx *WebContext, params *dto.CommonDeleteReq, rsp *dto.CommonDeleteRsp) error {
|
||||
return func(ctx *WebContext, params *dto.CommonDeleteReq, rsp *dto.CommonDeleteRsp) error {
|
||||
return ctl.CommonDelete(ctx, resourceName, params, rsp)
|
||||
}
|
||||
}
|
48
admin/apps/mockpro/server/route_desc.go
Normal file
48
admin/apps/mockpro/server/route_desc.go
Normal file
@ -0,0 +1,48 @@
|
||||
package server
|
||||
|
||||
import (
|
||||
"admin/apps/mockpro/internal/model/dto"
|
||||
"admin/lib/web"
|
||||
)
|
||||
|
||||
type PathInfo struct {
|
||||
Path string `json:"path"`
|
||||
Method string `json:"method"`
|
||||
}
|
||||
type ResourceInfo struct {
|
||||
Desc string `json:"desc"`
|
||||
Paths []*PathInfo `json:"paths"`
|
||||
}
|
||||
type CmdListRsp struct {
|
||||
List []*ResourceInfo `json:"list"`
|
||||
}
|
||||
|
||||
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) {
|
||||
find := false
|
||||
for _, v := range paths {
|
||||
if v.Desc == parentDesc {
|
||||
v.Paths = append(v.Paths, &PathInfo{
|
||||
Path: path,
|
||||
Method: method,
|
||||
})
|
||||
find = true
|
||||
break
|
||||
}
|
||||
}
|
||||
if !find {
|
||||
paths = append(paths, &ResourceInfo{
|
||||
Desc: parentDesc,
|
||||
Paths: []*PathInfo{
|
||||
&PathInfo{
|
||||
Path: path,
|
||||
Method: method,
|
||||
},
|
||||
},
|
||||
})
|
||||
}
|
||||
})
|
||||
rsp.List = paths
|
||||
return nil
|
||||
}
|
29
admin/apps/mockpro/server/server.go
Normal file
29
admin/apps/mockpro/server/server.go
Normal file
@ -0,0 +1,29 @@
|
||||
package server
|
||||
|
||||
import (
|
||||
"admin/apps/mockpro/internal/global"
|
||||
"admin/apps/mockpro/service"
|
||||
"admin/lib/web"
|
||||
)
|
||||
|
||||
type Server struct {
|
||||
engine *web.Engine
|
||||
svc *service.Service
|
||||
ctl *controller
|
||||
}
|
||||
|
||||
func New(svc *service.Service) *Server {
|
||||
engine := web.New(NewWebContext)
|
||||
srv := &Server{
|
||||
engine: engine,
|
||||
ctl: newController(svc),
|
||||
}
|
||||
srv.Route(engine)
|
||||
go func() {
|
||||
err := engine.Run(":" + global.GLOB_BOOT_FLAGS.ApiPort)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}()
|
||||
return srv
|
||||
}
|
68
admin/apps/mockpro/service/service.go
Normal file
68
admin/apps/mockpro/service/service.go
Normal file
@ -0,0 +1,68 @@
|
||||
package service
|
||||
|
||||
import (
|
||||
"admin/apps/mockpro/domain"
|
||||
dto2 "admin/apps/mockpro/internal/model/dto"
|
||||
"context"
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
|
||||
type Service struct {
|
||||
db *gorm.DB
|
||||
whitelistSvc *domain.WhiteListSvc
|
||||
banSvc *domain.BanSvc
|
||||
}
|
||||
|
||||
func New(db *gorm.DB) *Service {
|
||||
return &Service{
|
||||
db: db,
|
||||
whitelistSvc: domain.NewWhiteListSvc(db),
|
||||
banSvc: domain.NewBanSvc(db),
|
||||
}
|
||||
}
|
||||
|
||||
func (svc *Service) CommonList(ctx context.Context, resourceName string, params *dto2.CommonListReq) (*dto2.CommonDtoList, error) {
|
||||
restfulDomainSvc, err := domain.FindRestfulResourceSvc(resourceName)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
dtoFieldsDescInfo, list, err := restfulDomainSvc.List(params.PageNo, params.PageLen)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
retList := make([]dto2.CommonDtoValues, 0, len(list))
|
||||
for _, v := range list {
|
||||
retList = append(retList, v.ToCommonDto())
|
||||
}
|
||||
return &dto2.CommonDtoList{FieldsDesc: dtoFieldsDescInfo, Rows: retList}, nil
|
||||
}
|
||||
|
||||
func (svc *Service) CommonPost(ctx context.Context, resourceName string, params dto2.CommonDtoValues) (dto2.CommonDtoValues, error) {
|
||||
restfulDomainSvc, err := domain.FindRestfulResourceSvc(resourceName)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
et, err := restfulDomainSvc.Post(params)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return et.ToCommonDto(), nil
|
||||
}
|
||||
func (svc *Service) CommonPut(ctx context.Context, resourceName string, params dto2.CommonDtoValues) (dto2.CommonDtoValues, error) {
|
||||
restfulDomainSvc, err := domain.FindRestfulResourceSvc(resourceName)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
et, err := restfulDomainSvc.Put(params)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return et.ToCommonDto(), nil
|
||||
}
|
||||
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)
|
||||
}
|
@ -2,6 +2,7 @@ package main
|
||||
|
||||
import (
|
||||
"admin/apps/game"
|
||||
"admin/apps/mockpro"
|
||||
"admin/internal/mynode"
|
||||
"admin/lib/node"
|
||||
)
|
||||
@ -11,6 +12,7 @@ var appList []*node.ApplicationDescInfo
|
||||
func init() {
|
||||
appList = []*node.ApplicationDescInfo{
|
||||
game.New(),
|
||||
mockpro.New(),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -3,41 +3,55 @@ package context
|
||||
import (
|
||||
"admin/internal/errcode"
|
||||
"admin/lib/web"
|
||||
"admin/lib/xlog"
|
||||
"context"
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
type WebContext struct {
|
||||
context.Context
|
||||
rawCtx web.RawContext
|
||||
rawCtx *gin.Context
|
||||
alreadySetRsp bool
|
||||
}
|
||||
|
||||
func NewWebContext() web.Context {
|
||||
return &WebContext{}
|
||||
func NewWebContext(rawCtx *gin.Context) web.IContext {
|
||||
return &WebContext{rawCtx: rawCtx}
|
||||
}
|
||||
|
||||
func (ctx *WebContext) Ok(data any) {
|
||||
ctx.rawCtx.Json(200, map[string]any{
|
||||
if ctx.alreadySetRsp {
|
||||
return
|
||||
}
|
||||
|
||||
ctx.rawCtx.JSON(200, map[string]any{
|
||||
"code": 200,
|
||||
"msg": "",
|
||||
"data": data,
|
||||
})
|
||||
|
||||
ctx.alreadySetRsp = true
|
||||
}
|
||||
|
||||
func (ctx *WebContext) Fail(err error) {
|
||||
if ctx.alreadySetRsp {
|
||||
return
|
||||
}
|
||||
|
||||
code, stack, msg := errcode.ParseError(err)
|
||||
ctx.rawCtx.Json(200, map[string]any{
|
||||
ctx.rawCtx.JSON(200, map[string]any{
|
||||
"code": code,
|
||||
"stack": stack,
|
||||
"msg": msg,
|
||||
"data": "",
|
||||
})
|
||||
|
||||
ctx.alreadySetRsp = true
|
||||
}
|
||||
|
||||
func (ctx *WebContext) SetRawContext(rawCtx web.RawContext) {
|
||||
ctx.Context = context.Background()
|
||||
ctx.rawCtx = rawCtx
|
||||
func (ctx *WebContext) HandleError(path string, err error) {
|
||||
xlog.Errorf("path:%v handle error:%v ", path, err)
|
||||
ctx.Fail(err)
|
||||
}
|
||||
|
||||
func (ctx *WebContext) GetRawContext() web.RawContext {
|
||||
return ctx.rawCtx
|
||||
func (ctx *WebContext) HandleSuccess(rspData any) {
|
||||
ctx.Ok(rspData)
|
||||
}
|
||||
|
@ -118,7 +118,7 @@ func tryCreateDB(dbName, dsn string) (string, error) {
|
||||
db.Raw("SELECT COUNT(*) FROM information_schema.schemata WHERE schema_name = ?", dbName).Scan(&count)
|
||||
if count == 0 {
|
||||
// 数据库不存在,创建它
|
||||
sql := fmt.Sprintf(`create database if not exists %s default charset utf8mb4 collate utf8mb4_unicode_ci`,
|
||||
sql := fmt.Sprintf("create database if not exists `%s` default charset utf8mb4 collate utf8mb4_unicode_ci",
|
||||
dbName)
|
||||
if e := db.Exec(sql).Error; e != nil {
|
||||
return "", fmt.Errorf("failed to create database:%v", e)
|
||||
|
6
admin/internal/global/consts.go
Normal file
6
admin/internal/global/consts.go
Normal file
@ -0,0 +1,6 @@
|
||||
package global
|
||||
|
||||
const (
|
||||
WebPathPermit_Read = 1
|
||||
WebPathPermit_Write = 2
|
||||
)
|
@ -14,7 +14,7 @@ func New() *node.Node {
|
||||
nd.ApplyOptions(node.WithNodeExBootFlags(global.GLOB_BOOT_FLAGS))
|
||||
|
||||
nd.AddInitTask("初始化全局api监听服务", func() error {
|
||||
global.GLOB_API_ENGINE = web.NewEngine("gin", context.NewWebContext)
|
||||
global.GLOB_API_ENGINE = web.New(context.NewWebContext)
|
||||
return nil
|
||||
})
|
||||
|
||||
|
73
admin/lib/httpclient/client.go
Normal file
73
admin/lib/httpclient/client.go
Normal file
@ -0,0 +1,73 @@
|
||||
package httpclient
|
||||
|
||||
import (
|
||||
"admin/internal/errcode"
|
||||
"admin/lib/xlog"
|
||||
"encoding/json"
|
||||
"io"
|
||||
"net/http"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
func Request(addr string, method string, body interface{}, resData interface{}) error {
|
||||
removeUrl := checkUrl(addr)
|
||||
|
||||
//xlog.Debugf("-->req url: %v", removeUrl)
|
||||
var res *http.Response
|
||||
var err error
|
||||
if method != "get" {
|
||||
var bodyReader io.Reader
|
||||
if body != nil {
|
||||
bodyBytes, err := json.Marshal(body)
|
||||
if err != nil {
|
||||
xlog.Warnf(err)
|
||||
return errcode.New(errcode.ServerError, "数据解析失败:%v", err)
|
||||
}
|
||||
bodyReader = strings.NewReader(string(bodyBytes))
|
||||
}
|
||||
client := &http.Client{
|
||||
Timeout: time.Second * 3,
|
||||
}
|
||||
req, err := http.NewRequest(method, removeUrl, bodyReader)
|
||||
if err != nil {
|
||||
xlog.Warnf(err)
|
||||
return errcode.New(errcode.ServerError, "数据请求创建失败:%v", err)
|
||||
}
|
||||
|
||||
res, err = client.Do(req)
|
||||
if err != nil {
|
||||
xlog.Warnf(err)
|
||||
return errcode.New(errcode.ServerError, "数据请求失败:%v", err)
|
||||
}
|
||||
} else {
|
||||
res, err = http.Get(removeUrl)
|
||||
}
|
||||
|
||||
// 获取数据
|
||||
defer res.Body.Close()
|
||||
|
||||
resBody, err := io.ReadAll(res.Body)
|
||||
if err != nil {
|
||||
xlog.Warnf(err)
|
||||
return errcode.New(errcode.ServerError, "数据解析失败:%v", err)
|
||||
}
|
||||
|
||||
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)
|
||||
}
|
||||
|
||||
//xlog.Debugf("%+v", resData)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func checkUrl(u string) string {
|
||||
if strings.Contains(u, `http://`) || strings.Contains(u, `https://`) {
|
||||
return u
|
||||
} else {
|
||||
return `http://` + u
|
||||
}
|
||||
}
|
@ -112,7 +112,7 @@ func (node *Node) initBootConfig() error {
|
||||
}
|
||||
|
||||
func (node *Node) initLog() error {
|
||||
logConfig := &LogBootConfig{}
|
||||
logConfig := DefaultLogBootConfig()
|
||||
if node.bootConfigFile.globalBootConfigFileContent != nil {
|
||||
logConfig = node.bootConfigFile.globalBootConfigFileContent.GetLogConfig().Check()
|
||||
}
|
||||
|
@ -16,6 +16,12 @@ type LogBootConfig struct {
|
||||
LogLevel string `yaml:"log_level"` // 日志等级: trace/debug/info/notice/warn/error/fatal
|
||||
}
|
||||
|
||||
func DefaultLogBootConfig() *LogBootConfig {
|
||||
return &LogBootConfig{
|
||||
LogLevel: "trace",
|
||||
}
|
||||
}
|
||||
|
||||
func (lc *LogBootConfig) Check() *LogBootConfig {
|
||||
if lc.LogDir == "" {
|
||||
lc.LogDir = "./logs"
|
||||
|
57
admin/lib/web/desc.go
Normal file
57
admin/lib/web/desc.go
Normal file
@ -0,0 +1,57 @@
|
||||
package web
|
||||
|
||||
type routesPath struct {
|
||||
method string // get|post|put|delete
|
||||
desc string
|
||||
permit int
|
||||
handlers []HandlerFunc
|
||||
}
|
||||
|
||||
type routesNode struct {
|
||||
path string
|
||||
methods []*routesPath
|
||||
child []*routesNode
|
||||
}
|
||||
|
||||
func newRoutesNode(method, path string, desc string, permit int, handlers ...HandlerFunc) *routesNode {
|
||||
n := &routesNode{
|
||||
path: path,
|
||||
}
|
||||
n.addMethod(method, desc, permit, handlers)
|
||||
return n
|
||||
}
|
||||
|
||||
func (n *routesNode) addChildren(method, path string, desc string, permit int, handlers ...HandlerFunc) *routesNode {
|
||||
for _, c := range n.child {
|
||||
if c.path == path {
|
||||
c.addMethod(method, desc, permit, handlers)
|
||||
return c
|
||||
}
|
||||
}
|
||||
|
||||
children := newRoutesNode(method, path, desc, permit, handlers)
|
||||
n.child = append(n.child, children)
|
||||
return children
|
||||
}
|
||||
|
||||
func (n *routesNode) addMethod(method string, desc string, permit int, handlers ...HandlerFunc) *routesNode {
|
||||
n.methods = append(n.methods, &routesPath{method: method, desc: desc, permit: permit, handlers: handlers})
|
||||
return n
|
||||
}
|
||||
|
||||
func (n *routesNode) travel(parentPath string, parentDesc string, travelFun func(parentDesc string, path string, method string, handlers ...HandlerFunc)) {
|
||||
curPath := parentPath + n.path
|
||||
curNodeDesc := ""
|
||||
if len(n.methods) > 0 {
|
||||
for _, method := range n.methods {
|
||||
if method.method == "" {
|
||||
curNodeDesc = method.desc
|
||||
continue
|
||||
}
|
||||
travelFun(curPath, parentDesc, method.method, method.handlers)
|
||||
}
|
||||
}
|
||||
for _, c := range n.child {
|
||||
c.travel(curPath, curNodeDesc, travelFun)
|
||||
}
|
||||
}
|
34
admin/lib/web/engine.go
Normal file
34
admin/lib/web/engine.go
Normal file
@ -0,0 +1,34 @@
|
||||
package web
|
||||
|
||||
import "github.com/gin-gonic/gin"
|
||||
|
||||
type Engine struct {
|
||||
*RoutesGroup
|
||||
newContextFun func(ctx *gin.Context) IContext
|
||||
rawEngine *gin.Engine
|
||||
}
|
||||
|
||||
func New(newContextFun func(ctx *gin.Context) IContext) *Engine {
|
||||
rawE := gin.Default()
|
||||
e := &Engine{
|
||||
RoutesGroup: newRoutesGroup(&rawE.RouterGroup, newContextFun),
|
||||
newContextFun: newContextFun,
|
||||
rawEngine: rawE,
|
||||
}
|
||||
|
||||
return e
|
||||
}
|
||||
|
||||
func (e *Engine) Use(middlewares ...HandlerFunc) {
|
||||
e.rawEngine.Use(getGinHandlerFunWithRequest(e.newContextFun, middlewares...)...)
|
||||
}
|
||||
|
||||
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)) {
|
||||
for _, c := range e.RoutesGroup.node.child {
|
||||
c.travel("", "", travelFun)
|
||||
}
|
||||
}
|
@ -1,212 +0,0 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"admin/lib/web"
|
||||
"fmt"
|
||||
"html/template"
|
||||
"sort"
|
||||
)
|
||||
|
||||
type MyContext struct {
|
||||
rawCtx web.RawContext
|
||||
}
|
||||
|
||||
func (ctx *MyContext) SetRawContext(rawCtx web.RawContext) {
|
||||
ctx.rawCtx = rawCtx
|
||||
}
|
||||
func (ctx *MyContext) GetRawContext() web.RawContext {
|
||||
return ctx.rawCtx
|
||||
}
|
||||
|
||||
func main() {
|
||||
coreRouter := "iris" // gin|iris
|
||||
engine := web.NewEngine(":8888", coreRouter, func() web.Context {
|
||||
return new(MyContext)
|
||||
})
|
||||
groupV1 := engine.Group("/v1")
|
||||
{
|
||||
type Test1 struct {
|
||||
RoleId string `json:"role_id" desc:"角色id字段" required:"true"`
|
||||
F1 int `json:"f1" desc:"这是字段1" default:"324"`
|
||||
F2 string `json:"f2" desc:"这是字段2" default:"abcd"`
|
||||
F3 bool `json:"f3" desc:"这是字段3" default:"false"`
|
||||
}
|
||||
groupV1.Get("/test1", "设置玩家背包数据", web.AccessMode_Write, Test1{}, func(ctx *MyContext, params *Test1) {
|
||||
fmt.Printf("receive test1 path params:%+v\n", params)
|
||||
ctx.GetRawContext().Json(200, map[string]any{
|
||||
"msg": "ok",
|
||||
"code": 200,
|
||||
})
|
||||
})
|
||||
groupV1.Post("/test1", "获取玩家数据", web.AccessMode_Read, Test1{}, func(ctx *MyContext, params *Test1) {
|
||||
fmt.Printf("receive test1 path params:%+v\n", params)
|
||||
ctx.GetRawContext().Json(200, map[string]any{
|
||||
"msg": "ok",
|
||||
"code": 200,
|
||||
})
|
||||
})
|
||||
// URI --> :8888/v1/test1?f1=123&f2=sdfsd&f3=true
|
||||
// BODY --> :8888/v1/test1 {"f1":123,"f2":"sdfds","f3":"true"}
|
||||
}
|
||||
engine.Get("/test2", "获取玩家比赛", web.AccessMode_Read, nil, func(ctx *MyContext) {
|
||||
fmt.Printf("receive test2 request\n")
|
||||
ctx.GetRawContext().Json(200, map[string]any{
|
||||
"msg": "ok",
|
||||
"code": 200,
|
||||
})
|
||||
})
|
||||
engine.Post("/test2", "测试gm指令名字", web.AccessMode_Read, nil, func(ctx *MyContext) {
|
||||
fmt.Printf("receive test2 request\n")
|
||||
ctx.GetRawContext().Json(200, map[string]any{
|
||||
"msg": "ok",
|
||||
"code": 200,
|
||||
})
|
||||
})
|
||||
groupV2 := engine.Group("v2")
|
||||
{
|
||||
type Test2 struct {
|
||||
F1 int `json:"f1" desc:"这是字段1"`
|
||||
F2 string `json:"f2" desc:"这是字段2"`
|
||||
F3 bool `json:"f3" desc:"这是字段3"`
|
||||
}
|
||||
groupV2.Post("test3", "测试gm指令名字123", web.AccessMode_Write, Test2{}, func(ctx *MyContext, params *Test2) {
|
||||
fmt.Printf("receive test3\n")
|
||||
ctx.GetRawContext().Json(200, map[string]any{
|
||||
"msg": "ok",
|
||||
"code": 200,
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
engine.Get("path_tree", "测试gm指令名字3424", web.AccessMode_Write, nil, func(ctx *MyContext) {
|
||||
tree := engine.TravelPathTree()
|
||||
ctx.GetRawContext().Json(200, tree)
|
||||
})
|
||||
|
||||
engine.Get("/grid", "获取指令描述表", web.AccessMode_Read, nil, func(c *MyContext) {
|
||||
tree := &Tree{tree: engine.TravelPathTree()}
|
||||
|
||||
tmpl, err := template.New("html_test").Funcs(template.FuncMap(map[string]any{
|
||||
"incr": incr,
|
||||
})).Parse(tplText)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
err = tmpl.Execute(c.GetRawContext().Writer(), tree)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
})
|
||||
|
||||
err := engine.Run()
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
|
||||
type Path struct {
|
||||
Path string
|
||||
Route *web.RouteDescInfo
|
||||
}
|
||||
|
||||
type Tree struct {
|
||||
tree map[string]*web.RouteDescInfo
|
||||
}
|
||||
|
||||
func (t *Tree) Paths() [][]*Path {
|
||||
splitCol := 4
|
||||
list := make([]*Path, 0)
|
||||
for k, v := range t.tree {
|
||||
list = append(list, &Path{Path: k, Route: v})
|
||||
}
|
||||
sort.SliceStable(list, func(i, j int) bool {
|
||||
return list[i].Path < list[j].Path
|
||||
})
|
||||
|
||||
if len(list) <= splitCol {
|
||||
return [][]*Path{list}
|
||||
}
|
||||
|
||||
section := len(list) / splitCol
|
||||
paths := make([][]*Path, splitCol)
|
||||
|
||||
for i := 0; i < splitCol; i++ {
|
||||
paths[i] = make([]*Path, 0)
|
||||
start := i * section
|
||||
for j := 0; j < section; j++ {
|
||||
start += j
|
||||
paths[i] = append(paths[i], list[start])
|
||||
}
|
||||
}
|
||||
|
||||
if len(list)%splitCol > 0 {
|
||||
idx := 0
|
||||
for i := len(list) - len(list)%splitCol; i < len(list); i++ {
|
||||
paths[idx] = append(paths[idx], list[i])
|
||||
idx++
|
||||
}
|
||||
}
|
||||
|
||||
return paths
|
||||
}
|
||||
|
||||
func incr(src int) int {
|
||||
return src + 1
|
||||
}
|
||||
|
||||
var tplText = `
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>GM MASTER</title>
|
||||
<div style="padding-left: 50px;">
|
||||
{{ $pathsList := .Paths }}
|
||||
{{ range $pidex, $paths := $pathsList }}
|
||||
<div style="float:left">
|
||||
<h1 style="text-align: center">指令列表{{ incr $pidex }}</h1>
|
||||
<div style="padding-left: 20px;padding-right: 20px">
|
||||
<table border = "1" align="center">
|
||||
{{ range $idx, $path := $paths }}
|
||||
<tr>
|
||||
<th colspan="5" style="background-color: green; text-align: left">{{ $path.Route.Desc }}</th>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><b>请求路径</b></td>
|
||||
<th colspan="4" style="text-align: left"> {{ $path.Path }}</th>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><b>方法</b></td>
|
||||
<th colspan="4" style="text-align: left"> {{ $path.Route.MethodDesc "或" }}</th>
|
||||
</tr>
|
||||
{{ if $path.Route.HasRequest }}
|
||||
{{ range $idx1, $field := $path.Route.Fields }}
|
||||
<tr>
|
||||
<td><b>{{ printf "参数%d" $idx1 }}</b></td>
|
||||
<td style="text-align: center">{{printf "%s" $field.Name }}</td>
|
||||
<td style="text-align: center">{{printf "%s" $field.Type }}</td>
|
||||
<td>{{printf "%s" $field.Desc }}</td>
|
||||
{{ if eq $field.Default "" }}
|
||||
<td>{{printf "默认:无" }}</td>
|
||||
{{ else }}
|
||||
<td>{{printf "默认:%s" $field.Default }}</td>
|
||||
{{ end }}
|
||||
</tr>
|
||||
{{ end }}
|
||||
{{ else }}
|
||||
<tr><th colspan="5">无需参数</th>
|
||||
{{ end }}
|
||||
<!--<tr><th colspan="5"><hr></th></tr>-->
|
||||
{{ end }}
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
{{ end }}
|
||||
</div>
|
||||
|
||||
</head>
|
||||
<body>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
`
|
1
admin/lib/web/example/main.go
Normal file
1
admin/lib/web/example/main.go
Normal file
@ -0,0 +1 @@
|
||||
package example
|
@ -1,183 +0,0 @@
|
||||
package web
|
||||
|
||||
type routeGroupInterface interface {
|
||||
Use(middlewares ...HandlerFunc)
|
||||
Group(path string, handlers ...HandlerFunc) routeGroupInterface
|
||||
Get(path string, desc string, req any, handlers ...HandlerFunc) routeGroupInterface
|
||||
Post(path string, desc string, req any, handlers ...HandlerFunc) routeGroupInterface
|
||||
Put(path string, desc string, req any, handlers ...HandlerFunc) routeGroupInterface
|
||||
Delete(path string, desc string, req any, handlers ...HandlerFunc) routeGroupInterface
|
||||
}
|
||||
|
||||
type Group struct {
|
||||
coreRouter routeGroupInterface
|
||||
DirectRoutes map[string]*RouteDescInfo
|
||||
GroupRoutes map[string]*Group
|
||||
}
|
||||
|
||||
func newGroup(coreRouter routeGroupInterface) *Group {
|
||||
g := &Group{
|
||||
coreRouter: coreRouter,
|
||||
DirectRoutes: make(map[string]*RouteDescInfo),
|
||||
GroupRoutes: make(map[string]*Group),
|
||||
}
|
||||
return g
|
||||
}
|
||||
|
||||
func (e *Group) Use(middlewares ...HandlerFunc) {
|
||||
e.coreRouter.Use(middlewares...)
|
||||
}
|
||||
|
||||
func (e *Group) Group(path string, handlers ...HandlerFunc) *Group {
|
||||
path = pathBeTheSame(path)
|
||||
routeGroup := e.coreRouter.Group(path, handlers...)
|
||||
group := newGroup(routeGroup)
|
||||
e.GroupRoutes[path] = group
|
||||
return group
|
||||
}
|
||||
|
||||
// Get 注册get方法路由,根据request请求体优先从body中以json格式解析参数,如果没有body,则从uri参数中解析出请求参数
|
||||
//
|
||||
// path:路径
|
||||
// desc:路由的一个简短描述
|
||||
// request:请求结构体
|
||||
// 格式:
|
||||
// type struct {
|
||||
// F1 int `json:"f1" desc:"字段描述" default:"234" required:"true"`
|
||||
// }
|
||||
// tag描述:
|
||||
// json:字段名
|
||||
// desc:字段简短描述,没有可以不写
|
||||
// default:默认值,没有可以不写
|
||||
// required:是否必填字段,没有要求可以不写
|
||||
// 注意,get、post注册的request结构字段,如果是uri参数方式类型只支持golang基础类型以及基础类型的切片,不能是结构体类型,
|
||||
// 例如:
|
||||
// type Field struct {
|
||||
// A int
|
||||
// B bool
|
||||
// }
|
||||
// type Request struct {
|
||||
// F1 *Field
|
||||
// }
|
||||
// F1字段就是非法的,无法解析,会报错
|
||||
// handlers:路由处理函数,如果没有请求体,就是func(ctx),否则就是func(ctx, request)
|
||||
func (e *Group) Get(path string, desc string, access AccessMode, request any, handler HandlerFunc) {
|
||||
path = pathBeTheSame(path)
|
||||
old, find := e.DirectRoutes[path]
|
||||
if !find {
|
||||
e.DirectRoutes[path] = newRouteDescInfo(path, desc, "GET", access, request)
|
||||
} else {
|
||||
old.Method = append(old.Method, "GET")
|
||||
e.DirectRoutes[path] = old
|
||||
}
|
||||
e.coreRouter.Get(path, desc, request, handler)
|
||||
}
|
||||
|
||||
// Post 注册post方法路由,根据request请求体优先从body中以json格式解析参数,如果没有body,则从uri参数中解析出请求参数
|
||||
//
|
||||
// path:路径
|
||||
// desc:路由的一个简短描述
|
||||
// request:请求结构体
|
||||
// 格式:
|
||||
// type struct {
|
||||
// F1 int `json:"f1" desc:"字段描述" default:"234" required:"true"`
|
||||
// }
|
||||
// tag描述:
|
||||
// json:字段名
|
||||
// desc:字段简短描述,没有可以不写
|
||||
// default:默认值,没有可以不写
|
||||
// required:是否必填字段,没有要求可以不写
|
||||
// 注意,get、post注册的request结构字段,如果是uri参数方式类型只支持golang基础类型以及基础类型的切片,不能是结构体类型,
|
||||
// 例如:
|
||||
// type Field struct {
|
||||
// A int
|
||||
// B bool
|
||||
// }
|
||||
// type Request struct {
|
||||
// F1 *Field
|
||||
// }
|
||||
// F1字段就是非法的,无法解析,会报错
|
||||
// handlers:路由处理函数,如果没有请求体,就是func(ctx),否则就是func(ctx, request)
|
||||
func (e *Group) Post(path, desc string, access AccessMode, request any, handler HandlerFunc) {
|
||||
path = pathBeTheSame(path)
|
||||
old, find := e.DirectRoutes[path]
|
||||
if !find {
|
||||
e.DirectRoutes[path] = newRouteDescInfo(path, desc, "POST", access, request)
|
||||
} else {
|
||||
old.Method = append(old.Method, "POST")
|
||||
e.DirectRoutes[path] = old
|
||||
}
|
||||
e.coreRouter.Post(path, desc, request, handler)
|
||||
}
|
||||
|
||||
func (e *Group) Put(path, desc string, access AccessMode, request any, handler HandlerFunc) {
|
||||
path = pathBeTheSame(path)
|
||||
old, find := e.DirectRoutes[path]
|
||||
if !find {
|
||||
e.DirectRoutes[path] = newRouteDescInfo(path, desc, "PUT", access, request)
|
||||
} else {
|
||||
old.Method = append(old.Method, "PUT")
|
||||
e.DirectRoutes[path] = old
|
||||
}
|
||||
e.coreRouter.Put(path, desc, request, handler)
|
||||
}
|
||||
|
||||
func (e *Group) Delete(path, desc string, access AccessMode, request any, handler HandlerFunc) {
|
||||
path = pathBeTheSame(path)
|
||||
old, find := e.DirectRoutes[path]
|
||||
if !find {
|
||||
e.DirectRoutes[path] = newRouteDescInfo(path, desc, "DELETE", access, request)
|
||||
} else {
|
||||
old.Method = append(old.Method, "DELETE")
|
||||
e.DirectRoutes[path] = old
|
||||
}
|
||||
e.coreRouter.Delete(path, desc, request, handler)
|
||||
}
|
||||
|
||||
// GetAndPost 注册get&post方法路由,根据request请求体优先从body中以json格式解析参数,如果没有body,则从uri参数中解析出请求参数
|
||||
//
|
||||
// path:路径
|
||||
// desc:路由的一个简短描述
|
||||
// request:请求结构体
|
||||
// 格式:
|
||||
// type struct {
|
||||
// F1 int `json:"f1" desc:"字段描述" default:"234" required:"true"`
|
||||
// }
|
||||
// tag描述:
|
||||
// json:字段名
|
||||
// desc:字段简短描述,没有可以不写
|
||||
// default:默认值,没有可以不写
|
||||
// required:是否必填字段,没有要求可以不写
|
||||
// 注意,get、post注册的request结构字段,如果是uri参数方式类型只支持golang基础类型以及基础类型的切片,不能是结构体类型,
|
||||
// 例如:
|
||||
// type Field struct {
|
||||
// A int
|
||||
// B bool
|
||||
// }
|
||||
// type Request struct {
|
||||
// F1 *Field
|
||||
// }
|
||||
// F1字段就是非法的,无法解析,会报错
|
||||
// handlers:路由处理函数,如果没有请求体,就是func(ctx),否则就是func(ctx, request)
|
||||
func (e *Group) GetAndPost(path, desc string, access AccessMode, request any, handler HandlerFunc) {
|
||||
path = pathBeTheSame(path)
|
||||
record := newRouteDescInfo(path, desc, "GET", access, request)
|
||||
record.Method = append(record.Method, "POST")
|
||||
e.DirectRoutes[path] = record
|
||||
e.coreRouter.Get(path, desc, request, handler)
|
||||
e.coreRouter.Post(path, desc, request, handler)
|
||||
}
|
||||
|
||||
func (e *Group) TravelPathTree() map[string]*RouteDescInfo {
|
||||
m := make(map[string]*RouteDescInfo)
|
||||
for k, route := range e.DirectRoutes {
|
||||
m[k] = route
|
||||
}
|
||||
for k, subG := range e.GroupRoutes {
|
||||
gm := subG.TravelPathTree()
|
||||
for k1, v1 := range gm {
|
||||
m[k+k1] = v1
|
||||
}
|
||||
}
|
||||
return m
|
||||
}
|
@ -1,24 +0,0 @@
|
||||
package web
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
)
|
||||
|
||||
type Context interface {
|
||||
SetRawContext(ctx RawContext)
|
||||
GetRawContext() RawContext
|
||||
}
|
||||
|
||||
type HandlerFunc any
|
||||
|
||||
type RawContext interface {
|
||||
Json(code int, v any)
|
||||
Writer() io.Writer
|
||||
}
|
||||
|
||||
var ParseParamsErrorHandler = func(ctx Context, path string, err error) {
|
||||
ctx.GetRawContext().Json(501, map[string]interface{}{
|
||||
"MSG": fmt.Sprintf("parse params error:%v", err),
|
||||
})
|
||||
}
|
@ -1,12 +0,0 @@
|
||||
|
||||
|
||||
注意,get、post注册的request结构字段,如果是uri参数方式类型只支持golang基础类型以及基础类型的切片,不能是结构体类型,
|
||||
例如:
|
||||
type Field struct {
|
||||
A int
|
||||
B bool
|
||||
}
|
||||
type Request struct {
|
||||
F1 *Field
|
||||
}
|
||||
F1字段就是非法的,无法解析,会报错
|
@ -1,173 +0,0 @@
|
||||
package web
|
||||
|
||||
import "fmt"
|
||||
|
||||
type routerInterface interface {
|
||||
routeGroupInterface
|
||||
Run(addr string) error
|
||||
}
|
||||
|
||||
type Engine struct {
|
||||
Addr string
|
||||
newContextFun func() Context
|
||||
DirectRoutes map[string]*RouteDescInfo
|
||||
GroupRoutes map[string]*Group
|
||||
coreRouter routerInterface
|
||||
}
|
||||
|
||||
// NewEngine 使用gin或者iris创建web引擎,newContextFun为调用方需要实现的context初始化函数
|
||||
// coreRouter指定不同web引擎,目前只支持gin
|
||||
func NewEngine(coreRouter string, newContextFun func() Context) *Engine {
|
||||
e := &Engine{
|
||||
newContextFun: newContextFun,
|
||||
DirectRoutes: make(map[string]*RouteDescInfo),
|
||||
GroupRoutes: make(map[string]*Group),
|
||||
}
|
||||
switch coreRouter {
|
||||
//case "iris":
|
||||
// e.coreRouter = newRouterIris(newContextFun)
|
||||
case "gin":
|
||||
e.coreRouter = newRouterGin(newContextFun)
|
||||
default:
|
||||
panic(fmt.Errorf("NewEngine only support irir or gin, invalid type:%v", coreRouter))
|
||||
}
|
||||
return e
|
||||
}
|
||||
|
||||
func (e *Engine) Use(middlewares ...HandlerFunc) {
|
||||
e.coreRouter.Use(middlewares...)
|
||||
}
|
||||
|
||||
func (e *Engine) Group(path string, handlers ...HandlerFunc) *Group {
|
||||
path = pathBeTheSame(path)
|
||||
routeGroup := e.coreRouter.Group(path, handlers...)
|
||||
group := newGroup(routeGroup)
|
||||
e.GroupRoutes[path] = group
|
||||
return group
|
||||
}
|
||||
|
||||
// Get 注册get方法路由,根据request请求体优先从body中以json格式解析参数,如果没有body,则从uri参数中解析出请求参数
|
||||
//
|
||||
// path:路径
|
||||
// desc:路由的一个简短描述
|
||||
// request:请求结构体
|
||||
// 格式:
|
||||
// type struct {
|
||||
// F1 int `json:"f1" desc:"字段描述" default:"234" required:"true"`
|
||||
// }
|
||||
// tag描述:
|
||||
// json:字段名
|
||||
// desc:字段简短描述,没有可以不写
|
||||
// default:默认值,没有可以不写
|
||||
// required:是否必填字段,没有要求可以不写
|
||||
// 注意,get、post注册的request结构字段,如果是uri参数方式类型只支持golang基础类型以及基础类型的切片,不能是结构体类型,
|
||||
// 例如:
|
||||
// type Field struct {
|
||||
// A int
|
||||
// B bool
|
||||
// }
|
||||
// type Request struct {
|
||||
// F1 *Field
|
||||
// }
|
||||
// F1字段就是非法的,无法解析,会报错
|
||||
// handlers:路由处理函数,如果没有请求体,就是func(ctx),否则就是func(ctx, request)
|
||||
func (e *Engine) Get(path string, desc string, access AccessMode, request any, handler HandlerFunc) {
|
||||
path = pathBeTheSame(path)
|
||||
old, find := e.DirectRoutes[path]
|
||||
if !find {
|
||||
e.DirectRoutes[path] = newRouteDescInfo(path, desc, "GET", access, request)
|
||||
} else {
|
||||
old.Method = append(old.Method, "GET")
|
||||
e.DirectRoutes[path] = old
|
||||
}
|
||||
e.coreRouter.Get(path, desc, request, handler)
|
||||
}
|
||||
|
||||
// Post 注册post方法路由,根据request请求体优先从body中以json格式解析参数,如果没有body,则从uri参数中解析出请求参数
|
||||
//
|
||||
// path:路径
|
||||
// desc:路由的一个简短描述
|
||||
// request:请求结构体
|
||||
// 格式:
|
||||
// type struct {
|
||||
// F1 int `json:"f1" desc:"字段描述" default:"234" required:"true"`
|
||||
// }
|
||||
// tag描述:
|
||||
// json:字段名
|
||||
// desc:字段简短描述,没有可以不写
|
||||
// default:默认值,没有可以不写
|
||||
// required:是否必填字段,没有要求可以不写
|
||||
// 注意,get、post注册的request结构字段,如果是uri参数方式类型只支持golang基础类型以及基础类型的切片,不能是结构体类型,
|
||||
// 例如:
|
||||
// type Field struct {
|
||||
// A int
|
||||
// B bool
|
||||
// }
|
||||
// type Request struct {
|
||||
// F1 *Field
|
||||
// }
|
||||
// F1字段就是非法的,无法解析,会报错
|
||||
// handlers:路由处理函数,如果没有请求体,就是func(ctx),否则就是func(ctx, request)
|
||||
func (e *Engine) Post(path, desc string, access AccessMode, request any, handler HandlerFunc) {
|
||||
path = pathBeTheSame(path)
|
||||
old, find := e.DirectRoutes[path]
|
||||
if !find {
|
||||
e.DirectRoutes[path] = newRouteDescInfo(path, desc, "POST", access, request)
|
||||
} else {
|
||||
old.Method = append(old.Method, "POST")
|
||||
e.DirectRoutes[path] = old
|
||||
}
|
||||
e.coreRouter.Post(path, desc, request, handler)
|
||||
}
|
||||
|
||||
func (e *Engine) Run(addr string) error {
|
||||
e.Addr = addr
|
||||
return e.coreRouter.Run(addr)
|
||||
}
|
||||
|
||||
// TravelPathTree 获取所有路径的描述表
|
||||
func (e *Engine) TravelPathTree() map[string]*RouteDescInfo {
|
||||
m := make(map[string]*RouteDescInfo)
|
||||
for k, route := range e.DirectRoutes {
|
||||
m[k] = route
|
||||
}
|
||||
for k, subG := range e.GroupRoutes {
|
||||
gm := subG.TravelPathTree()
|
||||
for k1, v1 := range gm {
|
||||
m[k+k1] = v1
|
||||
}
|
||||
}
|
||||
return m
|
||||
}
|
||||
|
||||
func pathBeTheSame(path string) string {
|
||||
if path == "" {
|
||||
return ""
|
||||
}
|
||||
if path == "/" {
|
||||
return path
|
||||
}
|
||||
if path[0] != '/' {
|
||||
path = "/" + path
|
||||
}
|
||||
if path[len(path)-1] == '/' {
|
||||
path = path[:len(path)-1]
|
||||
}
|
||||
return path
|
||||
}
|
||||
|
||||
func pathBeTheSame1(path string) string {
|
||||
if path == "" {
|
||||
return ""
|
||||
}
|
||||
if path == "/" {
|
||||
return path
|
||||
}
|
||||
if path[0] != '/' {
|
||||
path = "/" + path
|
||||
}
|
||||
if path[len(path)-1] == '/' {
|
||||
path = path[:len(path)-1]
|
||||
}
|
||||
return path
|
||||
}
|
@ -1,85 +0,0 @@
|
||||
package web
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
"strings"
|
||||
)
|
||||
|
||||
type AccessMode int
|
||||
|
||||
const (
|
||||
AccessMode_Read = 1
|
||||
AccessMode_Write = 2
|
||||
)
|
||||
|
||||
type RouteDescInfo struct {
|
||||
Path string
|
||||
Desc string
|
||||
Method []string
|
||||
AccessMode
|
||||
rawRequest any
|
||||
Fields []*FieldDescInfo
|
||||
}
|
||||
|
||||
func newRouteDescInfo(path, desc, method string, access AccessMode, request any) *RouteDescInfo {
|
||||
info := &RouteDescInfo{
|
||||
Path: path,
|
||||
Desc: desc,
|
||||
Method: []string{method},
|
||||
AccessMode: access,
|
||||
rawRequest: request,
|
||||
}
|
||||
info.RequestFieldsDesc()
|
||||
return info
|
||||
}
|
||||
|
||||
func (info *RouteDescInfo) MethodDesc(sep string) string {
|
||||
return strings.Join(info.Method, sep)
|
||||
}
|
||||
|
||||
func (info *RouteDescInfo) RequestFieldsDesc() []*FieldDescInfo {
|
||||
if !info.HasRequest() {
|
||||
return []*FieldDescInfo{}
|
||||
}
|
||||
|
||||
list := make([]*FieldDescInfo, 0)
|
||||
to := reflect.TypeOf(info.rawRequest)
|
||||
if to.Kind() == reflect.Ptr {
|
||||
to = to.Elem()
|
||||
}
|
||||
for i := 0; i < to.NumField(); i++ {
|
||||
field := to.Field(i)
|
||||
list = append(list, newFieldDescInfo(field))
|
||||
}
|
||||
info.Fields = list
|
||||
return list
|
||||
}
|
||||
|
||||
func (info *RouteDescInfo) HasRequest() bool {
|
||||
return info.rawRequest != nil
|
||||
}
|
||||
|
||||
type FieldDescInfo struct {
|
||||
Name string
|
||||
FieldName string
|
||||
Type string
|
||||
Desc string
|
||||
Required bool
|
||||
Default string
|
||||
rawTypeOfField reflect.StructField
|
||||
}
|
||||
|
||||
func newFieldDescInfo(field reflect.StructField) *FieldDescInfo {
|
||||
desc := &FieldDescInfo{
|
||||
Name: field.Tag.Get("json"),
|
||||
FieldName: field.Name,
|
||||
Type: field.Type.String(),
|
||||
Desc: field.Tag.Get("desc"),
|
||||
rawTypeOfField: field,
|
||||
}
|
||||
if field.Tag.Get("required") == "true" {
|
||||
desc.Required = true
|
||||
}
|
||||
desc.Default = desc.rawTypeOfField.Tag.Get("default")
|
||||
return desc
|
||||
}
|
@ -1,303 +0,0 @@
|
||||
package web
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"github.com/gin-gonic/gin"
|
||||
"io"
|
||||
"reflect"
|
||||
"strconv"
|
||||
"strings"
|
||||
)
|
||||
|
||||
type routerGroupGin struct {
|
||||
group *gin.RouterGroup
|
||||
newContextFun func() Context
|
||||
}
|
||||
|
||||
func (group *routerGroupGin) Use(middlewares ...HandlerFunc) {
|
||||
group.group.Use(getGinHandlerFun(group.newContextFun, middlewares...)...)
|
||||
}
|
||||
func (group *routerGroupGin) Group(path string, handlers ...HandlerFunc) routeGroupInterface {
|
||||
ginGroup := group.group.Group(path, getGinHandlerFun(group.newContextFun, handlers...)...)
|
||||
group1 := &routerGroupGin{group: ginGroup, newContextFun: group.newContextFun}
|
||||
return group1
|
||||
}
|
||||
func (group *routerGroupGin) Get(path string, desc string, req any, handlers ...HandlerFunc) routeGroupInterface {
|
||||
if req == nil {
|
||||
group.group.GET(path, getGinHandlerFun(group.newContextFun, handlers...)...)
|
||||
} else {
|
||||
group.group.GET(path, getGinHandlerFunWithRequest(group.newContextFun, req, handlers...)...)
|
||||
}
|
||||
return group
|
||||
}
|
||||
func (group *routerGroupGin) Post(path string, desc string, req any, handlers ...HandlerFunc) routeGroupInterface {
|
||||
if req == nil {
|
||||
group.group.POST(path, getGinHandlerFun(group.newContextFun, handlers...)...)
|
||||
} else {
|
||||
group.group.POST(path, getGinHandlerFunWithRequest(group.newContextFun, req, handlers...)...)
|
||||
}
|
||||
return group
|
||||
}
|
||||
|
||||
func (group *routerGroupGin) Put(path string, desc string, req any, handlers ...HandlerFunc) routeGroupInterface {
|
||||
if req == nil {
|
||||
group.group.PUT(path, getGinHandlerFun(group.newContextFun, handlers...)...)
|
||||
} else {
|
||||
group.group.PUT(path, getGinHandlerFunWithRequest(group.newContextFun, req, handlers...)...)
|
||||
}
|
||||
return group
|
||||
}
|
||||
|
||||
func (group *routerGroupGin) Delete(path string, desc string, req any, handlers ...HandlerFunc) routeGroupInterface {
|
||||
if req == nil {
|
||||
group.group.DELETE(path, getGinHandlerFun(group.newContextFun, handlers...)...)
|
||||
} else {
|
||||
group.group.DELETE(path, getGinHandlerFunWithRequest(group.newContextFun, req, handlers...)...)
|
||||
}
|
||||
return group
|
||||
}
|
||||
|
||||
type routerGin struct {
|
||||
engine *gin.Engine
|
||||
newContextFun func() Context
|
||||
}
|
||||
|
||||
func newRouterGin(newContextFun func() Context) routerInterface {
|
||||
engine := gin.Default()
|
||||
router := &routerGin{
|
||||
engine: engine,
|
||||
newContextFun: newContextFun,
|
||||
}
|
||||
return router
|
||||
}
|
||||
|
||||
func (router *routerGin) Use(middlewares ...HandlerFunc) {
|
||||
router.engine.Use(getGinHandlerFun(router.newContextFun, middlewares...)...)
|
||||
}
|
||||
func (router *routerGin) Group(path string, handlers ...HandlerFunc) routeGroupInterface {
|
||||
ginGroup := router.engine.Group(path, getGinHandlerFun(router.newContextFun, handlers...)...)
|
||||
group := &routerGroupGin{
|
||||
group: ginGroup,
|
||||
newContextFun: router.newContextFun,
|
||||
}
|
||||
return group
|
||||
}
|
||||
func (router *routerGin) Get(path string, desc string, req any, handlers ...HandlerFunc) routeGroupInterface {
|
||||
if req == nil {
|
||||
router.engine.GET(path, getGinHandlerFun(router.newContextFun, handlers...)...)
|
||||
} else {
|
||||
router.engine.GET(path, getGinHandlerFunWithRequest(router.newContextFun, req, handlers...)...)
|
||||
}
|
||||
return router
|
||||
}
|
||||
func (router *routerGin) Post(path string, desc string, req any, handlers ...HandlerFunc) routeGroupInterface {
|
||||
if req == nil {
|
||||
router.engine.POST(path, getGinHandlerFun(router.newContextFun, handlers...)...)
|
||||
} else {
|
||||
router.engine.POST(path, getGinHandlerFunWithRequest(router.newContextFun, req, handlers...)...)
|
||||
}
|
||||
return router
|
||||
}
|
||||
|
||||
func (router *routerGin) Put(path string, desc string, req any, handlers ...HandlerFunc) routeGroupInterface {
|
||||
if req == nil {
|
||||
router.engine.PUT(path, getGinHandlerFun(router.newContextFun, handlers...)...)
|
||||
} else {
|
||||
router.engine.PUT(path, getGinHandlerFunWithRequest(router.newContextFun, req, handlers...)...)
|
||||
}
|
||||
return router
|
||||
}
|
||||
|
||||
func (router *routerGin) Delete(path string, desc string, req any, handlers ...HandlerFunc) routeGroupInterface {
|
||||
if req == nil {
|
||||
router.engine.DELETE(path, getGinHandlerFun(router.newContextFun, handlers...)...)
|
||||
} else {
|
||||
router.engine.DELETE(path, getGinHandlerFunWithRequest(router.newContextFun, req, handlers...)...)
|
||||
}
|
||||
return router
|
||||
}
|
||||
|
||||
func getGinHandlerFun(newContextFun func() Context, handlers ...HandlerFunc) []gin.HandlerFunc {
|
||||
list := make([]gin.HandlerFunc, 0, len(handlers))
|
||||
for _, handler := range handlers {
|
||||
list = append(list, func(rawCtx *gin.Context) {
|
||||
rawCtx1 := &ginCtx{ctx: rawCtx}
|
||||
ctx := newContextFun()
|
||||
ctx.SetRawContext(rawCtx1)
|
||||
reflect.ValueOf(handler).Call([]reflect.Value{reflect.ValueOf(ctx)})
|
||||
if rawCtx.IsAborted() {
|
||||
return
|
||||
}
|
||||
})
|
||||
}
|
||||
return list
|
||||
}
|
||||
|
||||
func getGinHandlerFunWithRequest(newContextFun func() Context, requestTemplate any, handlers ...HandlerFunc) []gin.HandlerFunc {
|
||||
list := make([]gin.HandlerFunc, 0, len(handlers))
|
||||
for _, handler := range handlers {
|
||||
list = append(list, func(rawCtx *gin.Context) {
|
||||
rawCtx1 := &ginCtx{ctx: rawCtx}
|
||||
ctx := newContextFun()
|
||||
ctx.SetRawContext(rawCtx1)
|
||||
request, err := rawCtx1.parseRequest(requestTemplate)
|
||||
if err != nil {
|
||||
ParseParamsErrorHandler(ctx, rawCtx.Request.RequestURI, err)
|
||||
return
|
||||
}
|
||||
reflect.ValueOf(handler).Call([]reflect.Value{reflect.ValueOf(ctx), reflect.ValueOf(request)})
|
||||
})
|
||||
}
|
||||
return list
|
||||
}
|
||||
|
||||
func (router *routerGin) Run(addr string) error {
|
||||
return router.engine.Run(addr)
|
||||
}
|
||||
|
||||
type ginCtx struct {
|
||||
ctx *gin.Context
|
||||
}
|
||||
|
||||
func (ctx *ginCtx) Json(code int, v any) {
|
||||
ctx.ctx.JSON(code, v)
|
||||
}
|
||||
|
||||
func (ctx *ginCtx) Writer() io.Writer {
|
||||
return ctx.ctx.Writer
|
||||
}
|
||||
|
||||
func (ctx *ginCtx) body() ([]byte, error) {
|
||||
buf, err := io.ReadAll(ctx.ctx.Request.Body)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("read body error:%v", err)
|
||||
}
|
||||
|
||||
return buf, nil
|
||||
}
|
||||
|
||||
func (ctx *ginCtx) parseRequest(request any) (any, error) {
|
||||
if request == nil {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
requestType := reflect.TypeOf(request)
|
||||
newRequest := reflect.New(requestType).Interface()
|
||||
|
||||
body, err := ctx.body()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if len(body) == 0 {
|
||||
newRequestValue := reflect.ValueOf(newRequest).Elem()
|
||||
newRequestValueType := newRequestValue.Type()
|
||||
for i := 0; i < newRequestValue.NumField(); i++ {
|
||||
f := newRequestValueType.Field(i)
|
||||
fieldTagName := f.Tag.Get("json")
|
||||
if fieldTagName == "" {
|
||||
fieldTagName = f.Name
|
||||
}
|
||||
|
||||
field := newRequestValue.Field(i)
|
||||
if !field.CanSet() {
|
||||
continue
|
||||
}
|
||||
fieldStr := ctx.ctx.Query(fieldTagName)
|
||||
err := setValue(field, fieldStr, f.Tag.Get("default"), f.Tag.Get("required"))
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("parse uri params field(%v) set value(%v) error:%v", f.Name, fieldStr, err)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
err = json.Unmarshal(body, newRequest)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("json unmarshal body error:%v", err)
|
||||
}
|
||||
}
|
||||
return newRequest, nil
|
||||
}
|
||||
|
||||
// setValue 设置结构体一个字段的值
|
||||
func setValue(field reflect.Value, value string, defaultValue string, required string) error {
|
||||
if value == "" {
|
||||
value = defaultValue
|
||||
}
|
||||
if value == "" && required == "true" {
|
||||
return fmt.Errorf("field is required, please give a valid value")
|
||||
}
|
||||
|
||||
if field.Kind() == reflect.Ptr {
|
||||
if value == "" {
|
||||
return nil
|
||||
}
|
||||
|
||||
if field.IsNil() {
|
||||
field.Set(reflect.New(field.Type().Elem()))
|
||||
}
|
||||
field = field.Elem()
|
||||
}
|
||||
switch field.Kind() {
|
||||
case reflect.String:
|
||||
field.SetString(value)
|
||||
case reflect.Bool:
|
||||
if value == "" {
|
||||
field.SetBool(false)
|
||||
} else {
|
||||
b, err := strconv.ParseBool(value)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
field.SetBool(b)
|
||||
}
|
||||
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
|
||||
if value == "" {
|
||||
field.SetInt(0)
|
||||
} else {
|
||||
i, err := strconv.ParseInt(value, 0, field.Type().Bits())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
field.SetInt(i)
|
||||
}
|
||||
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
|
||||
if value == "" {
|
||||
field.SetUint(0)
|
||||
break
|
||||
}
|
||||
ui, err := strconv.ParseUint(value, 0, field.Type().Bits())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
field.SetUint(ui)
|
||||
case reflect.Float32, reflect.Float64:
|
||||
if value == "" {
|
||||
field.SetFloat(0)
|
||||
break
|
||||
}
|
||||
f, err := strconv.ParseFloat(value, field.Type().Bits())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
field.SetFloat(f)
|
||||
case reflect.Struct:
|
||||
return fmt.Errorf("unsupport struct field:%v", field.Type())
|
||||
case reflect.Slice:
|
||||
values := strings.Split(value, ",")
|
||||
if len(values) == 1 && values[0] == "" {
|
||||
values = []string{}
|
||||
}
|
||||
field.Set(reflect.MakeSlice(field.Type(), len(values), len(values)))
|
||||
for i := 0; i < len(values); i++ {
|
||||
err := setValue(field.Index(i), values[i], "", "")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
default:
|
||||
return fmt.Errorf("no support type %s", field.Type())
|
||||
}
|
||||
return nil
|
||||
}
|
228
admin/lib/web/routes_group.go
Normal file
228
admin/lib/web/routes_group.go
Normal file
@ -0,0 +1,228 @@
|
||||
package web
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"github.com/gin-gonic/gin"
|
||||
"io"
|
||||
"reflect"
|
||||
"strconv"
|
||||
"strings"
|
||||
)
|
||||
|
||||
type IContext interface {
|
||||
HandleError(path string, err error)
|
||||
HandleSuccess(rspData any)
|
||||
}
|
||||
|
||||
type HandlerFunc any
|
||||
|
||||
type RoutesGroup struct {
|
||||
newContextFun func(ctx *gin.Context) IContext
|
||||
rawGroup *gin.RouterGroup
|
||||
node *routesNode
|
||||
}
|
||||
|
||||
func newRoutesGroup(rawGroup *gin.RouterGroup, newContextFun func(ctx *gin.Context) IContext) *RoutesGroup {
|
||||
g := &RoutesGroup{
|
||||
rawGroup: rawGroup,
|
||||
newContextFun: newContextFun,
|
||||
node: &routesNode{},
|
||||
}
|
||||
return g
|
||||
}
|
||||
|
||||
func (group *RoutesGroup) Group(path string, desc string, handlers ...HandlerFunc) *RoutesGroup {
|
||||
rawGroup := group.rawGroup.Group(path, getGinHandlerFunWithRequest(group.newContextFun, handlers...)...)
|
||||
nextRoutesGroup := newRoutesGroup(rawGroup, group.newContextFun)
|
||||
nextGroupNode := group.addChildren("", path, desc, 0, handlers...)
|
||||
nextRoutesGroup.node = nextGroupNode
|
||||
return nextRoutesGroup
|
||||
}
|
||||
|
||||
func (group *RoutesGroup) Use(middlewares ...HandlerFunc) {
|
||||
group.rawGroup.Use(getGinHandlerFunWithRequest(group.newContextFun, middlewares...)...)
|
||||
}
|
||||
|
||||
func (group *RoutesGroup) Get(path string, desc string, permit int, handlers ...HandlerFunc) {
|
||||
group.rawGroup.GET(path, getGinHandlerFunWithRequest(group.newContextFun, handlers...)...)
|
||||
group.addChildren("GET", path, desc, permit, handlers...)
|
||||
}
|
||||
|
||||
func (group *RoutesGroup) Post(path string, desc string, permit int, handlers ...HandlerFunc) {
|
||||
group.rawGroup.POST(path, getGinHandlerFunWithRequest(group.newContextFun, handlers...)...)
|
||||
group.addChildren("POST", path, desc, permit, handlers...)
|
||||
}
|
||||
|
||||
func (group *RoutesGroup) Put(path string, desc string, permit int, handlers ...HandlerFunc) {
|
||||
group.rawGroup.PUT(path, getGinHandlerFunWithRequest(group.newContextFun, handlers...)...)
|
||||
group.addChildren("PUT", path, desc, permit, handlers...)
|
||||
}
|
||||
|
||||
func (group *RoutesGroup) Delete(path string, desc string, permit int, handlers ...HandlerFunc) {
|
||||
group.rawGroup.DELETE(path, getGinHandlerFunWithRequest(group.newContextFun, handlers...)...)
|
||||
group.addChildren("DELETE", path, desc, permit, handlers...)
|
||||
}
|
||||
|
||||
func (group *RoutesGroup) addChildren(method, path string, desc string, permit int, handlers ...HandlerFunc) *routesNode {
|
||||
return group.node.addChildren(method, path, desc, permit, handlers...)
|
||||
}
|
||||
|
||||
func getGinHandlerFunWithRequest(newContextFun func(ctx *gin.Context) IContext, handlers ...HandlerFunc) []gin.HandlerFunc {
|
||||
list := make([]gin.HandlerFunc, 0, len(handlers))
|
||||
|
||||
for _, handler := range handlers {
|
||||
list = append(list, func(rawCtx *gin.Context) {
|
||||
|
||||
ctx := newContextFun(rawCtx)
|
||||
|
||||
handlerTo := reflect.TypeOf(handler)
|
||||
numParams := handlerTo.NumIn()
|
||||
if numParams != 3 {
|
||||
ctx.HandleError(rawCtx.Request.RequestURI, fmt.Errorf("register callback handler params len(%v) invalid", numParams))
|
||||
return
|
||||
}
|
||||
|
||||
paramsTo := handlerTo.In(1)
|
||||
params := reflect.New(paramsTo.Elem()).Interface()
|
||||
err := parseRequest(rawCtx, params)
|
||||
if err != nil {
|
||||
ctx.HandleError(rawCtx.Request.RequestURI, err)
|
||||
return
|
||||
}
|
||||
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)})
|
||||
errInt := rets[0]
|
||||
if errInt.Interface() == nil {
|
||||
ctx.HandleSuccess(rsp)
|
||||
} else {
|
||||
err, ok := errInt.Interface().(error)
|
||||
if ok {
|
||||
ctx.HandleError(rawCtx.Request.RequestURI, err)
|
||||
} else {
|
||||
ctx.HandleError(rawCtx.Request.RequestURI, fmt.Errorf("handle request ret error, but parse return error:%+v not ok", err))
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
return list
|
||||
}
|
||||
|
||||
func parseRequest(rawCtx *gin.Context, params any) error {
|
||||
bodyBuf, err := io.ReadAll(rawCtx.Request.Body)
|
||||
if err != nil {
|
||||
return fmt.Errorf("read body error:%v", err)
|
||||
}
|
||||
|
||||
if len(bodyBuf) == 0 {
|
||||
newRequestValue := reflect.ValueOf(params).Elem()
|
||||
newRequestValueType := newRequestValue.Type()
|
||||
for i := 0; i < newRequestValue.NumField(); i++ {
|
||||
f := newRequestValueType.Field(i)
|
||||
fieldTagName := f.Tag.Get("json")
|
||||
if fieldTagName == "" {
|
||||
fieldTagName = f.Name
|
||||
}
|
||||
|
||||
field := newRequestValue.Field(i)
|
||||
if !field.CanSet() {
|
||||
continue
|
||||
}
|
||||
fieldStr := rawCtx.Query(fieldTagName)
|
||||
err := setValue(field, fieldStr, f.Tag.Get("default"), f.Tag.Get("required"))
|
||||
if err != nil {
|
||||
return fmt.Errorf("parse uri params field(%v) set value(%v) error:%v", f.Name, fieldStr, err)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
err = json.Unmarshal(bodyBuf, params)
|
||||
if err != nil {
|
||||
return fmt.Errorf("json unmarshal body error:%v", err)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// setValue 设置结构体一个字段的值
|
||||
func setValue(field reflect.Value, value string, defaultValue string, required string) error {
|
||||
if value == "" {
|
||||
value = defaultValue
|
||||
}
|
||||
if value == "" && required == "true" {
|
||||
return fmt.Errorf("field is required, please give a valid value")
|
||||
}
|
||||
|
||||
if field.Kind() == reflect.Ptr {
|
||||
if value == "" {
|
||||
return nil
|
||||
}
|
||||
|
||||
if field.IsNil() {
|
||||
field.Set(reflect.New(field.Type().Elem()))
|
||||
}
|
||||
field = field.Elem()
|
||||
}
|
||||
switch field.Kind() {
|
||||
case reflect.String:
|
||||
field.SetString(value)
|
||||
case reflect.Bool:
|
||||
if value == "" {
|
||||
field.SetBool(false)
|
||||
} else {
|
||||
b, err := strconv.ParseBool(value)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
field.SetBool(b)
|
||||
}
|
||||
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
|
||||
if value == "" {
|
||||
field.SetInt(0)
|
||||
} else {
|
||||
i, err := strconv.ParseInt(value, 0, field.Type().Bits())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
field.SetInt(i)
|
||||
}
|
||||
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
|
||||
if value == "" {
|
||||
field.SetUint(0)
|
||||
break
|
||||
}
|
||||
ui, err := strconv.ParseUint(value, 0, field.Type().Bits())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
field.SetUint(ui)
|
||||
case reflect.Float32, reflect.Float64:
|
||||
if value == "" {
|
||||
field.SetFloat(0)
|
||||
break
|
||||
}
|
||||
f, err := strconv.ParseFloat(value, field.Type().Bits())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
field.SetFloat(f)
|
||||
case reflect.Struct:
|
||||
return fmt.Errorf("unsupport struct field:%v", field.Type())
|
||||
case reflect.Slice:
|
||||
values := strings.Split(value, ",")
|
||||
if len(values) == 1 && values[0] == "" {
|
||||
values = []string{}
|
||||
}
|
||||
field.Set(reflect.MakeSlice(field.Type(), len(values), len(values)))
|
||||
for i := 0; i < len(values); i++ {
|
||||
err := setValue(field.Index(i), values[i], "", "")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
default:
|
||||
return fmt.Errorf("no support type %s", field.Type())
|
||||
}
|
||||
return nil
|
||||
}
|
@ -125,7 +125,7 @@ func SetLogLevel(level LogLevel) {
|
||||
func ParseLogLevelString(level string) LogLevel {
|
||||
lvEnum, find := LogLevelStr2Enum[level]
|
||||
if !find {
|
||||
return LogLevelDebug
|
||||
return LogLevelTrace
|
||||
}
|
||||
return lvEnum
|
||||
}
|
||||
|
124
ui/package-lock.json
generated
124
ui/package-lock.json
generated
@ -17,6 +17,7 @@
|
||||
"devDependencies": {
|
||||
"@vitejs/plugin-vue": "^5.2.3",
|
||||
"unplugin-auto-import": "^19.1.2",
|
||||
"unplugin-icons": "^22.1.0",
|
||||
"unplugin-vue-components": "^28.5.0",
|
||||
"vite": "^6.2.4",
|
||||
"vite-plugin-vue-devtools": "^7.7.2"
|
||||
@ -36,6 +37,20 @@
|
||||
"node": ">=6.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@antfu/install-pkg": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmmirror.com/@antfu/install-pkg/-/install-pkg-1.0.0.tgz",
|
||||
"integrity": "sha512-xvX6P/lo1B3ej0OsaErAjqgFYzYVcJpamjLAFLYh9vRJngBrMoUG7aVnrGTeqM7yxbyTD5p3F2+0/QUEh8Vzhw==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"package-manager-detector": "^0.2.8",
|
||||
"tinyexec": "^0.3.2"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/antfu"
|
||||
}
|
||||
},
|
||||
"node_modules/@antfu/utils": {
|
||||
"version": "0.7.10",
|
||||
"resolved": "https://registry.npmmirror.com/@antfu/utils/-/utils-0.7.10.tgz",
|
||||
@ -959,6 +974,53 @@
|
||||
"integrity": "sha512-MDWhGtE+eHw5JW7lq4qhc5yRLS11ERl1c7Z6Xd0a58DozHES6EnNNwUWbMiG4J9Cgj053Bhk8zvlhFYKVhULwg==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/@iconify/types": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmmirror.com/@iconify/types/-/types-2.0.0.tgz",
|
||||
"integrity": "sha512-+wluvCrRhXrhyOmRDJ3q8mux9JkKy5SJ/v8ol2tu4FVjyYvtEzkc/3pK15ET6RKg4b4w4BmTk1+gsCUhf21Ykg==",
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/@iconify/utils": {
|
||||
"version": "2.3.0",
|
||||
"resolved": "https://registry.npmmirror.com/@iconify/utils/-/utils-2.3.0.tgz",
|
||||
"integrity": "sha512-GmQ78prtwYW6EtzXRU1rY+KwOKfz32PD7iJh6Iyqw68GiKuoZ2A6pRtzWONz5VQJbp50mEjXh/7NkumtrAgRKA==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@antfu/install-pkg": "^1.0.0",
|
||||
"@antfu/utils": "^8.1.0",
|
||||
"@iconify/types": "^2.0.0",
|
||||
"debug": "^4.4.0",
|
||||
"globals": "^15.14.0",
|
||||
"kolorist": "^1.8.0",
|
||||
"local-pkg": "^1.0.0",
|
||||
"mlly": "^1.7.4"
|
||||
}
|
||||
},
|
||||
"node_modules/@iconify/utils/node_modules/@antfu/utils": {
|
||||
"version": "8.1.1",
|
||||
"resolved": "https://registry.npmmirror.com/@antfu/utils/-/utils-8.1.1.tgz",
|
||||
"integrity": "sha512-Mex9nXf9vR6AhcXmMrlz/HVgYYZpVGJ6YlPgwl7UnaFpnshXs6EK/oa5Gpf3CzENMjkvEx2tQtntGnb7UtSTOQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/antfu"
|
||||
}
|
||||
},
|
||||
"node_modules/@iconify/utils/node_modules/globals": {
|
||||
"version": "15.15.0",
|
||||
"resolved": "https://registry.npmmirror.com/globals/-/globals-15.15.0.tgz",
|
||||
"integrity": "sha512-7ACyT3wmyp3I61S4fG682L0VA2RGD9otkqGJIwNUMF1SWUombIIk+af1unuDYgMm082aHYwD+mzJvv9Iu8dsgg==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/sindresorhus"
|
||||
}
|
||||
},
|
||||
"node_modules/@jridgewell/gen-mapping": {
|
||||
"version": "0.3.8",
|
||||
"resolved": "https://registry.npmmirror.com/@jridgewell/gen-mapping/-/gen-mapping-0.3.8.tgz",
|
||||
@ -3001,6 +3063,16 @@
|
||||
"url": "https://github.com/sponsors/sindresorhus"
|
||||
}
|
||||
},
|
||||
"node_modules/package-manager-detector": {
|
||||
"version": "0.2.11",
|
||||
"resolved": "https://registry.npmmirror.com/package-manager-detector/-/package-manager-detector-0.2.11.tgz",
|
||||
"integrity": "sha512-BEnLolu+yuz22S56CU1SUKq3XC3PkwD5wv4ikR4MfGvnRVcmzXR9DwSlW2fEamyTPyXHomBJRzgapeuBvRNzJQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"quansync": "^0.2.7"
|
||||
}
|
||||
},
|
||||
"node_modules/parse-ms": {
|
||||
"version": "4.0.0",
|
||||
"resolved": "https://registry.npmmirror.com/parse-ms/-/parse-ms-4.0.0.tgz",
|
||||
@ -3372,6 +3444,13 @@
|
||||
"node": ">=16"
|
||||
}
|
||||
},
|
||||
"node_modules/tinyexec": {
|
||||
"version": "0.3.2",
|
||||
"resolved": "https://registry.npmmirror.com/tinyexec/-/tinyexec-0.3.2.tgz",
|
||||
"integrity": "sha512-KQQR9yN7R5+OSwaK0XQoj22pwHoTlgYqmUscPYoknOoWCWfj/5/ABTMRi69FrKU5ffPVh5QcFikpWJI/P1ocHA==",
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/tinyglobby": {
|
||||
"version": "0.2.12",
|
||||
"resolved": "https://registry.npmmirror.com/tinyglobby/-/tinyglobby-0.2.12.tgz",
|
||||
@ -3526,6 +3605,51 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/unplugin-icons": {
|
||||
"version": "22.1.0",
|
||||
"resolved": "https://registry.npmmirror.com/unplugin-icons/-/unplugin-icons-22.1.0.tgz",
|
||||
"integrity": "sha512-ect2ZNtk1Zgwb0NVHd0C1IDW/MV+Jk/xaq4t8o6rYdVS3+L660ZdD5kTSQZvsgdwCvquRw+/wYn75hsweRjoIA==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@antfu/install-pkg": "^1.0.0",
|
||||
"@iconify/utils": "^2.3.0",
|
||||
"debug": "^4.4.0",
|
||||
"local-pkg": "^1.0.0",
|
||||
"unplugin": "^2.2.0"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/antfu"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@svgr/core": ">=7.0.0",
|
||||
"@svgx/core": "^1.0.1",
|
||||
"@vue/compiler-sfc": "^3.0.2 || ^2.7.0",
|
||||
"svelte": "^3.0.0 || ^4.0.0 || ^5.0.0",
|
||||
"vue-template-compiler": "^2.6.12",
|
||||
"vue-template-es2015-compiler": "^1.9.0"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"@svgr/core": {
|
||||
"optional": true
|
||||
},
|
||||
"@svgx/core": {
|
||||
"optional": true
|
||||
},
|
||||
"@vue/compiler-sfc": {
|
||||
"optional": true
|
||||
},
|
||||
"svelte": {
|
||||
"optional": true
|
||||
},
|
||||
"vue-template-compiler": {
|
||||
"optional": true
|
||||
},
|
||||
"vue-template-es2015-compiler": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/unplugin-utils": {
|
||||
"version": "0.2.4",
|
||||
"resolved": "https://registry.npmmirror.com/unplugin-utils/-/unplugin-utils-0.2.4.tgz",
|
||||
|
@ -18,6 +18,7 @@
|
||||
"devDependencies": {
|
||||
"@vitejs/plugin-vue": "^5.2.3",
|
||||
"unplugin-auto-import": "^19.1.2",
|
||||
"unplugin-icons": "^22.1.0",
|
||||
"unplugin-vue-components": "^28.5.0",
|
||||
"vite": "^6.2.4",
|
||||
"vite-plugin-vue-devtools": "^7.7.2"
|
||||
|
9
ui/src/api/game_api.js
Normal file
9
ui/src/api/game_api.js
Normal file
@ -0,0 +1,9 @@
|
||||
import request from '@/utils/request'
|
||||
|
||||
export function gameApiRequest(url, method, data) {
|
||||
return request({
|
||||
url: url,
|
||||
method: method,
|
||||
params: data
|
||||
})
|
||||
}
|
@ -1,9 +0,0 @@
|
||||
import request from '@/utils/request'
|
||||
|
||||
export function getProjectList(params) {
|
||||
return request({
|
||||
url: '/project',
|
||||
method: 'get',
|
||||
params: params
|
||||
})
|
||||
}
|
34
ui/src/api/resource.js
Normal file
34
ui/src/api/resource.js
Normal file
@ -0,0 +1,34 @@
|
||||
import request from '@/utils/request'
|
||||
|
||||
export function resourceList(url, params) {
|
||||
return request({
|
||||
url: url,
|
||||
method: 'get',
|
||||
data: params
|
||||
})
|
||||
}
|
||||
|
||||
export function resourcePost(url, params) {
|
||||
return request({
|
||||
url: url,
|
||||
method: 'post',
|
||||
data: {'dto': params}
|
||||
// params: {'dto': params}
|
||||
})
|
||||
}
|
||||
|
||||
export function resourcePut(url, params) {
|
||||
return request({
|
||||
url: url,
|
||||
method: 'put',
|
||||
data: {'dto': params}
|
||||
})
|
||||
}
|
||||
|
||||
export function resourceDelete(url, params) {
|
||||
return request({
|
||||
url: url,
|
||||
method: 'delete',
|
||||
data: params
|
||||
})
|
||||
}
|
@ -1,38 +1,219 @@
|
||||
<script setup>
|
||||
import {ElNotification} from "element-plus";
|
||||
import {resourceDelete, resourceList, resourcePost, resourcePut} from "@/api/resource.js";
|
||||
import {ref, toRaw} from "vue";
|
||||
|
||||
const props = defineProps({
|
||||
rows: {}
|
||||
// rows: {},
|
||||
resource_url: '',
|
||||
row_click_handler: null,
|
||||
})
|
||||
|
||||
const fieldsDescInfo = props.rows.fields_desc
|
||||
const rows = props.rows.rows
|
||||
const listRsp = ref({fields_desc: [], rows: []})
|
||||
const getListOk = ref(false)
|
||||
const resource_url = props.resource_url
|
||||
const fieldsDescInfo = ref([])
|
||||
const rows = ref([])
|
||||
const rules = ref({})
|
||||
|
||||
console.log("fields desc:", fieldsDescInfo)
|
||||
console.log("rows:", props.rows)
|
||||
const listData = async () => {
|
||||
try {
|
||||
const rspData = await resourceList(resource_url, {page_no: 0, page_len: 100});
|
||||
listRsp.value = rspData;
|
||||
if (listRsp.value.code !== 200) throw new Error("请求失败,错误码:", listRsp.code);
|
||||
fieldsDescInfo.value = listRsp.value.data.fields_desc
|
||||
rows.value = listRsp.value.data.rows
|
||||
|
||||
|
||||
for (let i = 0; i < fieldsDescInfo.value.length; i++) {
|
||||
var field = fieldsDescInfo.value[i]
|
||||
dialogAddForm.value[field.key] = ''
|
||||
if (field.require == true) {
|
||||
rules.value[field.key] = [{required: true, message: field.name + "不能为空", trigger: "blur"}]
|
||||
}
|
||||
}
|
||||
|
||||
console.log('await list rsp:', listRsp.value)
|
||||
console.log("await fields:", fieldsDescInfo.value)
|
||||
console.log("await rows:", toRaw(rows.value))
|
||||
console.log("await rules:", toRaw(rules.value))
|
||||
|
||||
getListOk.value = true
|
||||
} catch (err) {
|
||||
console.log(err)
|
||||
} finally {
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
listData();
|
||||
})
|
||||
|
||||
const dialogAddVisible = ref(false)
|
||||
const dialogEditVisible = ref(false)
|
||||
const dialogAddFormRef = ref(null)
|
||||
const dialogEditFormRef = ref(null)
|
||||
|
||||
const dialogAddForm = ref({})
|
||||
const dialogEditForm = ref({})
|
||||
|
||||
|
||||
const submitAdd = async () => {
|
||||
try {
|
||||
await dialogAddFormRef.value.validate(valid => {
|
||||
if (valid) {
|
||||
resourcePost(resource_url, dialogAddForm.value).then((res) => {
|
||||
ElNotification({
|
||||
title: "添加结果通知",
|
||||
message: "添加成功!",
|
||||
type: 'success',
|
||||
duration: 4000,
|
||||
"show-close": true,
|
||||
})
|
||||
rows.value.push(dialogAddForm.value)
|
||||
dialogAddVisible.value = false
|
||||
}, (err) => {
|
||||
console.log("添加报错:", err)
|
||||
})
|
||||
console.log("提交数据:", dialogAddForm.value)
|
||||
}
|
||||
})
|
||||
} catch (error) {
|
||||
console.log("校验失败:", error)
|
||||
}
|
||||
}
|
||||
|
||||
const submitEdit = async () => {
|
||||
try {
|
||||
await dialogEditFormRef.value.validate(valid => {
|
||||
if (valid) {
|
||||
resourcePut(resource_url, dialogEditForm.value).then((res) => {
|
||||
ElNotification({
|
||||
title: "编辑结果通知",
|
||||
message: "编辑成功!",
|
||||
type: 'success',
|
||||
duration: 4000,
|
||||
"show-close": true,
|
||||
})
|
||||
dialogEditVisible.value = false
|
||||
rows.value[dialogEditForm.value.oldIndex] = res.data.dto
|
||||
}, (err) => {
|
||||
console.log("添加报错:", err)
|
||||
})
|
||||
console.log("提交数据:", dialogEditForm.value)
|
||||
}
|
||||
})
|
||||
} catch (error) {
|
||||
console.log("校验失败:", error)
|
||||
}
|
||||
}
|
||||
|
||||
const handleEdit = (oper, index, row) => {
|
||||
dialogEditForm.value.oldData = row
|
||||
dialogEditForm.value.oldIndex = index
|
||||
dialogEditForm.value = row
|
||||
console.log("edit data:", row)
|
||||
dialogEditVisible.value = true
|
||||
}
|
||||
|
||||
const handleDelete = (oper, index, row) => {
|
||||
resourceDelete(resource_url, {id: row.ID}).then((res) => {
|
||||
ElNotification({
|
||||
title: "删除结果通知",
|
||||
message: "删除指令服务器[" + row.name + "]成功!",
|
||||
type: 'success',
|
||||
duration: 4000,
|
||||
"show-close": true,
|
||||
})
|
||||
rows.value.splice(index, 1)
|
||||
}, (err) => {
|
||||
console.log("delet error:", err)
|
||||
})
|
||||
}
|
||||
|
||||
const tableRowClick = (index, row) => {
|
||||
console.log("row is clicked:", row)
|
||||
if (props.row_click_handler != null) {
|
||||
props.row_click_handler(row)
|
||||
}
|
||||
}
|
||||
|
||||
const handleCloseDialog = () => {
|
||||
dialogAddVisible.value = false
|
||||
dialogEditVisible.value = false
|
||||
dialogAddForm.value = {}
|
||||
dialogEditForm.value = {}
|
||||
}
|
||||
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div>
|
||||
<el-container>
|
||||
<el-header>
|
||||
<el-button size="large" type="primary">添加</el-button>
|
||||
</el-header>
|
||||
<el-main>
|
||||
<el-table :data="rows" style="width: 100%" table-layout="auto" stripe>
|
||||
<template v-for="fieldDescInfo in fieldsDescInfo">
|
||||
<el-table-column :prop="fieldDescInfo.key" :label="fieldDescInfo.name"></el-table-column>/
|
||||
<el-container v-if="getListOk">
|
||||
<el-header>
|
||||
<el-button @click="dialogAddVisible = true" size="large" type="primary">添加</el-button>
|
||||
</el-header>
|
||||
<el-main>
|
||||
<el-table :data="rows" style="width: 100%" table-layout="auto" stripe>
|
||||
<template v-for="fieldDescInfo in fieldsDescInfo">
|
||||
<el-table-column :prop="fieldDescInfo.key" :label="fieldDescInfo.name"></el-table-column>
|
||||
</template>
|
||||
<el-table-column prop="func" label="功 能">
|
||||
<template #default="scope">
|
||||
<el-button size="large" type="primary" @click="tableRowClick(scope.$index, scope.row)">
|
||||
<el-icon style="vertical-align: middle">
|
||||
<ArrowRightBold/>
|
||||
</el-icon>
|
||||
<span>进入</span>
|
||||
</el-button>
|
||||
<el-button size="large" type="success" @click="handleEdit('operation', scope.$index, scope.row)">
|
||||
<el-icon style="vertical-align: middle">
|
||||
<Operation/>
|
||||
</el-icon>
|
||||
<span>编辑</span>
|
||||
</el-button>
|
||||
<el-button size="large" type="danger" @click="handleDelete('operation', scope.$index, scope.row)">
|
||||
<el-icon style="vertical-align: middle">
|
||||
<Delete/>
|
||||
</el-icon>
|
||||
<span>删除</span>
|
||||
</el-button>
|
||||
</template>
|
||||
</el-table>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
|
||||
<el-dialog v-model="addvisible" title="添加" modal="true" :before-close="handleCloseAdd" destroy-on-close>
|
||||
|
||||
</el-dialog>
|
||||
<el-dialog v-model="dialogAddVisible" :mask="true" title="添加" :modal="true" :before-close="handleCloseDialog"
|
||||
destroy-on-close>
|
||||
<el-form ref="dialogAddFormRef" :model="dialogAddForm" :rules="rules">
|
||||
<template v-for="fieldDescInfo in fieldsDescInfo">
|
||||
<el-form-item :label="fieldDescInfo.name" :prop="fieldDescInfo.key">
|
||||
<el-input v-model="dialogAddForm[fieldDescInfo.key]" :placeholder="fieldDescInfo.name"></el-input>
|
||||
</el-form-item>
|
||||
</template>
|
||||
|
||||
</el-main>
|
||||
</el-container>
|
||||
</div>
|
||||
<el-form-item>
|
||||
<el-button @click="submitAdd(dialogAddFormRef)" size="large" type="primary">提交</el-button>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</el-dialog>
|
||||
|
||||
<el-dialog v-model="dialogEditVisible" :mask="true" title="编辑" :modal="true" :before-close="handleCloseDialog"
|
||||
destroy-on-close>
|
||||
<el-form ref="dialogEditFormRef" :model="dialogEditForm" :rules="rules">
|
||||
<template v-for="fieldDescInfo in fieldsDescInfo">
|
||||
<el-form-item :label="fieldDescInfo.name" :prop="fieldDescInfo.key">
|
||||
<el-input v-model="dialogEditForm[fieldDescInfo.key]"></el-input>
|
||||
</el-form-item>
|
||||
</template>
|
||||
|
||||
<el-form-item>
|
||||
<el-button @click="submitEdit(dialogEditFormRef)" size="large" type="primary">提交</el-button>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</el-dialog>
|
||||
|
||||
</el-main>
|
||||
</el-container>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
|
@ -6,9 +6,14 @@ import ElementPlus from 'element-plus'
|
||||
import 'element-plus/dist/index.css'
|
||||
import App from './App.vue'
|
||||
import router from './router'
|
||||
import * as ElementPlusIconsVue from '@element-plus/icons-vue'
|
||||
|
||||
const app = createApp(App)
|
||||
|
||||
for (const [key, component] of Object.entries(ElementPlusIconsVue)) {
|
||||
app.component(key, component)
|
||||
}
|
||||
|
||||
app.use(ElementPlus)
|
||||
app.use(createPinia())
|
||||
app.use(router)
|
||||
|
@ -1,27 +1,41 @@
|
||||
import { createRouter, createWebHistory } from 'vue-router'
|
||||
import {createRouter, createWebHistory} from 'vue-router'
|
||||
import Home from '../views/Home.vue'
|
||||
|
||||
const query = () => {
|
||||
return {
|
||||
t: Date.now(),
|
||||
}
|
||||
}
|
||||
|
||||
const router = createRouter({
|
||||
history: createWebHistory(import.meta.env.BASE_URL),
|
||||
routes: [
|
||||
{
|
||||
path: '/',
|
||||
name: 'home',
|
||||
component: Home,
|
||||
children: [
|
||||
history: createWebHistory(import.meta.env.BASE_URL),
|
||||
routes: [
|
||||
{
|
||||
path: '/user',
|
||||
name: 'user',
|
||||
component: import('@/views/user/user.vue')
|
||||
path: '/',
|
||||
name: 'home',
|
||||
component: Home,
|
||||
children: [
|
||||
{
|
||||
path: '/user',
|
||||
name: 'user',
|
||||
component: () => import('@/views/user/user.vue')
|
||||
},
|
||||
{
|
||||
path: '/project',
|
||||
name: 'project',
|
||||
component: () => import('@/views/project/project.vue'),
|
||||
query: query(),
|
||||
children: [
|
||||
{
|
||||
path: 'operation',
|
||||
name: "ProjectOperation",
|
||||
component: () => import('@/views/project/operation.vue')
|
||||
},
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
path: '/project',
|
||||
name: 'project',
|
||||
component: import('@/views/project/project.vue')
|
||||
}
|
||||
]
|
||||
},
|
||||
],
|
||||
],
|
||||
})
|
||||
|
||||
export default router
|
||||
|
@ -1,12 +0,0 @@
|
||||
import { ref, computed } from 'vue'
|
||||
import { defineStore } from 'pinia'
|
||||
|
||||
export const useCounterStore = defineStore('counter', () => {
|
||||
const count = ref(0)
|
||||
const doubleCount = computed(() => count.value * 2)
|
||||
function increment() {
|
||||
count.value++
|
||||
}
|
||||
|
||||
return { count, doubleCount, increment }
|
||||
})
|
12
ui/src/stores/project.js
Normal file
12
ui/src/stores/project.js
Normal file
@ -0,0 +1,12 @@
|
||||
import {ref} from 'vue'
|
||||
import {defineStore} from 'pinia'
|
||||
|
||||
export const cachedProject = defineStore('clickedProject', () => {
|
||||
const project = ref({})
|
||||
const set = (setProject) => project.value = setProject
|
||||
const get = () => project.value
|
||||
return {
|
||||
set,
|
||||
get,
|
||||
}
|
||||
})
|
@ -1,6 +1,6 @@
|
||||
<script setup>
|
||||
import { useRouter, useRoute } from 'vue-router'
|
||||
import { computed } from 'vue'
|
||||
import {useRoute, useRouter} from 'vue-router'
|
||||
import {computed} from 'vue'
|
||||
import avatarUrl from '@/assets/icon/header.png'
|
||||
|
||||
const router = useRouter()
|
||||
@ -34,8 +34,10 @@ const handleMenuSelect = (index) => {
|
||||
</el-menu>
|
||||
</el-aside>
|
||||
<el-container>
|
||||
<el-header>Header</el-header>
|
||||
<el-header><router-view/></el-header>
|
||||
<el-header>游戏后台管理系统</el-header>
|
||||
<el-main>
|
||||
<router-view/>
|
||||
</el-main>
|
||||
</el-container>
|
||||
</el-container>
|
||||
</div>
|
||||
|
49
ui/src/views/project/operation.vue
Normal file
49
ui/src/views/project/operation.vue
Normal file
@ -0,0 +1,49 @@
|
||||
<script setup>
|
||||
import {cachedProject} from '@/stores/project.js'
|
||||
import {gameApiRequest} from '@/api/game_api.js'
|
||||
|
||||
const cachedProject1 = cachedProject()
|
||||
|
||||
const curProject = cachedProject1.get()
|
||||
|
||||
const commandList = ref([])
|
||||
|
||||
console.log("handle project:", curProject)
|
||||
console.log("command api addr:", curProject.ApiAddr)
|
||||
|
||||
gameApiRequest("/project/commandlist", "get", {addr: curProject.ApiAddr}).then((res) => {
|
||||
// console.log("请求commandlist成功!", res)
|
||||
commandList.value = res.data.list
|
||||
}, (err) => {
|
||||
|
||||
})
|
||||
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<el-container>
|
||||
<el-aside width="200px">
|
||||
<el-menu
|
||||
:default-active="activeMenu"
|
||||
@select="handleMenuSelect"
|
||||
>
|
||||
<el-menu-item index="/user">
|
||||
<span>用户管理</span>
|
||||
</el-menu-item>
|
||||
<el-menu-item index="/project">
|
||||
<span>项目管理</span>
|
||||
</el-menu-item>
|
||||
</el-menu>
|
||||
</el-aside>
|
||||
<el-container>
|
||||
<el-header>游戏后台管理系统</el-header>
|
||||
<el-main>
|
||||
<router-view/>
|
||||
</el-main>
|
||||
</el-container>
|
||||
</el-container>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
|
||||
</style>
|
@ -1,27 +1,33 @@
|
||||
<script setup>
|
||||
import {ref} from "vue";
|
||||
import {getProjectList} from '@/api/project/project.js'
|
||||
import tableComp from "@/components/restful/table.vue"
|
||||
|
||||
const rows = ref([])
|
||||
const getProjectListOk = ref(false)
|
||||
import table from '@/components/restful/table.vue'
|
||||
import operation from '@/views/project/operation.vue'
|
||||
import {cachedProject} from '@/stores/project.js'
|
||||
import {useRouter} from 'vue-router'
|
||||
|
||||
getProjectList({page_no: 0, page_len: 100}).then((response) => {
|
||||
console.log(response)
|
||||
rows.value = response.data
|
||||
getProjectListOk.value = true
|
||||
}, (err) => {
|
||||
console.log(err)
|
||||
})
|
||||
const cachedProject1 = cachedProject()
|
||||
|
||||
const router = useRouter()
|
||||
|
||||
const page = ref('project')
|
||||
|
||||
const row_click_handler = (row, column, event) => {
|
||||
// console.log("project row is clicked:", row)
|
||||
cachedProject1.set(row)
|
||||
const cachePro = cachedProject1.get()
|
||||
console.log('cached project:', cachePro)
|
||||
console.log("router:", router.getRoutes())
|
||||
page.value = 'operation'
|
||||
}
|
||||
|
||||
</script>
|
||||
|
||||
<template>
|
||||
项目
|
||||
<div>
|
||||
<template v-if="getProjectListOk">
|
||||
<component :is="tableComp" :rows="rows"></component>
|
||||
</template>
|
||||
<div v-if="page === 'project'">
|
||||
<component :is="table" resource_url="/project" :row_click_handler="row_click_handler"></component>
|
||||
</div>
|
||||
<div v-else-if="page === 'operation'">
|
||||
<component :is="operation" resource_url="/project" :row_click_handler="row_click_handler"></component>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
|
@ -2,6 +2,8 @@ import { fileURLToPath, URL } from 'node:url'
|
||||
|
||||
import { defineConfig } from 'vite'
|
||||
import vue from '@vitejs/plugin-vue'
|
||||
import Icons from 'unplugin-icons/vite'
|
||||
import IconsResolver from 'unplugin-icons/resolver'
|
||||
import vueDevTools from 'vite-plugin-vue-devtools'
|
||||
|
||||
import AutoImport from 'unplugin-auto-import/vite'
|
||||
@ -18,10 +20,25 @@ export default defineConfig(({ mode, command }) => {
|
||||
vue(),
|
||||
vueDevTools(),
|
||||
AutoImport({
|
||||
resolvers: [ElementPlusResolver()],
|
||||
imports: ['vue'],
|
||||
resolvers: [
|
||||
ElementPlusResolver(),
|
||||
IconsResolver({
|
||||
prefix: 'Icon',
|
||||
}),
|
||||
],
|
||||
}),
|
||||
Components({
|
||||
resolvers: [ElementPlusResolver()],
|
||||
resolvers: [
|
||||
IconsResolver({
|
||||
enabledCollections: ['ep'],
|
||||
}),
|
||||
ElementPlusResolver(),
|
||||
],
|
||||
}),
|
||||
|
||||
Icons({
|
||||
autoInstall: true,
|
||||
}),
|
||||
],
|
||||
resolve: {
|
||||
|
Loading…
x
Reference in New Issue
Block a user