From 13ea1f2e043104995526541336bf5ee9a97e0c1e Mon Sep 17 00:00:00 2001 From: yumaojun03 <719118794@qq.com> Date: Sun, 22 Jun 2025 23:53:53 +0800 Subject: [PATCH] add label --- devcloud/etc/application.toml | 2 +- devcloud/mcenter/apps/label/README..md | 9 ++ devcloud/mcenter/apps/label/design.drawio | 37 ++++++ devcloud/mcenter/apps/label/enum.go | 15 +++ devcloud/mcenter/apps/label/impl/impl.go | 31 +++++ devcloud/mcenter/apps/label/impl/impl_test.go | 18 +++ devcloud/mcenter/apps/label/impl/label.go | 62 +++++++++ .../mcenter/apps/label/impl/label_test.go | 24 ++++ devcloud/mcenter/apps/label/interface.go | 57 +++++++++ devcloud/mcenter/apps/label/model.go | 120 ++++++++++++++++++ .../mcenter/apps/policy/impl/policy_test.go | 2 +- devcloud/mcenter/apps/registry.go | 1 + .../apps/application/impl/application.go | 8 -- 13 files changed, 376 insertions(+), 10 deletions(-) create mode 100644 devcloud/mcenter/apps/label/README..md create mode 100644 devcloud/mcenter/apps/label/design.drawio create mode 100644 devcloud/mcenter/apps/label/enum.go create mode 100644 devcloud/mcenter/apps/label/impl/impl.go create mode 100644 devcloud/mcenter/apps/label/impl/impl_test.go create mode 100644 devcloud/mcenter/apps/label/impl/label.go create mode 100644 devcloud/mcenter/apps/label/impl/label_test.go create mode 100644 devcloud/mcenter/apps/label/interface.go create mode 100644 devcloud/mcenter/apps/label/model.go diff --git a/devcloud/etc/application.toml b/devcloud/etc/application.toml index f32d246..8b94ce8 100644 --- a/devcloud/etc/application.toml +++ b/devcloud/etc/application.toml @@ -11,7 +11,7 @@ database = "devcloud_go18" username = "root" password = "123456" - auto_migrate = false + auto_migrate = true debug = true [mongo] diff --git a/devcloud/mcenter/apps/label/README..md b/devcloud/mcenter/apps/label/README..md new file mode 100644 index 0000000..82db9f3 --- /dev/null +++ b/devcloud/mcenter/apps/label/README..md @@ -0,0 +1,9 @@ +# 资源标签管理(数据字典) + ++ key:value + +Team Label: 用户组 +![](./design.drawio) + +## 如何基于关系性数据库设计Tree结构 + diff --git a/devcloud/mcenter/apps/label/design.drawio b/devcloud/mcenter/apps/label/design.drawio new file mode 100644 index 0000000..5546d26 --- /dev/null +++ b/devcloud/mcenter/apps/label/design.drawio @@ -0,0 +1,37 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/devcloud/mcenter/apps/label/enum.go b/devcloud/mcenter/apps/label/enum.go new file mode 100644 index 0000000..eda577b --- /dev/null +++ b/devcloud/mcenter/apps/label/enum.go @@ -0,0 +1,15 @@ +package label + +// 值类型 +type VALUE_TYPE string + +const ( + // 文本 + VALUE_TYPE_TEXT VALUE_TYPE = "text" + // 布尔值, 只能是ture或者false + VALUE_TYPE_BOOLEAN VALUE_TYPE = "bool" + // 枚举 + VALUE_TYPE_ENUM VALUE_TYPE = "enum" + // 基于url的远程选项拉去, 仅存储URL地址, 前端自己处理 + VALUE_TYPE_HTTP_ENUM VALUE_TYPE = "http_enum" +) diff --git a/devcloud/mcenter/apps/label/impl/impl.go b/devcloud/mcenter/apps/label/impl/impl.go new file mode 100644 index 0000000..a52ad99 --- /dev/null +++ b/devcloud/mcenter/apps/label/impl/impl.go @@ -0,0 +1,31 @@ +package impl + +import ( + "122.51.31.227/go-course/go18/devcloud/mcenter/apps/label" + "github.com/infraboard/mcube/v2/ioc" + "github.com/infraboard/mcube/v2/ioc/config/datasource" +) + +func init() { + ioc.Controller().Registry(&LabelServiceImpl{}) +} + +var _ label.Service = (*LabelServiceImpl)(nil) + +type LabelServiceImpl struct { + ioc.ObjectImpl +} + +func (i *LabelServiceImpl) Init() error { + if datasource.Get().AutoMigrate { + err := datasource.DB().AutoMigrate(&label.Label{}) + if err != nil { + return err + } + } + return nil +} + +func (i *LabelServiceImpl) Name() string { + return label.APP_NAME +} diff --git a/devcloud/mcenter/apps/label/impl/impl_test.go b/devcloud/mcenter/apps/label/impl/impl_test.go new file mode 100644 index 0000000..cd319be --- /dev/null +++ b/devcloud/mcenter/apps/label/impl/impl_test.go @@ -0,0 +1,18 @@ +package impl_test + +import ( + "context" + + "122.51.31.227/go-course/go18/devcloud/mcenter/apps/label" + "122.51.31.227/go-course/go18/devcloud/mcenter/test" +) + +var ( + svc label.Service + ctx = context.Background() +) + +func init() { + test.DevelopmentSetUp() + svc = label.GetService() +} diff --git a/devcloud/mcenter/apps/label/impl/label.go b/devcloud/mcenter/apps/label/impl/label.go new file mode 100644 index 0000000..f716935 --- /dev/null +++ b/devcloud/mcenter/apps/label/impl/label.go @@ -0,0 +1,62 @@ +package impl + +import ( + "context" + + "122.51.31.227/go-course/go18/devcloud/mcenter/apps/label" + "github.com/infraboard/mcube/v2/ioc/config/datasource" + "github.com/infraboard/mcube/v2/types" +) + +// CreateLabel implements label.Service. +func (i *LabelServiceImpl) CreateLabel(ctx context.Context, in *label.CreateLabelRequest) (*label.Label, error) { + ins, err := label.NewLabel(in) + if err != nil { + return nil, err + } + + if err := datasource.DBFromCtx(ctx). + Create(ins). + Error; err != nil { + return nil, err + } + return ins, nil +} + +// QueryLabel implements label.Service. +func (i *LabelServiceImpl) QueryLabel(ctx context.Context, in *label.QueryLabelRequest) (*types.Set[*label.Label], error) { + set := types.New[*label.Label]() + + query := datasource.DBFromCtx(ctx).Model(&label.Label{}) + err := query.Count(&set.Total).Error + if err != nil { + return nil, err + } + + err = query. + Order("created_at desc"). + Offset(int(in.ComputeOffset())). + Limit(int(in.PageSize)). + Find(&set.Items). + Error + if err != nil { + return nil, err + } + + return set, nil +} + +// DeleteLabel implements label.Service. +func (i *LabelServiceImpl) DeleteLabel(ctx context.Context, in *label.DeleteLabelRequest) (*label.Label, error) { + panic("unimplemented") +} + +// DescribeLabel implements label.Service. +func (i *LabelServiceImpl) DescribeLabel(ctx context.Context, in *label.DescribeLabelRequest) (*label.Label, error) { + panic("unimplemented") +} + +// UpdateLabel implements label.Service. +func (i *LabelServiceImpl) UpdateLabel(ctx context.Context, in *label.UpdateLabelRequest) (*label.Label, error) { + panic("unimplemented") +} diff --git a/devcloud/mcenter/apps/label/impl/label_test.go b/devcloud/mcenter/apps/label/impl/label_test.go new file mode 100644 index 0000000..22b406d --- /dev/null +++ b/devcloud/mcenter/apps/label/impl/label_test.go @@ -0,0 +1,24 @@ +package impl_test + +import ( + "testing" + + "122.51.31.227/go-course/go18/devcloud/mcenter/apps/label" +) + +func TestCreateLabel(t *testing.T) { + req := label.NewCreateLabelRequest() + req.Key = "tech" + req.KeyDesc = "技术部" + req.ValueType = label.VALUE_TYPE_ENUM + req.AddEnumOption(&label.EnumOption{ + Label: "开发一组", + Value: "dev01", + }) + + ins, err := svc.CreateLabel(ctx, req) + if err != nil { + t.Fatal(err) + } + t.Log(ins) +} diff --git a/devcloud/mcenter/apps/label/interface.go b/devcloud/mcenter/apps/label/interface.go new file mode 100644 index 0000000..9b3303f --- /dev/null +++ b/devcloud/mcenter/apps/label/interface.go @@ -0,0 +1,57 @@ +package label + +import ( + "context" + + "github.com/infraboard/mcube/v2/http/request" + "github.com/infraboard/mcube/v2/ioc" + "github.com/infraboard/mcube/v2/types" +) + +const ( + APP_NAME = "lable" +) + +func GetService() Service { + return ioc.Controller().Get(APP_NAME).(Service) +} + +type Service interface { + // 创建标签 + CreateLabel(context.Context, *CreateLabelRequest) (*Label, error) + // 修改标签 + UpdateLabel(context.Context, *UpdateLabelRequest) (*Label, error) + // 删除标签 + DeleteLabel(context.Context, *DeleteLabelRequest) (*Label, error) + // 查询标签列表 + QueryLabel(context.Context, *QueryLabelRequest) (*types.Set[*Label], error) + // 查询标签列表 + DescribeLabel(context.Context, *DescribeLabelRequest) (*Label, error) +} + +type UpdateLabelRequest struct { + DescribeLabelRequest + // 更新人 + UpdateBy string `json:"update_by"` + // 标签信息 + Spec *CreateLabelRequest `json:"spec"` +} + +type DeleteLabelRequest struct { + DescribeLabelRequest +} + +func NewQueryLabelRequest() *QueryLabelRequest { + return &QueryLabelRequest{ + PageRequest: request.NewDefaultPageRequest(), + } +} + +type QueryLabelRequest struct { + *request.PageRequest +} + +type DescribeLabelRequest struct { + // 标签Id + Id string `json:"id"` +} diff --git a/devcloud/mcenter/apps/label/model.go b/devcloud/mcenter/apps/label/model.go new file mode 100644 index 0000000..bb32516 --- /dev/null +++ b/devcloud/mcenter/apps/label/model.go @@ -0,0 +1,120 @@ +package label + +import ( + "github.com/infraboard/mcube/v2/ioc/config/validator" + "github.com/infraboard/mcube/v2/tools/pretty" + "github.com/infraboard/modules/iam/apps" +) + +func NewLabel(spc *CreateLabelRequest) (*Label, error) { + if err := spc.Validate(); err != nil { + return nil, err + } + return &Label{ + ResourceMeta: *apps.NewResourceMeta(), + Spec: spc, + }, nil +} + +type Label struct { + // 基础数据 + apps.ResourceMeta + // 空间定义 + Spec *CreateLabelRequest `json:"spec" bson:",inline" gorm:"embedded"` +} + +func (l *Label) TableName() string { + return "labels" +} + +func (l *Label) String() string { + return pretty.ToJSON(l) +} + +func NewCreateLabelRequest() *CreateLabelRequest { + return &CreateLabelRequest{ + CreateCreateLabelSpec: CreateCreateLabelSpec{ + Resources: []string{}, + EnumOptions: []*EnumOption{}, + Extras: map[string]string{}, + }, + } +} + +type CreateLabelRequest struct { + // 创建人 + CreateBy string `json:"create_by" bson:"create_by" gorm:"column:create_by;type:varchar(255)"` + // 标签的键 + Domain string `json:"domain" bson:"domain" gorm:"column:domain;type:varchar(100)"` + // 标签的键 + Namespace string `json:"namespace" bson:"namespace" gorm:"column:namespace;type:varchar(100)"` + // 用户参数 + CreateCreateLabelSpec +} + +func (r *CreateLabelRequest) Validate() error { + return validator.Validate(r) +} + +func (r *CreateLabelRequest) AddEnumOption(enums ...*EnumOption) *CreateLabelRequest { + r.EnumOptions = append(r.EnumOptions, enums...) + return r +} + +type CreateCreateLabelSpec struct { + // 适用于那些资源 + Resources []string `json:"resources" bson:"resources" gorm:"column:resources;type:json;serializer:json;" description:"适用于那些资源" optional:"true"` + + // 标签的键, 标签的Key不允许修改, 带前缀的 tech.dev.frontend01 tech.dev.backend01 + Key string `json:"key" bson:"key" gorm:"column:key;type:varchar(255)" validate:"required"` + // 标签的键的描述 + KeyDesc string `json:"key_desc" bson:"key_desc" gorm:"column:key_desc;type:varchar(255)" validate:"required"` + // 标签的颜色 + Color string `json:"color" bson:"color" gorm:"column:color;type:varchar(100)"` + + // 值类型 + ValueType VALUE_TYPE `json:"value_type" gorm:"column:value_type;type:varchar(20)" bson:"value_type"` + // 标签默认值 + DefaultValue string `json:"default_value" gorm:"column:default_value;type:text" bson:"default_value"` + // 值描述 + ValueDesc string `json:"value_desc" gorm:"column:value_desc;type:text" bson:"value_desc"` + // 是否是多选 + Multiple bool `json:"multiple" bson:"multiple" gorm:"column:multiple;tinyint(1)"` + // 枚举值的选项 + EnumOptions []*EnumOption `json:"enum_options,omitempty" bson:"enum_options" gorm:"column:enum_options;type:json;serializer:json;"` + // 基于Http枚举的配置 + HttpEnumConfig HttpEnumConfig `json:"http_enum_config,omitempty" gorm:"embedded" bson:"http_enum_config"` + // 值的样例 + Example string `json:"example" bson:"example" gorm:"column:example;type:text"` + + // 扩展属性 + Extras map[string]string `json:"extras" bson:"extras" gorm:"column:extras;type:json;serializer:json;"` +} + +type EnumOption struct { + // 选项的说明 + Label string `json:"label" bson:"label"` + // 用户输入 + Input string `json:"input" bson:"input" validate:"required"` + // 选项的值, 根据parent.input + children.input 自动生成 + Value string `json:"value" bson:"value"` + // 标签的颜色 + Color string `json:"color" bson:"color"` + // 是否废弃 + Deprecate bool `json:"deprecate" bson:"deprecate"` + // 废弃说明 + DeprecateDesc string `json:"deprecate_desc" bson:"deprecate_desc"` + // 枚举的子选项 + Children []*EnumOption `json:"children,omitempty" bson:"children"` + // 扩展属性 + Extensions map[string]string `json:"extensions" bson:"extensions"` +} + +type HttpEnumConfig struct { + // 基于枚举的URL, 注意只支持Get方法 + Url string `json:"url" bson:"url" gorm:"column:http_enum_config_url;type:text"` + // Enum Label映射的字段名 + KeyFiled string `json:"enum_label_name" bson:"enum_label_name" gorm:"column:http_enum_config_key_filed;type:varchar(100)"` + // Enum Value映射的字段名 + ValueFiled string `json:"enum_label_value" bson:"enum_label_value" gorm:"column:http_enum_config_value_filed;type:varchar(100)"` +} diff --git a/devcloud/mcenter/apps/policy/impl/policy_test.go b/devcloud/mcenter/apps/policy/impl/policy_test.go index 61c78c1..cecf5ab 100644 --- a/devcloud/mcenter/apps/policy/impl/policy_test.go +++ b/devcloud/mcenter/apps/policy/impl/policy_test.go @@ -20,9 +20,9 @@ func TestQueryPolicy(t *testing.T) { func TestCreatePolicy(t *testing.T) { req := policy.NewCreatePolicyRequest() - req.SetNamespaceId(1) req.UserId = 2 req.RoleId = []uint64{1} + req.SetNamespaceId(1) set, err := impl.CreatePolicy(ctx, req) if err != nil { t.Fatal(err) diff --git a/devcloud/mcenter/apps/registry.go b/devcloud/mcenter/apps/registry.go index 3a55215..269fc01 100644 --- a/devcloud/mcenter/apps/registry.go +++ b/devcloud/mcenter/apps/registry.go @@ -9,6 +9,7 @@ import ( // 鉴权 _ "122.51.31.227/go-course/go18/devcloud/mcenter/apps/endpoint/impl" + _ "122.51.31.227/go-course/go18/devcloud/mcenter/apps/label/impl" _ "122.51.31.227/go-course/go18/devcloud/mcenter/apps/namespace/impl" _ "122.51.31.227/go-course/go18/devcloud/mcenter/apps/policy/impl" _ "122.51.31.227/go-course/go18/devcloud/mcenter/apps/role/impl" diff --git a/devcloud/mpaas/apps/application/impl/application.go b/devcloud/mpaas/apps/application/impl/application.go index f9b4eaa..8fbab96 100644 --- a/devcloud/mpaas/apps/application/impl/application.go +++ b/devcloud/mpaas/apps/application/impl/application.go @@ -40,14 +40,6 @@ func (i *ApplicationServiceImpl) QueryApplication(ctx context.Context, in *appli query = query.Where("ready = ?", *in.Ready) } - if in.NamespaceId != nil { - query = query.Where("namespace = ?", in.NamespaceId) - } - // 过滤条件, Label - - if in.Scope != nil { - } - err := query.Count(&set.Total).Error if err != nil { return nil, err