Merge branch 'master' of http://8.137.58.20:3000/lkness/uniugm
This commit is contained in:
		
						commit
						a2897f288e
					
				@ -39,7 +39,7 @@ func NewCommonResourceService(db *gorm.DB) *CommonResourceService {
 | 
			
		||||
	return svc
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (svc *CommonResourceService) List(projectId int, resource string, pageNo, pageLen int, extraQuery string, args ...any) ([]*dto.CommonDtoFieldDesc, []dto.CommonDtoValues, error) {
 | 
			
		||||
func (svc *CommonResourceService) List(projectId int, resource string, listParams *dto.CommonListReq) ([]*dto.CommonDtoFieldDesc, []dto.CommonDtoValues, error) {
 | 
			
		||||
	_, projectEt, find, err := svc.projectRepo.GetById(projectId)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, nil, err
 | 
			
		||||
@ -48,7 +48,8 @@ func (svc *CommonResourceService) List(projectId int, resource string, pageNo, p
 | 
			
		||||
		return nil, nil, errcode.New(errcode.ServerError, "not found project %v db data", projectId)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	fieldsDescInfo, etList, err := findCommResourceRepo(resource).List(projectEt, pageNo, pageLen, extraQuery, args...)
 | 
			
		||||
	fieldsDescInfo, etList, err := findCommResourceRepo(resource).List(projectEt,
 | 
			
		||||
		listParams.PageNo, listParams.PageLen, listParams.ParsedWhereConditions.Conditions)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, nil, err
 | 
			
		||||
	}
 | 
			
		||||
@ -59,7 +60,7 @@ func (svc *CommonResourceService) List(projectId int, resource string, pageNo, p
 | 
			
		||||
 | 
			
		||||
	// 执行各个项目特定的钩子方法
 | 
			
		||||
	if hook, ok := projects.GetProjectResourceHook(projectEt, resource).(projects.IPostResourceOpListHook); ok {
 | 
			
		||||
		return hook.List(projectEt, resource, pageNo, pageLen, fieldsDescInfo, retList, extraQuery, args...)
 | 
			
		||||
		return hook.List(projectEt, resource, listParams.PageNo, listParams.PageLen, fieldsDescInfo, retList, "")
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return fieldsDescInfo, retList, nil
 | 
			
		||||
 | 
			
		||||
@ -52,6 +52,7 @@ func getFieldTypeDtoDescInfo(project *Project, poValue reflect.Value, fieldType
 | 
			
		||||
		Choices:     make([]*dto.CommonDtoFieldChoice, 0),
 | 
			
		||||
		MultiChoice: fieldType.Tag.Get("multi_choice") == "true",
 | 
			
		||||
		Uneditable:  fieldType.Tag.Get("uneditable") == "true",
 | 
			
		||||
		Where:       fieldType.Tag.Get("where"),
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if f1.Key == "CreatedAt" {
 | 
			
		||||
 | 
			
		||||
@ -2,8 +2,10 @@ package domain
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"admin/apps/game/domain/entity"
 | 
			
		||||
	"admin/apps/game/domain/projects"
 | 
			
		||||
	"admin/apps/game/domain/repo"
 | 
			
		||||
	"admin/apps/game/model/dto"
 | 
			
		||||
	"admin/internal/errcode"
 | 
			
		||||
	"gorm.io/gorm"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
@ -68,3 +70,20 @@ func (svc *ProjectService) GetProjectInvokeApiAddr(projectId int, serverIds []in
 | 
			
		||||
	}
 | 
			
		||||
	return []string{et.Po.ApiAddr}, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (svc *ProjectService) GetAllItems(projectId int) ([]*dto.CommonDtoFieldChoice, error) {
 | 
			
		||||
	_, projectEt, find, err := svc.repo.GetById(projectId)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
	if !find {
 | 
			
		||||
		return nil, errcode.New(errcode.ServerError, "not found project %v db data", projectId)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	handler := projects.GetProjectValueChoicesGetHook(projectEt.Po.ProjectType)
 | 
			
		||||
	if handler == nil {
 | 
			
		||||
		return nil, errcode.New(errcode.ServerError, "not found project %v items handler", projectEt.Po.ProjectType)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return handler.GetItems(projectEt)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -25,6 +25,7 @@ var projectsValueChoicesGetHook = map[string]IGetAllValueChoicesHook{
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func GetProjectResourceHook(project *entity.Project, resource string) any {
 | 
			
		||||
	return nil
 | 
			
		||||
	projectResourceHooks, find := projectsResourceHookMgr[project.Po.ProjectType]
 | 
			
		||||
	if !find {
 | 
			
		||||
		return nil
 | 
			
		||||
 | 
			
		||||
@ -11,6 +11,12 @@ type Items struct {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (items *Items) GetItems(projectInfo *entity.Project) ([]*dto.CommonDtoFieldChoice, error) {
 | 
			
		||||
	return []*dto.CommonDtoFieldChoice{
 | 
			
		||||
		{Desc: "黄金战甲", Value: 123, Type: 1},
 | 
			
		||||
		{Desc: "黄金头盔", Value: 234, Type: 1},
 | 
			
		||||
		{Desc: "黄金大刀", Value: 346, Type: 1},
 | 
			
		||||
		{Desc: "白银大刀", Value: 346, Type: 1},
 | 
			
		||||
	}, nil
 | 
			
		||||
	alisrvAddr := projectInfo.GetApiAddr()
 | 
			
		||||
	if alisrvAddr == "" {
 | 
			
		||||
		return nil, errcode.New(errcode.ServerError, "项目%v没有配置api服务器地址", projectInfo.Po.Name)
 | 
			
		||||
 | 
			
		||||
@ -5,13 +5,18 @@ import (
 | 
			
		||||
	"admin/apps/game/model"
 | 
			
		||||
	"admin/apps/game/model/dto"
 | 
			
		||||
	"admin/internal/errcode"
 | 
			
		||||
	"admin/lib/xlog"
 | 
			
		||||
	"errors"
 | 
			
		||||
	"fmt"
 | 
			
		||||
	"gorm.io/gorm"
 | 
			
		||||
	"gorm.io/gorm/schema"
 | 
			
		||||
	"reflect"
 | 
			
		||||
	"strings"
 | 
			
		||||
	"time"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
type ICommonResourceRepo interface {
 | 
			
		||||
	List(project *entity.Project, pageNo, pageLen int, extraQuery string, args ...any) ([]*dto.CommonDtoFieldDesc, []*entity.CommonResource, error)
 | 
			
		||||
	List(project *entity.Project, pageNo, pageLen int, whereConditions []*dto.GetWhereCondition) ([]*dto.CommonDtoFieldDesc, []*entity.CommonResource, error)
 | 
			
		||||
	GetById(projectEt *entity.Project, id int) ([]*dto.CommonDtoFieldDesc, *entity.CommonResource, bool, error)
 | 
			
		||||
	Create(projectEt *entity.Project, et dto.CommonDtoValues) (*entity.CommonResource, error)
 | 
			
		||||
	Edit(projectEt *entity.Project, et dto.CommonDtoValues) error
 | 
			
		||||
@ -34,15 +39,28 @@ func newCommonResourceRepoImpl(db *gorm.DB, poTemplate model.IModel) *commonReso
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (repo *commonResourceRepoImpl) List(projectEt *entity.Project, pageNo, pageLen int,
 | 
			
		||||
	extraQuery string, args ...any) ([]*dto.CommonDtoFieldDesc, []*entity.CommonResource, error) {
 | 
			
		||||
	whereConditions []*dto.GetWhereCondition) ([]*dto.CommonDtoFieldDesc, []*entity.CommonResource, error) {
 | 
			
		||||
 | 
			
		||||
	if pageNo < 0 || pageLen <= 0 {
 | 
			
		||||
		return nil, nil, errcode.New(errcode.ParamsInvalid, "page no or page len invalid:%v,%v", pageNo, pageLen)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	limitStart := pageNo * pageLen
 | 
			
		||||
	limitLen := pageLen
 | 
			
		||||
 | 
			
		||||
	listType := reflect.New(reflect.SliceOf(reflect.TypeOf(repo.poTemplate)))
 | 
			
		||||
 | 
			
		||||
	var tx *gorm.DB
 | 
			
		||||
	var err error
 | 
			
		||||
	if extraQuery == "" {
 | 
			
		||||
		err = repo.db.Find(listType.Interface()).Error
 | 
			
		||||
	if len(whereConditions) <= 0 {
 | 
			
		||||
		tx = repo.db.Offset(limitStart).Limit(limitLen)
 | 
			
		||||
	} else {
 | 
			
		||||
		err = repo.db.Where(extraQuery, args...).Find(listType.Interface()).Error
 | 
			
		||||
		whereSql, whereArgs := repo.parseWhereConditions2Sql(whereConditions)
 | 
			
		||||
		xlog.Debugf("list resource %v where sql:%v, args:%+v",
 | 
			
		||||
			repo.poTemplate.TableName(), whereSql, whereArgs)
 | 
			
		||||
		tx = repo.db.Where(whereSql, whereArgs...).Offset(limitStart).Limit(limitLen)
 | 
			
		||||
	}
 | 
			
		||||
	err = tx.Find(listType.Interface()).Error
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, nil, errcode.New(errcode.DBError, "list resource %v error:%v", repo.poTemplate.TableName(), err)
 | 
			
		||||
	}
 | 
			
		||||
@ -110,3 +128,52 @@ func (repo *commonResourceRepoImpl) Delete(projectEt *entity.Project, id int) (*
 | 
			
		||||
func (repo *commonResourceRepoImpl) newEmptyPo() model.IModel {
 | 
			
		||||
	return reflect.New(reflect.TypeOf(repo.poTemplate).Elem()).Interface().(model.IModel)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (repo *commonResourceRepoImpl) parseWhereConditions2Sql(conditions []*dto.GetWhereCondition) (whereSql string, args []any) {
 | 
			
		||||
	namer := new(schema.NamingStrategy)
 | 
			
		||||
	to := reflect.TypeOf(repo.poTemplate).Elem()
 | 
			
		||||
	whereClause := make([]string, 0, len(conditions))
 | 
			
		||||
	whereArgs := make([]interface{}, 0, len(conditions))
 | 
			
		||||
	for _, cond := range conditions {
 | 
			
		||||
		for i := 0; i < to.NumField(); i++ {
 | 
			
		||||
			field := to.Field(i)
 | 
			
		||||
			if field.Name != cond.Key {
 | 
			
		||||
				continue
 | 
			
		||||
			}
 | 
			
		||||
			dbFieldName := namer.ColumnName("", field.Name)
 | 
			
		||||
			if field.Type.Name() == "Time" {
 | 
			
		||||
				cond.Value1, _ = time.ParseInLocation("2006/01/02 15:04:05", cond.Value1.(string), time.Local)
 | 
			
		||||
				cond.Value2, _ = time.ParseInLocation("2006/01/02 15:04:05", cond.Value2.(string), time.Local)
 | 
			
		||||
			}
 | 
			
		||||
			switch field.Tag.Get("where") {
 | 
			
		||||
			case "eq":
 | 
			
		||||
				whereClause = append(whereClause, fmt.Sprintf("`%v` = ?", dbFieldName))
 | 
			
		||||
				whereArgs = append(whereArgs, cond.Value1)
 | 
			
		||||
			case "gt":
 | 
			
		||||
				whereClause = append(whereClause, fmt.Sprintf("`%v` > ?", dbFieldName))
 | 
			
		||||
				whereArgs = append(whereArgs, cond.Value1)
 | 
			
		||||
			case "lt":
 | 
			
		||||
				whereClause = append(whereClause, fmt.Sprintf("`%v` < ?", dbFieldName))
 | 
			
		||||
				whereArgs = append(whereArgs, cond.Value1)
 | 
			
		||||
			case "le":
 | 
			
		||||
				whereClause = append(whereClause, fmt.Sprintf("`%v` <= ?", dbFieldName))
 | 
			
		||||
				whereArgs = append(whereArgs, cond.Value1)
 | 
			
		||||
			case "ge":
 | 
			
		||||
				whereClause = append(whereClause, fmt.Sprintf("`%v` >= ?", dbFieldName))
 | 
			
		||||
				whereArgs = append(whereArgs, cond.Value1)
 | 
			
		||||
			case "like":
 | 
			
		||||
				whereClause = append(whereClause, fmt.Sprintf("`%v` like ?", dbFieldName))
 | 
			
		||||
				whereArgs = append(whereArgs, cond.Value1)
 | 
			
		||||
			case "range":
 | 
			
		||||
				whereClause = append(whereClause, fmt.Sprintf("`%v` >= ? and `%v` <= ?", dbFieldName, dbFieldName))
 | 
			
		||||
				whereArgs = append(whereArgs, cond.Value1, cond.Value2)
 | 
			
		||||
			case "":
 | 
			
		||||
			default:
 | 
			
		||||
				panic(fmt.Errorf("unsupport where tag %v", field.Tag))
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	whereSql = strings.Join(whereClause, " AND ")
 | 
			
		||||
	return whereSql, whereArgs
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -12,8 +12,8 @@ func init() {
 | 
			
		||||
// Account 空表,就是用来兼容资源增删改查公共操作的,实际列举账号等都是走各个项目api拉取
 | 
			
		||||
type Account struct {
 | 
			
		||||
	ProjectId       int
 | 
			
		||||
	Account         string    `name:"账号" json:"account"`
 | 
			
		||||
	ServerConfId    string    `name:"区服id" json:"serveId"`
 | 
			
		||||
	Account         string    `name:"账号" json:"account" where:"eq"`
 | 
			
		||||
	ServerConfId    string    `name:"区服id" json:"serveId" where:"eq"`
 | 
			
		||||
	RoleIds         []string  `gorm:"type:json;serializer:json" name:"角色id列表" json:"roleIds"`
 | 
			
		||||
	LatestLoginTime time.Time `name:"最近登录时间" json:"latest_login_time"`
 | 
			
		||||
	CreateTime      time.Time `name:"创建时间" json:"create_time"`
 | 
			
		||||
 | 
			
		||||
@ -25,6 +25,7 @@ type CommonDtoFieldDesc struct {
 | 
			
		||||
	Choices     []*CommonDtoFieldChoice `json:"choices"`      // 可选项,用于字段做下拉框
 | 
			
		||||
	MultiChoice bool                    `json:"multi_choice"` // 是否多选
 | 
			
		||||
	Uneditable  bool                    `json:"uneditable"`   // 不可编辑,某些数据一旦新增之后不能修改,例如封禁的值、服务器的id等
 | 
			
		||||
	Where       string                  `json:"where"`        // sql list的where条件,用于表格页面查询条件编写,值:eq gt lt ge lt range like
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
//type CommonDtoValue struct {
 | 
			
		||||
@ -43,3 +44,10 @@ type PathInfo struct {
 | 
			
		||||
	Path   string `json:"path"`
 | 
			
		||||
	Method string `json:"method"`
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type GetWhereCondition struct {
 | 
			
		||||
	Key    string `json:"key"`
 | 
			
		||||
	Op     string `json:"op"` // eq,gt,lt,range
 | 
			
		||||
	Value1 any    `json:"value1"`
 | 
			
		||||
	Value2 any    `json:"value2"`
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -5,12 +5,16 @@ type NilReq struct {
 | 
			
		||||
 | 
			
		||||
type NilRsp = NilReq
 | 
			
		||||
 | 
			
		||||
type ListWhereConditionInfo struct {
 | 
			
		||||
	Conditions []*GetWhereCondition `json:"conditions"`
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type CommonListReq struct {
 | 
			
		||||
	PageNo      int    `json:"page_no"`
 | 
			
		||||
	PageLen     int    `json:"page_len"`
 | 
			
		||||
	WhereValue1 string `json:"where_value1"`
 | 
			
		||||
	WhereValue2 string `json:"where_value2"`
 | 
			
		||||
	WhereValue3 string `json:"where_value3"`
 | 
			
		||||
	PageNo  int `json:"page_no"`
 | 
			
		||||
	PageLen int `json:"page_len"`
 | 
			
		||||
	//WhereConditions []*GetWhereCondition `json:"where_conditions"`
 | 
			
		||||
	WhereConditions       string                  `json:"where_conditions"` // json序列化数据,内容是{"conditions": []*GetWhereCondition}
 | 
			
		||||
	ParsedWhereConditions *ListWhereConditionInfo `json:"-"`
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type CommonPostReq struct {
 | 
			
		||||
@ -46,3 +50,7 @@ type CommandListReq struct {
 | 
			
		||||
type CommandListRsp struct {
 | 
			
		||||
	List []*PathInfo `json:"list"`
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type GetProjectAllItemsRsp struct {
 | 
			
		||||
	Items []*CommonDtoFieldChoice `json:"items"`
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -10,17 +10,15 @@ func init() {
 | 
			
		||||
	db.RegisterTableModels(GlobalMail{})
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
var ProjectsAllItems = make(map[string][]*dto.CommonDtoFieldChoice)
 | 
			
		||||
 | 
			
		||||
type GlobalMail struct {
 | 
			
		||||
	ID        int `gorm:"primarykey" readonly:"true"`
 | 
			
		||||
	ProjectId int
 | 
			
		||||
	ServerIDs []string          `gorm:"type:json;serializer:json" name:"区服" type:"[]string" choices:"GetChoiceServers" multi_choice:"true"`
 | 
			
		||||
	Title     string            `name:"邮件标题" required:"true"`
 | 
			
		||||
	Content   string            `name:"邮件内容" required:"true"`
 | 
			
		||||
	Attach    []*MailAttachItem `gorm:"type:json;serializer:json" name:"邮件附件" type:"items" choices:"GetChoiceItems"`
 | 
			
		||||
	Attach    []*MailAttachItem `gorm:"type:json;serializer:json" name:"邮件附件" type:"items" desc:"搜索道具并点击添加"`
 | 
			
		||||
 | 
			
		||||
	CreatedAt time.Time `readonly:"true"`
 | 
			
		||||
	CreatedAt time.Time `readonly:"true" where:"range"`
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (lm *GlobalMail) TableName() string {
 | 
			
		||||
@ -34,7 +32,3 @@ func (m *GlobalMail) GetId() int {
 | 
			
		||||
func (m *GlobalMail) GetChoiceServers(project *Project) []*dto.CommonDtoFieldChoice {
 | 
			
		||||
	return getChoiceServers(project)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (m *GlobalMail) GetChoiceItems(project *Project) []*dto.CommonDtoFieldChoice {
 | 
			
		||||
	return ProjectsAllItems[project.ProjectType]
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -12,10 +12,10 @@ func init() {
 | 
			
		||||
// Role 空表,就是用来兼容资源增删改查公共操作的,实际列举账号等都是走各个项目api拉取
 | 
			
		||||
type Role struct {
 | 
			
		||||
	ProjectId       int
 | 
			
		||||
	RoleId          string    `name:"角色ID" json:"roleId"`
 | 
			
		||||
	Account         string    `name:"账号" json:"account"`
 | 
			
		||||
	ServerConfId    string    `name:"区服id" json:"serverId"`
 | 
			
		||||
	Name            string    `name:"名称" json:"roleName"`
 | 
			
		||||
	RoleId          string    `name:"角色ID" json:"roleId" where:"eq"`
 | 
			
		||||
	Account         string    `name:"账号" json:"account" where:"eq"`
 | 
			
		||||
	ServerConfId    string    `name:"区服id" json:"serverId" where:"eq"`
 | 
			
		||||
	Name            string    `name:"名称" json:"roleName" where:"eq"`
 | 
			
		||||
	Status          string    `name:"状态" desc:"离线|在线" json:"status"`
 | 
			
		||||
	Level           int       `name:"等级" json:"roleLevel"`
 | 
			
		||||
	Profession      string    `name:"职业" json:"profession"`
 | 
			
		||||
 | 
			
		||||
@ -20,12 +20,12 @@ type RoleMail struct {
 | 
			
		||||
	ID        int `gorm:"primarykey" readonly:"true"`
 | 
			
		||||
	ProjectId int
 | 
			
		||||
	RoleIDs   []string          `gorm:"type:json;serializer:json" name:"生效的角色id" desc:"生效的角色id,逗号分隔多个" required:"true"`
 | 
			
		||||
	ServerID  string            `name:"所属区服" choices:"GetChoiceServers" required:"true"`
 | 
			
		||||
	ServerID  string            `name:"所属区服" choices:"GetChoiceServers" required:"true" where:"eq"`
 | 
			
		||||
	Title     string            `name:"邮件标题" required:"true"`
 | 
			
		||||
	Content   string            `name:"邮件内容" required:"true"`
 | 
			
		||||
	Attach    []*MailAttachItem `gorm:"type:json;serializer:json" name:"邮件附件" type:"items" choices:"GetChoiceItems"`
 | 
			
		||||
	Attach    []*MailAttachItem `gorm:"type:json;serializer:json" name:"邮件附件" type:"items" desc:"搜索道具并点击添加"`
 | 
			
		||||
 | 
			
		||||
	CreatedAt time.Time `readonly:"true"`
 | 
			
		||||
	CreatedAt time.Time `readonly:"true" where:"range"`
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (lm *RoleMail) TableName() string {
 | 
			
		||||
@ -39,7 +39,3 @@ func (m *RoleMail) GetId() int {
 | 
			
		||||
func (m *RoleMail) GetChoiceServers(project *Project) []*dto.CommonDtoFieldChoice {
 | 
			
		||||
	return getChoiceServers(project)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (m *RoleMail) GetChoiceItems(project *Project) []*dto.CommonDtoFieldChoice {
 | 
			
		||||
	return ProjectsAllItems[project.ProjectType]
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -13,11 +13,11 @@ func init() {
 | 
			
		||||
type WhiteList struct {
 | 
			
		||||
	ID           int    `gorm:"primarykey" readonly:"true"`
 | 
			
		||||
	ProjectId    int    `gorm:"uniqueIndex:idx_whitelist"`
 | 
			
		||||
	ServerConfID string `gorm:"type:varchar(200);uniqueIndex:idx_server" name:"区服id" required:"true" choices:"GetChoiceServers"`
 | 
			
		||||
	ServerConfID string `gorm:"type:varchar(200);uniqueIndex:idx_server" name:"区服id" required:"true" choices:"GetChoiceServers" where:"eq"`
 | 
			
		||||
	Account      string `gorm:"type:varchar(128);uniqueIndex:idx_whitelist" name:"账户" required:"true"`
 | 
			
		||||
	Desc         string `name:"描述"`
 | 
			
		||||
 | 
			
		||||
	CreatedAt time.Time `readonly:"true"`
 | 
			
		||||
	CreatedAt time.Time `readonly:"true" where:"range"`
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (lm *WhiteList) TableName() string {
 | 
			
		||||
 | 
			
		||||
@ -3,6 +3,7 @@ package server
 | 
			
		||||
import (
 | 
			
		||||
	"admin/apps/game/model/dto"
 | 
			
		||||
	"admin/internal/context"
 | 
			
		||||
	stdContext "context"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
func (ctl *controller) CommonList(ctx *context.WebContext, params *dto.CommonListReq, rsp *dto.CommonListRsp) error {
 | 
			
		||||
@ -17,7 +18,11 @@ func (ctl *controller) CommonList(ctx *context.WebContext, params *dto.CommonLis
 | 
			
		||||
 | 
			
		||||
func (ctl *controller) CommonPost(ctx *context.WebContext, params *dto.CommonPostReq, rsp *dto.CommonPostRsp) error {
 | 
			
		||||
	projectId, resource := getCtxURIProjectIdAndResource(ctx)
 | 
			
		||||
	newObj, err := ctl.svc.CommonPost(ctx, projectId, resource, *params.Dto)
 | 
			
		||||
 | 
			
		||||
	ctx1 := stdContext.WithValue(ctx.Context, "user_id", ctx.Header.UserId)
 | 
			
		||||
	ctx1 = stdContext.WithValue(ctx1, "user_name", ctx.Header.UserId)
 | 
			
		||||
 | 
			
		||||
	newObj, err := ctl.svc.CommonPost(ctx1, projectId, resource, *params.Dto)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
@ -47,3 +52,13 @@ func (ctl *controller) CommonDelete(ctx *context.WebContext, params *dto.CommonD
 | 
			
		||||
func (ctl *controller) OnClickCustomButton(ctx *context.WebContext, params *dto.CommonDeleteReq, rsp *dto.CommonDeleteRsp) error {
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (ctl *controller) GetProjectAllItems(ctx *context.WebContext, params *dto.NilReq, rsp *dto.GetProjectAllItemsRsp) error {
 | 
			
		||||
	projectId := getCtxURIProjectId(ctx)
 | 
			
		||||
	items, err := ctl.svc.GetAllItems(projectId)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
	rsp.Items = items
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -23,6 +23,8 @@ func (srv *Server) CheckToken(ctx *context.WebContext) {
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	ctx.Header.UserName = authRsp.User.NickName
 | 
			
		||||
 | 
			
		||||
	ctx.GinCtx().Set("userInfo", authRsp)
 | 
			
		||||
	return
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -6,6 +6,8 @@ import (
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
func (srv *Server) Route(engine *web.Engine) {
 | 
			
		||||
	engine.Use(srv.CheckToken)
 | 
			
		||||
 | 
			
		||||
	apiGroup := engine.Group("/api", "")
 | 
			
		||||
 | 
			
		||||
	{
 | 
			
		||||
@ -24,5 +26,7 @@ func (srv *Server) Route(engine *web.Engine) {
 | 
			
		||||
			resourceUnderProjectGroup.Put("", "编辑", consts.WebPathPermit_Read, srv.ctl.CommonPut)
 | 
			
		||||
			resourceUnderProjectGroup.Delete("", "删除", consts.WebPathPermit_Read, srv.ctl.CommonDelete)
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		projectGroup.Get("/:projectId/items", "获取项目所有道具列表", consts.WebPathPermit_Read, srv.ctl.GetProjectAllItems)
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -5,7 +5,10 @@ import (
 | 
			
		||||
	"admin/apps/game/domain"
 | 
			
		||||
	"admin/apps/game/model/dto"
 | 
			
		||||
	"admin/internal/consts"
 | 
			
		||||
	"admin/internal/errcode"
 | 
			
		||||
	"admin/internal/event"
 | 
			
		||||
	"context"
 | 
			
		||||
	"encoding/json"
 | 
			
		||||
	"gorm.io/gorm"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
@ -30,17 +33,26 @@ func New(db *gorm.DB) (*Service, error) {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (svc *Service) CommonList(ctx context.Context, projectId int, resourceName string, params *dto.CommonListReq) (*dto.CommonDtoList, error) {
 | 
			
		||||
	var (
 | 
			
		||||
		query string
 | 
			
		||||
		args  []any
 | 
			
		||||
	)
 | 
			
		||||
 | 
			
		||||
	params.ParsedWhereConditions = &dto.ListWhereConditionInfo{}
 | 
			
		||||
	if params.WhereConditions != "" {
 | 
			
		||||
		err := json.Unmarshal([]byte(params.WhereConditions), params.ParsedWhereConditions)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return nil, errcode.New(errcode.ParamsInvalid, "unmarshal list condition:%v error:%v",
 | 
			
		||||
				params.WhereConditions, err)
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	switch resourceName {
 | 
			
		||||
	case consts.ResourcesName_Project:
 | 
			
		||||
	default:
 | 
			
		||||
		query = "project_id = ?"
 | 
			
		||||
		args = append(args, projectId)
 | 
			
		||||
		params.ParsedWhereConditions.Conditions = append([]*dto.GetWhereCondition{&dto.GetWhereCondition{
 | 
			
		||||
			Key:    "ProjectId",
 | 
			
		||||
			Op:     "eq",
 | 
			
		||||
			Value1: projectId,
 | 
			
		||||
		}}, params.ParsedWhereConditions.Conditions...)
 | 
			
		||||
	}
 | 
			
		||||
	fieldsDescInfo, rows, err := svc.resourceSvc.List(projectId, resourceName, params.PageNo, params.PageLen, query, args)
 | 
			
		||||
	fieldsDescInfo, rows, err := svc.resourceSvc.List(projectId, resourceName, params)
 | 
			
		||||
	return &dto.CommonDtoList{FieldsDesc: fieldsDescInfo, Rows: rows}, err
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -48,18 +60,61 @@ func (svc *Service) CommonPost(ctx context.Context, projectId int, resourceName
 | 
			
		||||
	if resourceName != consts.ResourcesName_Project {
 | 
			
		||||
		params["ProjectId"] = projectId
 | 
			
		||||
	}
 | 
			
		||||
	return svc.resourceSvc.Create(projectId, resourceName, params)
 | 
			
		||||
 | 
			
		||||
	values, err := svc.resourceSvc.Create(projectId, resourceName, params)
 | 
			
		||||
 | 
			
		||||
	userId := ctx.Value("user_id").(int)
 | 
			
		||||
	userName := ctx.Value("user_name").(string)
 | 
			
		||||
 | 
			
		||||
	event.GetMgrInstance().Publish(event.EventTopic_UserExecute, &event.EventPayload_UserExecute{
 | 
			
		||||
		UserId:    userId,
 | 
			
		||||
		UserName:  userName,
 | 
			
		||||
		ProjectId: projectId,
 | 
			
		||||
		Resource:  resourceName,
 | 
			
		||||
		Method:    "新增",
 | 
			
		||||
		NewData:   params,
 | 
			
		||||
	})
 | 
			
		||||
 | 
			
		||||
	return values, err
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (svc *Service) CommonPut(ctx context.Context, projectId int, resourceName string, params dto.CommonDtoValues) error {
 | 
			
		||||
	if resourceName != consts.ResourcesName_Project {
 | 
			
		||||
		params["ProjectId"] = projectId
 | 
			
		||||
	}
 | 
			
		||||
	return svc.resourceSvc.Edit(projectId, resourceName, params)
 | 
			
		||||
	err := svc.resourceSvc.Edit(projectId, resourceName, params)
 | 
			
		||||
 | 
			
		||||
	userId := ctx.Value("user_id").(int)
 | 
			
		||||
	userName := ctx.Value("user_name").(string)
 | 
			
		||||
 | 
			
		||||
	event.GetMgrInstance().Publish(event.EventTopic_UserExecute, &event.EventPayload_UserExecute{
 | 
			
		||||
		UserId:    userId,
 | 
			
		||||
		UserName:  userName,
 | 
			
		||||
		ProjectId: projectId,
 | 
			
		||||
		Resource:  resourceName,
 | 
			
		||||
		Method:    "编辑",
 | 
			
		||||
		NewData:   params,
 | 
			
		||||
	})
 | 
			
		||||
 | 
			
		||||
	return err
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (svc *Service) CommonDelete(ctx context.Context, projectId int, resourceName string, id int) error {
 | 
			
		||||
	return svc.resourceSvc.Delete(projectId, resourceName, id)
 | 
			
		||||
	err := svc.resourceSvc.Delete(projectId, resourceName, id)
 | 
			
		||||
 | 
			
		||||
	userId := ctx.Value("user_id").(int)
 | 
			
		||||
	userName := ctx.Value("user_name").(string)
 | 
			
		||||
 | 
			
		||||
	event.GetMgrInstance().Publish(event.EventTopic_UserExecute, &event.EventPayload_UserExecute{
 | 
			
		||||
		UserId:    userId,
 | 
			
		||||
		UserName:  userName,
 | 
			
		||||
		ProjectId: projectId,
 | 
			
		||||
		Resource:  resourceName,
 | 
			
		||||
		Method:    "删除",
 | 
			
		||||
		NewData:   id,
 | 
			
		||||
	})
 | 
			
		||||
 | 
			
		||||
	return err
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (svc *Service) GetSupportResourcesList(permissions []string) []*api.ResourceInitInfo {
 | 
			
		||||
 | 
			
		||||
@ -3,6 +3,7 @@ package service
 | 
			
		||||
import (
 | 
			
		||||
	"admin/apps/game/api"
 | 
			
		||||
	"admin/apps/game/domain/entity"
 | 
			
		||||
	"admin/apps/game/model/dto"
 | 
			
		||||
	"admin/internal/consts"
 | 
			
		||||
	"admin/internal/permission"
 | 
			
		||||
)
 | 
			
		||||
@ -66,3 +67,7 @@ func (svc *Service) GetProjectList() ([]*entity.Project, error) {
 | 
			
		||||
func (svc *Service) GetProjectInvokeApiAddr(projectId int, serverIds []int) ([]string, error) {
 | 
			
		||||
	return svc.projectSvc.GetProjectInvokeApiAddr(projectId, serverIds)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (svc *Service) GetAllItems(projectId int) ([]*dto.CommonDtoFieldChoice, error) {
 | 
			
		||||
	return svc.projectSvc.GetAllItems(projectId)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -24,6 +24,7 @@ type AuthReq struct {
 | 
			
		||||
 | 
			
		||||
type UserInfo struct {
 | 
			
		||||
	UserId      int      `json:"user_id"`
 | 
			
		||||
	UserName    string   `json:"user_name"`
 | 
			
		||||
	NickName    string   `json:"nick_name"`
 | 
			
		||||
	Icon        string   `json:"icon"`
 | 
			
		||||
	Character   string   `json:"character"`
 | 
			
		||||
 | 
			
		||||
@ -38,14 +38,22 @@ func (impl *userRepoImpl) CreateAdminUsers() error {
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if err := impl.db.Create(adminCharacter).Error; err != nil {
 | 
			
		||||
		if !strings.Contains(err.Error(), "Duplicate entry") {
 | 
			
		||||
		if strings.Contains(err.Error(), "Duplicate entry") {
 | 
			
		||||
 | 
			
		||||
		} else if strings.Contains(err.Error(), "UNIQUE constraint") {
 | 
			
		||||
 | 
			
		||||
		} else {
 | 
			
		||||
			return errcode.New(errcode.DBError, "create admin character fail:%v", err)
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if err := impl.db.Create(adminList).Error; err != nil {
 | 
			
		||||
		if !strings.Contains(err.Error(), "Duplicate entry") {
 | 
			
		||||
			return errcode.New(errcode.DBError, "create admin fail:%v", err)
 | 
			
		||||
		if strings.Contains(err.Error(), "Duplicate entry") {
 | 
			
		||||
 | 
			
		||||
		} else if strings.Contains(err.Error(), "UNIQUE constraint") {
 | 
			
		||||
 | 
			
		||||
		} else {
 | 
			
		||||
			return errcode.New(errcode.DBError, "create admin character fail:%v", err)
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										35
									
								
								admin/apps/user/model/history.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										35
									
								
								admin/apps/user/model/history.go
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,35 @@
 | 
			
		||||
package model
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"admin/internal/db"
 | 
			
		||||
	"admin/internal/global"
 | 
			
		||||
	"time"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
func init() {
 | 
			
		||||
	db.RegisterTableModels(History{})
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// History 用户执行历史
 | 
			
		||||
type History struct {
 | 
			
		||||
	ID         int `gorm:"primarykey" readonly:"true"`
 | 
			
		||||
	UserId     int
 | 
			
		||||
	UserName   string
 | 
			
		||||
	ProjectId  int
 | 
			
		||||
	Resource   string
 | 
			
		||||
	Method     string
 | 
			
		||||
	Data       string `gorm:"type:longtext"`
 | 
			
		||||
	CreateTime time.Time
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (m *History) TableName() string {
 | 
			
		||||
	return "history"
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (m *History) GetId() int {
 | 
			
		||||
	return m.ID
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (m *History) Create() error {
 | 
			
		||||
	return global.GLOB_DB.Create(m).Error
 | 
			
		||||
}
 | 
			
		||||
@ -1,6 +1,12 @@
 | 
			
		||||
package server
 | 
			
		||||
 | 
			
		||||
import "admin/apps/user/service"
 | 
			
		||||
import (
 | 
			
		||||
	"admin/apps/user/model"
 | 
			
		||||
	"admin/apps/user/service"
 | 
			
		||||
	"admin/internal/event"
 | 
			
		||||
	"admin/lib/xlog"
 | 
			
		||||
	"encoding/json"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
type Server struct {
 | 
			
		||||
	svc *service.Service
 | 
			
		||||
@ -13,3 +19,28 @@ func New(svc *service.Service) *Server {
 | 
			
		||||
		ctl: newController(svc),
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (srv *Server) jobsSubscribe() {
 | 
			
		||||
	event.GetMgrInstance().Subscribe("user", event.EventTopic_UserExecute, srv.subscriberHandlerUserExecute)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (srv *Server) subscriberHandlerUserExecute(msg *event.Msg) {
 | 
			
		||||
	po := new(model.History)
 | 
			
		||||
	msgHistory := &event.EventPayload_UserExecute{}
 | 
			
		||||
	err := json.Unmarshal(msg.Payload, msgHistory)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		xlog.Errorf("unmarshal msg(%+v) err:%v", string(msg.Payload), err)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	po.UserId = msgHistory.UserId
 | 
			
		||||
	po.UserName = msgHistory.UserName
 | 
			
		||||
	po.ProjectId = msgHistory.ProjectId
 | 
			
		||||
	po.Resource = msgHistory.Resource
 | 
			
		||||
	po.Method = msgHistory.Method
 | 
			
		||||
	po.Data = string(msg.Payload)
 | 
			
		||||
 | 
			
		||||
	err = po.Create()
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		xlog.Errorf("create user execute(%+v) err:%v", string(msg.Payload), err)
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -40,6 +40,7 @@ func (svc *Service) Auth(ctx context.Context, req *apiUser.AuthReq) (*apiUser.Au
 | 
			
		||||
	}
 | 
			
		||||
	rsp.User = &apiUser.UserInfo{
 | 
			
		||||
		UserId:      info.User.UserId,
 | 
			
		||||
		UserName:    info.User.NickName,
 | 
			
		||||
		NickName:    info.User.NickName,
 | 
			
		||||
		Icon:        info.User.Icon,
 | 
			
		||||
		Character:   info.User.Character,
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										
											BIN
										
									
								
								admin/cmd/all_in_one/all_in_one.exe
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								admin/cmd/all_in_one/all_in_one.exe
									
									
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							@ -9,6 +9,7 @@ require (
 | 
			
		||||
	github.com/golang-jwt/jwt/v5 v5.2.2
 | 
			
		||||
	github.com/prometheus/client_golang v1.22.0
 | 
			
		||||
	github.com/rs/zerolog v1.34.0
 | 
			
		||||
	golang.org/x/crypto v0.37.0
 | 
			
		||||
	gopkg.in/yaml.v3 v3.0.1
 | 
			
		||||
	gorm.io/driver/mysql v1.5.7
 | 
			
		||||
	gorm.io/driver/sqlite v1.5.7
 | 
			
		||||
@ -46,7 +47,6 @@ require (
 | 
			
		||||
	github.com/twitchyliquid64/golang-asm v0.15.1 // indirect
 | 
			
		||||
	github.com/ugorji/go/codec v1.2.12 // indirect
 | 
			
		||||
	golang.org/x/arch v0.16.0 // indirect
 | 
			
		||||
	golang.org/x/crypto v0.37.0 // indirect
 | 
			
		||||
	golang.org/x/net v0.38.0 // indirect
 | 
			
		||||
	golang.org/x/sys v0.32.0 // indirect
 | 
			
		||||
	golang.org/x/text v0.24.0 // indirect
 | 
			
		||||
 | 
			
		||||
@ -2,7 +2,7 @@ package config
 | 
			
		||||
 | 
			
		||||
type CommonBootFlags struct {
 | 
			
		||||
	ApiPort string `env:"api_port" default:"8080" desc:"api端口,客户端请求的地址端口"`
 | 
			
		||||
	DBType  string `env:"db_type" default:"sqlite3" desc:"数据库类型,默认sqlite,可选:sqlite|mysql|pg"`
 | 
			
		||||
	DBType  string `env:"db_type" default:"sqlite" desc:"数据库类型,默认sqlite,可选:sqlite|mysql|pg"`
 | 
			
		||||
	DBAddr  string `env:"db_addr" default:"localhost" desc:"数据库地址"`
 | 
			
		||||
	DBName  string `env:"db_name" default:"uniugm" desc:"数据库名字"`
 | 
			
		||||
	DBUser  string `env:"db_user" default:"root" desc:"数据库用户名"`
 | 
			
		||||
 | 
			
		||||
@ -9,9 +9,10 @@ import (
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
type WebHeader struct {
 | 
			
		||||
	UserId int    `json:"UserId"` // 用户id,会与下面token解析出用户id做匹配校验
 | 
			
		||||
	Token  string `json:"Token"`  // jwt token,内置一些信息
 | 
			
		||||
	Ip     string `json:"IP"`
 | 
			
		||||
	UserId   int    `json:"UserId"` // 用户id,会与下面token解析出用户id做匹配校验
 | 
			
		||||
	Token    string `json:"Token"`  // jwt token,内置一些信息
 | 
			
		||||
	Ip       string `json:"IP"`
 | 
			
		||||
	UserName string `json:"-"`
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type WebContext struct {
 | 
			
		||||
 | 
			
		||||
@ -9,6 +9,7 @@ import (
 | 
			
		||||
	"gorm.io/driver/mysql"
 | 
			
		||||
	"gorm.io/driver/sqlite"
 | 
			
		||||
	"gorm.io/gorm"
 | 
			
		||||
	"strings"
 | 
			
		||||
	"sync"
 | 
			
		||||
	"time"
 | 
			
		||||
)
 | 
			
		||||
@ -25,39 +26,54 @@ func RegisterTableModels(models ...any) {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func NewDB(dbType, dbAddr, dbName, dbUser, dbPass string) (db *gorm.DB, err error) {
 | 
			
		||||
	switch dbType {
 | 
			
		||||
	case "sqlite":
 | 
			
		||||
		db, err = gorm.Open(sqlite.Open(dbName+".db"), &gorm.Config{})
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return nil, err
 | 
			
		||||
		}
 | 
			
		||||
	case "mysql":
 | 
			
		||||
		dsn := fmt.Sprintf("%v:%v@tcp(%v)/%v?charset=utf8mb4&parseTime=True&loc=Local", dbUser, dbPass, dbAddr, dbName)
 | 
			
		||||
		dsnWithoutDB := fmt.Sprintf("%v:%v@tcp(%v)/?charset=utf8mb4&parseTime=True&loc=Local", dbUser, dbPass, dbAddr)
 | 
			
		||||
		db, err = createDBAndGuaranteeMigrate(dsnWithoutDB, dsn, globalTables)
 | 
			
		||||
	dsn := fmt.Sprintf("%v:%v@tcp(%v)/%v?charset=utf8mb4&parseTime=True&loc=Local", dbUser, dbPass, dbAddr, dbName)
 | 
			
		||||
	dsnWithoutDB := fmt.Sprintf("%v:%v@tcp(%v)/?charset=utf8mb4&parseTime=True&loc=Local", dbUser, dbPass, dbAddr)
 | 
			
		||||
	db, err = createDBAndGuaranteeMigrate(dbType, dsnWithoutDB, dsn, globalTables)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
	global.GLOB_DB = db
 | 
			
		||||
	return db, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func createDBAndGuaranteeMigrate(dsnWithoutDb, dsn string, tables []any) (*gorm.DB, error) {
 | 
			
		||||
func createDBAndGuaranteeMigrate(dbType string, dsnWithoutDb, dsn string, tables []any) (*gorm.DB, error) {
 | 
			
		||||
	mysqlDriverConf, err := mysqlDriver.ParseDSN(dsn)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, fmt.Errorf("parse dsn:%v error:%v", dsn, err)
 | 
			
		||||
	}
 | 
			
		||||
	dbName := mysqlDriverConf.DBName
 | 
			
		||||
	_, err = tryCreateDB(dbName, dsnWithoutDb)
 | 
			
		||||
 | 
			
		||||
	var dialector gorm.Dialector
 | 
			
		||||
	switch dbType {
 | 
			
		||||
	case "sqlite":
 | 
			
		||||
		dialector = sqlite.Open(dbName)
 | 
			
		||||
	case "mysql":
 | 
			
		||||
		dialector = mysql.Open(dsnWithoutDb)
 | 
			
		||||
	default:
 | 
			
		||||
		panic(fmt.Errorf("unsupported db type: %v", dbType))
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	_, err = tryCreateDB(dbType, dialector, dbName)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		xlog.Fatalf(err)
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	driverConf := mysql.Config{
 | 
			
		||||
		DSN:                     dsn,
 | 
			
		||||
		DontSupportRenameColumn: true,
 | 
			
		||||
		//SkipInitializeWithVersion: false, // 根据数据库版本自动配置
 | 
			
		||||
	switch dbType {
 | 
			
		||||
	case "sqlite":
 | 
			
		||||
		dialector = sqlite.Open(dbName)
 | 
			
		||||
	case "mysql":
 | 
			
		||||
		dialector = mysql.Open(dsn)
 | 
			
		||||
	default:
 | 
			
		||||
		panic(fmt.Errorf("unsupported db type: %v", dbType))
 | 
			
		||||
	}
 | 
			
		||||
	dialector := mysql.New(driverConf)
 | 
			
		||||
 | 
			
		||||
	//driverConf := mysql.Config{
 | 
			
		||||
	//	DSN:                     dsn,
 | 
			
		||||
	//	DontSupportRenameColumn: true,
 | 
			
		||||
	//	//SkipInitializeWithVersion: false, // 根据数据库版本自动配置
 | 
			
		||||
	//}
 | 
			
		||||
	//dialector = mysql.New(driverConf)
 | 
			
		||||
 | 
			
		||||
	//slowLogger := logger.New(
 | 
			
		||||
	//	syslog.New(xlog.GetGlobalWriter(), "\n", syslog.LstdFlags),
 | 
			
		||||
@ -97,13 +113,7 @@ func createDBAndGuaranteeMigrate(dsnWithoutDb, dsn string, tables []any) (*gorm.
 | 
			
		||||
	return db, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func tryCreateDB(dbName, dsn string) (string, error) {
 | 
			
		||||
	driverConf := mysql.Config{
 | 
			
		||||
		DSN:                     dsn,
 | 
			
		||||
		DontSupportRenameColumn: true,
 | 
			
		||||
		//SkipInitializeWithVersion: false, // 根据数据库版本自动配置
 | 
			
		||||
	}
 | 
			
		||||
	dialector := mysql.New(driverConf)
 | 
			
		||||
func tryCreateDB(dbType string, dialector gorm.Dialector, dbName string) (string, error) {
 | 
			
		||||
 | 
			
		||||
	db, err := gorm.Open(dialector, &gorm.Config{
 | 
			
		||||
		PrepareStmt: false, // 关闭缓存sql语句功能,因为后续use db会报错,这个缓存会无限存储可能导致内存泄露
 | 
			
		||||
@ -114,14 +124,16 @@ func tryCreateDB(dbName, dsn string) (string, error) {
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// 检查数据库是否存在
 | 
			
		||||
	var count int
 | 
			
		||||
	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",
 | 
			
		||||
			dbName)
 | 
			
		||||
		if e := db.Exec(sql).Error; e != nil {
 | 
			
		||||
			return "", fmt.Errorf("failed to create database:%v", e)
 | 
			
		||||
	if dbType != "sqlite" {
 | 
			
		||||
		var count int
 | 
			
		||||
		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",
 | 
			
		||||
				dbName)
 | 
			
		||||
			if e := db.Exec(sql).Error; e != nil {
 | 
			
		||||
				return "", fmt.Errorf("failed to create database:%v", e)
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
@ -135,8 +147,17 @@ func autoMigrate(db *gorm.DB, tables ...interface{}) error {
 | 
			
		||||
	// 这个函数是在InitConn之后调用的
 | 
			
		||||
 | 
			
		||||
	// 初始化表
 | 
			
		||||
	if err := db.AutoMigrate(tables...); err != nil {
 | 
			
		||||
		return errcode.New(errcode.DBError, "failed to init tables:%v", err)
 | 
			
		||||
	for _, table := range tables {
 | 
			
		||||
		if err := db.AutoMigrate(table); err != nil {
 | 
			
		||||
			if strings.Contains(err.Error(), "there is already a table named") {
 | 
			
		||||
				continue
 | 
			
		||||
			}
 | 
			
		||||
			if strings.Contains(err.Error(), "already exists") {
 | 
			
		||||
				continue
 | 
			
		||||
			}
 | 
			
		||||
			return errcode.New(errcode.DBError, "failed to init tables:%v", err)
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -9,4 +9,5 @@ const (
 | 
			
		||||
	TokenInvalid        = 5
 | 
			
		||||
	UserOrPassInValid   = 7 // 用户名或密码错误
 | 
			
		||||
	NoPermission        = 8 // 没有权限
 | 
			
		||||
	ParamsInvalid       = 9
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										15
									
								
								admin/internal/event/event.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										15
									
								
								admin/internal/event/event.go
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,15 @@
 | 
			
		||||
package event
 | 
			
		||||
 | 
			
		||||
import "admin/lib/eventmgr"
 | 
			
		||||
 | 
			
		||||
type Msg = eventmgr.Msg
 | 
			
		||||
 | 
			
		||||
var manager *eventmgr.Mgr
 | 
			
		||||
 | 
			
		||||
func init() {
 | 
			
		||||
	manager = eventmgr.NewMgr()
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func GetMgrInstance() *eventmgr.Mgr {
 | 
			
		||||
	return manager
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										15
									
								
								admin/internal/event/topic.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										15
									
								
								admin/internal/event/topic.go
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,15 @@
 | 
			
		||||
package event
 | 
			
		||||
 | 
			
		||||
const (
 | 
			
		||||
	EventTopic_UserExecute = "user.execute"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
type EventPayload_UserExecute struct {
 | 
			
		||||
	UserId    int    `json:"user_id"`
 | 
			
		||||
	UserName  string `json:"user_name"`
 | 
			
		||||
	ProjectId int    `json:"project_id"`
 | 
			
		||||
	Resource  string `json:"resource"`
 | 
			
		||||
	Method    string `json:"method"`
 | 
			
		||||
	OldData   any    `json:"old_data"`
 | 
			
		||||
	NewData   any    `json:"new_data"`
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										66
									
								
								admin/lib/eventmgr/event.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										66
									
								
								admin/lib/eventmgr/event.go
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,66 @@
 | 
			
		||||
package eventmgr
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"admin/lib/xlog"
 | 
			
		||||
	"encoding/json"
 | 
			
		||||
	"runtime"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
type Msg struct {
 | 
			
		||||
	Event   string
 | 
			
		||||
	Payload []byte
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type subscriber struct {
 | 
			
		||||
	name    string
 | 
			
		||||
	topic   string
 | 
			
		||||
	handler func(*Msg)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type Mgr struct {
 | 
			
		||||
	subscribers []*subscriber
 | 
			
		||||
	broker      chan *Msg
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func NewMgr() *Mgr {
 | 
			
		||||
	mgr := &Mgr{
 | 
			
		||||
		subscribers: make([]*subscriber, 0),
 | 
			
		||||
		broker:      make(chan *Msg, 1024),
 | 
			
		||||
	}
 | 
			
		||||
	mgr.start()
 | 
			
		||||
	return mgr
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (m *Mgr) start() {
 | 
			
		||||
	for i := 0; i < runtime.NumCPU(); i++ {
 | 
			
		||||
		go func() {
 | 
			
		||||
			for {
 | 
			
		||||
				select {
 | 
			
		||||
				case msg := <-m.broker:
 | 
			
		||||
					for _, sub := range m.subscribers {
 | 
			
		||||
						if sub.topic == msg.Event {
 | 
			
		||||
							sub.handler(msg)
 | 
			
		||||
						}
 | 
			
		||||
					}
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
		}()
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (m *Mgr) Subscribe(name string, topic string, handler func(*Msg)) {
 | 
			
		||||
	m.subscribers = append(m.subscribers, &subscriber{name: name, topic: topic, handler: handler})
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (m *Mgr) Publish(event string, payload any) {
 | 
			
		||||
	payloadBin, err := json.Marshal(payload)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		panic(err)
 | 
			
		||||
	}
 | 
			
		||||
	msg := &Msg{Event: event, Payload: payloadBin}
 | 
			
		||||
	select {
 | 
			
		||||
	case m.broker <- msg:
 | 
			
		||||
	default:
 | 
			
		||||
		xlog.Errorf("publish event:%v broker is full", event)
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										
											BIN
										
									
								
								admin/uniugm
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								admin/uniugm
									
									
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							@ -1,2 +1,2 @@
 | 
			
		||||
VITE_APP_BASE_API = '/api'
 | 
			
		||||
VITE_APP_BASE_URL = 'http://192.168.78.128:8080/api'
 | 
			
		||||
VITE_APP_BASE_URL = 'http://localhost:8080/api'
 | 
			
		||||
							
								
								
									
										26
									
								
								ui/README.md
									
									
									
									
									
								
							
							
						
						
									
										26
									
								
								ui/README.md
									
									
									
									
									
								
							@ -1,29 +1,5 @@
 | 
			
		||||
# ui
 | 
			
		||||
 | 
			
		||||
This template should help get you started developing with Vue 3 in Vite.
 | 
			
		||||
 | 
			
		||||
## Recommended IDE Setup
 | 
			
		||||
 | 
			
		||||
[VSCode](https://code.visualstudio.com/) + [Volar](https://marketplace.visualstudio.com/items?itemName=Vue.volar) (and disable Vetur).
 | 
			
		||||
 | 
			
		||||
## Customize configuration
 | 
			
		||||
 | 
			
		||||
See [Vite Configuration Reference](https://vite.dev/config/).
 | 
			
		||||
 | 
			
		||||
## Project Setup
 | 
			
		||||
 | 
			
		||||
```sh
 | 
			
		||||
npm install
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
### Compile and Hot-Reload for Development
 | 
			
		||||
 | 
			
		||||
```sh
 | 
			
		||||
npm install --registry=https://registry.npmmirror.com
 | 
			
		||||
npm run dev
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
### Compile and Minify for Production
 | 
			
		||||
 | 
			
		||||
```sh
 | 
			
		||||
npm run build
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
@ -38,4 +38,11 @@ export function resourceDelete(url, params) {
 | 
			
		||||
        method: 'delete',
 | 
			
		||||
        data: params
 | 
			
		||||
    })
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export function resourceGetAllItems(projectId) {
 | 
			
		||||
    return request({
 | 
			
		||||
        url: '/project/' + projectId.toString() + "/items",
 | 
			
		||||
        method: 'get',
 | 
			
		||||
    })
 | 
			
		||||
}
 | 
			
		||||
@ -1,20 +1,24 @@
 | 
			
		||||
<script setup>
 | 
			
		||||
import {ElNotification} from "element-plus";
 | 
			
		||||
import {resourceDelete, resourceList, resourcePost, resourcePut} from "@/api/resource.js";
 | 
			
		||||
import {resourceDelete, resourceList, resourcePost, resourcePut, resourceGetAllItems} from "@/api/resource.js";
 | 
			
		||||
import {ref, toRaw} from "vue";
 | 
			
		||||
import {useRoute} from 'vue-router';
 | 
			
		||||
import LocalCache from "@/stores/localCache.js";
 | 
			
		||||
import empty from '@/components/restful/empty.vue';
 | 
			
		||||
import {getWhereConditionDesc} from "@/utils/string.js";
 | 
			
		||||
 | 
			
		||||
const cachedResource = LocalCache.getCache("resource");
 | 
			
		||||
 | 
			
		||||
const listRsp = ref({fields_desc: [], rows: []})
 | 
			
		||||
const listDataOK = ref(false)
 | 
			
		||||
const projectId = cachedResource.meta.projectId
 | 
			
		||||
const resource_raw_node = cachedResource;
 | 
			
		||||
const hasListPermit = resource_raw_node.meta.methods.get !== undefined && resource_raw_node.meta.methods.get === true;
 | 
			
		||||
 | 
			
		||||
const resource_url = cachedResource.meta.resource_url;
 | 
			
		||||
const fieldsDescInfo = ref([])
 | 
			
		||||
const whereFieldsDescInfo = ref([])
 | 
			
		||||
const calcElColSpan = ref(0)
 | 
			
		||||
const rows = ref([])
 | 
			
		||||
const rules = ref({})
 | 
			
		||||
 | 
			
		||||
@ -22,7 +26,7 @@ const current_page = ref(0)
 | 
			
		||||
const page_size = ref(0)
 | 
			
		||||
 | 
			
		||||
const item = ref({
 | 
			
		||||
  id: 0,
 | 
			
		||||
  id: '',
 | 
			
		||||
  number: 1,
 | 
			
		||||
})
 | 
			
		||||
 | 
			
		||||
@ -33,7 +37,22 @@ const listData = async () => {
 | 
			
		||||
    let listParams = {
 | 
			
		||||
      page_no: 0,
 | 
			
		||||
      page_len: 100,
 | 
			
		||||
      where_conditions: "",
 | 
			
		||||
    }
 | 
			
		||||
    let whereReqConditions = {
 | 
			
		||||
      conditions: []
 | 
			
		||||
    }
 | 
			
		||||
    whereFieldsDescInfo.value.forEach((field) => {
 | 
			
		||||
      if (field.value1) {
 | 
			
		||||
        whereReqConditions.conditions.push({
 | 
			
		||||
          key: field.key,
 | 
			
		||||
          op: field.where,
 | 
			
		||||
          value1: field.value1,
 | 
			
		||||
          value2: field.value2,
 | 
			
		||||
        })
 | 
			
		||||
      }
 | 
			
		||||
    })
 | 
			
		||||
    listParams.where_conditions = JSON.stringify(whereReqConditions)
 | 
			
		||||
    // console.log("list params:", listParams)
 | 
			
		||||
    const rspData = await resourceList(resource_url, listParams);
 | 
			
		||||
    listRsp.value = rspData;
 | 
			
		||||
@ -41,7 +60,6 @@ const listData = async () => {
 | 
			
		||||
    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] = ''
 | 
			
		||||
@ -56,8 +74,41 @@ const listData = async () => {
 | 
			
		||||
          rows.value[j].jsonValue = JSON.stringify(rows.value[j][field.key])
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      if (field.where !== "") {
 | 
			
		||||
        field.value1 = ""
 | 
			
		||||
        field.value2 = ""
 | 
			
		||||
        field.whereDesc = getWhereConditionDesc(field.where)
 | 
			
		||||
        let find = false
 | 
			
		||||
        for (let i = 0; i < whereFieldsDescInfo.value.length; i++) {
 | 
			
		||||
          let whereField = whereFieldsDescInfo.value[i]
 | 
			
		||||
          if (whereField.key === field.key) {
 | 
			
		||||
            whereFieldsDescInfo.value[i].type = field.type
 | 
			
		||||
            whereFieldsDescInfo.value[i].where = field.where
 | 
			
		||||
            whereFieldsDescInfo.value[i].whereDesc = getWhereConditionDesc(field.where)
 | 
			
		||||
            find = true
 | 
			
		||||
            break
 | 
			
		||||
          }
 | 
			
		||||
        }
 | 
			
		||||
        if (!find) {
 | 
			
		||||
          whereFieldsDescInfo.value.push(field)
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    calcElColSpan.value = 0
 | 
			
		||||
    // 计算el-col占用24格子的span数量
 | 
			
		||||
    let calcElColSpanTmp = 1
 | 
			
		||||
    whereFieldsDescInfo.value.forEach((field) => {
 | 
			
		||||
      if (field.where === "range") {
 | 
			
		||||
        calcElColSpanTmp += 2
 | 
			
		||||
      } else {
 | 
			
		||||
        calcElColSpanTmp += 1
 | 
			
		||||
      }
 | 
			
		||||
    })
 | 
			
		||||
    calcElColSpan.value = 24/calcElColSpanTmp
 | 
			
		||||
 | 
			
		||||
    console.log("where fields:", whereFieldsDescInfo.value)
 | 
			
		||||
    // console.log('await list  rsp:', listRsp.value, fieldsDescInfo.value, toRaw(rows.value), toRaw(rules.value))
 | 
			
		||||
 | 
			
		||||
    listDataOK.value = true
 | 
			
		||||
@ -208,6 +259,27 @@ const handleCloseDialog = () => {
 | 
			
		||||
  dialogEditForm.value = {}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
const loadingRemoteItems = ref(false)
 | 
			
		||||
const itemChoices = ref({})
 | 
			
		||||
const handleQueryItem = (itemQueryStr) => {
 | 
			
		||||
  if (!itemQueryStr) {
 | 
			
		||||
    itemChoices.value = []
 | 
			
		||||
    return
 | 
			
		||||
  }
 | 
			
		||||
  loadingRemoteItems.value = true
 | 
			
		||||
  itemQueryStr = itemQueryStr.replace(/[\s\u3000]/g, "")
 | 
			
		||||
  resourceGetAllItems(projectId).then((res) => {
 | 
			
		||||
    console.log("获取所有道具返回:", res.data)
 | 
			
		||||
    console.log("查询字符串:[" +  itemQueryStr + "]")
 | 
			
		||||
    itemChoices.value = res.data.items.filter((item) => {
 | 
			
		||||
      return item.desc.includes(itemQueryStr)
 | 
			
		||||
    })
 | 
			
		||||
    loadingRemoteItems.value = false
 | 
			
		||||
  }, (err) => {
 | 
			
		||||
    itemChoices.value = []
 | 
			
		||||
  })
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
</script>
 | 
			
		||||
 | 
			
		||||
<template>
 | 
			
		||||
@ -217,10 +289,45 @@ const handleCloseDialog = () => {
 | 
			
		||||
  <template v-else>
 | 
			
		||||
    <el-container v-if="listDataOK">
 | 
			
		||||
      <el-header>
 | 
			
		||||
        <el-button @click="dialogAddVisible = true" size="large" type="primary"
 | 
			
		||||
                   v-if="(resource_raw_node.meta.methods.post === true)">
 | 
			
		||||
          添加
 | 
			
		||||
        </el-button>
 | 
			
		||||
        <el-row :gutter="20" v-if="(whereFieldsDescInfo.length !== 0)">
 | 
			
		||||
          <template v-for="fieldDescInfo in whereFieldsDescInfo">
 | 
			
		||||
            <template v-if="(fieldDescInfo.where === 'range')">
 | 
			
		||||
              <el-col :span="calcElColSpan">
 | 
			
		||||
                <el-date-picker v-model="fieldDescInfo.value1" type="datetime"
 | 
			
		||||
                                :placeholder="(fieldDescInfo.name + '起始')" format="YYYY/MM/DD HH:mm:ss"
 | 
			
		||||
                                value-format="YYYY/MM/DD HH:mm:ss"></el-date-picker>
 | 
			
		||||
              </el-col>
 | 
			
		||||
              <el-col :span="calcElColSpan">
 | 
			
		||||
                <el-date-picker v-model="fieldDescInfo.value2" type="datetime"
 | 
			
		||||
                               :placeholder="(fieldDescInfo.name + '结束')" format="YYYY/MM/DD HH:mm:ss"
 | 
			
		||||
                               value-format="YYYY/MM/DD HH:mm:ss"></el-date-picker>
 | 
			
		||||
              </el-col>
 | 
			
		||||
            </template>
 | 
			
		||||
            <template v-else>
 | 
			
		||||
              <el-col :span="calcElColSpan">
 | 
			
		||||
                <el-select v-model="fieldDescInfo.value1" :placeholder="(fieldDescInfo.multi_choice === true ? '--多选--' : '--单选--')"
 | 
			
		||||
                           style="width: 150px"
 | 
			
		||||
                           filterable v-if="(fieldDescInfo.choices.length > 0)">
 | 
			
		||||
                  <el-option v-for="choice in fieldDescInfo.choices" :key="choice.value" :label="choice.desc"
 | 
			
		||||
                             :value="choice.value"></el-option>
 | 
			
		||||
                </el-select>
 | 
			
		||||
                <el-input v-model="fieldDescInfo.value1"
 | 
			
		||||
                          :placeholder="(fieldDescInfo.name + fieldDescInfo.whereDesc)"
 | 
			
		||||
                          style="width: 150px" v-else></el-input>
 | 
			
		||||
              </el-col>
 | 
			
		||||
            </template>
 | 
			
		||||
          </template>
 | 
			
		||||
          <el-col :span="calcElColSpan">
 | 
			
		||||
            <el-button @click="listData" type="primary">条件搜索</el-button>
 | 
			
		||||
          </el-col>
 | 
			
		||||
        </el-row>
 | 
			
		||||
 | 
			
		||||
        <el-row style="margin-top: 10px">
 | 
			
		||||
          <el-button @click="dialogAddVisible = true" size="large" type="primary"
 | 
			
		||||
                     v-if="(resource_raw_node.meta.methods.post === true)">
 | 
			
		||||
            添加
 | 
			
		||||
          </el-button>
 | 
			
		||||
        </el-row>
 | 
			
		||||
      </el-header>
 | 
			
		||||
      <el-main>
 | 
			
		||||
        <el-table :data="rows" style="width: 100%" table-layout="auto" stripe>
 | 
			
		||||
@ -273,9 +380,11 @@ const handleCloseDialog = () => {
 | 
			
		||||
                <el-form :inline="true" :model="item" label-position="right">
 | 
			
		||||
                  <el-form-item :label="fieldDescInfo.name" :prop="fieldDescInfo.key" label-width="130px">
 | 
			
		||||
                    <el-tooltip effect="light" :content="fieldDescInfo.help_text" placement="bottom-start">
 | 
			
		||||
                      <el-select placeholder="--选择道具后填数量点击添加--" v-model="item.id" style="width: 150px"
 | 
			
		||||
                                 filterable>
 | 
			
		||||
                        <el-option v-for="info in fieldDescInfo.choices" :key="info.desc" :label="info.desc"
 | 
			
		||||
                      <el-select v-model="item.id" placeholder="--搜索道具--" style="width: 150px"
 | 
			
		||||
                                 filterable remote
 | 
			
		||||
                                 :remote-method="handleQueryItem"
 | 
			
		||||
                                 :loading="loadingRemoteItems">
 | 
			
		||||
                        <el-option v-for="info in itemChoices" :key="info.value" :label="info.desc"
 | 
			
		||||
                                   :value="info.value"></el-option>
 | 
			
		||||
                      </el-select>
 | 
			
		||||
                    </el-tooltip>
 | 
			
		||||
@ -354,9 +463,9 @@ const handleCloseDialog = () => {
 | 
			
		||||
                         label-width="130px">
 | 
			
		||||
                  <el-form-item :label="fieldDescInfo.name" :prop="fieldDescInfo.key">
 | 
			
		||||
                    <el-tooltip effect="light" :content="fieldDescInfo.help_text" placement="bottom-start">
 | 
			
		||||
                      <el-select placeholder="--选择道具后填数量点击添加--" v-model="item.id" style="width: 150px"
 | 
			
		||||
                                 filterable>
 | 
			
		||||
                        <el-option v-for="info in fieldDescInfo.choices" :key="info.desc" :label="info.desc"
 | 
			
		||||
                      <el-select placeholder="--搜索道具--" v-model="item.id" style="width: 150px"
 | 
			
		||||
                                 filterable remote :remote-method="handleQueryItem" :loading="loadingRemoteItems">
 | 
			
		||||
                        <el-option v-for="info in itemChoices" :key="info.value" :label="info.desc"
 | 
			
		||||
                                   :value="info.value"></el-option>
 | 
			
		||||
                      </el-select>
 | 
			
		||||
                    </el-tooltip>
 | 
			
		||||
 | 
			
		||||
@ -115,6 +115,7 @@ export function setProjectOperationRoutes(projectList) {
 | 
			
		||||
                name: projectRoute.name + "_" + resource.resource,
 | 
			
		||||
                meta: {
 | 
			
		||||
                    desc: resource.desc,
 | 
			
		||||
                    projectId: project.project_id,
 | 
			
		||||
                    resource: resource.resource,
 | 
			
		||||
                    resource_url: routePath,
 | 
			
		||||
                    methods: {},
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										19
									
								
								ui/src/utils/string.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										19
									
								
								ui/src/utils/string.js
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,19 @@
 | 
			
		||||
 | 
			
		||||
export function getWhereConditionDesc(where) {
 | 
			
		||||
    switch (where) {
 | 
			
		||||
        case 'eq':
 | 
			
		||||
            return "等于"
 | 
			
		||||
        case 'gt':
 | 
			
		||||
            return "大于"
 | 
			
		||||
        case 'lt':
 | 
			
		||||
            return "小于"
 | 
			
		||||
        case 'ge':
 | 
			
		||||
            return "大于等于"
 | 
			
		||||
        case 'le':
 | 
			
		||||
            return "小于等于"
 | 
			
		||||
        case 'like':
 | 
			
		||||
            return "包含"
 | 
			
		||||
        case 'range':
 | 
			
		||||
            return  ""
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@ -236,12 +236,12 @@ h1 {
 | 
			
		||||
 | 
			
		||||
:deep(.el-menu-vertical-demo .el-menu-item) {
 | 
			
		||||
  color: #fff;
 | 
			
		||||
  background-color: cadetblue;
 | 
			
		||||
  background-color: #4d4f52;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
:deep(.el-menu-vertical-demo .el-sub-menu) {
 | 
			
		||||
  color: #fff;
 | 
			
		||||
  background-color: cadetblue;
 | 
			
		||||
  background-color: #4d4f52;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
:deep(.el-menu-vertical-demo .el-sub-menu__title) {
 | 
			
		||||
@ -255,7 +255,7 @@ h1 {
 | 
			
		||||
 | 
			
		||||
:deep(.el-menu-vertical-demo .el-menu-item.is-active),
 | 
			
		||||
:deep(.el-menu-vertical-demo .el-sub-menu__title.is-active) {
 | 
			
		||||
  background-color: #ffd04b;
 | 
			
		||||
  background-color: #e91f63;
 | 
			
		||||
  color: #545c64;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										7
									
								
								ui/todo.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										7
									
								
								ui/todo.md
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,7 @@
 | 
			
		||||
# todo列表
 | 
			
		||||
- [x] 道具列表选择支持远程搜索(避免道具列表太长卡顿)
 | 
			
		||||
- [ ] 表格各种项目支持分页(难点是账户、角色、订单如何分)
 | 
			
		||||
- [ ] 表格字段排序
 | 
			
		||||
- [ ] 表格字段搜索
 | 
			
		||||
- [ ] 表格定制化按钮,比如服务器列表支持单个服务器维护、一键维护(难点是带页面跳转的比如角色列表快速封禁)
 | 
			
		||||
- [ ] 执行历史记录
 | 
			
		||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user