Compare commits

...

10 Commits
v0.0.9 ... main

Author SHA1 Message Date
fcl 1056b4d222 update rest version 2025-08-01 18:33:07 +08:00
fcl 5d678e122a 添加多级组件定义 2025-07-30 13:51:51 +08:00
Yavolte 30a4143507 Merge branch 'main' of git.dialme.cn:golang/aeus-admin 2025-07-24 17:51:42 +08:00
Yavolte 300f600d66 添加文档说明 2025-07-24 17:51:09 +08:00
fcl 29fa44cb31 修复多域的处理 2025-07-23 18:46:14 +08:00
Yavolte 822603d14e 优化proto 2025-07-23 17:38:06 +08:00
Yavolte caf2ede72d update proto 2025-07-23 17:36:53 +08:00
Yavolte 016ae8a014 优化多租户的方案 2025-07-23 17:11:52 +08:00
Yavolte 9bbda7bfe3 优化多租户支持 2025-07-23 17:07:51 +08:00
Yavolte 556f7abf25 修复组件名称BUG 2025-07-23 15:32:57 +08:00
29 changed files with 468 additions and 188 deletions

View File

@ -1,2 +1,67 @@
# 权限配置
# 命名规则
## 模块命名
模块命名的话需要使用单个单词,不包含下划线,不用说驼峰命令
## 组件名称
1. 顶层组件
组件名称应该和模块名称和菜单层级保持一致, 比如`system`模块, 那么最顶级的组件名称应该为`System`
2. 子组件
子组件应该在父组件基础上加上自己的名称, 比如`System`模块下有一个`User`组件, 那么组件名称应该为`SystemUser`, 同时菜单也需要配置父组件为`System`
如果组件下面没有孙子组件, 那么视图为:
```
views/system/user/Index.vue
```
3. 孙子组件
孙子组件应该在父组件的基础上加上自己的名称, 比如`System`模块下有一个`User`组件, 那么组件名称应该为`SystemUser`, 同时自己的名称为`Login`, 那么组件名称应该为`SystemUserLogin`, 菜单的父组件为`SystemUser`, 生成对应的视图文件路径为:
```
views/system/user/login/Index.vue
```
# 子模块处理
处理子表的情况, 比如有一个菜单表和权限表, 权限隶属于菜单表下面, 那么在试图页面处理权限的的时候可以如下处理:
1. 菜单配置
这里需要手动指定下路由地址, 另外配置菜单为隐藏的菜单
``` go
func (m *AclRule) GetMenu() *types.Menu {
return &types.Menu{
Name: "SettingAclRule",
Parent: "Setting",
Label: "ACL规则",
Hidden: true,
Uri: "/setting/acl/rule/:acl",
}
}
```
2. 界面配置
需要配置组件`Viewer`的`knownColumns`属性, 表示这个是已知的字段值, 表现为不会再界面显示, 添加和更新的时候自动赋值, 查询的时候自动赋值
```vue
<viewer :known-columns="knownColumns"></viewer>
```
```js
onMounted(() => {
knownColumns.value['name'] = route.params['acl']
})
```

View File

@ -42,6 +42,7 @@ func (s *ActivityRecorder) onAfterCreate(ctx context.Context, tx *gorm.DB, model
}
data := &models.Activity{}
data.Uid = runtimeScope.User
data.Domain = runtimeScope.Domain
data.Module = runtimeScope.ModuleName
data.Table = runtimeScope.TableName
data.Action = types.ScenarioCreate
@ -65,6 +66,7 @@ func (s *ActivityRecorder) onAfterUpdate(ctx context.Context, tx *gorm.DB, model
}
data := &models.Activity{}
data.Uid = runtimeScope.User
data.Domain = runtimeScope.Domain
data.Module = runtimeScope.ModuleName
data.Table = runtimeScope.TableName
data.Action = types.ScenarioUpdate
@ -95,6 +97,7 @@ func (s *ActivityRecorder) onAfterDelete(ctx context.Context, tx *gorm.DB, model
}
data := &models.Activity{}
data.Uid = runtimeScope.User
data.Domain = runtimeScope.Domain
data.Module = runtimeScope.ModuleName
data.Table = runtimeScope.TableName
data.Action = types.ScenarioDelete

View File

@ -5,6 +5,7 @@ import (
"fmt"
"git.nobla.cn/golang/aeus-admin/internal/logic"
"git.nobla.cn/golang/aeus-admin/utils"
"git.nobla.cn/golang/aeus/pkg/cache"
"git.nobla.cn/golang/rest"
"git.nobla.cn/golang/rest/types"
@ -20,7 +21,7 @@ type Formatter struct {
}
func (f *Formatter) FormatUser(ctx context.Context, value, model any, scm *types.Schema) any {
if values, err := f.user.GetLabels(ctx); err == nil {
if values, err := f.user.GetLabels(ctx, utils.GetDomainFromContext(ctx)); err == nil {
for _, row := range values {
if row.Value == value {
return fmt.Sprintf("%s(%s)", row.Label, row.Value)
@ -31,7 +32,7 @@ func (f *Formatter) FormatUser(ctx context.Context, value, model any, scm *types
}
func (f *Formatter) FormatDepartment(ctx context.Context, value, model any, scm *types.Schema) any {
if values, err := f.department.GetLabels(ctx); err == nil {
if values, err := f.department.GetLabels(ctx, utils.GetDomainFromContext(ctx)); err == nil {
for _, row := range values {
if row.Value == value {
return row.Label
@ -42,7 +43,7 @@ func (f *Formatter) FormatDepartment(ctx context.Context, value, model any, scm
}
func (f *Formatter) FormatRole(ctx context.Context, value, model any, scm *types.Schema) any {
if values, err := f.role.GetLabels(ctx); err == nil {
if values, err := f.role.GetLabels(ctx, utils.GetDomainFromContext(ctx)); err == nil {
for _, row := range values {
if row.Value == value {
return row.Label

2
go.mod
View File

@ -6,7 +6,7 @@ toolchain go1.23.10
require (
git.nobla.cn/golang/aeus v0.0.11
git.nobla.cn/golang/rest v0.1.4
git.nobla.cn/golang/rest v0.1.9
github.com/envoyproxy/protoc-gen-validate v1.2.1
golang.org/x/text v0.23.0 // indirect
google.golang.org/protobuf v1.36.6

4
go.sum
View File

@ -4,8 +4,8 @@ git.nobla.cn/golang/aeus v0.0.11 h1:gbXIOVOQRDTIQTjw9wPVfNC9nXBaTJCABeDYmrHW2Oc=
git.nobla.cn/golang/aeus v0.0.11/go.mod h1:oOEwqIp6AhKKqj6sLFO8x7IycOROYHCb/2/CjF4+9CU=
git.nobla.cn/golang/kos v0.1.32 h1:sFVCA7vKc8dPUd0cxzwExOSPX2mmMh2IuwL6cYS1pBc=
git.nobla.cn/golang/kos v0.1.32/go.mod h1:35Z070+5oB39WcVrh5DDlnVeftL/Ccmscw2MZFe9fUg=
git.nobla.cn/golang/rest v0.1.4 h1:9/XscfNXI3aPESpy8CPtVl17VSMxU9BihhedeG+h8YY=
git.nobla.cn/golang/rest v0.1.4/go.mod h1:4viDk7VujDokpUeHQGbnSp2bkkVZEoIkWQIs/l/TTPQ=
git.nobla.cn/golang/rest v0.1.9 h1:oI57jWoaJ98rRQyjH5EPoe7TYGs4MzLZ2zVRfUB0sS4=
git.nobla.cn/golang/rest v0.1.9/go.mod h1:4viDk7VujDokpUeHQGbnSp2bkkVZEoIkWQIs/l/TTPQ=
github.com/bytedance/sonic v1.11.6 h1:oUp34TzMlL+OY1OUWxHqsdkgC/Zfc85zGqw9siXjrc0=
github.com/bytedance/sonic v1.11.6/go.mod h1:LysEHSvpvDySVdC2f87zGWf6CIKJcAvqab1ZaiQtds4=
github.com/bytedance/sonic/loader v0.1.1 h1:c+e5Pt1k/cy5wMveRDyk2X4B9hF4g7an8N3zCYjJFNM=

View File

@ -49,10 +49,15 @@ func (u *Department) RecursiveDepartment(ctx context.Context, parent int64, leve
}
// GetLevelLabels 获取层级标签
func (u *Department) GetLevelLabels(ctx context.Context) (values []*types.TypeValue[int64], err error) {
values, err = dbcache.TryCache(ctx, fmt.Sprintf("department:level:labels"), func(tx *gorm.DB) ([]*types.TypeValue[int64], error) {
func (u *Department) GetLevelLabels(ctx context.Context, domainName string) (values []*types.TypeValue[int64], err error) {
values, err = dbcache.TryCache(ctx, fmt.Sprintf("department:level:labels:%s", domainName), func(tx *gorm.DB) ([]*types.TypeValue[int64], error) {
var values []*models.Department
if err = tx.Find(&values).Error; err != nil {
if domainName == "" {
err = tx.Find(&values).Error
} else {
err = tx.Where("`domain` = ?", domainName).Find(&values).Error
}
if err != nil {
return nil, err
}
return u.RecursiveDepartment(ctx, 0, 0, values), nil
@ -65,9 +70,9 @@ func (u *Department) GetLevelLabels(ctx context.Context) (values []*types.TypeVa
}
// GetLabels 获取用户标签
func (u *Department) GetLabels(ctx context.Context) (values []*types.TypeValue[int64], err error) {
values, err = dbcache.TryCache(ctx, fmt.Sprintf("department:labels"), func(tx *gorm.DB) ([]*types.TypeValue[int64], error) {
return rest.ModelTypes[int64](ctx, tx, &models.Department{}, "", "name", "id")
func (u *Department) GetLabels(ctx context.Context, domainName string) (values []*types.TypeValue[int64], err error) {
values, err = dbcache.TryCache(ctx, fmt.Sprintf("department:labels:%s", domainName), func(tx *gorm.DB) ([]*types.TypeValue[int64], error) {
return rest.ModelTypes[int64](ctx, tx, &models.Department{}, domainName, "name", "id")
},
dbcache.WithDB(u.db),
dbcache.WithCache(u.cache),
@ -77,10 +82,14 @@ func (u *Department) GetLabels(ctx context.Context) (values []*types.TypeValue[i
}
// GetDepartments 获取部门列表
func (u *Department) GetDepartments(ctx context.Context) (values []*models.Department, err error) {
values, err = dbcache.TryCache(ctx, fmt.Sprintf("department:list"), func(tx *gorm.DB) ([]*models.Department, error) {
func (u *Department) GetDepartments(ctx context.Context, domainName string) (values []*models.Department, err error) {
values, err = dbcache.TryCache(ctx, fmt.Sprintf("department:list:%s", domainName), func(tx *gorm.DB) ([]*models.Department, error) {
var items []*models.Department
err = tx.Find(&items).Error
if domainName == "" {
err = tx.Find(&items).Error
} else {
err = tx.Where("`domain` = ?", domainName).Find(&items).Error
}
return items, err
},
dbcache.WithDB(u.db),

View File

@ -2,7 +2,6 @@ package logic
import (
"context"
"fmt"
"git.nobla.cn/golang/aeus-admin/models"
"git.nobla.cn/golang/aeus-admin/pkg/dbcache"
@ -31,7 +30,7 @@ func (u *Menu) GetMenus(ctx context.Context) (values []*models.Menu, err error)
}
func (u *Menu) GetLabels(ctx context.Context) (values []*types.TypeValue[string], err error) {
return dbcache.TryCache(ctx, fmt.Sprintf("menu:labels"), func(tx *gorm.DB) ([]*types.TypeValue[string], error) {
return dbcache.TryCache(ctx, "menu:labels", func(tx *gorm.DB) ([]*types.TypeValue[string], error) {
return rest.ModelTypes[string](ctx, tx, &models.Menu{}, "", "label", "name")
},
dbcache.WithDB(u.db),

View File

@ -19,9 +19,9 @@ type Role struct {
permissionSqlDependency *dbcache.SqlDependency
}
func (u *Role) GetLabels(ctx context.Context) (values []*types.TypeValue[string], err error) {
values, err = dbcache.TryCache(ctx, fmt.Sprintf("role:labels"), func(tx *gorm.DB) ([]*types.TypeValue[string], error) {
return rest.ModelTypes[string](ctx, tx, &models.Role{}, "", "label", "name")
func (u *Role) GetLabels(ctx context.Context, domainName string) (values []*types.TypeValue[string], err error) {
values, err = dbcache.TryCache(ctx, fmt.Sprintf("role:labels:%s", domainName), func(tx *gorm.DB) ([]*types.TypeValue[string], error) {
return rest.ModelTypes[string](ctx, tx, &models.Role{}, domainName, "label", "name")
},
dbcache.WithDB(u.db),
dbcache.WithCache(u.cache),

View File

@ -40,9 +40,9 @@ func (u *User) GetPermissions(ctx context.Context, uid string) (permissions []st
}
// GetLabels 获取用户标签
func (u *User) GetLabels(ctx context.Context) (values []*types.TypeValue[string], err error) {
values, err = dbcache.TryCache(ctx, fmt.Sprintf("user:labels"), func(tx *gorm.DB) ([]*types.TypeValue[string], error) {
return rest.ModelTypes[string](ctx, tx, &models.User{}, "", "username", "uid")
func (u *User) GetLabels(ctx context.Context, domainName string) (values []*types.TypeValue[string], err error) {
values, err = dbcache.TryCache(ctx, fmt.Sprintf("user:labels:%s", domainName), func(tx *gorm.DB) ([]*types.TypeValue[string], error) {
return rest.ModelTypes[string](ctx, tx, &models.User{}, domainName, "username", "uid")
},
dbcache.WithDB(u.db),
dbcache.WithCache(u.cache),
@ -52,10 +52,14 @@ func (u *User) GetLabels(ctx context.Context) (values []*types.TypeValue[string]
}
// GeUsers 获取部门列表
func (u *User) GeUsers(ctx context.Context) (values []*models.User, err error) {
values, err = dbcache.TryCache(ctx, fmt.Sprintf("user:list"), func(tx *gorm.DB) ([]*models.User, error) {
func (u *User) GeUsers(ctx context.Context, domainName string) (values []*models.User, err error) {
values, err = dbcache.TryCache(ctx, fmt.Sprintf("user:list:%s", domainName), func(tx *gorm.DB) ([]*models.User, error) {
var items []*models.User
err = tx.Find(&items).Error
if domainName != "" {
err = tx.Where("`domain` = ?", domainName).Find(&items).Error
} else {
err = tx.Find(&items).Error
}
return items, err
},
dbcache.WithDB(u.db),

View File

@ -11,7 +11,7 @@ import (
func Menu(db *gorm.DB, datas ...*models.Menu) (err error) {
tx := db.Begin()
for _, model := range datas {
if err = tx.Where("name = ?", model.Name).First(model).Error; err != nil {
if err = tx.Where("`name` = ?", model.Name).First(model).Error; err != nil {
if errors.Is(err, gorm.ErrRecordNotFound) {
if err = tx.Create(model).Error; err != nil {
tx.Rollback()
@ -39,7 +39,7 @@ func Permission(db *gorm.DB, menuName string, permission string, label string) (
}
// Default 合并初始化数据集
func Default(db *gorm.DB) (err error) {
func Default(db *gorm.DB, domain string) (err error) {
var (
n int64
)
@ -49,6 +49,9 @@ func Default(db *gorm.DB) (err error) {
}
}
if db.Model(&models.Role{}).Count(&n); n == 0 {
for i := range defaultRoles {
defaultRoles[i].Domain = domain
}
db.Create(defaultRoles)
permissions := make([]*models.Permission, 0)
db.Find(&permissions)
@ -65,9 +68,15 @@ func Default(db *gorm.DB) (err error) {
}
if db.Model(&models.Department{}).Count(&n); n == 0 {
for i := range defaultDepartments {
defaultDepartments[i].Domain = domain
}
db.Create(defaultDepartments)
}
if db.Model(&models.User{}).Count(&n); n == 0 {
for i := range defaultUsers {
defaultUsers[i].Domain = domain
}
db.Create(defaultUsers)
}
return

View File

@ -172,9 +172,10 @@ type Role struct {
Id int64 `protobuf:"varint,1,opt,name=id,proto3" json:"id,omitempty"`
CreatedAt int64 `protobuf:"varint,2,opt,name=created_at,json=createdAt,proto3" json:"created_at,omitempty"`
UpdatedAt int64 `protobuf:"varint,3,opt,name=updated_at,json=updatedAt,proto3" json:"updated_at,omitempty"`
Name string `protobuf:"bytes,4,opt,name=name,proto3" json:"name,omitempty"`
Label string `protobuf:"bytes,5,opt,name=label,proto3" json:"label,omitempty"`
Description string `protobuf:"bytes,6,opt,name=description,proto3" json:"description,omitempty"`
Domain string `protobuf:"bytes,4,opt,name=domain,proto3" json:"domain,omitempty"`
Name string `protobuf:"bytes,5,opt,name=name,proto3" json:"name,omitempty"`
Label string `protobuf:"bytes,6,opt,name=label,proto3" json:"label,omitempty"`
Description string `protobuf:"bytes,7,opt,name=description,proto3" json:"description,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
@ -230,6 +231,13 @@ func (x *Role) GetUpdatedAt() int64 {
return 0
}
func (x *Role) GetDomain() string {
if x != nil {
return x.Domain
}
return ""
}
func (x *Role) GetName() string {
if x != nil {
return x.Name
@ -403,18 +411,19 @@ type User struct {
Id int64 `protobuf:"varint,1,opt,name=id,proto3" json:"id,omitempty"`
CreatedAt int64 `protobuf:"varint,2,opt,name=created_at,json=createdAt,proto3" json:"created_at,omitempty"`
UpdatedAt int64 `protobuf:"varint,3,opt,name=updated_at,json=updatedAt,proto3" json:"updated_at,omitempty"`
Uid string `protobuf:"bytes,4,opt,name=uid,proto3" json:"uid,omitempty"`
Username string `protobuf:"bytes,5,opt,name=username,proto3" json:"username,omitempty"`
Role string `protobuf:"bytes,6,opt,name=role,proto3" json:"role,omitempty"`
Admin bool `protobuf:"varint,7,opt,name=admin,proto3" json:"admin,omitempty"`
Status string `protobuf:"bytes,8,opt,name=status,proto3" json:"status,omitempty"`
DeptId int64 `protobuf:"varint,9,opt,name=dept_id,json=deptId,proto3" json:"dept_id,omitempty"`
Tag string `protobuf:"bytes,10,opt,name=tag,proto3" json:"tag,omitempty"`
Password string `protobuf:"bytes,11,opt,name=password,proto3" json:"password,omitempty"`
Email string `protobuf:"bytes,12,opt,name=email,proto3" json:"email,omitempty"`
Avatar string `protobuf:"bytes,13,opt,name=avatar,proto3" json:"avatar,omitempty"`
Gender string `protobuf:"bytes,14,opt,name=gender,proto3" json:"gender,omitempty"`
Description string `protobuf:"bytes,15,opt,name=description,proto3" json:"description,omitempty"`
Domain string `protobuf:"bytes,4,opt,name=domain,proto3" json:"domain,omitempty"`
Uid string `protobuf:"bytes,5,opt,name=uid,proto3" json:"uid,omitempty"`
Username string `protobuf:"bytes,6,opt,name=username,proto3" json:"username,omitempty"`
Role string `protobuf:"bytes,7,opt,name=role,proto3" json:"role,omitempty"`
Admin bool `protobuf:"varint,8,opt,name=admin,proto3" json:"admin,omitempty"`
Status string `protobuf:"bytes,9,opt,name=status,proto3" json:"status,omitempty"`
DeptId int64 `protobuf:"varint,10,opt,name=dept_id,json=deptId,proto3" json:"dept_id,omitempty"`
Tag string `protobuf:"bytes,11,opt,name=tag,proto3" json:"tag,omitempty"`
Password string `protobuf:"bytes,12,opt,name=password,proto3" json:"password,omitempty"`
Email string `protobuf:"bytes,13,opt,name=email,proto3" json:"email,omitempty"`
Avatar string `protobuf:"bytes,14,opt,name=avatar,proto3" json:"avatar,omitempty"`
Gender string `protobuf:"bytes,15,opt,name=gender,proto3" json:"gender,omitempty"`
Description string `protobuf:"bytes,16,opt,name=description,proto3" json:"description,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
@ -470,6 +479,13 @@ func (x *User) GetUpdatedAt() int64 {
return 0
}
func (x *User) GetDomain() string {
if x != nil {
return x.Domain
}
return ""
}
func (x *User) GetUid() string {
if x != nil {
return x.Uid
@ -560,9 +576,10 @@ type Department struct {
Id int64 `protobuf:"varint,1,opt,name=id,proto3" json:"id,omitempty"`
CreatedAt int64 `protobuf:"varint,2,opt,name=created_at,json=createdAt,proto3" json:"created_at,omitempty"`
UpdatedAt int64 `protobuf:"varint,3,opt,name=updated_at,json=updatedAt,proto3" json:"updated_at,omitempty"`
ParentId int64 `protobuf:"varint,4,opt,name=parent_id,json=parentId,proto3" json:"parent_id,omitempty"`
Name string `protobuf:"bytes,5,opt,name=name,proto3" json:"name,omitempty"`
Description string `protobuf:"bytes,6,opt,name=description,proto3" json:"description,omitempty"`
Domain string `protobuf:"bytes,4,opt,name=domain,proto3" json:"domain,omitempty"`
ParentId int64 `protobuf:"varint,5,opt,name=parent_id,json=parentId,proto3" json:"parent_id,omitempty"`
Name string `protobuf:"bytes,6,opt,name=name,proto3" json:"name,omitempty"`
Description string `protobuf:"bytes,7,opt,name=description,proto3" json:"description,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
@ -618,6 +635,13 @@ func (x *Department) GetUpdatedAt() int64 {
return 0
}
func (x *Department) GetDomain() string {
if x != nil {
return x.Domain
}
return ""
}
func (x *Department) GetParentId() int64 {
if x != nil {
return x.ParentId
@ -643,13 +667,14 @@ type Login struct {
state protoimpl.MessageState `protogen:"open.v1"`
Id int64 `protobuf:"varint,1,opt,name=id,proto3" json:"id,omitempty"`
CreatedAt int64 `protobuf:"varint,2,opt,name=created_at,json=createdAt,proto3" json:"created_at,omitempty"`
Uid string `protobuf:"bytes,4,opt,name=uid,proto3" json:"uid,omitempty"`
Ip string `protobuf:"bytes,5,opt,name=ip,proto3" json:"ip,omitempty"`
Browser string `protobuf:"bytes,6,opt,name=browser,proto3" json:"browser,omitempty"`
Os string `protobuf:"bytes,7,opt,name=os,proto3" json:"os,omitempty"`
Platform string `protobuf:"bytes,8,opt,name=platform,proto3" json:"platform,omitempty"`
AccessToken string `protobuf:"bytes,9,opt,name=access_token,json=accessToken,proto3" json:"access_token,omitempty"`
UserAgent string `protobuf:"bytes,10,opt,name=user_agent,json=userAgent,proto3" json:"user_agent,omitempty"`
Domain string `protobuf:"bytes,4,opt,name=domain,proto3" json:"domain,omitempty"`
Uid string `protobuf:"bytes,5,opt,name=uid,proto3" json:"uid,omitempty"`
Ip string `protobuf:"bytes,6,opt,name=ip,proto3" json:"ip,omitempty"`
Browser string `protobuf:"bytes,7,opt,name=browser,proto3" json:"browser,omitempty"`
Os string `protobuf:"bytes,8,opt,name=os,proto3" json:"os,omitempty"`
Platform string `protobuf:"bytes,9,opt,name=platform,proto3" json:"platform,omitempty"`
AccessToken string `protobuf:"bytes,10,opt,name=access_token,json=accessToken,proto3" json:"access_token,omitempty"`
UserAgent string `protobuf:"bytes,11,opt,name=user_agent,json=userAgent,proto3" json:"user_agent,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
@ -698,6 +723,13 @@ func (x *Login) GetCreatedAt() int64 {
return 0
}
func (x *Login) GetDomain() string {
if x != nil {
return x.Domain
}
return ""
}
func (x *Login) GetUid() string {
if x != nil {
return x.Uid
@ -3032,7 +3064,7 @@ const file_organize_proto_rawDesc = "" +
"\vdescription\x18\f \x01(\tBJ\xfaB\x05r\x03\x18\x80\b\xb2\xb9\x19>\n" +
"\tsize:1024\x12\f备注说明\x1a\x19create;update;view;export*\btextareaR\vdescription\x127\n" +
"\bposition\x18\r \x01(\x03B\x1b\xb2\xb9\x19\x17\x12\x06排序\x1a\rcreate;updateR\bposition:\v\xba\xb9\x19\a\n" +
"\x05menus\"\xd1\x03\n" +
"\x05menus\"\x9f\x04\n" +
"\x04Role\x12*\n" +
"\x02id\x18\x01 \x01(\x03B\x1a\xb2\xb9\x19\x16\n" +
"\n" +
@ -3041,12 +3073,14 @@ const file_organize_proto_rawDesc = "" +
"created_at\x18\x02 \x01(\x03B\x1f\xb2\xb9\x19\x1b\x12\f创建时间\x1a\vview;exportR\tcreatedAt\x12E\n" +
"\n" +
"updated_at\x18\x03 \x01(\x03B&\xb2\xb9\x19\"\n" +
"\x05index\x12\f更新时间\x1a\vview;exportR\tupdatedAt\x12W\n" +
"\x04name\x18\x04 \x01(\tBC\xfaB\x04r\x02\x18<\xb2\xb9\x198\n" +
"\x05index\x12\f更新时间\x1a\vview;exportR\tupdatedAt\x12L\n" +
"\x06domain\x18\x04 \x01(\tB4\xb2\xb9\x190\n" +
"!index;size:60;not null;default:''\x12\x03域\x1a\x06exportR\x06domain\x12W\n" +
"\x04name\x18\x05 \x01(\tBC\xfaB\x04r\x02\x18<\xb2\xb9\x198\n" +
"\rindex;size:60\x12\f角色名称2\x0freadonly:update:\brequiredR\x04name\x12B\n" +
"\x05label\x18\x05 \x01(\tB,\xfaB\x04r\x02\x18<\xb2\xb9\x19!\n" +
"\x05label\x18\x06 \x01(\tB,\xfaB\x04r\x02\x18<\xb2\xb9\x19!\n" +
"\asize:60\x12\f角色标题:\brequiredR\x05label\x12l\n" +
"\vdescription\x18\x06 \x01(\tBJ\xfaB\x05r\x03\x18\x80\b\xb2\xb9\x19>\n" +
"\vdescription\x18\a \x01(\tBJ\xfaB\x05r\x03\x18\x80\b\xb2\xb9\x19>\n" +
"\tsize:1024\x12\f备注说明\x1a\x19list;create;update;export*\btextareaR\vdescription:\v\xba\xb9\x19\a\n" +
"\x05roles\"\xb1\x03\n" +
"\n" +
@ -3078,7 +3112,7 @@ const file_organize_proto_rawDesc = "" +
"permission\x18\x03 \x01(\tB\x1f\xb2\xb9\x19\x1b\n" +
"\asize:60\x12\x06权限:\brequiredR\n" +
"permission:\x16\xba\xb9\x19\x12\n" +
"\x10role_permissions\"\xa2\v\n" +
"\x10role_permissions\"\xf0\v\n" +
"\x04User\x12$\n" +
"\x02id\x18\x01 \x01(\x03B\x14\xb2\xb9\x19\x10\n" +
"\n" +
@ -3087,33 +3121,35 @@ const file_organize_proto_rawDesc = "" +
"created_at\x18\x02 \x01(\x03B\x1f\xb2\xb9\x19\x1b\x12\f创建时间\x1a\vview;exportR\tcreatedAt\x12E\n" +
"\n" +
"updated_at\x18\x03 \x01(\x03B&\xb2\xb9\x19\"\n" +
"\x05index\x12\f更新时间\x1a\vview;exportR\tupdatedAt\x12x\n" +
"\x03uid\x18\x04 \x01(\tBf\xfaB\x06r\x04\x10\x05\x18\x14\xb2\xb9\x19Y\n" +
"\x05index\x12\f更新时间\x1a\vview;exportR\tupdatedAt\x12L\n" +
"\x06domain\x18\x04 \x01(\tB4\xb2\xb9\x190\n" +
"!index;size:60;not null;default:''\x12\x03域\x1a\x06exportR\x06domain\x12x\n" +
"\x03uid\x18\x05 \x01(\tBf\xfaB\x06r\x04\x10\x05\x18\x14\xb2\xb9\x19Y\n" +
"\rindex;size:20\x12\f用户工号2\x0freadonly:update:)required;unique;regexp:^[a-zA-Z0-9]{3,8}$R\x03uid\x12J\n" +
"\busername\x18\x05 \x01(\tB.\xfaB\x06r\x04\x10\x05\x18\x14\xb2\xb9\x19!\n" +
"\busername\x18\x06 \x01(\tB.\xfaB\x06r\x04\x10\x05\x18\x14\xb2\xb9\x19!\n" +
"\asize:20\x12\f用户名称:\brequiredR\busername\x12z\n" +
"\x04role\x18\x06 \x01(\tBf\xfaB\x04r\x02\x18<\xb2\xb9\x19[\n" +
"\x04role\x18\a \x01(\tBf\xfaB\x04r\x02\x18<\xb2\xb9\x19[\n" +
"\x1bsize:60;not null;default:''\x12\f所属角色*\x04role:\brequiredB\x1etype:dropdown;url:/role/labelsR\x04role\x12-\n" +
"\x05admin\x18\a \x01(\bB\x17\xb2\xb9\x19\x13\x12\t管理员\x1a\x06createR\x05admin\x12u\n" +
"\x06status\x18\b \x01(\tB]\xb2\xb9\x19Y\n" +
"\x05admin\x18\b \x01(\bB\x17\xb2\xb9\x19\x13\x12\t管理员\x1a\x06createR\x05admin\x12u\n" +
"\x06status\x18\t \x01(\tB]\xb2\xb9\x19Y\n" +
"\x16size:20;default:normal\x12\x06状态\x1a\x19create,update,list,searchR\x1cnormal:正常;disable:禁用R\x06status\x12{\n" +
"\adept_id\x18\t \x01(\x03Bb\xb2\xb9\x19^\n" +
"\adept_id\x18\n" +
" \x01(\x03Bb\xb2\xb9\x19^\n" +
"\x12not null;default:0\x12\f所属部门*\n" +
"department:\brequiredB$type:dropdown;url:/department/labelsR\x06deptId\x12\x88\x01\n" +
"\x03tag\x18\n" +
" \x01(\tBv\xfaB\x04r\x02\x18<\xb2\xb9\x19k\n" +
"\x03tag\x18\v \x01(\tBv\xfaB\x04r\x02\x18<\xb2\xb9\x19k\n" +
"\asize:60\x12\f用户标签\x1a\x12list;create;updateB\x1ctype:dropdown;url:/user/tagsJ created;filterable;default_firstR\x03tag\x12P\n" +
"\bpassword\x18\v \x01(\tB4\xfaB\x04r\x02\x18<\xb2\xb9\x19)\n" +
"\bpassword\x18\f \x01(\tB4\xfaB\x04r\x02\x18<\xb2\xb9\x19)\n" +
"\asize:60\x12\f用户密码\x1a\x06create:\brequiredR\bpassword\x12X\n" +
"\x05email\x18\f \x01(\tBB\xfaB\x04r\x02\x18<\xb2\xb9\x197\n" +
"\x05email\x18\r \x01(\tBB\xfaB\x04r\x02\x18<\xb2\xb9\x197\n" +
"\asize:60\x12\f用户邮箱\x1a\x1ecreate;update;view;list;exportR\x05email\x12C\n" +
"\x06avatar\x18\r \x01(\tB+\xfaB\x05r\x03\x18\x80\b\xb2\xb9\x19\x1f\n" +
"\x06avatar\x18\x0e \x01(\tB+\xfaB\x05r\x03\x18\x80\b\xb2\xb9\x19\x1f\n" +
"\tsize:1024\x12\f用户头像\x1a\x04viewR\x06avatar\x12\x90\x01\n" +
"\x06gender\x18\x0e \x01(\tBx\xfaB\x04r\x02\x18\x14\xb2\xb9\x19m\n" +
"\x06gender\x18\x0f \x01(\tBx\xfaB\x04r\x02\x18\x14\xb2\xb9\x19m\n" +
"\x13size:20;default:man\x12\f用户性别\x1a\x1elist;create;update;view;export:\brequiredR\x1eman:男;woman:女;other:其他R\x06gender\x12l\n" +
"\vdescription\x18\x0f \x01(\tBJ\xfaB\x05r\x03\x18\x80\b\xb2\xb9\x19>\n" +
"\vdescription\x18\x10 \x01(\tBJ\xfaB\x05r\x03\x18\x80\b\xb2\xb9\x19>\n" +
"\tsize:1024\x12\f备注说明\x1a\x19create;update;view;export*\btextareaR\vdescription:\v\xba\xb9\x19\a\n" +
"\x05users\"\xea\x03\n" +
"\x05users\"\xb8\x04\n" +
"\n" +
"Department\x12$\n" +
"\x02id\x18\x01 \x01(\x03B\x14\xb2\xb9\x19\x10\n" +
@ -3123,35 +3159,39 @@ const file_organize_proto_rawDesc = "" +
"created_at\x18\x02 \x01(\x03B\x1f\xb2\xb9\x19\x1b\x12\f创建时间\x1a\vview;exportR\tcreatedAt\x12E\n" +
"\n" +
"updated_at\x18\x03 \x01(\x03B&\xb2\xb9\x19\"\n" +
"\x05index\x12\f更新时间\x1a\vview;exportR\tupdatedAt\x12g\n" +
"\tparent_id\x18\x04 \x01(\x03BJ\xb2\xb9\x19F\x12\f父级部门*\n" +
"\x05index\x12\f更新时间\x1a\vview;exportR\tupdatedAt\x12L\n" +
"\x06domain\x18\x04 \x01(\tB4\xb2\xb9\x190\n" +
"!index;size:60;not null;default:''\x12\x03域\x1a\x06exportR\x06domain\x12g\n" +
"\tparent_id\x18\x05 \x01(\x03BJ\xb2\xb9\x19F\x12\f父级部门*\n" +
"departmentB*type:dropdown;url:/department/level-labelsR\bparentId\x12@\n" +
"\x04name\x18\x05 \x01(\tB,\xfaB\x04r\x02\x18\x14\xb2\xb9\x19!\n" +
"\x04name\x18\x06 \x01(\tB,\xfaB\x04r\x02\x18\x14\xb2\xb9\x19!\n" +
"\asize:20\x12\f部门名称:\brequiredR\x04name\x12q\n" +
"\vdescription\x18\x06 \x01(\tBO\xfaB\x05r\x03\x18\x80\b\xb2\xb9\x19C\n" +
"\vdescription\x18\a \x01(\tBO\xfaB\x05r\x03\x18\x80\b\xb2\xb9\x19C\n" +
"\tsize:1024\x12\f备注说明\x1a\x1ecreate;update;view;export;list*\btextareaR\vdescription:\x11\xba\xb9\x19\r\n" +
"\vdepartments\"\x9e\x05\n" +
"\vdepartments\"\xec\x05\n" +
"\x05Login\x12$\n" +
"\x02id\x18\x01 \x01(\x03B\x14\xb2\xb9\x19\x10\n" +
"\n" +
"primaryKey\x12\x02IDR\x02id\x12J\n" +
"\n" +
"created_at\x18\x02 \x01(\x03B+\xb2\xb9\x19'\x12\f登录时间\x1a\x17list;search;view;exportR\tcreatedAt\x12W\n" +
"\x03uid\x18\x04 \x01(\tBE\xfaB\x06r\x04\x10\x05\x18\x14\xb2\xb9\x198\n" +
"created_at\x18\x02 \x01(\x03B+\xb2\xb9\x19'\x12\f登录时间\x1a\x17list;search;view;exportR\tcreatedAt\x12L\n" +
"\x06domain\x18\x04 \x01(\tB4\xb2\xb9\x190\n" +
"!index;size:60;not null;default:''\x12\x03域\x1a\x06exportR\x06domain\x12W\n" +
"\x03uid\x18\x05 \x01(\tBE\xfaB\x06r\x04\x10\x05\x18\x14\xb2\xb9\x198\n" +
"\rindex;size:20\x12\x06用户*\x04user2\x0freadonly:update:\brequiredR\x03uid\x12E\n" +
"\x02ip\x18\x05 \x01(\tB5\xb2\xb9\x191\n" +
"\x02ip\x18\x06 \x01(\tB5\xb2\xb9\x191\n" +
"\bsize:128\x12\f登录地址\x1a\x17list;search;view;exportR\x02ip\x12E\n" +
"\abrowser\x18\x06 \x01(\tB+\xb2\xb9\x19'\n" +
"\abrowser\x18\a \x01(\tB+\xb2\xb9\x19'\n" +
"\bsize:128\x12\t浏览器\x1a\x10list;view;exportR\abrowser\x12>\n" +
"\x02os\x18\a \x01(\tB.\xb2\xb9\x19*\n" +
"\x02os\x18\b \x01(\tB.\xb2\xb9\x19*\n" +
"\bsize:128\x12\f操作系统\x1a\x10list;view;exportR\x02os\x12J\n" +
"\bplatform\x18\b \x01(\tB.\xb2\xb9\x19*\n" +
"\bplatform\x18\t \x01(\tB.\xb2\xb9\x19*\n" +
"\bsize:128\x12\f系统平台\x1a\x10list;view;exportR\bplatform\x12R\n" +
"\faccess_token\x18\t \x01(\tB/\xb2\xb9\x19+\n" +
"\faccess_token\x18\n" +
" \x01(\tB/\xb2\xb9\x19+\n" +
"\tsize:1024\x12\f访问令牌\x1a\x10list;view;exportR\vaccessToken\x12N\n" +
"\n" +
"user_agent\x18\n" +
" \x01(\tB/\xb2\xb9\x19+\n" +
"user_agent\x18\v \x01(\tB/\xb2\xb9\x19+\n" +
"\tsize:1024\x12\f用户代理\x1a\x10list;view;exportR\tuserAgent:\f\xba\xb9\x19\b\n" +
"\x06logins\"8\n" +
"\n" +

View File

@ -240,6 +240,8 @@ func (m *Role) validate(all bool) error {
// no validation rules for UpdatedAt
// no validation rules for Domain
if utf8.RuneCountInString(m.GetName()) > 60 {
err := RoleValidationError{
field: "Name",
@ -621,6 +623,8 @@ func (m *User) validate(all bool) error {
// no validation rules for UpdatedAt
// no validation rules for Domain
if l := utf8.RuneCountInString(m.GetUid()); l < 5 || l > 20 {
err := UserValidationError{
field: "Uid",
@ -831,6 +835,8 @@ func (m *Department) validate(all bool) error {
// no validation rules for UpdatedAt
// no validation rules for Domain
// no validation rules for ParentId
if utf8.RuneCountInString(m.GetName()) > 20 {
@ -957,6 +963,8 @@ func (m *Login) validate(all bool) error {
// no validation rules for CreatedAt
// no validation rules for Domain
if l := utf8.RuneCountInString(m.GetUid()); l < 5 || l > 20 {
err := LoginValidationError{
field: "Uid",

View File

@ -37,9 +37,10 @@ message Role {
int64 id = 1 [(aeus.field) = {gorm:"primaryKey",comment: "角色ID"}];
int64 created_at = 2 [(aeus.field)={scenarios:"view;export",comment:"创建时间"}];
int64 updated_at = 3 [(aeus.field)={gorm:"index",scenarios:"view;export",comment:"更新时间"}];
string name = 4 [(aeus.field)={gorm:"index;size:60",rule:"required",props:"readonly:update",comment: "角色名称"},(validate.rules).string = {max_len: 60}];
string label = 5 [(aeus.field)={gorm:"size:60",rule:"required",comment: "角色标题"},(validate.rules).string = {max_len: 60}];
string description = 6 [(aeus.field)={gorm:"size:1024",scenarios:"list;create;update;export",format:"textarea",comment: "备注说明"},(validate.rules).string = {max_len: 1024}];
string domain = 4 [(aeus.field)={gorm:"index;size:60;not null;default:''",comment:"域",scenarios:"export"}];
string name = 5 [(aeus.field)={gorm:"index;size:60",rule:"required",props:"readonly:update",comment: "角色名称"},(validate.rules).string = {max_len: 60}];
string label = 6 [(aeus.field)={gorm:"size:60",rule:"required",comment: "角色标题"},(validate.rules).string = {max_len: 60}];
string description = 7 [(aeus.field)={gorm:"size:1024",scenarios:"list;create;update;export",format:"textarea",comment: "备注说明"},(validate.rules).string = {max_len: 1024}];
}
// Permission
@ -73,18 +74,19 @@ message User {
int64 id = 1 [(aeus.field) = {gorm:"primaryKey",comment: "ID"}];
int64 created_at = 2 [(aeus.field)={scenarios:"view;export",comment:"创建时间"}];
int64 updated_at = 3 [(aeus.field)={gorm:"index",scenarios:"view;export",comment:"更新时间"}];
string uid = 4 [(aeus.field) = {gorm:"index;size:20",rule:"required;unique;regexp:^[a-zA-Z0-9]{3,8}$",props:"readonly:update",comment: "用户工号"},(validate.rules).string = {min_len: 5, max_len: 20}];
string username = 5 [(aeus.field)={gorm:"size:20",rule:"required",comment: "用户名称"},(validate.rules).string = {min_len: 5, max_len: 20}];
string role = 6 [(aeus.field)={gorm:"size:60;not null;default:''",rule:"required",format:"role",live:"type:dropdown;url:/role/labels",comment: "所属角色"},(validate.rules).string = {max_len: 60}];
bool admin = 7 [(aeus.field)={scenarios:"create",comment:"管理员"}];
string status = 8 [(aeus.field)={scenarios:"create,update,list,search",gorm:"size:20;default:normal",enum:"normal:正常;disable:禁用",comment:"状态"}];
int64 dept_id = 9 [(aeus.field) = {gorm:"not null;default:0",rule:"required",live:"type:dropdown;url:/department/labels",format:"department",comment: "所属部门"}];
string tag = 10 [ (aeus.field)={gorm:"size:60",scenarios:"list;create;update",dropdown:"created;filterable;default_first",live:"type:dropdown;url:/user/tags",comment: "用户标签"},(validate.rules).string = {max_len: 60}];
string password = 11 [(aeus.field)={gorm:"size:60",rule:"required",scenarios:"create",comment: "用户密码"},(validate.rules).string = {max_len: 60}];
string email = 12 [(aeus.field)={gorm:"size:60",scenarios:"create;update;view;list;export",comment: "用户邮箱"},(validate.rules).string = {max_len: 60}];
string avatar = 13 [(aeus.field)={gorm:"size:1024",scenarios:"view",comment: "用户头像"},(validate.rules).string = {max_len: 1024}];
string gender = 14 [(aeus.field)={gorm:"size:20;default:man",rule:"required",scenarios:"list;create;update;view;export",enum:"man:男;woman:女;other:其他",comment: "用户性别"},(validate.rules).string = {max_len: 20}];
string description = 15 [(aeus.field)={gorm:"size:1024",format:"textarea",scenarios:"create;update;view;export",comment: "备注说明"},(validate.rules).string = {max_len: 1024}];
string domain = 4 [(aeus.field)={gorm:"index;size:60;not null;default:''",comment:"域",scenarios:"export"}];
string uid = 5 [(aeus.field) = {gorm:"index;size:20",rule:"required;unique;regexp:^[a-zA-Z0-9]{3,8}$",props:"readonly:update",comment: "用户工号"},(validate.rules).string = {min_len: 5, max_len: 20}];
string username = 6 [(aeus.field)={gorm:"size:20",rule:"required",comment: "用户名称"},(validate.rules).string = {min_len: 5, max_len: 20}];
string role = 7 [(aeus.field)={gorm:"size:60;not null;default:''",rule:"required",format:"role",live:"type:dropdown;url:/role/labels",comment: "所属角色"},(validate.rules).string = {max_len: 60}];
bool admin = 8 [(aeus.field)={scenarios:"create",comment:"管理员"}];
string status = 9 [(aeus.field)={scenarios:"create,update,list,search",gorm:"size:20;default:normal",enum:"normal:正常;disable:禁用",comment:"状态"}];
int64 dept_id = 10 [(aeus.field) = {gorm:"not null;default:0",rule:"required",live:"type:dropdown;url:/department/labels",format:"department",comment: "所属部门"}];
string tag = 11 [ (aeus.field)={gorm:"size:60",scenarios:"list;create;update",dropdown:"created;filterable;default_first",live:"type:dropdown;url:/user/tags",comment: "用户标签"},(validate.rules).string = {max_len: 60}];
string password = 12 [(aeus.field)={gorm:"size:60",rule:"required",scenarios:"create",comment: "用户密码"},(validate.rules).string = {max_len: 60}];
string email = 13 [(aeus.field)={gorm:"size:60",scenarios:"create;update;view;list;export",comment: "用户邮箱"},(validate.rules).string = {max_len: 60}];
string avatar = 14 [(aeus.field)={gorm:"size:1024",scenarios:"view",comment: "用户头像"},(validate.rules).string = {max_len: 1024}];
string gender = 15 [(aeus.field)={gorm:"size:20;default:man",rule:"required",scenarios:"list;create;update;view;export",enum:"man:男;woman:女;other:其他",comment: "用户性别"},(validate.rules).string = {max_len: 20}];
string description = 16 [(aeus.field)={gorm:"size:1024",format:"textarea",scenarios:"create;update;view;export",comment: "备注说明"},(validate.rules).string = {max_len: 1024}];
}
// Department
@ -95,9 +97,10 @@ message Department {
int64 id = 1 [(aeus.field) = {gorm:"primaryKey",comment:"ID"}];
int64 created_at = 2 [(aeus.field)={scenarios:"view;export",comment:"创建时间"}];
int64 updated_at = 3 [(aeus.field)={gorm:"index",scenarios:"view;export",comment:"更新时间"}];
int64 parent_id = 4 [(aeus.field)={live:"type:dropdown;url:/department/level-labels",format:"department",comment:"父级部门"}];
string name = 5 [(aeus.field)={gorm:"size:20",rule:"required",comment: "部门名称"},(validate.rules).string = {max_len: 20}];
string description = 6 [(aeus.field)={gorm:"size:1024",scenarios:"create;update;view;export;list",format:"textarea",comment: "备注说明"},(validate.rules).string = {max_len: 1024}];
string domain = 4 [(aeus.field)={gorm:"index;size:60;not null;default:''",comment:"域",scenarios:"export"}];
int64 parent_id = 5 [(aeus.field)={live:"type:dropdown;url:/department/level-labels",format:"department",comment:"父级部门"}];
string name = 6 [(aeus.field)={gorm:"size:20",rule:"required",comment: "部门名称"},(validate.rules).string = {max_len: 20}];
string description = 7 [(aeus.field)={gorm:"size:1024",scenarios:"create;update;view;export;list",format:"textarea",comment: "备注说明"},(validate.rules).string = {max_len: 1024}];
}
message Login {
@ -106,13 +109,14 @@ message Login {
};
int64 id = 1 [(aeus.field) = {gorm:"primaryKey",comment:"ID"}];
int64 created_at = 2 [(aeus.field)={scenarios:"list;search;view;export",comment:"登录时间"}];
string uid = 4 [(aeus.field)={gorm:"index;size:20",rule:"required",props:"readonly:update",format:"user",comment: "用户"},(validate.rules).string = {min_len: 5, max_len: 20}];
string ip = 5 [(aeus.field)={gorm:"size:128",scenarios:"list;search;view;export",comment: "登录地址"}];
string browser = 6 [(aeus.field)={gorm:"size:128",scenarios:"list;view;export",comment: "浏览器"}];
string os = 7 [(aeus.field)={gorm:"size:128",scenarios:"list;view;export",comment: "操作系统"}];
string platform = 8 [(aeus.field)={gorm:"size:128",scenarios:"list;view;export",comment: "系统平台"}];
string access_token = 9 [(aeus.field)={gorm:"size:1024",scenarios:"list;view;export",comment: "访问令牌"}];
string user_agent = 10 [(aeus.field)={gorm:"size:1024",scenarios:"list;view;export",comment: "用户代理"}];
string domain = 4 [(aeus.field)={gorm:"index;size:60;not null;default:''",comment:"域",scenarios:"export"}];
string uid = 5 [(aeus.field)={gorm:"index;size:20",rule:"required",props:"readonly:update",format:"user",comment: "用户"},(validate.rules).string = {min_len: 5, max_len: 20}];
string ip = 6 [(aeus.field)={gorm:"size:128",scenarios:"list;search;view;export",comment: "登录地址"}];
string browser = 7 [(aeus.field)={gorm:"size:128",scenarios:"list;view;export",comment: "浏览器"}];
string os = 8 [(aeus.field)={gorm:"size:128",scenarios:"list;view;export",comment: "操作系统"}];
string platform = 9 [(aeus.field)={gorm:"size:128",scenarios:"list;view;export",comment: "系统平台"}];
string access_token = 10 [(aeus.field)={gorm:"size:1024",scenarios:"list;view;export",comment: "访问令牌"}];
string user_agent = 11 [(aeus.field)={gorm:"size:1024",scenarios:"list;view;export",comment: "用户代理"}];
}
message LabelValue {

View File

@ -1,6 +1,6 @@
// Code generated by protoc-gen-go-aeus. DO NOT EDIT.
// source: organize.proto
// date: 2025-07-22 18:30:59
// date: 2025-07-23 17:37:42
package pb

View File

@ -1,6 +1,6 @@
// Code generated by protoc-gen-go-aeus. DO NOT EDIT.
// source: organize.proto
// date: 2025-07-22 18:30:59
// date: 2025-07-23 17:37:42
package pb
@ -98,6 +98,7 @@ type RoleModel struct {
Id int64 `json:"id" yaml:"id" xml:"id" gorm:"primaryKey;column:id" comment:"角色ID"`
CreatedAt int64 `json:"created_at" yaml:"createdAt" xml:"createdAt" gorm:"column:created_at" comment:"创建时间" scenarios:"view;export"`
UpdatedAt int64 `json:"updated_at" yaml:"updatedAt" xml:"updatedAt" gorm:"index;column:updated_at" comment:"更新时间" scenarios:"view;export"`
Domain string `json:"domain" yaml:"domain" xml:"domain" gorm:"index;size:60;not null;default:'';column:domain" comment:"域" scenarios:"export"`
Name string `json:"name" yaml:"name" xml:"name" gorm:"index;size:60;column:name" comment:"角色名称" props:"readonly:update" rule:"required"`
Label string `json:"label" yaml:"label" xml:"label" gorm:"size:60;column:label" comment:"角色标题" rule:"required"`
Description string `json:"description" yaml:"description" xml:"description" gorm:"size:1024;column:description" comment:"备注说明" scenarios:"list;create;update;export" format:"textarea"`
@ -111,6 +112,7 @@ func (m *RoleModel) FromValue(x *Role) {
m.Id = x.Id
m.CreatedAt = x.CreatedAt
m.UpdatedAt = x.UpdatedAt
m.Domain = x.Domain
m.Name = x.Name
m.Label = x.Label
m.Description = x.Description
@ -121,6 +123,7 @@ func (m *RoleModel) ToValue() (x *Role) {
x.Id = m.Id
x.CreatedAt = m.CreatedAt
x.UpdatedAt = m.UpdatedAt
x.Domain = m.Domain
x.Name = m.Name
x.Label = m.Label
x.Description = m.Description
@ -284,6 +287,7 @@ type UserModel struct {
Id int64 `json:"id" yaml:"id" xml:"id" gorm:"primaryKey;column:id" comment:"ID"`
CreatedAt int64 `json:"created_at" yaml:"createdAt" xml:"createdAt" gorm:"column:created_at" comment:"创建时间" scenarios:"view;export"`
UpdatedAt int64 `json:"updated_at" yaml:"updatedAt" xml:"updatedAt" gorm:"index;column:updated_at" comment:"更新时间" scenarios:"view;export"`
Domain string `json:"domain" yaml:"domain" xml:"domain" gorm:"index;size:60;not null;default:'';column:domain" comment:"域" scenarios:"export"`
Uid string `json:"uid" yaml:"uid" xml:"uid" gorm:"index;size:20;column:uid" comment:"用户工号" props:"readonly:update" rule:"required;unique;regexp:^[a-zA-Z0-9]{3,8}$"`
Username string `json:"username" yaml:"username" xml:"username" gorm:"size:20;column:username" comment:"用户名称" rule:"required"`
Role string `json:"role" yaml:"role" xml:"role" gorm:"size:60;not null;default:'';column:role" comment:"所属角色" format:"role" rule:"required" live:"type:dropdown;url:/role/labels"`
@ -306,6 +310,7 @@ func (m *UserModel) FromValue(x *User) {
m.Id = x.Id
m.CreatedAt = x.CreatedAt
m.UpdatedAt = x.UpdatedAt
m.Domain = x.Domain
m.Uid = x.Uid
m.Username = x.Username
m.Role = x.Role
@ -325,6 +330,7 @@ func (m *UserModel) ToValue() (x *User) {
x.Id = m.Id
x.CreatedAt = m.CreatedAt
x.UpdatedAt = m.UpdatedAt
x.Domain = m.Domain
x.Uid = m.Uid
x.Username = m.Username
x.Role = m.Role
@ -376,6 +382,7 @@ type DepartmentModel struct {
Id int64 `json:"id" yaml:"id" xml:"id" gorm:"primaryKey;column:id" comment:"ID"`
CreatedAt int64 `json:"created_at" yaml:"createdAt" xml:"createdAt" gorm:"column:created_at" comment:"创建时间" scenarios:"view;export"`
UpdatedAt int64 `json:"updated_at" yaml:"updatedAt" xml:"updatedAt" gorm:"index;column:updated_at" comment:"更新时间" scenarios:"view;export"`
Domain string `json:"domain" yaml:"domain" xml:"domain" gorm:"index;size:60;not null;default:'';column:domain" comment:"域" scenarios:"export"`
ParentId int64 `json:"parent_id" yaml:"parentId" xml:"parentId" gorm:"column:parent_id" comment:"父级部门" format:"department" live:"type:dropdown;url:/department/level-labels"`
Name string `json:"name" yaml:"name" xml:"name" gorm:"size:20;column:name" comment:"部门名称" rule:"required"`
Description string `json:"description" yaml:"description" xml:"description" gorm:"size:1024;column:description" comment:"备注说明" scenarios:"create;update;view;export;list" format:"textarea"`
@ -389,6 +396,7 @@ func (m *DepartmentModel) FromValue(x *Department) {
m.Id = x.Id
m.CreatedAt = x.CreatedAt
m.UpdatedAt = x.UpdatedAt
m.Domain = x.Domain
m.ParentId = x.ParentId
m.Name = x.Name
m.Description = x.Description
@ -399,6 +407,7 @@ func (m *DepartmentModel) ToValue() (x *Department) {
x.Id = m.Id
x.CreatedAt = m.CreatedAt
x.UpdatedAt = m.UpdatedAt
x.Domain = m.Domain
x.ParentId = m.ParentId
x.Name = m.Name
x.Description = m.Description
@ -440,6 +449,7 @@ func NewDepartmentModel() *DepartmentModel {
type LoginModel struct {
Id int64 `json:"id" yaml:"id" xml:"id" gorm:"primaryKey;column:id" comment:"ID"`
CreatedAt int64 `json:"created_at" yaml:"createdAt" xml:"createdAt" gorm:"column:created_at" comment:"登录时间" scenarios:"list;search;view;export"`
Domain string `json:"domain" yaml:"domain" xml:"domain" gorm:"index;size:60;not null;default:'';column:domain" comment:"域" scenarios:"export"`
Uid string `json:"uid" yaml:"uid" xml:"uid" gorm:"index;size:20;column:uid" comment:"用户" format:"user" props:"readonly:update" rule:"required"`
Ip string `json:"ip" yaml:"ip" xml:"ip" gorm:"size:128;column:ip" comment:"登录地址" scenarios:"list;search;view;export"`
Browser string `json:"browser" yaml:"browser" xml:"browser" gorm:"size:128;column:browser" comment:"浏览器" scenarios:"list;view;export"`
@ -456,6 +466,7 @@ func (m *LoginModel) TableName() string {
func (m *LoginModel) FromValue(x *Login) {
m.Id = x.Id
m.CreatedAt = x.CreatedAt
m.Domain = x.Domain
m.Uid = x.Uid
m.Ip = x.Ip
m.Browser = x.Browser
@ -469,6 +480,7 @@ func (m *LoginModel) ToValue() (x *Login) {
x = &Login{}
x.Id = m.Id
x.CreatedAt = m.CreatedAt
x.Domain = m.Domain
x.Uid = m.Uid
x.Ip = m.Ip
x.Browser = m.Browser

View File

@ -31,10 +31,11 @@ type Setting struct {
Id int64 `protobuf:"varint,1,opt,name=id,proto3" json:"id,omitempty"`
CreatedAt int64 `protobuf:"varint,2,opt,name=created_at,json=createdAt,proto3" json:"created_at,omitempty"`
UpdatedAt int64 `protobuf:"varint,3,opt,name=updated_at,json=updatedAt,proto3" json:"updated_at,omitempty"`
Name string `protobuf:"bytes,4,opt,name=name,proto3" json:"name,omitempty"`
Type string `protobuf:"bytes,5,opt,name=type,proto3" json:"type,omitempty"`
Value string `protobuf:"bytes,6,opt,name=value,proto3" json:"value,omitempty"`
Description string `protobuf:"bytes,7,opt,name=description,proto3" json:"description,omitempty"`
Domain string `protobuf:"bytes,4,opt,name=domain,proto3" json:"domain,omitempty"`
Name string `protobuf:"bytes,5,opt,name=name,proto3" json:"name,omitempty"`
Type string `protobuf:"bytes,6,opt,name=type,proto3" json:"type,omitempty"`
Value string `protobuf:"bytes,7,opt,name=value,proto3" json:"value,omitempty"`
Description string `protobuf:"bytes,8,opt,name=description,proto3" json:"description,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
@ -90,6 +91,13 @@ func (x *Setting) GetUpdatedAt() int64 {
return 0
}
func (x *Setting) GetDomain() string {
if x != nil {
return x.Domain
}
return ""
}
func (x *Setting) GetName() string {
if x != nil {
return x.Name
@ -123,11 +131,12 @@ type Activity struct {
state protoimpl.MessageState `protogen:"open.v1"`
Id int64 `protobuf:"varint,1,opt,name=id,proto3" json:"id,omitempty"`
CreatedAt int64 `protobuf:"varint,2,opt,name=created_at,json=createdAt,proto3" json:"created_at,omitempty"`
Uid string `protobuf:"bytes,3,opt,name=uid,proto3" json:"uid,omitempty"`
Action string `protobuf:"bytes,4,opt,name=action,proto3" json:"action,omitempty"`
Module string `protobuf:"bytes,5,opt,name=module,proto3" json:"module,omitempty"`
Table string `protobuf:"bytes,6,opt,name=table,proto3" json:"table,omitempty"`
Data string `protobuf:"bytes,7,opt,name=data,proto3" json:"data,omitempty"`
Domain string `protobuf:"bytes,3,opt,name=domain,proto3" json:"domain,omitempty"`
Uid string `protobuf:"bytes,4,opt,name=uid,proto3" json:"uid,omitempty"`
Action string `protobuf:"bytes,5,opt,name=action,proto3" json:"action,omitempty"`
Module string `protobuf:"bytes,6,opt,name=module,proto3" json:"module,omitempty"`
Table string `protobuf:"bytes,7,opt,name=table,proto3" json:"table,omitempty"`
Data string `protobuf:"bytes,8,opt,name=data,proto3" json:"data,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
@ -176,6 +185,13 @@ func (x *Activity) GetCreatedAt() int64 {
return 0
}
func (x *Activity) GetDomain() string {
if x != nil {
return x.Domain
}
return ""
}
func (x *Activity) GetUid() string {
if x != nil {
return x.Uid
@ -355,7 +371,7 @@ var File_system_proto protoreflect.FileDescriptor
const file_system_proto_rawDesc = "" +
"\n" +
"\fsystem.proto\x12\x06system\x1a\x0faeus/rest.proto\x1a\x17validate/validate.proto\x1a google/protobuf/descriptor.proto\x1a\x1cgoogle/api/annotations.proto\"\xb7\x04\n" +
"\fsystem.proto\x12\x06system\x1a\x0faeus/rest.proto\x1a\x17validate/validate.proto\x1a google/protobuf/descriptor.proto\x1a\x1cgoogle/api/annotations.proto\"\x85\x05\n" +
"\aSetting\x12$\n" +
"\x02id\x18\x01 \x01(\x03B\x14\xb2\xb9\x19\x10\n" +
"\n" +
@ -363,32 +379,36 @@ const file_system_proto_rawDesc = "" +
"\n" +
"created_at\x18\x02 \x01(\x03B\x1f\xb2\xb9\x19\x1b\x12\f创建时间\x1a\vview;exportR\tcreatedAt\x12>\n" +
"\n" +
"updated_at\x18\x03 \x01(\x03B\x1f\xb2\xb9\x19\x1b\x12\f更新时间\x1a\vview;exportR\tupdatedAt\x12N\n" +
"\x04name\x18\x04 \x01(\tB:\xfaB\x04r\x02\x18\x14\xb2\xb9\x19/\n" +
"updated_at\x18\x03 \x01(\x03B\x1f\xb2\xb9\x19\x1b\x12\f更新时间\x1a\vview;exportR\tupdatedAt\x12L\n" +
"\x06domain\x18\x04 \x01(\tB4\xb2\xb9\x190\n" +
"!index;size:60;not null;default:''\x12\x03域\x1a\x06exportR\x06domain\x12N\n" +
"\x04name\x18\x05 \x01(\tB:\xfaB\x04r\x02\x18\x14\xb2\xb9\x19/\n" +
"\asize:60\x12\t配置项2\x0freadonly:update:\brequiredR\x04name\x12e\n" +
"\x04type\x18\x05 \x01(\tBQ\xfaB\x04r\x02\x18\x14\xb2\xb9\x19F\n" +
"\x04type\x18\x06 \x01(\tBQ\xfaB\x04r\x02\x18\x14\xb2\xb9\x19F\n" +
"\asize:20\x12\f数据类型:\brequiredR#text:文本;number:数字;json:JSONR\x04type\x12L\n" +
"\x05value\x18\x06 \x01(\tB6\xfaB\x05r\x03\x18\x80\b\xb2\xb9\x19*\n" +
"\x05value\x18\a \x01(\tB6\xfaB\x05r\x03\x18\x80\b\xb2\xb9\x19*\n" +
"\tsize:1024\x12\t配置值*\btextarea:\brequiredR\x05value\x12q\n" +
"\vdescription\x18\a \x01(\tBO\xfaB\x05r\x03\x18\x80\b\xb2\xb9\x19C\n" +
"\vdescription\x18\b \x01(\tBO\xfaB\x05r\x03\x18\x80\b\xb2\xb9\x19C\n" +
"\tsize:1024\x12\f备注说明\x1a\x1elist;create;update;view;export*\btextareaR\vdescription:\x0e\xba\xb9\x19\n" +
"\n" +
"\bsettings\"\xe2\x05\n" +
"\bsettings\"\xb0\x06\n" +
"\bActivity\x12$\n" +
"\x02id\x18\x01 \x01(\x03B\x14\xb2\xb9\x19\x10\n" +
"\n" +
"primaryKey\x12\x02IDR\x02id\x12L\n" +
"\n" +
"created_at\x18\x02 \x01(\x03B-\xb2\xb9\x19)\x12\f创建时间\x1a\x19search;search;view;exportR\tcreatedAt\x12W\n" +
"\x03uid\x18\x03 \x01(\tBE\xfaB\x06r\x04\x10\x05\x18\x14\xb2\xb9\x198\n" +
"created_at\x18\x02 \x01(\x03B-\xb2\xb9\x19)\x12\f创建时间\x1a\x19search;search;view;exportR\tcreatedAt\x12L\n" +
"\x06domain\x18\x03 \x01(\tB4\xb2\xb9\x190\n" +
"!index;size:60;not null;default:''\x12\x03域\x1a\x06exportR\x06domain\x12W\n" +
"\x03uid\x18\x04 \x01(\tBE\xfaB\x06r\x04\x10\x05\x18\x14\xb2\xb9\x198\n" +
"\rindex;size:20\x12\x06用户*\x04user2\x0freadonly:update:\brequiredR\x03uid\x12\xc9\x01\n" +
"\x06action\x18\x04 \x01(\tB\xb0\x01\xb2\xb9\x19\xab\x01\n" +
"\x06action\x18\x05 \x01(\tB\xb0\x01\xb2\xb9\x19\xab\x01\n" +
"!index;size:20;not null;default:''\x12\x06行为\x1a%search;list;create;update;view;export2\rmatch:exactly:\brequiredR>create:新建#198754;update:更新#f09d00;delete:删除#e63757R\x06action\x12h\n" +
"\x06module\x18\x05 \x01(\tBP\xb2\xb9\x19L\n" +
"\x06module\x18\x06 \x01(\tBP\xb2\xb9\x19L\n" +
"\x1bsize:60;not null;default:''\x12\x06模块\x1a%search;list;create;update;view;exportR\x06module\x12_\n" +
"\x05table\x18\x06 \x01(\tBI\xb2\xb9\x19E\n" +
"\x05table\x18\a \x01(\tBI\xb2\xb9\x19E\n" +
"\x1bsize:60;not null;default:''\x12\x06模型\x1a\x1elist;create;update;view;exportR\x05table\x12`\n" +
"\x04data\x18\a \x01(\tBL\xb2\xb9\x19H\n" +
"\x04data\x18\b \x01(\tBL\xb2\xb9\x19H\n" +
"\x1esize:10240;not null;default:''\x12\x06内容\x1a\x1elist;create;update;view;exportR\x04data:\x10\xba\xb9\x19\f\n" +
"\n" +
"activities\"K\n" +

View File

@ -62,6 +62,8 @@ func (m *Setting) validate(all bool) error {
// no validation rules for UpdatedAt
// no validation rules for Domain
if utf8.RuneCountInString(m.GetName()) > 20 {
err := SettingValidationError{
field: "Name",
@ -209,6 +211,8 @@ func (m *Activity) validate(all bool) error {
// no validation rules for CreatedAt
// no validation rules for Domain
if l := utf8.RuneCountInString(m.GetUid()); l < 5 || l > 20 {
err := ActivityValidationError{
field: "Uid",

View File

@ -18,10 +18,11 @@ message Setting {
int64 id = 1 [(aeus.field) = {gorm:"primaryKey",comment:"ID"}];
int64 created_at = 2 [(aeus.field)={scenarios:"view;export",comment:"创建时间"}];
int64 updated_at = 3 [(aeus.field)={scenarios:"view;export",comment:"更新时间"}];
string name = 4 [(aeus.field)={gorm:"size:60",rule:"required",props:"readonly:update",comment: "配置项"},(validate.rules).string = {max_len: 20}];
string type = 5 [(aeus.field)={gorm:"size:20",rule:"required",enum:"text:文本;number:数字;json:JSON",comment: "数据类型"},(validate.rules).string = {max_len: 20}];
string value = 6 [(aeus.field)={gorm:"size:1024",rule:"required",format:"textarea",comment: "配置值"},(validate.rules).string = {max_len: 1024}];
string description = 7 [(aeus.field)={gorm:"size:1024",format:"textarea",scenarios:"list;create;update;view;export",comment: "备注说明"},(validate.rules).string = {max_len: 1024}];
string domain = 4 [(aeus.field)={gorm:"index;size:60;not null;default:''",comment:"域",scenarios:"export"}];
string name = 5 [(aeus.field)={gorm:"size:60",rule:"required",props:"readonly:update",comment: "配置项"},(validate.rules).string = {max_len: 20}];
string type = 6 [(aeus.field)={gorm:"size:20",rule:"required",enum:"text:文本;number:数字;json:JSON",comment: "数据类型"},(validate.rules).string = {max_len: 20}];
string value = 7 [(aeus.field)={gorm:"size:1024",rule:"required",format:"textarea",comment: "配置值"},(validate.rules).string = {max_len: 1024}];
string description = 8 [(aeus.field)={gorm:"size:1024",format:"textarea",scenarios:"list;create;update;view;export",comment: "备注说明"},(validate.rules).string = {max_len: 1024}];
}
@ -32,11 +33,12 @@ message Activity {
};
int64 id = 1 [(aeus.field) = {gorm:"primaryKey",comment:"ID"}];
int64 created_at = 2 [(aeus.field)={scenarios:"search;search;view;export",comment:"创建时间"}];
string uid = 3 [(aeus.field)={gorm:"index;size:20",rule:"required",props:"readonly:update",format:"user",comment: "用户"},(validate.rules).string = {min_len: 5, max_len: 20}];
string action = 4 [(aeus.field)={props:"match:exactly",rule:"required",gorm:"index;size:20;not null;default:''",comment:"行为",enum:"create:新建#198754;update:更新#f09d00;delete:删除#e63757",scenarios:"search;list;create;update;view;export"}];
string module = 5 [(aeus.field)={gorm:"size:60;not null;default:''",comment:"模块",scenarios:"search;list;create;update;view;export"}];
string table = 6 [(aeus.field)={gorm:"size:60;not null;default:''",comment:"模型",scenarios:"list;create;update;view;export"}];
string data = 7 [(aeus.field)={gorm:"size:10240;not null;default:''",comment:"内容",scenarios:"list;create;update;view;export"}];
string domain = 3 [(aeus.field)={gorm:"index;size:60;not null;default:''",comment:"域",scenarios:"export"}];
string uid = 4 [(aeus.field)={gorm:"index;size:20",rule:"required",props:"readonly:update",format:"user",comment: "用户"},(validate.rules).string = {min_len: 5, max_len: 20}];
string action = 5 [(aeus.field)={props:"match:exactly",rule:"required",gorm:"index;size:20;not null;default:''",comment:"行为",enum:"create:新建#198754;update:更新#f09d00;delete:删除#e63757",scenarios:"search;list;create;update;view;export"}];
string module = 6 [(aeus.field)={gorm:"size:60;not null;default:''",comment:"模块",scenarios:"search;list;create;update;view;export"}];
string table = 7 [(aeus.field)={gorm:"size:60;not null;default:''",comment:"模型",scenarios:"list;create;update;view;export"}];
string data = 8 [(aeus.field)={gorm:"size:10240;not null;default:''",comment:"内容",scenarios:"list;create;update;view;export"}];
}

View File

@ -1,6 +1,6 @@
// Code generated by protoc-gen-go-aeus. DO NOT EDIT.
// source: system.proto
// date: 2025-07-22 18:30:59
// date: 2025-07-23 17:37:42
package pb

View File

@ -1,6 +1,6 @@
// Code generated by protoc-gen-go-aeus. DO NOT EDIT.
// source: system.proto
// date: 2025-07-22 18:30:59
// date: 2025-07-23 17:37:42
package pb
@ -12,6 +12,7 @@ type SettingModel struct {
Id int64 `json:"id" yaml:"id" xml:"id" gorm:"primaryKey;column:id" comment:"ID"`
CreatedAt int64 `json:"created_at" yaml:"createdAt" xml:"createdAt" gorm:"column:created_at" comment:"创建时间" scenarios:"view;export"`
UpdatedAt int64 `json:"updated_at" yaml:"updatedAt" xml:"updatedAt" gorm:"column:updated_at" comment:"更新时间" scenarios:"view;export"`
Domain string `json:"domain" yaml:"domain" xml:"domain" gorm:"index;size:60;not null;default:'';column:domain" comment:"域" scenarios:"export"`
Name string `json:"name" yaml:"name" xml:"name" gorm:"size:60;column:name" comment:"配置项" props:"readonly:update" rule:"required"`
Type string `json:"type" yaml:"type" xml:"type" gorm:"size:20;column:type" comment:"数据类型" rule:"required" enum:"text:文本;number:数字;json:JSON"`
Value string `json:"value" yaml:"value" xml:"value" gorm:"size:1024;column:value" comment:"配置值" format:"textarea" rule:"required"`
@ -26,6 +27,7 @@ func (m *SettingModel) FromValue(x *Setting) {
m.Id = x.Id
m.CreatedAt = x.CreatedAt
m.UpdatedAt = x.UpdatedAt
m.Domain = x.Domain
m.Name = x.Name
m.Type = x.Type
m.Value = x.Value
@ -37,6 +39,7 @@ func (m *SettingModel) ToValue() (x *Setting) {
x.Id = m.Id
x.CreatedAt = m.CreatedAt
x.UpdatedAt = m.UpdatedAt
x.Domain = m.Domain
x.Name = m.Name
x.Type = m.Type
x.Value = m.Value
@ -79,6 +82,7 @@ func NewSettingModel() *SettingModel {
type ActivityModel struct {
Id int64 `json:"id" yaml:"id" xml:"id" gorm:"primaryKey;column:id" comment:"ID"`
CreatedAt int64 `json:"created_at" yaml:"createdAt" xml:"createdAt" gorm:"column:created_at" comment:"创建时间" scenarios:"search;search;view;export"`
Domain string `json:"domain" yaml:"domain" xml:"domain" gorm:"index;size:60;not null;default:'';column:domain" comment:"域" scenarios:"export"`
Uid string `json:"uid" yaml:"uid" xml:"uid" gorm:"index;size:20;column:uid" comment:"用户" format:"user" props:"readonly:update" rule:"required"`
Action string `json:"action" yaml:"action" xml:"action" gorm:"index;size:20;not null;default:'';column:action" comment:"行为" scenarios:"search;list;create;update;view;export" props:"match:exactly" rule:"required" enum:"create:新建#198754;update:更新#f09d00;delete:删除#e63757"`
Module string `json:"module" yaml:"module" xml:"module" gorm:"size:60;not null;default:'';column:module" comment:"模块" scenarios:"search;list;create;update;view;export"`
@ -93,6 +97,7 @@ func (m *ActivityModel) TableName() string {
func (m *ActivityModel) FromValue(x *Activity) {
m.Id = x.Id
m.CreatedAt = x.CreatedAt
m.Domain = x.Domain
m.Uid = x.Uid
m.Action = x.Action
m.Module = x.Module
@ -104,6 +109,7 @@ func (m *ActivityModel) ToValue() (x *Activity) {
x = &Activity{}
x.Id = m.Id
x.CreatedAt = m.CreatedAt
x.Domain = m.Domain
x.Uid = m.Uid
x.Action = m.Action
x.Module = m.Module

View File

@ -42,6 +42,31 @@ func getModels() []any {
}
}
func getViewPath(prefix string, model *rest.Model) string {
viewPath := path.Join(prefix, model.Naming().ModuleName, model.Naming().Singular, "Index.vue")
refVal := reflect.New(model.Value().Type()).Interface()
if v, ok := refVal.(adminTypes.MenuModel); ok {
instance := v.GetMenu()
if instance == nil {
return viewPath
}
// 多级别的定义, 比如 CallcenterRoute -> callcenter/route
if instance.Parent != "" {
words := strings.Split(inflector.Camel2id(instance.Parent), "_")
names := []string{prefix}
for _, word := range words {
word = strings.TrimSpace(word)
if word != "" {
names = append(names, strings.ToLower(word))
}
}
names = append(names, model.Naming().Singular, "Index.vue")
viewPath = path.Join(names...)
}
}
return viewPath
}
// checkModelMenu 检查模型菜单
func checkModelMenu(db *gorm.DB, viewPath string, apiPrefix string, model *rest.Model, translate Translate) (value *models.Menu, err error) {
refVal := reflect.New(model.Value().Type()).Interface()
@ -72,7 +97,7 @@ func checkModelMenu(db *gorm.DB, viewPath string, apiPrefix string, model *rest.
value.Uri = strings.TrimPrefix(model.Uri(types.ScenarioList), apiPrefix)
}
if value.ViewPath == "" {
value.ViewPath = path.Join(viewPath, model.ModuleName(), model.Naming().Singular, "Index.vue")
value.ViewPath = getViewPath(viewPath, model)
}
err = db.Create(value).Error
}
@ -142,20 +167,11 @@ func checkModel(opts *options, model *rest.Model) (err error) {
// generateVueFile 生成Vue文件
func generateVueFile(prefix string, apiPrefix string, mv *rest.Model) (err error) {
refVal := reflect.New(mv.Value().Type()).Interface()
if v, ok := refVal.(adminTypes.MenuModel); ok {
instance := v.GetMenu()
if instance != nil {
if instance.Hidden {
return
}
}
}
filename := path.Join(prefix, mv.Naming().ModuleName, mv.Naming().Singular, "Index.vue")
if _, err = os.Stat(filename); err == nil {
viewPath := getViewPath(prefix, mv)
if _, err = os.Stat(viewPath); err == nil {
return
}
dirname := path.Dir(filename)
dirname := path.Dir(viewPath)
if _, err = os.Stat(dirname); err != nil {
if err = os.MkdirAll(dirname, os.ModePerm); err != nil {
return
@ -185,23 +201,37 @@ func generateVueFile(prefix string, apiPrefix string, mv *rest.Model) (err error
Readonly: !editable,
ApiPrefix: strings.TrimPrefix(apiPrefix, "/"),
}
//调整组件名称
refVal := reflect.New(mv.Value().Type()).Interface()
if v, ok := refVal.(adminTypes.MenuModel); ok {
if v.GetMenu().Name != "" {
data.Component = v.GetMenu().Name
}
}
writer := pool.GetBuffer()
defer pool.PutBuffer(writer)
if err = temp.Execute(writer, data); err != nil {
return
}
return os.WriteFile(filename, writer.Bytes(), 0644)
return os.WriteFile(viewPath, writer.Bytes(), 0644)
}
// restValueLookup 特殊字段获取方式
func restValueLookup(column string, w httpkg.ResponseWriter, r *httpkg.Request) string {
switch column {
case "user":
case types.FieldUser:
// 从授权信息里面获取用户的ID
if t, ok := auth.FromContext(r.Context()); ok {
uid, _ := t.GetSubject()
return uid
}
case types.FieldDomain:
// 从授权信息里面获取用户的domain
if t, ok := auth.FromContext(r.Context()); ok {
if v, ok := t.(*adminTypes.Claims); ok {
return v.Domain
}
}
}
return r.Header.Get(column)
}
@ -219,6 +249,9 @@ func initREST(ctx context.Context, o *options) (err error) {
if o.apiPrefix != "" {
opts = append(opts, rest.WithUriPrefix(o.apiPrefix))
}
if !o.enableDomain {
opts = append(opts, rest.WithoutDomain())
}
if err = rest.Init(opts...); err != nil {
return
}
@ -260,6 +293,7 @@ func registerRESTRoute(domain string, db *gorm.DB, hs *http.Server) {
schemas []*restTypes.Schema
)
scenario := ctx.Request().URL.Query().Get("scenario")
domainName := restValueLookup(types.FieldDomain, ctx.Response(), ctx.Request())
if scenario == "" {
schemas, err = dbcache.TryCache(
ctx.Request().Context(),
@ -268,7 +302,7 @@ func registerRESTRoute(domain string, db *gorm.DB, hs *http.Server) {
return rest.GetSchemas(
ctx.Request().Context(),
tx,
"",
domainName,
ctx.Param("module"),
ctx.Param("table"),
)
@ -284,7 +318,7 @@ func registerRESTRoute(domain string, db *gorm.DB, hs *http.Server) {
return rest.VisibleSchemas(
ctx.Request().Context(),
db.WithContext(ctx.Request().Context()),
"",
domainName,
ctx.Param("module"),
ctx.Param("table"),
scenario,
@ -372,8 +406,9 @@ func registerRESTRoute(domain string, db *gorm.DB, hs *http.Server) {
} else {
opts = append(opts, dbcache.WithCacheDuration(time.Minute))
}
if pairs, err = dbcache.TryCache(ctx.Context(), fmt.Sprintf("rest:kvpairs:%s:%s:%s:%s", moduleName, tableName, labelColumn, valueColumn), func(tx *gorm.DB) ([]*restTypes.TypeValue[any], error) {
return rest.ModelTypes[any](ctx.Context(), db, modelValue, "", labelColumn, valueColumn)
domainName := restValueLookup(types.FieldDomain, ctx.Response(), ctx.Request())
if pairs, err = dbcache.TryCache(ctx.Context(), fmt.Sprintf("rest:kvpairs:%s:%s:%s:%s:%s", domainName, moduleName, tableName, labelColumn, valueColumn), func(tx *gorm.DB) ([]*restTypes.TypeValue[any], error) {
return rest.ModelTypes[any](ctx.Context(), db, modelValue, domainName, labelColumn, valueColumn)
}, opts...); err == nil {
return ctx.Success(pairs)
} else {
@ -420,8 +455,9 @@ func registerRESTRoute(domain string, db *gorm.DB, hs *http.Server) {
} else {
opts = append(opts, dbcache.WithCacheDuration(time.Minute))
}
if pairs, err = dbcache.TryCache(ctx.Context(), fmt.Sprintf("rest:tierpairs:%s:%s:%s:%s", moduleName, tableName, labelColumn, valueColumn), func(tx *gorm.DB) ([]*restTypes.TierValue[string], error) {
return rest.ModelTiers[string](ctx.Context(), db, modelValue, "", parentColumn, labelColumn, valueColumn)
domainName := restValueLookup(types.FieldDomain, ctx.Response(), ctx.Request())
if pairs, err = dbcache.TryCache(ctx.Context(), fmt.Sprintf("rest:tierpairs:%s:%s:%s:%s:%s", domainName, moduleName, tableName, labelColumn, valueColumn), func(tx *gorm.DB) ([]*restTypes.TierValue[string], error) {
return rest.ModelTiers[string](ctx.Context(), db, modelValue, domainName, parentColumn, labelColumn, valueColumn)
}, opts...); err == nil {
return ctx.Success(pairs)
} else {
@ -468,8 +504,9 @@ func registerRESTRoute(domain string, db *gorm.DB, hs *http.Server) {
} else {
opts = append(opts, dbcache.WithCacheDuration(time.Minute))
}
if pairs, err = dbcache.TryCache(ctx.Context(), fmt.Sprintf("rest:tierpairs:%s:%s:%s:%s", moduleName, tableName, labelColumn, valueColumn), func(tx *gorm.DB) ([]*restTypes.TierValue[int64], error) {
return rest.ModelTiers[int64](ctx.Context(), db, modelValue, "", parentColumn, labelColumn, valueColumn)
domainName := restValueLookup(types.FieldDomain, ctx.Response(), ctx.Request())
if pairs, err = dbcache.TryCache(ctx.Context(), fmt.Sprintf("rest:tierpairs:%s:%s:%s:%s:%s", domainName, moduleName, tableName, labelColumn, valueColumn), func(tx *gorm.DB) ([]*restTypes.TierValue[int64], error) {
return rest.ModelTiers[int64](ctx.Context(), db, modelValue, domainName, parentColumn, labelColumn, valueColumn)
}, opts...); err == nil {
return ctx.Success(pairs)
} else {
@ -526,7 +563,7 @@ func Init(ctx context.Context, cbs ...Option) (err error) {
registerRESTRoute(opts.domain, opts.db, opts.httpServer)
}
if !opts.disableDefault {
if err = migrate.Default(opts.db); err != nil {
if err = migrate.Default(opts.db, opts.domain); err != nil {
return
}
}

View File

@ -28,6 +28,7 @@ type (
turnstileValidateUrl string
turnstileSiteKey string
enableRefreshToken bool
enableDomain bool
}
turnstileRequest struct {
@ -60,13 +61,19 @@ func WithAuthDB(db *gorm.DB) AuthOption {
}
}
func WithAuthDomain() AuthOption {
return func(o *authOptions) {
o.enableDomain = true
}
}
func WithAuthCache(cache cache.Cache) AuthOption {
return func(o *authOptions) {
o.cache = cache
}
}
func WithRefreshToken() AuthOption {
func WithAuthRefreshToken() AuthOption {
return func(o *authOptions) {
o.enableRefreshToken = true
}
@ -159,7 +166,9 @@ func (s *AuthService) Login(ctx context.Context, req *pb.LoginRequest) (res *pb.
IssuedAt: time.Now().Unix(),
ExpirationAt: time.Now().Add(time.Second * time.Duration(s.opts.ttl)).Unix(),
}
if s.opts.enableDomain {
claims.Domain = model.Domain
}
token := jwt.NewWithClaims(jwt.SigningMethodHS256, claims)
res = &pb.LoginResponse{}
if res.Token, err = token.SignedString(s.opts.secret); err == nil {
@ -167,6 +176,7 @@ func (s *AuthService) Login(ctx context.Context, req *pb.LoginRequest) (res *pb.
res.Username = model.Username
res.Expires = s.opts.ttl
}
if s.opts.enableRefreshToken {
refreshClaims := types.Claims{
Uid: model.Uid,
@ -175,11 +185,15 @@ func (s *AuthService) Login(ctx context.Context, req *pb.LoginRequest) (res *pb.
IssuedAt: time.Now().Unix(),
ExpirationAt: time.Now().Add(time.Hour * 48).Unix(),
}
if s.opts.enableDomain {
refreshClaims.Domain = model.Domain
}
refreshToken := jwt.NewWithClaims(jwt.SigningMethodHS256, refreshClaims)
res.RefreshToken, err = refreshToken.SignedString(s.opts.secret)
}
loginModel := &models.Login{}
loginModel.Uid = model.Uid
loginModel.Domain = model.Domain
loginModel.AccessToken = res.Token
md := metadata.FromContext(ctx)
if s.opts.tokenStore != nil {
@ -225,6 +239,7 @@ func (s *AuthService) RefreshToken(ctx context.Context, req *pb.RefreshTokenRequ
Uid: refreshClaims.Uid,
Role: refreshClaims.Role,
Admin: refreshClaims.Admin,
Domain: refreshClaims.Domain,
IssuedAt: time.Now().Unix(),
ExpirationAt: time.Now().Add(time.Second * time.Duration(s.opts.ttl)).Unix(),
}

View File

@ -8,6 +8,7 @@ import (
"git.nobla.cn/golang/aeus-admin/internal/logic"
"git.nobla.cn/golang/aeus-admin/models"
"git.nobla.cn/golang/aeus-admin/pb"
"git.nobla.cn/golang/aeus-admin/utils"
"git.nobla.cn/golang/aeus/pkg/cache"
"git.nobla.cn/golang/rest/types"
"gorm.io/gorm"
@ -42,7 +43,8 @@ func WithDepartmentDB(db *gorm.DB) DepartmentOption {
func (s *DepartmentService) GetDepartmentLabels(ctx context.Context, req *pb.GetDepartmentLabelRequest) (res *pb.GetDepartmentLabelResponse, err error) {
res = &pb.GetDepartmentLabelResponse{}
var values []*types.TypeValue[int64]
if values, err = s.logic.GetLabels(ctx); err == nil {
domainName := utils.GetDomainFromContext(ctx)
if values, err = s.logic.GetLabels(ctx, domainName); err == nil {
res.Data = make([]*pb.DepartmentLabelValue, 0, len(values))
for _, row := range values {
res.Data = append(res.Data, &pb.DepartmentLabelValue{
@ -100,10 +102,11 @@ func (s *DepartmentService) GetDepartmentUsers(ctx context.Context, req *pb.GetD
users []*models.User
departments []*models.Department
)
if departments, err = s.logic.GetDepartments(ctx); err != nil {
domainName := utils.GetDomainFromContext(ctx)
if departments, err = s.logic.GetDepartments(ctx, domainName); err != nil {
return
}
if users, err = s.user.GeUsers(ctx); err != nil {
if users, err = s.user.GeUsers(ctx, domainName); err != nil {
return
}
res = &pb.GetDepartmentUserResponse{
@ -116,7 +119,8 @@ func (s *DepartmentService) GetDepartmentLevelLabels(ctx context.Context, req *p
var (
departments []*models.Department
)
if departments, err = s.logic.GetDepartments(ctx); err != nil {
domainName := utils.GetDomainFromContext(ctx)
if departments, err = s.logic.GetDepartments(ctx, domainName); err != nil {
return
}
res = &pb.GetDepartmentLevelLabelsResponse{

View File

@ -6,6 +6,7 @@ import (
"git.nobla.cn/golang/aeus-admin/internal/logic"
"git.nobla.cn/golang/aeus-admin/models"
"git.nobla.cn/golang/aeus-admin/pb"
"git.nobla.cn/golang/aeus-admin/utils"
"git.nobla.cn/golang/aeus/pkg/cache"
"git.nobla.cn/golang/rest/types"
"gorm.io/gorm"
@ -39,7 +40,8 @@ func WithRoleDB(db *gorm.DB) RoleOption {
func (s *RoleService) GetRoleLabels(ctx context.Context, req *pb.GetRoleLabelRequest) (res *pb.GetRoleLabelResponse, err error) {
res = &pb.GetRoleLabelResponse{}
var values []*types.TypeValue[string]
if values, err = s.logic.GetLabels(ctx); err == nil {
domainName := utils.GetDomainFromContext(ctx)
if values, err = s.logic.GetLabels(ctx, domainName); err == nil {
res.Data = make([]*pb.LabelValue, 0, len(values))
for _, row := range values {
res.Data = append(res.Data, &pb.LabelValue{

View File

@ -10,6 +10,7 @@ import (
"git.nobla.cn/golang/aeus-admin/models"
"git.nobla.cn/golang/aeus-admin/pb"
"git.nobla.cn/golang/aeus-admin/pkg/dbcache"
"git.nobla.cn/golang/aeus-admin/utils"
"git.nobla.cn/golang/aeus/middleware/auth"
"git.nobla.cn/golang/aeus/pkg/cache"
"git.nobla.cn/golang/aeus/pkg/errors"
@ -105,19 +106,21 @@ func (s *UserService) recursiveNestedMenu(ctx context.Context, parent string, pe
func (s *UserService) GetMenus(ctx context.Context, req *pb.GetUserMenuRequest) (res *pb.GetUserMenuResponse, err error) {
var (
uid string
domainName string
permissions []*models.Permission
)
if uid, err = s.getUidFromContext(ctx); err != nil {
return
}
domainName = utils.GetDomainFromContext(ctx)
res = &pb.GetUserMenuResponse{}
res.Data, err = dbcache.TryCache(ctx, fmt.Sprintf("user:menu:%s:%v", uid, req.Permission), func(tx *gorm.DB) ([]*pb.MenuItem, error) {
res.Data, err = dbcache.TryCache(ctx, fmt.Sprintf("user:menu:%s:%s:%v", domainName, uid, req.Permission), func(tx *gorm.DB) ([]*pb.MenuItem, error) {
var (
userModel *models.User
menus []*models.Menu
)
userModel = &models.User{}
if err = tx.Where("`uid`=?", uid).First(userModel).Error; err != nil {
if err = tx.Where("`uid`=? AND `domain`=?", uid, domainName).First(userModel).Error; err != nil {
return nil, err
}
if menus, err = s.menu.GetMenus(ctx); err != nil {
@ -228,7 +231,8 @@ func (s *UserService) GetPermissions(ctx context.Context, req *pb.GetPermissionR
func (s *UserService) GetUserLabels(ctx context.Context, req *pb.GetUserLabelRequest) (res *pb.GetUserLabelResponse, err error) {
res = &pb.GetUserLabelResponse{}
var values []*types.TypeValue[string]
if values, err = s.user.GetLabels(ctx); err == nil {
domainName := utils.GetDomainFromContext(ctx)
if values, err = s.user.GetLabels(ctx, domainName); err == nil {
res.Data = make([]*pb.LabelValue, 0, len(values))
for _, row := range values {
res.Data = append(res.Data, &pb.LabelValue{
@ -246,11 +250,11 @@ func (s *UserService) DepartmentUserNested(ctx context.Context) []*types.NestedV
users []*models.User
departments []*models.Department
)
if departments, err = s.department.GetDepartments(ctx); err != nil {
domainName := utils.GetDomainFromContext(ctx)
if departments, err = s.department.GetDepartments(ctx, domainName); err != nil {
return nil
}
if users, err = s.user.GeUsers(ctx); err != nil {
if users, err = s.user.GeUsers(ctx, domainName); err != nil {
return nil
}
depts := s.department.RecursiveDepartment(ctx, 0, 0, departments)
@ -276,9 +280,15 @@ func (s *UserService) DepartmentUserNested(ctx context.Context) []*types.NestedV
func (s *UserService) GetUserTags(ctx context.Context, req *pb.GetUserTagRequest) (res *pb.GetUserTagResponse, err error) {
res = &pb.GetUserTagResponse{}
res.Data, err = dbcache.TryCache(ctx, fmt.Sprintf("user:tags"), func(tx *gorm.DB) ([]*pb.LabelValue, error) {
domainName := utils.GetDomainFromContext(ctx)
res.Data, err = dbcache.TryCache(ctx, fmt.Sprintf("user:tags:%s", domainName), func(tx *gorm.DB) ([]*pb.LabelValue, error) {
values := make([]*models.User, 0)
if err = tx.Select("DISTINCT(`tag`) AS `tag`").Find(&values).Error; err == nil {
if domainName == "" {
err = tx.Select("DISTINCT(`tag`) AS `tag`").Find(&values).Error
} else {
err = tx.Select("DISTINCT(`tag`) AS `tag`").Where("`domain`=?", domainName).Find(&values).Error
}
if err == nil {
items := make([]*pb.LabelValue, 0, len(values))
for _, v := range values {
if v.Tag == "" {

View File

@ -21,7 +21,7 @@ import Viewer from '@/components/fragment/Viewer.vue';
import { computed } from 'vue';
defineOptions({
name: '{{.Name}}'
name: '{{.Component}}'
})
const props = defineProps({

View File

@ -34,6 +34,7 @@ type (
disableModels bool
httpServer *http.Server
restOpts []rest.Option
enableDomain bool
}
Option func(*options)
@ -73,6 +74,13 @@ func WithCache(cache cache.Cache) Option {
}
}
func WithDomain(domain string) Option {
return func(o *options) {
o.enableDomain = true
o.domain = domain
}
}
func WithoutDefault() Option {
return func(o *options) {
o.disableDefault = true

View File

@ -13,6 +13,7 @@ type Claims struct {
Issuer string `json:"iss"`
IssuedAt int64 `json:"iat"`
ExpirationAt int64 `json:"exp"`
Domain string `json:"dom,omitempty"`
Audience []string `json:"aud,omitempty"`
}

17
utils/domain.go 100644
View File

@ -0,0 +1,17 @@
package utils
import (
"context"
"git.nobla.cn/golang/aeus-admin/types"
"git.nobla.cn/golang/aeus/middleware/auth"
)
func GetDomainFromContext(ctx context.Context) string {
if claims, ok := auth.FromContext(ctx); ok {
if v, ok := claims.(*types.Claims); ok {
return v.Domain
}
}
return ""
}