publish: 发布2.7.4版本Beta (#1880)

* 媒体库增加批量导入URL

* fix 描述错误

* feature: 自动化代码方法支持增加方法描述

* update: 更新依赖,升级为最新版本

* feature: 自动化代码预览部分支持黑夜模式

* fixed: 修复keepalive上线后失效的bug

* feature: 增加自动化基础模板功能

* feature: 增加自动化基础模板功能

* 将用户配置保存到数据库,刷新或者异地登录配置不丢失

* update: 清除无用的userinfo配置信息

* fixed: 清理开发阶段页面无端进入404的bug

* feature: 前端主题配置跟随用户,不再单独设置json编译生效。

* feature: 增加个人中心配置兼容性

* fix(package): 包名设置为中文会导致无法自动生成代码,禁止包名设置为中文

* feature: 格式化代码

* feature: 对严格模式新建根角色进行调整。

* feature: 版本变更为2.7.4

---------

Co-authored-by: sliboy <34034053+sliboy@users.noreply.github.com>
Co-authored-by: ba0ch3ng <ba0ch3ng@foxmail.com>
Co-authored-by: task <121913992@qq.com>
Co-authored-by: task <ms.yangdan@gmail.com>
Co-authored-by: 爱丽-黑子 <62006632+ailiheizi@users.noreply.github.com>
Co-authored-by: sliboy <sliboy@hotmail.com>
This commit is contained in:
PiexlMax(奇淼
2024-09-12 20:48:03 +08:00
committed by GitHub
co-authored by sliboy ba0ch3ng task task 爱丽-黑子 sliboy
parent df3fc0a9ef
commit c20ea7e030
68 changed files with 713 additions and 407 deletions
@@ -108,3 +108,26 @@ func (b *FileUploadAndDownloadApi) GetFileList(c *gin.Context) {
PageSize: pageInfo.PageSize,
}, "获取成功", c)
}
// ImportURL
// @Tags ExaFileUploadAndDownload
// @Summary 导入URL
// @Security ApiKeyAuth
// @Produce application/json
// @Param data body example.ExaFileUploadAndDownload true "对象"
// @Success 200 {object} response.Response{msg=string} "导入URL"
// @Router /fileUploadAndDownload/importURL [post]
func (b *FileUploadAndDownloadApi) ImportURL(c *gin.Context) {
var file []example.ExaFileUploadAndDownload
err := c.ShouldBindJSON(&file)
if err != nil {
response.FailWithMessage(err.Error(), c)
return
}
if err := fileUploadAndDownloadService.ImportURL(&file); err != nil {
global.GVA_LOG.Error("导入URL失败!", zap.Error(err))
response.FailWithMessage("导入URL失败", c)
return
}
response.OkWithMessage("导入URL成功", c)
}
+4
View File
@@ -36,6 +36,10 @@ func (a *AuthorityApi) CreateAuthority(c *gin.Context) {
return
}
if *authority.ParentId == 0 && global.GVA_CONFIG.System.UseStrictAuth {
authority.ParentId = utils.Pointer(utils.GetUserAuthorityId(c))
}
if authBack, err = authorityService.CreateAuthority(authority); err != nil {
global.GVA_LOG.Error("创建失败!", zap.Error(err))
response.FailWithMessage("创建失败"+err.Error(), c)
+27 -2
View File
@@ -1,6 +1,7 @@
package system
import (
"gorm.io/datatypes"
"strconv"
"time"
@@ -368,7 +369,6 @@ func (b *BaseApi) SetUserInfo(c *gin.Context) {
HeaderImg: user.HeaderImg,
Phone: user.Phone,
Email: user.Email,
SideMode: user.SideMode,
Enable: user.Enable,
})
if err != nil {
@@ -404,7 +404,6 @@ func (b *BaseApi) SetSelfInfo(c *gin.Context) {
HeaderImg: user.HeaderImg,
Phone: user.Phone,
Email: user.Email,
SideMode: user.SideMode,
Enable: user.Enable,
})
if err != nil {
@@ -415,6 +414,32 @@ func (b *BaseApi) SetSelfInfo(c *gin.Context) {
response.OkWithMessage("设置成功", c)
}
// SetSelfSetting
// @Tags SysUser
// @Summary 设置用户配置
// @Security ApiKeyAuth
// @accept application/json
// @Produce application/json
// @Param data body datatypes.JSON
// @Success 200 {object} response.Response{data=map[string]interface{},msg=string} "设置用户配置"
// @Router /user/SetSelfSetting [put]
func (b *BaseApi) SetSelfSetting(c *gin.Context) {
var req datatypes.JSON
err := c.ShouldBindJSON(&req)
if err != nil {
response.FailWithMessage(err.Error(), c)
return
}
err = userService.SetSelfSetting(&req, utils.GetUserID(c))
if err != nil {
global.GVA_LOG.Error("设置失败!", zap.Error(err))
response.FailWithMessage("设置失败", c)
return
}
response.OkWithMessage("设置成功", c)
}
// GetUserInfo
// @Tags SysUser
// @Summary 获取用户信息
+11
View File
@@ -31,6 +31,17 @@ redis:
- "172.21.0.4:7001"
- "172.21.0.2:7002"
# redis-list configuration
redis-list:
- name: cache # 数据库的名称,注意: name 需要在 redis-list 中唯一
useCluster: false # 是否使用redis集群模式
addr: 127.0.0.1:6379 # 使用集群模式addr和db默认无效
password: ""
db: 0
clusterAddrs:
- "172.21.0.3:7000"
- "172.21.0.4:7001"
- "172.21.0.2:7002"
# mongo configuration
mongo:
+8 -7
View File
@@ -1,13 +1,14 @@
package config
type Server struct {
JWT JWT `mapstructure:"jwt" json:"jwt" yaml:"jwt"`
Zap Zap `mapstructure:"zap" json:"zap" yaml:"zap"`
Redis Redis `mapstructure:"redis" json:"redis" yaml:"redis"`
Mongo Mongo `mapstructure:"mongo" json:"mongo" yaml:"mongo"`
Email Email `mapstructure:"email" json:"email" yaml:"email"`
System System `mapstructure:"system" json:"system" yaml:"system"`
Captcha Captcha `mapstructure:"captcha" json:"captcha" yaml:"captcha"`
JWT JWT `mapstructure:"jwt" json:"jwt" yaml:"jwt"`
Zap Zap `mapstructure:"zap" json:"zap" yaml:"zap"`
Redis Redis `mapstructure:"redis" json:"redis" yaml:"redis"`
RedisList []Redis `mapstructure:"redis-list" json:"redis-list" yaml:"redis-list"`
Mongo Mongo `mapstructure:"mongo" json:"mongo" yaml:"mongo"`
Email Email `mapstructure:"email" json:"email" yaml:"email"`
System System `mapstructure:"system" json:"system" yaml:"system"`
Captcha Captcha `mapstructure:"captcha" json:"captcha" yaml:"captcha"`
// auto
AutoCode Autocode `mapstructure:"autocode" json:"autocode" yaml:"autocode"`
// gorm
+1
View File
@@ -1,6 +1,7 @@
package config
type Redis struct {
Name string `mapstructure:"name" json:"name" yaml:"name"` // 代表当前实例的名字
Addr string `mapstructure:"addr" json:"addr" yaml:"addr"` // 服务器地址:端口
Password string `mapstructure:"password" json:"password" yaml:"password"` // 密码
DB int `mapstructure:"db" json:"db" yaml:"db"` // 单实例模式下redis的哪个数据库
+4 -1
View File
@@ -17,6 +17,9 @@ func RunWindowsServer() {
// 初始化redis服务
initialize.Redis()
}
initialize.RedisList()
if global.GVA_CONFIG.System.UseMongo {
err := initialize.Mongo.Initialization()
if err != nil {
@@ -38,7 +41,7 @@ func RunWindowsServer() {
fmt.Printf(`
欢迎使用 gin-vue-admin
当前版本:v2.7.3
当前版本:v2.7.4
加群方式:微信号:shouzi_1994 QQ群:470239250
项目地址:https://github.com/flipped-aurora/gin-vue-admin
插件市场:https://plugin.gin-vue-admin.com
+1 -1
View File
@@ -8087,7 +8087,7 @@ const docTemplate = `{
// SwaggerInfo holds exported Swagger Info so clients can modify it
var SwaggerInfo = &swag.Spec{
Version: "v2.7.3",
Version: "v2.7.4",
Host: "",
BasePath: "",
Schemes: []string{},
+1 -1
View File
@@ -4,7 +4,7 @@
"description": "使用gin+vue进行极速开发的全栈开发基础平台",
"title": "Gin-Vue-Admin Swagger API接口文档",
"contact": {},
"version": "v2.7.3"
"version": "v2.7.4"
},
"paths": {
"/api/createApi": {
+1 -1
View File
@@ -1634,7 +1634,7 @@ info:
contact: {}
description: 使用gin+vue进行极速开发的全栈开发基础平台
title: Gin-Vue-Admin Swagger API接口文档
version: v2.7.3
version: v2.7.4
paths:
/api/createApi:
post:
+18 -7
View File
@@ -1,9 +1,11 @@
package global
import (
"fmt"
"sync"
"github.com/gin-gonic/gin"
"github.com/qiniu/qmgo"
"sync"
"github.com/flipped-aurora/gin-vue-admin/server/utils/timer"
"github.com/songzhibin97/gkit/cache/local_cache"
@@ -20,12 +22,13 @@ import (
)
var (
GVA_DB *gorm.DB
GVA_DBList map[string]*gorm.DB
GVA_REDIS redis.UniversalClient
GVA_MONGO *qmgo.QmgoClient
GVA_CONFIG config.Server
GVA_VP *viper.Viper
GVA_DB *gorm.DB
GVA_DBList map[string]*gorm.DB
GVA_REDIS redis.UniversalClient
GVA_REDISList map[string]redis.UniversalClient
GVA_MONGO *qmgo.QmgoClient
GVA_CONFIG config.Server
GVA_VP *viper.Viper
// GVA_LOG *oplogging.Logger
GVA_LOG *zap.Logger
GVA_Timer timer.Timer = timer.NewTimerTask()
@@ -53,3 +56,11 @@ func MustGetGlobalDBByDBName(dbname string) *gorm.DB {
}
return db
}
func GetRedis(name string) redis.UniversalClient {
redis, ok := GVA_REDISList[name]
if !ok || redis == nil {
panic(fmt.Sprintf("redis `%s` no init", name))
}
return redis
}
+29 -7
View File
@@ -3,14 +3,14 @@ package initialize
import (
"context"
"github.com/flipped-aurora/gin-vue-admin/server/config"
"github.com/flipped-aurora/gin-vue-admin/server/global"
"github.com/redis/go-redis/v9"
"go.uber.org/zap"
)
func Redis() {
redisCfg := global.GVA_CONFIG.Redis
func initRedisClient(redisCfg config.Redis) (redis.UniversalClient, error) {
var client redis.UniversalClient
// 使用集群模式
if redisCfg.UseCluster {
@@ -28,10 +28,32 @@ func Redis() {
}
pong, err := client.Ping(context.Background()).Result()
if err != nil {
global.GVA_LOG.Error("redis connect ping failed, err:", zap.Error(err))
panic(err)
} else {
global.GVA_LOG.Info("redis connect ping response:", zap.String("pong", pong))
global.GVA_REDIS = client
global.GVA_LOG.Error("redis connect ping failed, err:", zap.String("name", redisCfg.Name), zap.Error(err))
return nil, err
}
global.GVA_LOG.Info("redis connect ping response:", zap.String("name", redisCfg.Name), zap.String("pong", pong))
return client, nil
}
func Redis() {
redisClient, err := initRedisClient(global.GVA_CONFIG.Redis)
if err != nil {
panic(err)
}
global.GVA_REDIS = redisClient
}
func RedisList() {
redisMap := make(map[string]redis.UniversalClient)
for _, redisCfg := range global.GVA_CONFIG.RedisList {
client, err := initRedisClient(redisCfg)
if err != nil {
panic(err)
}
redisMap[redisCfg.Name] = client
}
global.GVA_REDISList = redisMap
}
+1 -1
View File
@@ -15,7 +15,7 @@ import (
//go:generate go mod download
// @title Gin-Vue-Admin Swagger API接口文档
// @version v2.7.3
// @version v2.7.4
// @description 使用gin+vue进行极速开发的全栈开发基础平台
// @securityDefinitions.apikey ApiKeyAuth
// @in header
@@ -25,6 +25,7 @@ type AutoCode struct {
AutoCreateApiToSql bool `json:"autoCreateApiToSql" example:"false"` // 是否自动创建api
AutoCreateMenuToSql bool `json:"autoCreateMenuToSql" example:"false"` // 是否自动创建menu
AutoCreateBtnAuth bool `json:"autoCreateBtnAuth" example:"false"` // 是否自动创建按钮权限
OnlyTemplate bool `json:"onlyTemplate" example:"false"` // 是否只生成模板
Fields []*AutoCodeField `json:"fields"`
DictTypes []string `json:"-"`
PrimaryField *AutoCodeField `json:"primaryField"`
@@ -236,6 +237,7 @@ type AutoFunc struct {
Package string `json:"package"`
FuncName string `json:"funcName"` // 方法名称
Router string `json:"router"` // 路由名称
FuncDesc string `json:"funcDesc"` // 方法介绍
BusinessDB string `json:"businessDB"` // 业务库
StructName string `json:"structName"` // Struct名称
PackageName string `json:"packageName"` // 文件名称
+13 -13
View File
@@ -3,6 +3,7 @@ package system
import (
"github.com/flipped-aurora/gin-vue-admin/server/global"
"github.com/gofrs/uuid/v5"
"gorm.io/datatypes"
)
type Login interface {
@@ -18,19 +19,18 @@ var _ Login = new(SysUser)
type SysUser struct {
global.GVA_MODEL
UUID uuid.UUID `json:"uuid" gorm:"index;comment:用户UUID"` // 用户UUID
Username string `json:"userName" gorm:"index;comment:用户登录名"` // 用户登录名
Password string `json:"-" gorm:"comment:用户登录密码"` // 用户登录密码
NickName string `json:"nickName" gorm:"default:系统用户;comment:用户昵称"` // 用户昵称
SideMode string `json:"sideMode" gorm:"default:dark;comment:用户侧边主题"` // 用户侧边主题
HeaderImg string `json:"headerImg" gorm:"default:https://qmplusimg.henrongyi.top/gva_header.jpg;comment:用户头像"` // 用户头像
BaseColor string `json:"baseColor" gorm:"default:#fff;comment:基础颜色"` // 基础颜色
AuthorityId uint `json:"authorityId" gorm:"default:888;comment:用户角色ID"` // 用户角色ID
Authority SysAuthority `json:"authority" gorm:"foreignKey:AuthorityId;references:AuthorityId;comment:用户角色"`
Authorities []SysAuthority `json:"authorities" gorm:"many2many:sys_user_authority;"`
Phone string `json:"phone" gorm:"comment:用户手机号"` // 用户手机号
Email string `json:"email" gorm:"comment:用户邮箱"` // 用户邮箱
Enable int `json:"enable" gorm:"default:1;comment:用户是否被冻结 1正常 2冻结"` //用户是否被冻结 1正常 2冻结
UUID uuid.UUID `json:"uuid" gorm:"index;comment:用户UUID"` // 用户UUID
Username string `json:"userName" gorm:"index;comment:用户登录名"` // 用户登录名
Password string `json:"-" gorm:"comment:用户登录密码"` // 用户登录密码
NickName string `json:"nickName" gorm:"default:系统用户;comment:用户昵称"` // 用户昵称
HeaderImg string `json:"headerImg" gorm:"default:https://qmplusimg.henrongyi.top/gva_header.jpg;comment:用户头像"` // 用户头像
AuthorityId uint `json:"authorityId" gorm:"default:888;comment:用户角色ID"` // 用户角色ID
Authority SysAuthority `json:"authority" gorm:"foreignKey:AuthorityId;references:AuthorityId;comment:用户角色"` // 用户角色
Authorities []SysAuthority `json:"authorities" gorm:"many2many:sys_user_authority;"` // 多用户角色
Phone string `json:"phone" gorm:"comment:用户手机号"` // 用户手机号
Email string `json:"email" gorm:"comment:用户邮箱"` // 用户邮箱
Enable int `json:"enable" gorm:"default:1;comment:用户是否被冻结 1正常 2冻结"` //用户是否被冻结 1正常 2冻结
OriginSetting datatypes.JSON `json:"originSetting" form:"originSetting" gorm:"default:null;column:origin_setting;comment:配置;"` //配置
}
func (SysUser) TableName() string {
+4 -4
View File
@@ -1,7 +1,7 @@
{{if .IsPlugin}}
// {{.FuncName}} 等待开发的的{{.Description}}接口
// {{.FuncName}} {{.FuncDesc}}
// @Tags {{.StructName}}
// @Summary 等待开发的的{{.Description}}接口
// @Summary {{.FuncDesc}}
// @accept application/json
// @Produce application/json
// @Param data query request.{{.StructName}}Search true "分页获取{{.Description}}列表"
@@ -20,9 +20,9 @@ func (a *{{.Abbreviation}}) {{.FuncName}}(c *gin.Context) {
{{- else -}}
// {{.FuncName}} 等待开发的的{{.Description}}接口
// {{.FuncName}} {{.FuncDesc}}
// @Tags {{.StructName}}
// @Summary 等待开发的的{{.Description}}接口
// @Summary {{.FuncDesc}}
// @accept application/json
// @Produce application/json
// @Param data query {{.Package}}Req.{{.StructName}}Search true "成功"
+4 -4
View File
@@ -1,7 +1,7 @@
{{if .IsPlugin}}
// {{.FuncName}} 等待开发的的{{.Description}}接口
// {{.FuncName}} {{.FuncDesc}}
// @Tags {{.StructName}}
// @Summary 等待开发的的{{.Description}}接口
// @Summary {{.FuncDesc}}
// @accept application/json
// @Produce application/json
// @Param data query request.{{.StructName}}Search true "分页获取{{.Description}}列表"
@@ -16,9 +16,9 @@ export const {{.Router}} = () => {
{{- else -}}
// {{.FuncName}} 等待开发的的{{.Description}}接口
// {{.FuncName}} {{.FuncDesc}}
// @Tags {{.StructName}}
// @Summary 等待开发的的{{.Description}}接口
// @Summary {{.FuncDesc}}
// @accept application/json
// @Produce application/json
// @Param data query {{.Package}}Req.{{.StructName}}Search true "成功"
+2 -2
View File
@@ -6,7 +6,7 @@
{{- end}}
{{if .IsPlugin}}
// {{.FuncName}} 请实现方法
// {{.FuncName}} {{.FuncDesc}}
// Author [yourname](https://github.com/yourname)
func (s *{{.Abbreviation}}) {{.FuncName}}() (err error) {
db := {{$db}}.Model(&model.{{.StructName}}{})
@@ -15,7 +15,7 @@ func (s *{{.Abbreviation}}) {{.FuncName}}() (err error) {
{{- else -}}
// {{.FuncName}} 请实现方法
// {{.FuncName}} {{.FuncDesc}}
// Author [yourname](https://github.com/yourname)
func ({{.Abbreviation}}Service *{{.StructName}}Service){{.FuncName}}() (err error) {
// 请在这里实现自己的业务逻辑
@@ -1,6 +1,7 @@
package {{.Package}}
import (
{{if not .OnlyTemplate}}
"github.com/flipped-aurora/gin-vue-admin/server/global"
"github.com/flipped-aurora/gin-vue-admin/server/model/common/response"
"github.com/flipped-aurora/gin-vue-admin/server/model/{{.Package}}"
@@ -10,10 +11,16 @@ import (
{{- if .AutoCreateResource}}
"github.com/flipped-aurora/gin-vue-admin/server/utils"
{{- end }}
{{- else}}
"github.com/flipped-aurora/gin-vue-admin/server/model/common/response"
"github.com/gin-gonic/gin"
{{- end}}
)
type {{.StructName}}Api struct {}
{{if not .OnlyTemplate}}
// Create{{.StructName}} 创建{{.Description}}
// @Tags {{.StructName}}
// @Summary 创建{{.Description}}
@@ -185,6 +192,8 @@ func ({{.Abbreviation}}Api *{{.StructName}}Api) Get{{.StructName}}DataSource(c *
}
{{- end }}
{{- end }}
// Get{{.StructName}}Public 不需要鉴权的{{.Description}}接口
// @Tags {{.StructName}}
// @Summary 不需要鉴权的{{.Description}}接口
@@ -196,6 +205,7 @@ func ({{.Abbreviation}}Api *{{.StructName}}Api) Get{{.StructName}}DataSource(c *
func ({{.Abbreviation}}Api *{{.StructName}}Api) Get{{.StructName}}Public(c *gin.Context) {
// 此接口不需要鉴权
// 示例为返回了一个固定的消息接口,一般本接口用于C端服务,需要自己实现业务逻辑
{{.Abbreviation}}Service.Get{{.StructName}}Public()
response.OkWithDetailed(gin.H{
"info": "不需要鉴权的{{.Description}}接口信息",
}, "获取成功", c)
@@ -1,6 +1,7 @@
// 自动生成模板{{.StructName}}
package {{.Package}}
{{- if not .OnlyTemplate}}
import (
{{- if .GvaModel }}
"github.com/flipped-aurora/gin-vue-admin/server/global"
@@ -12,9 +13,11 @@ import (
"gorm.io/datatypes"
{{- end }}
)
{{- end }}
// {{.Description}} 结构体 {{.StructName}}
type {{.StructName}} struct {
{{- if not .OnlyTemplate}}
{{- if .GvaModel }}
global.GVA_MODEL
{{- end }}
@@ -46,6 +49,7 @@ type {{.StructName}} struct {
UpdatedBy uint `gorm:"column:updated_by;comment:更新者"`
DeletedBy uint `gorm:"column:deleted_by;comment:删除者"`
{{- end }}
{{- end }}
}
{{ if .TableName }}
@@ -1,11 +1,14 @@
package request
import (
{{- if not .OnlyTemplate }}
"github.com/flipped-aurora/gin-vue-admin/server/model/common/request"
{{ if or .HasSearchTimer .GvaModel}}"time"{{ end }}
{{- end }}
)
type {{.StructName}}Search struct{
{{- if not .OnlyTemplate}}
{{- if .GvaModel }}
StartCreatedAt *time.Time `json:"startCreatedAt" form:"startCreatedAt"`
EndCreatedAt *time.Time `json:"endCreatedAt" form:"endCreatedAt"`
@@ -31,4 +34,5 @@ type {{.StructName}}Search struct{
Sort string `json:"sort" form:"sort"`
Order string `json:"order" form:"order"`
{{- end}}
{{- end}}
}
@@ -1,7 +1,7 @@
package {{.Package}}
import (
"github.com/flipped-aurora/gin-vue-admin/server/middleware"
{{if .OnlyTemplate}}// {{ end}}"github.com/flipped-aurora/gin-vue-admin/server/middleware"
"github.com/gin-gonic/gin"
)
@@ -9,9 +9,15 @@ type {{.StructName}}Router struct {}
// Init{{.StructName}}Router 初始化 {{.Description}} 路由信息
func (s *{{.StructName}}Router) Init{{.StructName}}Router(Router *gin.RouterGroup,PublicRouter *gin.RouterGroup) {
{{- if not .OnlyTemplate}}
{{.Abbreviation}}Router := Router.Group("{{.Abbreviation}}").Use(middleware.OperationRecord())
{{.Abbreviation}}RouterWithoutRecord := Router.Group("{{.Abbreviation}}")
{{- else }}
// {{.Abbreviation}}Router := Router.Group("{{.Abbreviation}}").Use(middleware.OperationRecord())
// {{.Abbreviation}}RouterWithoutRecord := Router.Group("{{.Abbreviation}}")
{{- end}}
{{.Abbreviation}}RouterWithoutAuth := PublicRouter.Group("{{.Abbreviation}}")
{{- if not .OnlyTemplate}}
{
{{.Abbreviation}}Router.POST("create{{.StructName}}", {{.Abbreviation}}Api.Create{{.StructName}}) // 新建{{.Description}}
{{.Abbreviation}}Router.DELETE("delete{{.StructName}}", {{.Abbreviation}}Api.Delete{{.StructName}}) // 删除{{.Description}}
@@ -26,6 +32,11 @@ func (s *{{.StructName}}Router) Init{{.StructName}}Router(Router *gin.RouterGrou
{{- if .HasDataSource}}
{{.Abbreviation}}RouterWithoutAuth.GET("get{{.StructName}}DataSource", {{.Abbreviation}}Api.Get{{.StructName}}DataSource) // 获取{{.Description}}数据源
{{- end}}
{{.Abbreviation}}RouterWithoutAuth.GET("get{{.StructName}}Public", {{.Abbreviation}}Api.Get{{.StructName}}Public) // 获取{{.Description}}列表
{{.Abbreviation}}RouterWithoutAuth.GET("get{{.StructName}}Public", {{.Abbreviation}}Api.Get{{.StructName}}Public) // {{.Description}}开放接口
}
{{- else}}
{
{{.Abbreviation}}RouterWithoutAuth.GET("get{{.StructName}}Public", {{.Abbreviation}}Api.Get{{.StructName}}Public) // {{.Description}}开放接口
}
{{ end }}
}
@@ -1,12 +1,14 @@
package {{.Package}}
import (
{{- if not .OnlyTemplate }}
"github.com/flipped-aurora/gin-vue-admin/server/global"
"github.com/flipped-aurora/gin-vue-admin/server/model/{{.Package}}"
{{.Package}}Req "github.com/flipped-aurora/gin-vue-admin/server/model/{{.Package}}/request"
{{- if .AutoCreateResource }}
"gorm.io/gorm"
{{- end}}
{{- end }}
)
type {{.StructName}}Service struct {}
@@ -18,6 +20,7 @@ type {{.StructName}}Service struct {}
{{- $db = printf "global.MustGetGlobalDBByDBName(\"%s\")" .BusinessDB }}
{{- end}}
{{- if not .OnlyTemplate }}
// Create{{.StructName}} 创建{{.Description}}记录
// Author [piexlmax](https://github.com/piexlmax)
func ({{.Abbreviation}}Service *{{.StructName}}Service) Create{{.StructName}}({{.Abbreviation}} *{{.Package}}.{{.StructName}}) (err error) {
@@ -151,4 +154,9 @@ func ({{.Abbreviation}}Service *{{.StructName}}Service)Get{{.StructName}}DataSou
{{- end }}
return
}
{{- end }}
{{- end }}
{{- end }}
func ({{.Abbreviation}}Service *{{.StructName}}Service)Get{{.StructName}}Public() {
// 此方法为获取数据源定义的数据
// 请自行实现
}
@@ -1,5 +1,6 @@
import service from '@/utils/request'
{{- if .OnlyTemplate}}
// @Tags {{.StructName}}
// @Summary 创建{{.Description}}
// @Security ApiKeyAuth
@@ -111,3 +112,19 @@ export const get{{.StructName}}DataSource = () => {
})
}
{{- end}}
{{- end}}
// @Tags {{.StructName}}
// @Summary 不需要鉴权的{{.Description}}接口
// @accept application/json
// @Produce application/json
// @Param data query {{.Package}}Req.{{.StructName}}Search true "分页获取{{.Description}}列表"
// @Success 200 {object} response.Response{data=object,msg=string} "获取成功"
// @Router /{{.Abbreviation}}/get{{.StructName}}Public [get]
export const get{{.StructName}}Public = () => {
return service({
url: '/{{.Abbreviation}}/get{{.StructName}}Public',
method: 'get',
})
}
@@ -1,3 +1,4 @@
{{- if not .OnlyTemplate }}
<template>
<div>
<div class="gva-form-box">
@@ -238,3 +239,12 @@ const back = () => {
<style>
</style>
{{- else }}
<template>
<div>form</div>
</template>
<script setup>
</script>
<style>
</style>
{{- end }}
@@ -1,5 +1,6 @@
{{- $global := . }}
{{- $templateID := printf "%s_%s" .Package .StructName }}
{{- if not .OnlyTemplate}}
<template>
<div>
<div class="gva-search-box">
@@ -894,3 +895,15 @@ const closeDetailShow = () => {
}
{{end}}
</style>
{{- else}}
<template>
<div>form</div>
</template>
<script setup>
defineOptions({
name: '{{.StructName}}'
})
</script>
<style>
</style>
{{- end}}
@@ -1,6 +1,7 @@
package api
import (
{{if not .OnlyTemplate}}
"github.com/flipped-aurora/gin-vue-admin/server/global"
"github.com/flipped-aurora/gin-vue-admin/server/model/common/response"
"github.com/flipped-aurora/gin-vue-admin/server/plugin/{{.Package}}/model"
@@ -10,12 +11,16 @@ import (
{{- if .AutoCreateResource}}
"github.com/flipped-aurora/gin-vue-admin/server/utils"
{{- end }}
{{- else }}
"github.com/flipped-aurora/gin-vue-admin/server/model/common/response"
"github.com/gin-gonic/gin"
{{- end }}
)
var {{.StructName}} = new({{.Abbreviation}})
type {{.Abbreviation}} struct {}
{{if not .OnlyTemplate}}
// Create{{.StructName}} 创建{{.Description}}
// @Tags {{.StructName}}
// @Summary 创建{{.Description}}
@@ -186,7 +191,7 @@ func (a *{{.Abbreviation}}) Get{{.StructName}}DataSource(c *gin.Context) {
response.OkWithData(dataSource, c)
}
{{- end }}
{{- end }}
// Get{{.StructName}}Public 不需要鉴权的{{.Description}}接口
// @Tags {{.StructName}}
// @Summary 不需要鉴权的{{.Description}}接口
@@ -197,5 +202,6 @@ func (a *{{.Abbreviation}}) Get{{.StructName}}DataSource(c *gin.Context) {
// @Router /{{.Abbreviation}}/get{{.StructName}}Public [get]
func (a *{{.Abbreviation}}) Get{{.StructName}}Public(c *gin.Context) {
// 此接口不需要鉴权 示例为返回了一个固定的消息接口,一般本接口用于C端服务,需要自己实现业务逻辑
service{{ .StructName }}.Get{{.StructName}}Public()
response.OkWithDetailed(gin.H{"info": "不需要鉴权的{{.Description}}接口信息"}, "获取成功", c)
}
@@ -1,5 +1,6 @@
package model
{{- if not .OnlyTemplate}}
import (
{{- if .GvaModel }}
"github.com/flipped-aurora/gin-vue-admin/server/global"
@@ -11,9 +12,11 @@ import (
"gorm.io/datatypes"
{{- end }}
)
{{- end }}
// {{.StructName}} {{.Description}} 结构体
type {{.StructName}} struct {
{{- if not .OnlyTemplate}}
{{- if .GvaModel }}
global.GVA_MODEL
{{- end }}
@@ -45,6 +48,7 @@ type {{.StructName}} struct {
UpdatedBy uint `gorm:"column:updated_by;comment:更新者"`
DeletedBy uint `gorm:"column:deleted_by;comment:删除者"`
{{- end }}
{{- end }}
}
{{ if .TableName }}
@@ -1,11 +1,13 @@
package request
{{- if not .OnlyTemplate}}
import (
"github.com/flipped-aurora/gin-vue-admin/server/model/common/request"
{{ if or .HasSearchTimer .GvaModel}}"time"{{ end }}
)
{{- end}}
type {{.StructName}}Search struct{
{{- if not .OnlyTemplate}}
{{- if .GvaModel }}
StartCreatedAt *time.Time `json:"startCreatedAt" form:"startCreatedAt"`
EndCreatedAt *time.Time `json:"endCreatedAt" form:"endCreatedAt"`
@@ -31,4 +33,5 @@ type {{.StructName}}Search struct{
Sort string `json:"sort" form:"sort"`
Order string `json:"order" form:"order"`
{{- end}}
{{- end}}
}
@@ -1,7 +1,7 @@
package router
import (
"github.com/flipped-aurora/gin-vue-admin/server/middleware"
{{if .OnlyTemplate }} // {{end}}"github.com/flipped-aurora/gin-vue-admin/server/middleware"
"github.com/gin-gonic/gin"
)
@@ -11,6 +11,7 @@ type {{.Abbreviation}} struct {}
// Init 初始化 {{.Description}} 路由信息
func (r *{{.Abbreviation}}) Init(public *gin.RouterGroup, private *gin.RouterGroup) {
{{- if not .OnlyTemplate }}
{
group := private.Group("{{.Abbreviation}}").Use(middleware.OperationRecord())
group.POST("create{{.StructName}}", api{{.StructName}}.Create{{.StructName}}) // 新建{{.Description}}
@@ -23,11 +24,23 @@ func (r *{{.Abbreviation}}) Init(public *gin.RouterGroup, private *gin.RouterGro
group.GET("find{{.StructName}}", api{{.StructName}}.Find{{.StructName}}) // 根据ID获取{{.Description}}
group.GET("get{{.StructName}}List", api{{.StructName}}.Get{{.StructName}}List) // 获取{{.Description}}列表
}
{{- if .HasDataSource}}
{
group := public.Group("{{.Abbreviation}}")
{{- if .HasDataSource}}
group.GET("get{{.StructName}}DataSource", api{{.StructName}}.Get{{.StructName}}DataSource) // 获取{{.Description}}数据源
group.GET("get{{.StructName}}Public", api{{.StructName}}.Get{{.StructName}}Public) // 获取{{.Description}}列表
{{- end}}
group.GET("get{{.StructName}}Public", api{{.StructName}}.Get{{.StructName}}Public) // {{.Description}}开放接口
}
{{- end}}
{{- else}}
// {
// group := private.Group("{{.Abbreviation}}").Use(middleware.OperationRecord())
// }
// {
// group := private.Group("{{.Abbreviation}}")
// }
{
group := public.Group("{{.Abbreviation}}")
group.GET("get{{.StructName}}Public", api{{.StructName}}.Get{{.StructName}}Public) // {{.Description}}开放接口
}
{{- end}}
}
@@ -1,12 +1,14 @@
package service
import (
{{- if not .OnlyTemplate }}
"github.com/flipped-aurora/gin-vue-admin/server/global"
"github.com/flipped-aurora/gin-vue-admin/server/plugin/{{.Package}}/model"
"github.com/flipped-aurora/gin-vue-admin/server/plugin/{{.Package}}/model/request"
{{- if .AutoCreateResource }}
"gorm.io/gorm"
{{- end}}
{{- end }}
)
var {{.StructName}} = new({{.Abbreviation}})
@@ -19,7 +21,7 @@ type {{.Abbreviation}} struct {}
{{- else}}
{{- $db = printf "global.MustGetGlobalDBByDBName(\"%s\")" .BusinessDB }}
{{- end}}
{{- if not .OnlyTemplate }}
// Create{{.StructName}} 创建{{.Description}}记录
// Author [piexlmax](https://github.com/piexlmax)
func (s *{{.Abbreviation}}) Create{{.StructName}}({{.Abbreviation}} *model.{{.StructName}}) (err error) {
@@ -153,3 +155,8 @@ func (s *{{.Abbreviation}})Get{{.StructName}}DataSource() (res map[string][]map[
return
}
{{- end }}
{{- end }}
func (s *{{.Abbreviation}})Get{{.StructName}}Public() {
}
+15 -1
View File
@@ -1,5 +1,5 @@
import service from '@/utils/request'
{{- if not .OnlyTemplate}}
// @Tags {{.StructName}}
// @Summary 创建{{.Description}}
// @Security ApiKeyAuth
@@ -111,3 +111,17 @@ export const get{{.StructName}}DataSource = () => {
})
}
{{- end}}
{{- end}}
// @Tags {{.StructName}}
// @Summary 不需要鉴权的{{.Description}}接口
// @accept application/json
// @Produce application/json
// @Param data query request.{{.StructName}}Search true "分页获取{{.Description}}列表"
// @Success 200 {object} response.Response{data=object,msg=string} "获取成功"
// @Router /{{.Abbreviation}}/get{{.StructName}}Public [get]
export const get{{.StructName}}Public = () => {
return service({
url: '/{{.Abbreviation}}/get{{.StructName}}Public',
method: 'get',
})
}
@@ -1,3 +1,4 @@
{{- if not .OnlyTemplate}}
<template>
<div>
<div class="gva-form-box">
@@ -239,3 +240,12 @@ const back = () => {
<style>
</style>
{{- else }}
<template>
<div>form</div>
</template>
<script setup>
</script>
<style>
</style>
{{- end }}
@@ -1,5 +1,6 @@
{{- $global := . }}
{{- $templateID := printf "%s_%s" .Package .StructName }}
{{- if not .OnlyTemplate}}
<template>
<div>
<div class="gva-search-box">
@@ -900,3 +901,15 @@ const closeDetailShow = () => {
}
{{end}}
</style>
{{- else}}
<template>
<div>form</div>
</template>
<script setup>
defineOptions({
name: '{{.StructName}}'
})
</script>
<style>
</style>
{{- end}}
@@ -17,5 +17,6 @@ func (e *FileUploadAndDownloadRouter) InitFileUploadAndDownloadRouter(Router *gi
fileUploadAndDownloadRouter.GET("findFile", exaFileUploadAndDownloadApi.FindFile) // 查询当前文件成功的切片
fileUploadAndDownloadRouter.POST("breakpointContinueFinish", exaFileUploadAndDownloadApi.BreakpointContinueFinish) // 切片传输完成
fileUploadAndDownloadRouter.POST("removeChunk", exaFileUploadAndDownloadApi.RemoveChunk) // 删除切片
fileUploadAndDownloadRouter.POST("importURL", exaFileUploadAndDownloadApi.ImportURL) // 导入URL
}
}
+1
View File
@@ -19,6 +19,7 @@ func (s *UserRouter) InitUserRouter(Router *gin.RouterGroup) {
userRouter.PUT("setSelfInfo", baseApi.SetSelfInfo) // 设置自身信息
userRouter.POST("setUserAuthorities", baseApi.SetUserAuthorities) // 设置用户权限组
userRouter.POST("resetPassword", baseApi.ResetPassword) // 设置用户权限组
userRouter.PUT("setSelfSetting", baseApi.SetSelfSetting) // 用户界面配置
}
{
userRouterWithoutRecord.POST("getUserList", baseApi.GetUserList) // 分页获取用户列表
@@ -106,3 +106,13 @@ func (e *FileUploadAndDownloadService) UploadFile(header *multipart.FileHeader,
}
return f, nil
}
//@author: [piexlmax](https://github.com/piexlmax)
//@function: ImportURL
//@description: 导入URL
//@param: file model.ExaFileUploadAndDownload
//@return: error
func (e *FileUploadAndDownloadService) ImportURL(file *[]example.ExaFileUploadAndDownload) error {
return global.GVA_DB.Create(&file).Error
}
+31 -20
View File
@@ -85,7 +85,7 @@ func (s *autoCodeTemplate) Create(ctx context.Context, info request.AutoCode) er
}
// 自动创建api
if info.AutoCreateApiToSql {
if info.AutoCreateApiToSql && !info.OnlyTemplate {
apis := info.Apis()
err := global.GVA_DB.WithContext(ctx).Transaction(func(tx *gorm.DB) error {
for _, v := range apis {
@@ -118,7 +118,7 @@ func (s *autoCodeTemplate) Create(ctx context.Context, info request.AutoCode) er
id = entity.ID
} else {
entity = info.Menu(autoPkg.Template)
if info.AutoCreateBtnAuth {
if info.AutoCreateBtnAuth && !info.OnlyTemplate {
entity.MenuBtn = []model.SysBaseMenuBtn{
{SysBaseMenuID: entity.ID, Name: "add", Desc: "新增"},
{SysBaseMenuID: entity.ID, Name: "batchDelete", Desc: "批量删除"},
@@ -200,8 +200,10 @@ func (s *autoCodeTemplate) Preview(ctx context.Context, info request.AutoCode) (
if len(key) > len(global.GVA_CONFIG.AutoCode.Root) {
key, _ = filepath.Rel(global.GVA_CONFIG.AutoCode.Root, key)
}
// 获取key的后缀 取消.
suffix := filepath.Ext(key)[1:]
var builder strings.Builder
builder.WriteString("```\n\n")
builder.WriteString("```" + suffix + "\n\n")
builder.WriteString(writer.String())
builder.WriteString("\n\n```")
preview[key] = builder.String()
@@ -229,28 +231,37 @@ func (s *autoCodeTemplate) generate(ctx context.Context, info request.AutoCode,
code[create] = builder
} // 生成文件
injections := make(map[string]utilsAst.Ast, len(asts))
if info.AutoMigrate {
for key, value := range asts {
keys := strings.Split(key, "=>")
if len(keys) == 2 {
if keys[1] == utilsAst.TypePluginInitializeV2 {
for key, value := range asts {
keys := strings.Split(key, "=>")
if len(keys) == 2 {
if keys[1] == utilsAst.TypePluginInitializeV2 {
continue
}
if info.OnlyTemplate {
if keys[1] == utilsAst.TypePackageInitializeGorm || keys[1] == utilsAst.TypePluginInitializeGorm {
continue
}
var builder strings.Builder
parse, _ := value.Parse("", &builder)
if parse != nil {
_ = value.Injection(parse)
err = value.Format("", &builder, parse)
if err != nil {
return nil, nil, nil, err
}
code[keys[0]] = builder
injections[keys[1]] = value
fmt.Println(keys[0], "注入成功!")
}
if !info.AutoMigrate {
if keys[1] == utilsAst.TypePackageInitializeGorm || keys[1] == utilsAst.TypePluginInitializeGorm {
continue
}
}
var builder strings.Builder
parse, _ := value.Parse("", &builder)
if parse != nil {
_ = value.Injection(parse)
err = value.Format("", &builder, parse)
if err != nil {
return nil, nil, nil, err
}
code[keys[0]] = builder
injections[keys[1]] = value
fmt.Println(keys[0], "注入成功!")
}
}
} // 注入代码
}
// 注入代码
return code, templates, injections, nil
}
+12 -2
View File
@@ -3,6 +3,7 @@ package system
import (
"errors"
"fmt"
"gorm.io/datatypes"
"time"
"github.com/flipped-aurora/gin-vue-admin/server/global"
@@ -213,7 +214,7 @@ func (userService *UserService) DeleteUser(id int) (err error) {
func (userService *UserService) SetUserInfo(req system.SysUser) error {
return global.GVA_DB.Model(&system.SysUser{}).
Select("updated_at", "nick_name", "header_img", "phone", "email", "sideMode", "enable").
Select("updated_at", "nick_name", "header_img", "phone", "email", "enable").
Where("id=?", req.ID).
Updates(map[string]interface{}{
"updated_at": time.Now(),
@@ -221,7 +222,6 @@ func (userService *UserService) SetUserInfo(req system.SysUser) error {
"header_img": req.HeaderImg,
"phone": req.Phone,
"email": req.Email,
"side_mode": req.SideMode,
"enable": req.Enable,
}).Error
}
@@ -238,6 +238,16 @@ func (userService *UserService) SetSelfInfo(req system.SysUser) error {
Updates(req).Error
}
//@author: [piexlmax](https://github.com/piexlmax)
//@function: SetSelfSetting
//@description: 设置用户配置
//@param: req datatypes.JSON, uid uint
//@return: err error
func (userService *UserService) SetSelfSetting(req *datatypes.JSON, uid uint) error {
return global.GVA_DB.Model(&system.SysUser{}).Where("id = ?", uid).Update("origin_setting", req).Error
}
//@author: [piexlmax](https://github.com/piexlmax)
//@author: [SliverHorn](https://github.com/SliverHorn)
//@function: GetUserInfo
+2
View File
@@ -55,6 +55,7 @@ func (i *initApi) InitializeData(ctx context.Context) (context.Context, error) {
{ApiGroup: "系统用户", Method: "POST", Path: "/user/changePassword", Description: "修改密码(建议选择)"},
{ApiGroup: "系统用户", Method: "POST", Path: "/user/setUserAuthority", Description: "修改用户角色(必选)"},
{ApiGroup: "系统用户", Method: "POST", Path: "/user/resetPassword", Description: "重置用户密码"},
{ApiGroup: "系统用户", Method: "PUT", Path: "/user/setSelfSetting", Description: "用户界面配置"},
{ApiGroup: "api", Method: "POST", Path: "/api/createApi", Description: "创建api"},
{ApiGroup: "api", Method: "POST", Path: "/api/deleteApi", Description: "删除Api"},
@@ -97,6 +98,7 @@ func (i *initApi) InitializeData(ctx context.Context) (context.Context, error) {
{ApiGroup: "文件上传与下载", Method: "POST", Path: "/fileUploadAndDownload/deleteFile", Description: "删除文件"},
{ApiGroup: "文件上传与下载", Method: "POST", Path: "/fileUploadAndDownload/editFileName", Description: "文件名或者备注编辑"},
{ApiGroup: "文件上传与下载", Method: "POST", Path: "/fileUploadAndDownload/getFileList", Description: "获取上传文件列表"},
{ApiGroup: "文件上传与下载", Method: "POST", Path: "/fileUploadAndDownload/importURL", Description: "导入URL"},
{ApiGroup: "系统服务", Method: "POST", Path: "/system/getServerInfo", Description: "获取服务器信息"},
{ApiGroup: "系统服务", Method: "POST", Path: "/system/getSystemConfig", Description: "获取配置文件内容"},
+4
View File
@@ -85,6 +85,7 @@ func (i *initCasbin) InitializeData(ctx context.Context) (context.Context, error
{Ptype: "p", V0: "888", V1: "/user/setUserAuthority", V2: "POST"},
{Ptype: "p", V0: "888", V1: "/user/setUserAuthorities", V2: "POST"},
{Ptype: "p", V0: "888", V1: "/user/resetPassword", V2: "POST"},
{Ptype: "p", V0: "888", V1: "/user/setSelfSetting", V2: "PUT"},
{Ptype: "p", V0: "888", V1: "/fileUploadAndDownload/findFile", V2: "GET"},
{Ptype: "p", V0: "888", V1: "/fileUploadAndDownload/breakpointContinueFinish", V2: "POST"},
@@ -95,6 +96,7 @@ func (i *initCasbin) InitializeData(ctx context.Context) (context.Context, error
{Ptype: "p", V0: "888", V1: "/fileUploadAndDownload/deleteFile", V2: "POST"},
{Ptype: "p", V0: "888", V1: "/fileUploadAndDownload/editFileName", V2: "POST"},
{Ptype: "p", V0: "888", V1: "/fileUploadAndDownload/getFileList", V2: "POST"},
{Ptype: "p", V0: "888", V1: "/fileUploadAndDownload/importURL", V2: "POST"},
{Ptype: "p", V0: "888", V1: "/casbin/updateCasbin", V2: "POST"},
{Ptype: "p", V0: "888", V1: "/casbin/getPolicyPathByAuthorityId", V2: "POST"},
@@ -203,6 +205,7 @@ func (i *initCasbin) InitializeData(ctx context.Context) (context.Context, error
{Ptype: "p", V0: "8881", V1: "/fileUploadAndDownload/getFileList", V2: "POST"},
{Ptype: "p", V0: "8881", V1: "/fileUploadAndDownload/deleteFile", V2: "POST"},
{Ptype: "p", V0: "8881", V1: "/fileUploadAndDownload/editFileName", V2: "POST"},
{Ptype: "p", V0: "8881", V1: "/fileUploadAndDownload/importURL", V2: "POST"},
{Ptype: "p", V0: "8881", V1: "/casbin/updateCasbin", V2: "POST"},
{Ptype: "p", V0: "8881", V1: "/casbin/getPolicyPathByAuthorityId", V2: "POST"},
{Ptype: "p", V0: "8881", V1: "/jwt/jsonInBlacklist", V2: "POST"},
@@ -244,6 +247,7 @@ func (i *initCasbin) InitializeData(ctx context.Context) (context.Context, error
{Ptype: "p", V0: "9528", V1: "/fileUploadAndDownload/getFileList", V2: "POST"},
{Ptype: "p", V0: "9528", V1: "/fileUploadAndDownload/deleteFile", V2: "POST"},
{Ptype: "p", V0: "9528", V1: "/fileUploadAndDownload/editFileName", V2: "POST"},
{Ptype: "p", V0: "9528", V1: "/fileUploadAndDownload/importURL", V2: "POST"},
{Ptype: "p", V0: "9528", V1: "/casbin/updateCasbin", V2: "POST"},
{Ptype: "p", V0: "9528", V1: "/casbin/getPolicyPathByAuthorityId", V2: "POST"},
{Ptype: "p", V0: "9528", V1: "/jwt/jsonInBlacklist", V2: "POST"},
+1 -1
View File
@@ -9,7 +9,7 @@ var (
RegisterVerify = Rules{"Username": {NotEmpty()}, "NickName": {NotEmpty()}, "Password": {NotEmpty()}, "AuthorityId": {NotEmpty()}}
PageInfoVerify = Rules{"Page": {NotEmpty()}, "PageSize": {NotEmpty()}}
CustomerVerify = Rules{"CustomerName": {NotEmpty()}, "CustomerPhoneData": {NotEmpty()}}
AutoCodeVerify = Rules{"Abbreviation": {NotEmpty()}, "StructName": {NotEmpty()}, "PackageName": {NotEmpty()}, "Fields": {NotEmpty()}}
AutoCodeVerify = Rules{"Abbreviation": {NotEmpty()}, "StructName": {NotEmpty()}, "PackageName": {NotEmpty()}}
AutoPackageVerify = Rules{"PackageName": {NotEmpty()}}
AuthorityVerify = Rules{"AuthorityId": {NotEmpty()}, "AuthorityName": {NotEmpty()}}
AuthorityIdVerify = Rules{"AuthorityId": {NotEmpty()}}