diff --git a/server/api/v1/example/exa_file_upload_download.go b/server/api/v1/example/exa_file_upload_download.go index 6e6bb6ad3..6899d59c9 100644 --- a/server/api/v1/example/exa_file_upload_download.go +++ b/server/api/v1/example/exa_file_upload_download.go @@ -108,3 +108,26 @@ func (b *FileUploadAndDownloadApi) GetFileList(c *gin.Context) { PageSize: pageInfo.PageSize, }, "general.getDataSuccess", 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) +} diff --git a/server/api/v1/system/sys_authority.go b/server/api/v1/system/sys_authority.go index 1cacc3894..3b9b28fe4 100644 --- a/server/api/v1/system/sys_authority.go +++ b/server/api/v1/system/sys_authority.go @@ -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(global.Translate("general.creationFail"), zap.Error(err)) response.FailWithMessage(global.Translate("general.creationFailErr")+" "+err.Error(), c) diff --git a/server/api/v1/system/sys_user.go b/server/api/v1/system/sys_user.go index e7a6e4224..32b172a37 100644 --- a/server/api/v1/system/sys_user.go +++ b/server/api/v1/system/sys_user.go @@ -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(global.Translate("general.setupSuccess"), 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 获取用户信息 diff --git a/server/config.yaml b/server/config.yaml index 7559a8dd7..bd814693d 100644 --- a/server/config.yaml +++ b/server/config.yaml @@ -1,225 +1,270 @@ -aliyun-oss: - endpoint: yourEndpoint - access-key-id: yourAccessKeyId - access-key-secret: yourAccessKeySecret - bucket-name: yourBucketName - bucket-url: yourBucketUrl - base-path: yourBasePath -autocode: - web: web/src - root: D:\Projects\Go\gin-vue-admin - server: server - module: github.com/flipped-aurora/gin-vue-admin/server - ai-path: "" -aws-s3: - bucket: xxxxx-10005608 - region: ap-shanghai - endpoint: "" - secret-id: your-secret-id - secret-key: your-secret-key - base-url: https://gin.vue.admin - path-prefix: github.com/flipped-aurora/gin-vue-admin/server - s3-force-path-style: false - disable-ssl: false -captcha: - key-long: 6 - img-width: 240 - img-height: 80 - open-captcha: 0 - open-captcha-timeout: 3600 -cloudflare-r2: - bucket: xxxx0bucket - base-url: https://gin.vue.admin.com - path: uploads - account-id: xxx_account_id - access-key-id: xxx_key_id - secret-access-key: xxx_secret_key -cors: - mode: strict-whitelist - whitelist: - - allow-origin: example1.com - allow-methods: POST, GET - allow-headers: Content-Type,AccessToken,X-CSRF-Token, Authorization, Token,X-Token,X-User-Id - expose-headers: Content-Length, Access-Control-Allow-Origin, Access-Control-Allow-Headers, Content-Type - allow-credentials: true - - allow-origin: example2.com - allow-methods: GET, POST - allow-headers: content-type - expose-headers: Content-Length, Access-Control-Allow-Origin, Access-Control-Allow-Headers, Content-Type - allow-credentials: true -db-list: - - type: "" - alias-name: "" - prefix: "" - port: "" - config: "" - db-name: "" - username: "" - password: "" - path: "" - engine: "" - log-mode: "" - max-idle-conns: 10 - max-open-conns: 100 - singular: false - log-zap: false - disable: true -disk-list: - - mount-point: / -email: - to: xxx@qq.com - from: xxx@163.com - host: smtp.163.com - secret: xxx - nickname: test - port: 465 - is-ssl: true -excel: - dir: ./resource/excel/ -hua-wei-obs: - path: you-path - bucket: you-bucket - endpoint: you-endpoint - access-key: you-access-key - secret-key: you-secret-key +# github.com/flipped-aurora/gin-vue-admin/server Global Configuration + +# jwt configuration jwt: - signing-key: e01c7de8-e79b-4dcc-b1df-bb7eb88402cd - expires-time: 7d - buffer-time: 1d - issuer: qmPlus -language: - language: en - dir: ./resource/lang/ -local: - path: uploads/file - store-path: uploads/file -mongo: - coll: "" - options: "" - database: "" - username: "" - password: "" - auth-source: "" - min-pool-size: 0 - max-pool-size: 100 - socket-timeout-ms: 0 - connect-timeout-ms: 0 - is-zap: false - hosts: - - host: "" - port: "" -mssql: - prefix: "" - port: "" - config: "" - db-name: "" - username: "" - password: "" - path: "" - engine: "" - log-mode: "" - max-idle-conns: 10 - max-open-conns: 100 - singular: false - log-zap: false -mysql: - prefix: "" - port: "3306" - config: charset=utf8mb4&parseTime=True&loc=Local - db-name: gva_db - username: mhassan - password: P@$$w0rD - path: 127.0.0.1 - engine: "" - log-mode: error - max-idle-conns: 10 - max-open-conns: 100 - singular: false - log-zap: false -oracle: - prefix: "" - port: "" - config: "" - db-name: "" - username: "" - password: "" - path: "" - engine: "" - log-mode: "" - max-idle-conns: 10 - max-open-conns: 100 - singular: false - log-zap: false -pgsql: - prefix: "" - port: "" - config: "" - db-name: "" - username: "" - password: "" - path: "" - engine: "" - log-mode: "" - max-idle-conns: 10 - max-open-conns: 100 - singular: false - log-zap: false -qiniu: - zone: ZoneHuaDong - bucket: "" - img-path: "" - access-key: "" - secret-key: "" - use-https: false - use-cdn-domains: false + signing-key: qmPlus + expires-time: 7d + buffer-time: 1d + issuer: qmPlus +# zap logger configuration +zap: + level: info + format: console + prefix: "[github.com/flipped-aurora/gin-vue-admin/server]" + director: log + show-line: true + encode-level: LowercaseColorLevelEncoder + stacktrace-key: stacktrace + log-in-console: true + retention-day: -1 + +# redis configuration redis: - addr: 127.0.0.1:6379 + #是否使用redis集群模式 + useCluster: false + #使用集群模式addr和db默认无效 + addr: 127.0.0.1:6379 + password: "" + db: 0 + clusterAddrs: + - "172.21.0.3:7000" + - "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 - useCluster: false clusterAddrs: - - 172.21.0.3:7000 - - 172.21.0.4:7001 - - 172.21.0.2:7002 + - "172.21.0.3:7000" + - "172.21.0.4:7001" + - "172.21.0.2:7002" + +# mongo configuration +mongo: + coll: '' + options: '' + database: '' + username: '' + password: '' + auth-source: '' + min-pool-size: 0 + max-pool-size: 100 + socket-timeout-ms: 0 + connect-timeout-ms: 0 + is-zap: false + hosts: + - host: '' + port: '' + +# email configuration +email: + to: xxx@qq.com + port: 465 + from: xxx@163.com + host: smtp.163.com + is-ssl: true + secret: xxx + nickname: test + +# system configuration +system: + env: local # 修改为public可以关闭路由日志输出 + addr: 8888 + db-type: mysql + oss-type: local # 控制oss选择走本地还是 七牛等其他仓 自行增加其他oss仓可以在 server/utils/upload/upload.go 中 NewOss函数配置 + use-redis: false # 使用redis + use-mongo: false # 使用mongo + use-multipoint: false + # IP限制次数 一个小时15000次 + iplimit-count: 15000 + # IP限制一个小时 + iplimit-time: 3600 + # 路由全局前缀 + router-prefix: "" + # 严格角色模式 打开后权限将会存在上下级关系 + use-strict-auth: false + +# captcha configuration +captcha: + key-long: 6 + img-width: 240 + img-height: 80 + open-captcha: 0 # 0代表一直开启,大于0代表限制次数 + open-captcha-timeout: 3600 # open-captcha大于0时才生效 + +# mysql connect configuration +# 未初始化之前请勿手动修改数据库信息!!!如果一定要手动初始化请看(https://gin-vue-admin.com/docs/first_master) +mysql: + path: "" + port: "" + config: "" + db-name: "" + username: "" + password: "" + max-idle-conns: 10 + max-open-conns: 100 + log-mode: "" + log-zap: false + +# pgsql connect configuration +# 未初始化之前请勿手动修改数据库信息!!!如果一定要手动初始化请看(https://gin-vue-admin.com/docs/first_master) +pgsql: + path: "" + port: "" + config: "" + db-name: "" + username: "" + password: "" + max-idle-conns: 10 + max-open-conns: 100 + log-mode: "" + log-zap: false +oracle: + path: "" + port: "" + config: "" + db-name: "" + username: "" + password: "" + max-idle-conns: 10 + max-open-conns: 100 + log-mode: "" + log-zap: false +mssql: + path: "" + port: "" + config: "" + db-name: "" + username: "" + password: "" + max-idle-conns: 10 + max-open-conns: 100 + log-mode: "" + log-zap: false sqlite: - prefix: "" + path: "" + port: "" + config: "" + db-name: "" + username: "" + password: "" + max-idle-conns: 10 + max-open-conns: 100 + log-mode: "" + log-zap: false +db-list: + - disable: true # 是否禁用 + type: "" # 数据库的类型,目前支持mysql、pgsql、mssql、oracle + alias-name: "" # 数据库的名称,注意: alias-name 需要在db-list中唯一 + path: "" port: "" config: "" db-name: "" username: "" password: "" - path: "" - engine: "" - log-mode: "" max-idle-conns: 10 max-open-conns: 100 - singular: false + log-mode: "" log-zap: false -system: - db-type: mysql - oss-type: local - router-prefix: "" - addr: 8888 - iplimit-count: 15000 - iplimit-time: 3600 - use-multipoint: false - use-redis: false - use-mongo: false - use-strict-auth: false + +# local configuration +local: + path: uploads/file + store-path: uploads/file + +# autocode configuration +autocode: + web: web/src + root: "" # root 自动适配项目根目录, 请不要手动配置,他会在项目加载的时候识别出根路径 + server: server + module: 'github.com/flipped-aurora/gin-vue-admin/server' + ai-path: "" # AI服务路径 + +# qiniu configuration (请自行七牛申请对应的 公钥 私钥 bucket 和 域名地址) +qiniu: + zone: ZoneHuaDong + bucket: "" + img-path: "" + use-https: false + access-key: "" + secret-key: "" + use-cdn-domains: false + +# aliyun oss configuration +aliyun-oss: + endpoint: yourEndpoint + access-key-id: yourAccessKeyId + access-key-secret: yourAccessKeySecret + bucket-name: yourBucketName + bucket-url: yourBucketUrl + base-path: yourBasePath + +# tencent cos configuration tencent-cos: - bucket: xxxxx-10005608 - region: ap-shanghai - secret-id: your-secret-id - secret-key: your-secret-key - base-url: https://gin.vue.admin - path-prefix: github.com/flipped-aurora/gin-vue-admin/server -zap: - level: info - prefix: '[github.com/flipped-aurora/gin-vue-admin/server]' - format: console - director: log - encode-level: LowercaseColorLevelEncoder - stacktrace-key: stacktrace - show-line: true - log-in-console: true - retention-day: -1 + bucket: xxxxx-10005608 + region: ap-shanghai + secret-id: your-secret-id + secret-key: your-secret-key + base-url: https://gin.vue.admin + path-prefix: github.com/flipped-aurora/gin-vue-admin/server + +# aws s3 configuration (minio compatible) +aws-s3: + bucket: xxxxx-10005608 + region: ap-shanghai + endpoint: "" + s3-force-path-style: false + disable-ssl: false + secret-id: your-secret-id + secret-key: your-secret-key + base-url: https://gin.vue.admin + path-prefix: github.com/flipped-aurora/gin-vue-admin/server + +# cloudflare r2 configuration +cloudflare-r2: + bucket: xxxx0bucket + base-url: https://gin.vue.admin.com + path: uploads + account-id: xxx_account_id + access-key-id: xxx_key_id + secret-access-key: xxx_secret_key + +# huawei obs configuration +hua-wei-obs: + path: you-path + bucket: you-bucket + endpoint: you-endpoint + access-key: you-access-key + secret-key: you-secret-key + +# excel configuration +excel: + dir: ./resource/excel/ + +# disk usage configuration +disk-list: + - mount-point: "/" + +# 跨域配置 +# 需要配合 server/initialize/router.go -> `Router.Use(middleware.CorsByRules())` 使用 +cors: + mode: strict-whitelist # 放行模式: allow-all, 放行全部; whitelist, 白名单模式, 来自白名单内域名的请求添加 cors 头; strict-whitelist 严格白名单模式, 白名单外的请求一律拒绝 + whitelist: + - allow-origin: example1.com + allow-headers: Content-Type,AccessToken,X-CSRF-Token, Authorization, Token,X-Token,X-User-Id + allow-methods: POST, GET + expose-headers: Content-Length, Access-Control-Allow-Origin, Access-Control-Allow-Headers, Content-Type + + allow-credentials: true # 布尔值 + - allow-origin: example2.com + allow-headers: content-type + allow-methods: GET, POST + expose-headers: Content-Length, Access-Control-Allow-Origin, Access-Control-Allow-Headers, Content-Type + allow-credentials: true # 布尔值 +language: + language: en + dir: ./resource/lang/ \ No newline at end of file diff --git a/server/config/config.go b/server/config/config.go index 63a507514..24f3fffee 100644 --- a/server/config/config.go +++ b/server/config/config.go @@ -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 diff --git a/server/config/redis.go b/server/config/redis.go index 33c0ccbbb..94b5bf6b5 100644 --- a/server/config/redis.go +++ b/server/config/redis.go @@ -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的哪个数据库 diff --git a/server/core/server.go b/server/core/server.go index c396f912b..6ffc106aa 100644 --- a/server/core/server.go +++ b/server/core/server.go @@ -17,7 +17,9 @@ func RunWindowsServer() { if global.GVA_CONFIG.System.UseMultipoint || global.GVA_CONFIG.System.UseRedis { // 初始化redis服务 initialize.Redis() + initialize.RedisList() } + if global.GVA_CONFIG.System.UseMongo { err := initialize.Mongo.Initialization() if err != nil { @@ -39,7 +41,7 @@ func RunWindowsServer() { fmt.Printf(` %s gin-vue-admin - %s:v2.7.3 + %s:v2.7.4 加群方式:微信号:shouzi_1994 QQ群:470239250 项目地址:https://github.com/flipped-aurora/gin-vue-admin 插件市场:https://plugin.gin-vue-admin.com diff --git a/server/docs/docs.go b/server/docs/docs.go index 7c16f6139..87f3feca1 100644 --- a/server/docs/docs.go +++ b/server/docs/docs.go @@ -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{}, diff --git a/server/docs/swagger.json b/server/docs/swagger.json index ff089bee4..5c27ada77 100644 --- a/server/docs/swagger.json +++ b/server/docs/swagger.json @@ -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": { diff --git a/server/docs/swagger.yaml b/server/docs/swagger.yaml index a048f2fb8..789d4db8a 100644 --- a/server/docs/swagger.yaml +++ b/server/docs/swagger.yaml @@ -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: diff --git a/server/global/global.go b/server/global/global.go index fbb4213d0..8a2319237 100644 --- a/server/global/global.go +++ b/server/global/global.go @@ -1,6 +1,7 @@ package global import ( + "fmt" "sync" "github.com/gin-gonic/gin" @@ -22,12 +23,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() @@ -67,3 +69,11 @@ func Translate(msg string) string { return msg } + +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 +} diff --git a/server/go.mod b/server/go.mod index fdf5fc577..d8c9bd169 100644 --- a/server/go.mod +++ b/server/go.mod @@ -36,6 +36,8 @@ require ( github.com/swaggo/gin-swagger v1.6.0 github.com/swaggo/swag v1.16.2 github.com/tencentyun/cos-go-sdk-v5 v0.7.42 + github.com/tidwall/gjson v1.17.3 + github.com/tidwall/sjson v1.2.5 github.com/unrolled/secure v1.13.0 github.com/xuri/excelize/v2 v2.8.0 go.mongodb.org/mongo-driver v1.12.1 @@ -129,6 +131,8 @@ require ( github.com/spf13/pflag v1.0.5 // indirect github.com/subosito/gotenv v1.4.2 // indirect github.com/therootcompany/xz v1.0.1 // indirect + github.com/tidwall/match v1.1.1 // indirect + github.com/tidwall/pretty v1.2.0 // indirect github.com/tklauser/go-sysconf v0.3.11 // indirect github.com/tklauser/numcpus v0.6.0 // indirect github.com/twitchyliquid64/golang-asm v0.15.1 // indirect diff --git a/server/go.sum b/server/go.sum index 8ad870b30..b974fdcc4 100644 --- a/server/go.sum +++ b/server/go.sum @@ -464,7 +464,16 @@ github.com/tencentyun/cos-go-sdk-v5 v0.7.42 h1:Up1704BJjI5orycXKjpVpvuOInt9GC5pq github.com/tencentyun/cos-go-sdk-v5 v0.7.42/go.mod h1:LUFnaqRmGk6pEHOaRmdn2dCZR2j0cSsM5xowWFPTPao= github.com/therootcompany/xz v1.0.1 h1:CmOtsn1CbtmyYiusbfmhmkpAAETj0wBIH6kCYaX+xzw= github.com/therootcompany/xz v1.0.1/go.mod h1:3K3UH1yCKgBneZYhuQUvJ9HPD19UEXEI0BWbMn8qNMY= +github.com/tidwall/gjson v1.14.2/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk= +github.com/tidwall/gjson v1.17.3 h1:bwWLZU7icoKRG+C+0PNwIKC6FCJO/Q3p2pZvuP0jN94= +github.com/tidwall/gjson v1.17.3/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk= +github.com/tidwall/match v1.1.1 h1:+Ho715JplO36QYgwN9PGYNhgZvoUSc9X2c80KVTi+GA= +github.com/tidwall/match v1.1.1/go.mod h1:eRSPERbgtNPcGhD8UCthc6PmLEQXEWd3PRB5JTxsfmM= github.com/tidwall/pretty v1.0.0/go.mod h1:XNkn88O1ChpSDQmQeStsy+sBenx6DDtFZJxhVysOjyk= +github.com/tidwall/pretty v1.2.0 h1:RWIZEg2iJ8/g6fDDYzMpobmaoGh5OLl4AXtGUGPcqCs= +github.com/tidwall/pretty v1.2.0/go.mod h1:ITEVvHYasfjBbM0u2Pg8T2nJnzm8xPwvNhhsoaGGjNU= +github.com/tidwall/sjson v1.2.5 h1:kLy8mja+1c9jlljvWTlSazM7cKDRfJuR/bOJhcY5NcY= +github.com/tidwall/sjson v1.2.5/go.mod h1:Fvgq9kS/6ociJEDnK0Fk1cpYF4FIW6ZF7LAe+6jwd28= github.com/tklauser/go-sysconf v0.3.11 h1:89WgdJhk5SNwJfu+GKyYveZ4IaJ7xAkecBo+KdJV0CM= github.com/tklauser/go-sysconf v0.3.11/go.mod h1:GqXfhXY3kiPa0nAXPDIQIWzJbMCB7AmcWpGR8lSZfqI= github.com/tklauser/numcpus v0.6.0 h1:kebhY2Qt+3U6RNK7UqpYNA+tJ23IBEGKkB7JQBfDYms= diff --git a/server/initialize/redis.go b/server/initialize/redis.go index 41dfd76e0..2d9c8f4eb 100644 --- a/server/initialize/redis.go +++ b/server/initialize/redis.go @@ -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 } diff --git a/server/main.go b/server/main.go index 32b947f57..405e16f3a 100644 --- a/server/main.go +++ b/server/main.go @@ -16,7 +16,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 diff --git a/server/model/common/basetypes.go b/server/model/common/basetypes.go new file mode 100644 index 000000000..870d975c6 --- /dev/null +++ b/server/model/common/basetypes.go @@ -0,0 +1,36 @@ +package common + +import ( + "database/sql/driver" + "encoding/json" + "errors" +) + +type JSONMap map[string]interface{} + +func (m JSONMap) Value() (driver.Value, error) { + if m == nil { + return nil, nil + } + return json.Marshal(m) +} + +func (m *JSONMap) Scan(value interface{}) error { + if value == nil { + *m = make(map[string]interface{}) + return nil + } + var err error + switch value.(type) { + case []byte: + err = json.Unmarshal(value.([]byte), m) + case string: + err = json.Unmarshal([]byte(value.(string)), m) + default: + err = errors.New("basetypes.JSONMap.Scan: invalid value type") + } + if err != nil { + return err + } + return nil +} diff --git a/server/model/system/request/sys_auto_code.go b/server/model/system/request/sys_auto_code.go index f22fab3e2..f26e4f530 100644 --- a/server/model/system/request/sys_auto_code.go +++ b/server/model/system/request/sys_auto_code.go @@ -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"` // 文件名称 diff --git a/server/model/system/sys_user.go b/server/model/system/sys_user.go index 9a6892abc..916c6b6e0 100644 --- a/server/model/system/sys_user.go +++ b/server/model/system/sys_user.go @@ -2,6 +2,7 @@ package system import ( "github.com/flipped-aurora/gin-vue-admin/server/global" + "github.com/flipped-aurora/gin-vue-admin/server/model/common" "github.com/gofrs/uuid/v5" ) @@ -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 common.JSONMap `json:"originSetting" form:"originSetting" gorm:"type:text;default:null;column:origin_setting;comment:配置;"` //配置 } func (SysUser) TableName() string { diff --git a/server/resource/function/api.go.tpl b/server/resource/function/api.go.tpl index c788a9fa1..1d276cff6 100644 --- a/server/resource/function/api.go.tpl +++ b/server/resource/function/api.go.tpl @@ -1,10 +1,9 @@ {{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}}列表" // @Success 200 {object} response.Response{data=object,msg=string} "获取成功" // @Router /{{.Abbreviation}}/{{.Router}} [{{.Method}}] func (a *{{.Abbreviation}}) {{.FuncName}}(c *gin.Context) { @@ -20,9 +19,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 "成功" diff --git a/server/resource/function/api.js.tpl b/server/resource/function/api.js.tpl index 524e8320f..5cc491fe3 100644 --- a/server/resource/function/api.js.tpl +++ b/server/resource/function/api.js.tpl @@ -1,10 +1,9 @@ {{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}}列表" // @Success 200 {object} response.Response{data=object,msg=string} "获取成功" // @Router /{{.Abbreviation}}/{{.Router}} [{{.Method}}] export const {{.Router}} = () => { @@ -16,12 +15,11 @@ 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 "成功" // @Success 200 {object} response.Response{data=object,msg=string} "成功" // @Router /{{.Abbreviation}}/{{.Router}} [{{.Method}}] export const {{.Router}} = () => { diff --git a/server/resource/function/server.go.tpl b/server/resource/function/server.go.tpl index da3f4fe22..1c5191c4b 100644 --- a/server/resource/function/server.go.tpl +++ b/server/resource/function/server.go.tpl @@ -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) { // 请在这里实现自己的业务逻辑 diff --git a/server/resource/lang/ar.json b/server/resource/lang/ar.json index bd6ab75fb..1b8b1de8f 100644 --- a/server/resource/lang/ar.json +++ b/server/resource/lang/ar.json @@ -1,291 +1,296 @@ { - "init": { - "dbAlreadyExist": "قاعدة البيانات موجودة بالفعل", - "initDB": "انتقل إلى تهيئة قاعدة البيانات", - "dbAlreadyInit": "لا تحتاج قاعدة البيانات إلى التهيئة" - }, - "general": { - "createSuccss": "تم إنشاؤه بنجاح", - "creationFail": "فشل في الإنشاء!", - "creationFailErr": "فشل في الإنشاء", - "deletFailErr": "فشل في الحذف", - "deleteFail": "فشل في الحذف!", - "deleteSuccess": "تم الحذف بنجاح", - "getDataFail": "فشل في الحصول على البيانات!", - "getDataFailErr": "فشل في الحصول على البيانات", - "getDataSuccess": "تم الحصول على البيانات بنجاح", - "modifyFail": "فشل في التعديل!", - "modifySuccess": "تم التعديل بنجاح", - "queryFail": "فشل في البحث!", - "queryFailErr": "فشل في البحث", - "querySuccess": "بحث ناجح", - "setupFail": "فشل الإعداد", - "setupFailErr": "فشل الإعداد!", - "setupSuccess": "تم الإعداد بنجاح", - "tabelDataInitFail": "فشل تهيئة بيانات الجدول!", - "updateFail": "فشل التحديث!", - "updateFailErr": "فشل التحديث", - "updateSuccess": "تم التحديث بنجاح" - }, - "sys_authority": { - "copyFail": "فشل النسخ!", - "copyFailErr": "فشل النسخ", - "copySuccess": "تم النسخ بنجاح" - }, - "sys_auto_code": { - "autoCreateFail": "فشل الإنشاء التلقائي! يرجى مسح البيانات غير المهمة بنفسك!", - "previewFail": "فشلت المعاينة!", - "previewFailErr": "فشلت المعاينة", - "previewSuccess": "تمت المعاينة بنجاح", - "queryTablesFail": "فشل الاستعلام عن الجدول" - }, - "sys_auto_code_history": { - "rollbackSuccess": "تمت الاستعادة بنجاح" - }, - "sys_captcha": { - "vCodeFail": "فشل في الحصول على رمز التحقق", - "vCodeFailErr": "فشل في الحصول على رمز التحقق!", - "vCodeSuccess": "تم الحصول على رمز التحقق بنجاح" - }, - "sys_initdb": { - "autoCreateDBFail": "فشل إنشاء قاعدة البيانات تلقائيًا", - "autoCreateDBFailErr": "فشل إنشاء قاعدة البيانات تلقائيًا ، يرجى التحقق من سجل الخلفية وتهيئته بعد التحقق", - "autoCreateDBSuccess": "نجح إنشاء قاعدة البيانات التلقائية", - "paramVerifyFail": "فشل التحقق من المعاملات!", - "paramVerifyFailErr": "فشل التحقق من المعاملات" - }, - "sys_jwt_blacklist": { - "jwtInvalidatedSuccess": "تم إلغاء JWT بنجاح", - "jwtInvalidationFailedErr": "فشل JWT في إلغاء" - }, - "sys_menu": { - "addFail": "فشل في الإضافة!", - "addFailErr": "فشل في الإضافة", - "addSuccess": "تمت الإضافة بنجاح" - }, - "sys_operation_record": { - "batchDeleteFail": "فشل في الحذف المجمع!", - "batchDeleteFailErr": "فشل في الحذف المجمع", - "batchDeleteSuccess": "تم الحذف المجمع بنجاح" - }, - "sys_system": { - "rebootFail": "فشل في إعادة التشغيل!", - "rebootFailErr": "فشل في إعادة التشغيل", - "rebootSuccess": "تم إعادة تشغيل النظام بنجاح" - }, - "sys_user": { - "changePWErr": "فشل التعديل، وكلمة المرور الأصلية لا تتطابق مع الحساب الجاري", - "deleteUserFail": "فشل في حذف المستخدم", - "getTokenErr": "فشل الحصول على الرمز المميز", - "getTokenFail": "فشل في الحصول على الرمز المميز!", - "jwtInvalidationFailed": "فشل في إلغاء JWT", - "loginFail": "فشل تسجيل الدخول! اسم المستخدم غير موجود أو كلمة المرور غير صحيحة!", - "loginStatusFail": "فشل في تعيين حالة تسجيل الدخول!", - "loginStatusFailErr": "فشل تعيين حالة تسجيل الدخول", - "loginSuccess": "تسجيل الدخول بنجاح", - "registrationFail": "فشل التسجيل!", - "registrationFailErr": "فشل التسجيل", - "registrationSuccess": "نجاح التسجيل", - "resetPWFail": "فشلت إعادة الضبط!", - "resetPWFailErr": "فشل في إعادة ضبط كلمة السر", - "resetPWSuccess": "تم إعادة ضبط كلمة السر بنجاح", - "userNameOrPasswordError": "اسم المستخدم غير موجود أو كلمة المرور غير صحيحة", - "vCodeErr": "رمز التحقق غير صحيح" - }, - "system": { - "api": { - "group": { - "systemUser": "مستخدم النظام", - "api": "API", - "role": "دور", - "casbin": "casbin", - "menu": "قائمة", - "partialUpload": "تحميل جزئي", - "fileUploadDownload": "تحميل وتنزيل الملفات", - "systemService": "خدمات النظام", - "customer": "العميل", - "codeGen": "مولد الشفرة", - "templateConfiguration": "تكوين القالب", - "codeGenHistory": "تاريخ مولد الشفرة", - "dictDetails": "تفاصيل القاموس النظامي", - "dictionary": "القاموس النظامي", - "optRecord": "سجل العمليات", - "resumeUpload": "استئناف التحميل (إصدار المكون)", - "email": "البريد الإلكتروني", - "buttonAuthority": "صلاحيات الأزرار", - "tableTemplate": "قالب الجدول", - "announcement": "الإعلان" - }, - "desc": { - "userLoginRequired": "تسجيل دخول المستخدم (مطلوب)", - "addMenu": "إضافة قائمة", - "addMenuRole": "إضافة علاقة قائمة ودور", - "changePassword": "تغيير كلمة المرور (مستوى مستفيد)", - "changeRoleAPIPermission": "تغيير صلاحيات API للدور", - "copyRole": "نسخ دور", - "createAPI": "إنشاء API", - "createRole": "إنشاء دور", - "deleteAPI": "حذف API", - "deleteAPIByID": "حذف API بشكل جماعي", - "deleteMenu": "حذف قائمة", - "deleteRole": "حذف دور", - "deleteUsers": "حذف المستخدمين", - "getAPIByID": "الحصول على تفاصيل API", - "getAPIList": "الحصول على قائمة API", - "getAllAPI": "الحصول على جميع API", - "getDynamicRoute": "الحصول على المسارات الديناميكية للمستخدم", - "getMenuByID": "الحصول على القائمة بناءً على الهوية", - "getMenuList": "الحصول على قائمة الأنواع الأساسية بشكل منقسم", - "getMenuRole": "الحصول على قائمة الدور", - "getMenuTree": "الحصول على شجرة القوائم (مطلوب)", - "getPermissionList": "الحصول على قائمة الأذونات", - "getRoleList": "الحصول على قائمة الأدوار", - "getSelfInfo": "الحصول على معلومات الشخصية (مطلوب)", - "getUsersList": "الحصول على قائمة المستخدمين", - "jwtAddedToBlackList": "إضافة JWT إلى القائمة السوداء (الخروج، مطلوب)", - "modifyUserRole": "تعديل دور المستخدم (مطلوب)", - "resetUserPassword": "إعادة تعيين كلمة مرور المستخدم", - "setPermissionGroup": "تعيين مجموعة الأذونات", - "setRolePermissions": "تعيين صلاحيات الموارد للدور", - "setSelfInfo": "تعيين معلومات الشخصية (مطلوب)", - "setUserInfo": "تعيين معلومات المستخدم", - "updateAPI": "تحديث API", - "updateMenu": "تحديث القائمة", - "updateRole": "تحديث معلومات الدور", - "userRegistration": "تسجيل المستخدم", - "configurationTemplates": "تكوين القوالب", - "getTemplateFile": "الحصول على ملف القالب", - "getAllTemplates": "الحصول على جميع القوالب", - "deleteTemplate": "حذف القالب", - "newAnnouncement": "إنشاء إعلان", - "deleteAnnouncement": "حذف الإعلان", - "batchDeleteAnnouncement": "حذف الإعلانات بشكل جماعي", - "updateAnnouncement": "تحديث الإعلان", - "getAnnouncementByID": "الحصول على الإعلان بناءً على الهوية", - "getAnnouncementList": "الحصول على قائمة الإعلانات", - "findTargetFile": "البحث عن الملف الهدف (الإرسال الفوري)", - "breakpointContinue": "استئناف التحميل", - "breakpointContinueFinish": "إنهاء استئناف التحميل", - "removeFileAfterUpload": "إزالة الملف بعد التحميل", - "fileUploadExample": "مثال على تحميل الملف", - "deleteFile": "حذف الملف", - "editFileNameOrRemark": "تعديل اسم الملف أو الملاحظة", - "getUploadFileList": "الحصول على قائمة الملفات المحملة", - "getServerInfo": "الحصول على معلومات الخادم", - "getConfigFileContent": "الحصول على محتوى ملف التكوين", - "setConfigFileContent": "تعيين محتوى ملف التكوين", - "updateCustomer": "تحديث العميل", - "createCustomer": "إنشاء عميل", - "deleteCustomer": "حذف العميل", - "getSingleCustomer": "الحصول على عميل واحد", - "getCustomerList": "الحصول على قائمة العملاء", - "getAllDatabases": "الحصول على جميع قواعد البيانات", - "getDatabaseTables": "الحصول على جداول قاعدة البيانات", - "autoCode": "شفرة تلقائية", - "previewAutoCode": "معاينة الشفرة التلقائية", - "getSelectedTableFields": "الحصول على جميع الحقول للجدول المحدد", - "createPluginPackage": "إنشاء حزمة المكون من البداية", - "installPlugin": "تثبيت المكون", - "packagePlugin": "تعيين حزمة المكون", - "getMetaInfo": "الحصول على معلومات الفوقية", - "rollbackAutoGeneratedCode": "تراجع الشفرة التلقائية المولدة", - "queryRollbackRecord": "البحث عن سجل التراجع", - "deleteRollbackRecord": "حذف سجل التراجع", - "addTemplateMethod": "إضافة طريقة القالب", - "updateDictionaryContent": "تحديث محتوى القاموس", - "createDictionaryContent": "إنشاء محتوى القاموس", - "deleteDictionaryContent": "حذف محتوى القاموس", - "getDictionaryContentById": "الحصول على محتوى القاموس بناءً على الهوية", - "getDictionaryContentList": "الحصول على قائمة محتوى القاموس", - "createDictionary": "إنشاء قاموس", - "deleteDictionary": "حذف قاموس", - "updateDictionary": "تحديث قاموس", - "getDictionaryById": "الحصول على قاموس بناءً على الهوية", - "getDictionaryList": "الحصول على قائمة القواميس", - "createOperationRecord": "إنشاء سجل عملية", - "getOperationRecordById": "الحصول على سجل عملية بناءً على الهوية", - "getOperationRecordList": "الحصول على قائمة سجل العمليات", - "deleteOperationRecord": "حذف سجل عملية", - "batchDeleteOperationHistory": "حذف تاريخ العمليات بشكل جماعي", - "pluginVersionResumableUpload": "استئناف التحميل بالشرائح (إصدار المكون)", - "fileIntegrityCheck": "فحص تامة الملف", - "mergeFileAfterUpload": "دمج الملف بعد التحميل", - "sendTestEmail": "إرسال بريد إلكتروني اختباري", - "sendEmail": "إرسال بريد إلكتروني", - "setButtonPermission": "تعيين صلاحيات الزر", - "getExistingButtonPermission": "الحصول على صلاحيات الزر الموجودة", - "deleteButton": "حذف زر", - "createExportTemplate": "إنشاء قالب للتصدير", - "deleteExportTemplate": "حذف قالب التصدير", - "batchDeleteExportTemplate": "حذف قوالب التصدير بشكل جماعي", - "updateExportTemplate": "تحديث قالب التصدير", - "getExportTemplateById": "الحصول على قالب التصدير بناءً على الهوية", - "getExportTemplateList": "الحصول على قائمة قوالب التصدير", - "exportExcel": "تصدير إكسل", - "downloadTemplate": "تنزيل القالب", - "importExcel": "استيراد إكسل", - "getSyncApi": "الحصول على API المتوقعة للتزام", - "getRouteGroup": "الحصول على مجموعة المسارات", - "confirmSyncApi": "تأكيد مزامنة API", - "ignoreApi": "تجاهل API" - } - }, - "authority": { - "normalUserSubRole": "عادي المستخدم subrole", - "normalUsers": "المستخدمين العاديين", - "testRole": "اختبار الدور" - }, - "dictionary": { - "boolType": "نوع bool قاعدة البيانات", - "floatType": "أرقام غير صحيحة", - "gender": "جنس", - "genderDict": "قاموس النوع الاجتماعي", - "intType": "أرقام صحيحة", - "intTypeDict": "نوع قاعدة البيانات المطابق لنوع int", - "stringType": "نصي", - "timeDateType": "نوع التاريخ الزمني لقاعدة البيانات", - "timeDateTypeDict": "نوع التاريخ الزمني لقاعدة البيانات" - }, - "dictionary_detail": { - "female": "انثي", - "male": "ذكر" - }, - "menu": { - "about": "معلومات عن النظام", - "adminTools": "أدوات إدارة النظام", - "apiManage": "إدارة API", - "autoCode": "مولد الأكواد", - "autoCodeEdit": "أتمتة الكود (إعادة الاستخدام)", - "autoCodeManage": "إدارة الكود الآلي", - "breakPoint": "HTTP", - "customerList": "قائمة العملاء (مثال مورد)", - "dashboard": "لوحة القيادة", - "dataTableInitFail": "فشل في تهيئة بيانات الجدول", - "dictDetail": "تفاصيل القاموس", - "dictManage": "إدارة القاموس", - "examples": "أمثلة", - "excelImportExport": "استيراد و تصدير Excel", - "formCreator": "منشئ النموذج", - "mediaLibUpDown": "مكتبة الوسائط (تحميل وتنزيل)", - "menuManage": "إدارة القوائم", - "operationLog": "سجل التدقيق", - "personalInfo": "معلومات شخصية", - "resumableUpload": "تحميل قابل لإعادة الإضافة (إصدار مكون إضافي)", - "resume": "استئناف من نقطة توقف (إصدار مكون إضافي)", - "roleManage": "إدارة الأدوار", - "serverStatus": "حالة الخادم", - "system": "أعدادات النظام", - "systemTools": "أدوات النظام", - "userManage": "إدارة المستخدم", - "website": "الموقع الرسمي", - "templateConfig": "تكوين القالب", - "pluginSystem": "نظام المكونات", - "pluginMarket": "سوق المكونات", - "pluginInstall": "تثبيت المكون", - "packagePlugin": "تعيين حزمة المكون", - "emailPlugin": "مكون البريد الإلكتروني", - "tableTemplate": "قالب الجدول", - "announcementManage": "إدارة الإعلانات [مثال]" - } - } + "general": { + "createSuccss": "تم إنشاؤه بنجاح", + "creationFail": "فشل في الإنشاء!", + "creationFailErr": "فشل في الإنشاء", + "deletFailErr": "فشل في الحذف", + "deleteFail": "فشل في الحذف!", + "deleteSuccess": "تم الحذف بنجاح", + "getDataFail": "فشل في الحصول على البيانات!", + "getDataFailErr": "فشل في الحصول على البيانات", + "getDataSuccess": "تم الحصول على البيانات بنجاح", + "modifyFail": "فشل في التعديل!", + "modifySuccess": "تم التعديل بنجاح", + "queryFail": "فشل في البحث!", + "queryFailErr": "فشل في البحث", + "querySuccess": "بحث ناجح", + "setupFail": "فشل الإعداد", + "setupFailErr": "فشل الإعداد!", + "setupSuccess": "تم الإعداد بنجاح", + "tabelDataInitFail": "فشل تهيئة بيانات الجدول!", + "updateFail": "فشل التحديث!", + "updateFailErr": "فشل التحديث", + "updateSuccess": "تم التحديث بنجاح" + }, + "init": { + "dbAlreadyExist": "قاعدة البيانات موجودة بالفعل", + "dbAlreadyInit": "لا تحتاج قاعدة البيانات إلى التهيئة", + "initDB": "انتقل إلى تهيئة قاعدة البيانات" + }, + "sys_authority": { + "copyFail": "فشل النسخ!", + "copyFailErr": "فشل النسخ", + "copySuccess": "تم النسخ بنجاح" + }, + "sys_auto_code": { + "autoCreateFail": "فشل الإنشاء التلقائي! يرجى مسح البيانات غير المهمة بنفسك!", + "previewFail": "فشلت المعاينة!", + "previewFailErr": "فشلت المعاينة", + "previewSuccess": "تمت المعاينة بنجاح", + "queryTablesFail": "فشل الاستعلام عن الجدول" + }, + "sys_auto_code_history": { + "rollbackSuccess": "تمت الاستعادة بنجاح" + }, + "sys_captcha": { + "vCodeFail": "فشل في الحصول على رمز التحقق", + "vCodeFailErr": "فشل في الحصول على رمز التحقق!", + "vCodeSuccess": "تم الحصول على رمز التحقق بنجاح" + }, + "sys_initdb": { + "autoCreateDBFail": "فشل إنشاء قاعدة البيانات تلقائيًا", + "autoCreateDBFailErr": "فشل إنشاء قاعدة البيانات تلقائيًا ، يرجى التحقق من سجل الخلفية وتهيئته بعد التحقق", + "autoCreateDBSuccess": "نجح إنشاء قاعدة البيانات التلقائية", + "paramVerifyFail": "فشل التحقق من المعاملات!", + "paramVerifyFailErr": "فشل التحقق من المعاملات" + }, + "sys_jwt_blacklist": { + "jwtInvalidatedSuccess": "تم إلغاء JWT بنجاح", + "jwtInvalidationFailedErr": "فشل JWT في إلغاء" + }, + "sys_menu": { + "addFail": "فشل في الإضافة!", + "addFailErr": "فشل في الإضافة", + "addSuccess": "تمت الإضافة بنجاح" + }, + "sys_operation_record": { + "batchDeleteFail": "فشل في الحذف المجمع!", + "batchDeleteFailErr": "فشل في الحذف المجمع", + "batchDeleteSuccess": "تم الحذف المجمع بنجاح" + }, + "sys_system": { + "rebootFail": "فشل في إعادة التشغيل!", + "rebootFailErr": "فشل في إعادة التشغيل", + "rebootSuccess": "تم إعادة تشغيل النظام بنجاح" + }, + "sys_user": { + "changePWErr": "فشل التعديل، وكلمة المرور الأصلية لا تتطابق مع الحساب الجاري", + "deleteUserFail": "فشل في حذف المستخدم", + "getTokenErr": "فشل الحصول على الرمز المميز", + "getTokenFail": "فشل في الحصول على الرمز المميز!", + "jwtInvalidationFailed": "فشل في إلغاء JWT", + "loginFail": "فشل تسجيل الدخول! اسم المستخدم غير موجود أو كلمة المرور غير صحيحة!", + "loginStatusFail": "فشل في تعيين حالة تسجيل الدخول!", + "loginStatusFailErr": "فشل تعيين حالة تسجيل الدخول", + "loginSuccess": "تسجيل الدخول بنجاح", + "registrationFail": "فشل التسجيل!", + "registrationFailErr": "فشل التسجيل", + "registrationSuccess": "نجاح التسجيل", + "resetPWFail": "فشلت إعادة الضبط!", + "resetPWFailErr": "فشل في إعادة ضبط كلمة السر", + "resetPWSuccess": "تم إعادة ضبط كلمة السر بنجاح", + "userNameOrPasswordError": "اسم المستخدم غير موجود أو كلمة المرور غير صحيحة", + "vCodeErr": "رمز التحقق غير صحيح" + }, + "system": { + "api": { + "desc": { + "addMenu": "إضافة قائمة", + "addMenuRole": "إضافة علاقة قائمة ودور", + "addTemplateMethod": "إضافة طريقة القالب", + + "autoCode": "شفرة تلقائية", + "batchDeleteAnnouncement": "حذف الإعلانات بشكل جماعي", + "batchDeleteExportTemplate": "حذف قوالب التصدير بشكل جماعي", + "batchDeleteOperationHistory": "حذف تاريخ العمليات بشكل جماعي", + + "breakpointContinue": "استئناف التحميل", + "breakpointContinueFinish": "إنهاء استئناف التحميل", + "changePassword": "تغيير كلمة المرور (مستوى مستفيد)", + "changeRoleAPIPermission": "تغيير صلاحيات API للدور", + "configurationTemplates": "تكوين القوالب", + "confirmSyncApi": "تأكيد مزامنة API", + "copyRole": "نسخ دور", + "createAPI": "إنشاء API", + "createCustomer": "إنشاء عميل", + "createDictionary": "إنشاء قاموس", + "createDictionaryContent": "إنشاء محتوى القاموس", + "createExportTemplate": "إنشاء قالب للتصدير", + "createOperationRecord": "إنشاء سجل عملية", + "createPluginPackage": "إنشاء حزمة المكون من البداية", + "createRole": "إنشاء دور", + "deleteAPI": "حذف API", + "deleteAPIByID": "حذف API بشكل جماعي", + "deleteAnnouncement": "حذف الإعلان", + "deleteButton": "حذف زر", + "deleteCustomer": "حذف العميل", + "deleteDictionary": "حذف قاموس", + "deleteDictionaryContent": "حذف محتوى القاموس", + "deleteExportTemplate": "حذف قالب التصدير", + "deleteFile": "حذف الملف", + "deleteMenu": "حذف قائمة", + "deleteOperationRecord": "حذف سجل عملية", + "deleteRole": "حذف دور", + "deleteRollbackRecord": "حذف سجل التراجع", + "deleteTemplate": "حذف القالب", + "deleteUsers": "حذف المستخدمين", + + "downloadTemplate": "تنزيل القالب", + "editFileNameOrRemark": "تعديل اسم الملف أو الملاحظة", + "exportExcel": "تصدير إكسل", + "fileIntegrityCheck": "فحص تامة الملف", + "fileUploadExample": "مثال على تحميل الملف", + + "getAPIByID": "الحصول على تفاصيل API", + "getAPIList": "الحصول على قائمة API", + "getAllAPI": "الحصول على جميع API", + "getAllDatabases": "الحصول على جميع قواعد البيانات", + "getAllTemplates": "الحصول على جميع القوالب", + "getAnnouncementByID": "الحصول على الإعلان بناءً على الهوية", + "getAnnouncementList": "الحصول على قائمة الإعلانات", + "getConfigFileContent": "الحصول على محتوى ملف التكوين", + "getCustomerList": "الحصول على قائمة العملاء", + "getDatabaseTables": "الحصول على جداول قاعدة البيانات", + "getDictionaryById": "الحصول على قاموس بناءً على الهوية", + "getDictionaryContentById": "الحصول على محتوى القاموس بناءً على الهوية", + "getDictionaryContentList": "الحصول على قائمة محتوى القاموس", + "getDictionaryList": "الحصول على قائمة القواميس", + "getDynamicRoute": "الحصول على المسارات الديناميكية للمستخدم", + "getExistingButtonPermission": "الحصول على صلاحيات الزر الموجودة", + "getExportTemplateById": "الحصول على قالب التصدير بناءً على الهوية", + "getExportTemplateList": "الحصول على قائمة قوالب التصدير", + "getMenuByID": "الحصول على القائمة بناءً على الهوية", + "getMenuList": "الحصول على قائمة الأنواع الأساسية بشكل منقسم", + "getMenuRole": "الحصول على قائمة الدور", + "getMenuTree": "الحصول على شجرة القوائم (مطلوب)", + "getMetaInfo": "الحصول على معلومات الفوقية", + "getOperationRecordById": "الحصول على سجل عملية بناءً على الهوية", + "getOperationRecordList": "الحصول على قائمة سجل العمليات", + "getPermissionList": "الحصول على قائمة الأذونات", + "getRoleList": "الحصول على قائمة الأدوار", + "getRouteGroup": "الحصول على مجموعة المسارات", + "getSelectedTableFields": "الحصول على جميع الحقول للجدول المحدد", + "getSelfInfo": "الحصول على معلومات الشخصية (مطلوب)", + "getServerInfo": "الحصول على معلومات الخادم", + "getSingleCustomer": "الحصول على عميل واحد", + "getSyncApi": "الحصول على API المتوقعة للتزام", + "getTemplateFile": "الحصول على ملف القالب", + "getUploadFileList": "الحصول على قائمة الملفات المحملة", + "getUsersList": "الحصول على قائمة المستخدمين", + "ignoreApi": "تجاهل API", + "importExcel": "استيراد إكسل", + "installPlugin": "تثبيت المكون", + "jwtAddedToBlackList": "إضافة JWT إلى القائمة السوداء (الخروج، مطلوب)", + + "mergeFileAfterUpload": "دمج الملف بعد التحميل", + "modifyUserRole": "تعديل دور المستخدم (مطلوب)", + "newAnnouncement": "إنشاء إعلان", + "packagePlugin": "تعيين حزمة المكون", + "pluginVersionResumableUpload": "استئناف التحميل بالشرائح (إصدار المكون)", + "previewAutoCode": "معاينة الشفرة التلقائية", + "queryRollbackRecord": "البحث عن سجل التراجع", + "removeFileAfterUpload": "إزالة الملف بعد التحميل", + "resetUserPassword": "إعادة تعيين كلمة مرور المستخدم", + "resetUserWeb": "تكوين واجهة المستخدم", + "rollbackAutoGeneratedCode": "تراجع الشفرة التلقائية المولدة", + "sendEmail": "إرسال بريد إلكتروني", + "sendTestEmail": "إرسال بريد إلكتروني اختباري", + "setButtonPermission": "تعيين صلاحيات الزر", + "setConfigFileContent": "تعيين محتوى ملف التكوين", + "setPermissionGroup": "تعيين مجموعة الأذونات", + "setRolePermissions": "تعيين صلاحيات الموارد للدور", + "setSelfInfo": "تعيين معلومات الشخصية (مطلوب)", + "setUserInfo": "تعيين معلومات المستخدم", + "updateAPI": "تحديث API", + "updateAnnouncement": "تحديث الإعلان", + "updateCustomer": "تحديث العميل", + "updateDictionary": "تحديث قاموس", + "updateDictionaryContent": "تحديث محتوى القاموس", + "updateExportTemplate": "تحديث قالب التصدير", + "updateMenu": "تحديث القائمة", + "updateRole": "تحديث معلومات الدور", + "userLoginRequired": "تسجيل دخول المستخدم (مطلوب)", + "userRegistration": "تسجيل المستخدم" + }, + "group": { + "announcement": "الإعلان", + "api": "API", + "buttonAuthority": "صلاحيات الأزرار", + "casbin": "casbin", + "codeGen": "مولد الشفرة", + "codeGenHistory": "تاريخ مولد الشفرة", + "customer": "العميل", + "dictDetails": "تفاصيل القاموس النظامي", + "dictionary": "القاموس النظامي", + "email": "البريد الإلكتروني", + "fileUploadDownload": "تحميل وتنزيل الملفات", + "menu": "قائمة", + "optRecord": "سجل العمليات", + "partialUpload": "تحميل جزئي", + "resumeUpload": "استئناف التحميل (إصدار المكون)", + "role": "دور", + "systemService": "خدمات النظام", + "systemUser": "مستخدم النظام", + "tableTemplate": "قالب الجدول", + "templateConfiguration": "تكوين القالب" + } + }, + "authority": { + "normalUserSubRole": "عادي المستخدم subrole", + "normalUsers": "المستخدمين العاديين", + "testRole": "اختبار الدور" + }, + "dictionary": { + "boolType": "نوع bool قاعدة البيانات", + "floatType": "أرقام غير صحيحة", + "gender": "جنس", + "genderDict": "قاموس النوع الاجتماعي", + "intType": "أرقام صحيحة", + "intTypeDict": "نوع قاعدة البيانات المطابق لنوع int", + "stringType": "نصي", + "timeDateType": "نوع التاريخ الزمني لقاعدة البيانات", + "timeDateTypeDict": "نوع التاريخ الزمني لقاعدة البيانات" + }, + "dictionary_detail": { + "female": "انثي", + "male": "ذكر" + }, + "menu": { + "about": "معلومات عن النظام", + "adminTools": "أدوات إدارة النظام", + "announcementManage": "إدارة الإعلانات [مثال]", + "apiManage": "إدارة API", + "autoCode": "مولد الأكواد", + "autoCodeEdit": "أتمتة الكود (إعادة الاستخدام)", + "autoCodeManage": "إدارة الكود الآلي", + "breakPoint": "HTTP", + "customerList": "قائمة العملاء (مثال مورد)", + "dashboard": "لوحة القيادة", + "dataTableInitFail": "فشل في تهيئة بيانات الجدول", + "dictDetail": "تفاصيل القاموس", + "dictManage": "إدارة القاموس", + "emailPlugin": "مكون البريد الإلكتروني", + "examples": "أمثلة", + "excelImportExport": "استيراد و تصدير Excel", + "formCreator": "منشئ النموذج", + "mediaLibUpDown": "مكتبة الوسائط (تحميل وتنزيل)", + "menuManage": "إدارة القوائم", + "operationLog": "سجل التدقيق", + "packagePlugin": "تعيين حزمة المكون", + "personalInfo": "معلومات شخصية", + "pluginInstall": "تثبيت المكون", + "pluginMarket": "سوق المكونات", + "pluginSystem": "نظام المكونات", + "resumableUpload": "تحميل قابل لإعادة الإضافة (إصدار مكون إضافي)", + "resume": "استئناف من نقطة توقف (إصدار مكون إضافي)", + "roleManage": "إدارة الأدوار", + "serverStatus": "حالة الخادم", + "system": "أعدادات النظام", + "systemTools": "أدوات النظام", + "tableTemplate": "قالب الجدول", + "templateConfig": "تكوين القالب", + "userManage": "إدارة المستخدم", + "website": "الموقع الرسمي" + } + } } diff --git a/server/resource/package/server/api/api.go.tpl b/server/resource/package/server/api/api.go.tpl index 7f2ce0c31..5b46f091e 100644 --- a/server/resource/package/server/api/api.go.tpl +++ b/server/resource/package/server/api/api.go.tpl @@ -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}} @@ -81,7 +88,7 @@ func ({{.Abbreviation}}Api *{{.StructName}}Api) Delete{{.StructName}}ByIds(c *gi err := {{.Abbreviation}}Service.Delete{{.StructName}}ByIds({{.PrimaryField.FieldJson}}s{{- if .AutoCreateResource }},userID{{- end }}) if err != nil { global.GVA_LOG.Error(global.Translate("sys_operation_record.batchDeleteFail"), zap.Error(err)) - response.FailWithMessage("sys_operation_record.batchDeleteFailErr"), c) + response.FailWithMessage(global.Translate("sys_operation_record.batchDeleteFailErr"), c) return } response.OkWithMessage(global.Translate("sys_operation_record.batchDeleteSuccess"), c) @@ -112,7 +119,7 @@ func ({{.Abbreviation}}Api *{{.StructName}}Api) Update{{.StructName}}(c *gin.Con response.FailWithMessage(global.Translate("general.updateFailErr"), c) return } - response.OkWithMessage("general.updateSuccess"), c) + response.OkWithMessage(global.Translate("general.updateSuccess"), c) } // Find{{.StructName}} 用id查询{{.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) diff --git a/server/resource/package/server/model/model.go.tpl b/server/resource/package/server/model/model.go.tpl index f1ccd1419..138456796 100644 --- a/server/resource/package/server/model/model.go.tpl +++ b/server/resource/package/server/model/model.go.tpl @@ -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 }} diff --git a/server/resource/package/server/model/request/request.go.tpl b/server/resource/package/server/model/request/request.go.tpl index a8d510e02..e97a0fd7a 100644 --- a/server/resource/package/server/model/request/request.go.tpl +++ b/server/resource/package/server/model/request/request.go.tpl @@ -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}} -} \ No newline at end of file +{{- end}} +} diff --git a/server/resource/package/server/router/router.go.tpl b/server/resource/package/server/router/router.go.tpl index 26376e957..9a4ba9de0 100644 --- a/server/resource/package/server/router/router.go.tpl +++ b/server/resource/package/server/router/router.go.tpl @@ -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}}开放接口 } -} \ No newline at end of file + {{- else}} + { + {{.Abbreviation}}RouterWithoutAuth.GET("get{{.StructName}}Public", {{.Abbreviation}}Api.Get{{.StructName}}Public) // {{.Description}}开放接口 + } + {{ end }} +} diff --git a/server/resource/package/server/service/service.go.tpl b/server/resource/package/server/service/service.go.tpl index b2ca1bc9e..731a3b324 100644 --- a/server/resource/package/server/service/service.go.tpl +++ b/server/resource/package/server/service/service.go.tpl @@ -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,15 +20,16 @@ type {{.StructName}}Service struct {} {{- $db = printf "global.MustGetGlobalDBByDBName(\"%s\")" .BusinessDB }} {{- end}} +{{- if not .OnlyTemplate }} // Create{{.StructName}} 创建{{.Description}}记录 -// Author [piexlmax](https://github.com/piexlmax) +// Author [yourname](https://github.com/yourname) func ({{.Abbreviation}}Service *{{.StructName}}Service) Create{{.StructName}}({{.Abbreviation}} *{{.Package}}.{{.StructName}}) (err error) { err = {{$db}}.Create({{.Abbreviation}}).Error return err } // Delete{{.StructName}} 删除{{.Description}}记录 -// Author [piexlmax](https://github.com/piexlmax) +// Author [yourname](https://github.com/yourname) func ({{.Abbreviation}}Service *{{.StructName}}Service)Delete{{.StructName}}({{.PrimaryField.FieldJson}} string{{- if .AutoCreateResource -}},userID uint{{- end -}}) (err error) { {{- if .AutoCreateResource }} err = {{$db}}.Transaction(func(tx *gorm.DB) error { @@ -45,7 +48,7 @@ func ({{.Abbreviation}}Service *{{.StructName}}Service)Delete{{.StructName}}({{. } // Delete{{.StructName}}ByIds 批量删除{{.Description}}记录 -// Author [piexlmax](https://github.com/piexlmax) +// Author [yourname](https://github.com/yourname) func ({{.Abbreviation}}Service *{{.StructName}}Service)Delete{{.StructName}}ByIds({{.PrimaryField.FieldJson}}s []string {{- if .AutoCreateResource }},deleted_by uint{{- end}}) (err error) { {{- if .AutoCreateResource }} err = {{$db}}.Transaction(func(tx *gorm.DB) error { @@ -64,21 +67,21 @@ func ({{.Abbreviation}}Service *{{.StructName}}Service)Delete{{.StructName}}ById } // Update{{.StructName}} 更新{{.Description}}记录 -// Author [piexlmax](https://github.com/piexlmax) +// Author [yourname](https://github.com/yourname) func ({{.Abbreviation}}Service *{{.StructName}}Service)Update{{.StructName}}({{.Abbreviation}} {{.Package}}.{{.StructName}}) (err error) { err = {{$db}}.Model(&{{.Package}}.{{.StructName}}{}).Where("{{.PrimaryField.ColumnName}} = ?",{{.Abbreviation}}.{{.PrimaryField.FieldName}}).Updates(&{{.Abbreviation}}).Error return err } // Get{{.StructName}} 根据{{.PrimaryField.FieldJson}}获取{{.Description}}记录 -// Author [piexlmax](https://github.com/piexlmax) +// Author [yourname](https://github.com/yourname) func ({{.Abbreviation}}Service *{{.StructName}}Service)Get{{.StructName}}({{.PrimaryField.FieldJson}} string) ({{.Abbreviation}} {{.Package}}.{{.StructName}}, err error) { err = {{$db}}.Where("{{.PrimaryField.ColumnName}} = ?", {{.PrimaryField.FieldJson}}).First(&{{.Abbreviation}}).Error return } // Get{{.StructName}}InfoList 分页获取{{.Description}}记录 -// Author [piexlmax](https://github.com/piexlmax) +// Author [yourname](https://github.com/yourname) func ({{.Abbreviation}}Service *{{.StructName}}Service)Get{{.StructName}}InfoList(info {{.Package}}Req.{{.StructName}}Search) (list []{{.Package}}.{{.StructName}}, total int64, err error) { limit := info.PageSize offset := info.PageSize * (info.Page - 1) @@ -136,7 +139,7 @@ func ({{.Abbreviation}}Service *{{.StructName}}Service)Get{{.StructName}}InfoLis if limit != 0 { db = db.Limit(limit).Offset(offset) } - + err = db.Find(&{{.Abbreviation}}s).Error return {{.Abbreviation}}s, total, err } @@ -151,4 +154,9 @@ func ({{.Abbreviation}}Service *{{.StructName}}Service)Get{{.StructName}}DataSou {{- end }} return } -{{- end }} \ No newline at end of file +{{- end }} +{{- end }} +func ({{.Abbreviation}}Service *{{.StructName}}Service)Get{{.StructName}}Public() { + // 此方法为获取数据源定义的数据 + // 请自行实现 +} diff --git a/server/resource/package/web/api/api.js.tpl b/server/resource/package/web/api/api.js.tpl index d656d78ed..94085baa1 100644 --- a/server/resource/package/web/api/api.js.tpl +++ b/server/resource/package/web/api/api.js.tpl @@ -1,5 +1,6 @@ import service from '@/utils/request' +{{- if not .OnlyTemplate}} // @Tags {{.StructName}} // @Summary 创建{{.Description}} // @Security ApiKeyAuth @@ -110,4 +111,20 @@ export const get{{.StructName}}DataSource = () => { method: 'get', }) } -{{- end}} \ No newline at end of file +{{- 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', + }) +} diff --git a/server/resource/package/web/view/form.vue.tpl b/server/resource/package/web/view/form.vue.tpl index 92692dee5..a59d031ae 100644 --- a/server/resource/package/web/view/form.vue.tpl +++ b/server/resource/package/web/view/form.vue.tpl @@ -1,4 +1,5 @@ {{- $top := . -}} +{{- if not .OnlyTemplate }} {{- else if eq .FieldType "array" }} - + {{- else }} - + {{- end }} {{- end }} {{- end }} - - 查看详情 - 变更 - 删除 - + +
@@ -283,10 +286,10 @@ @@ -294,14 +297,14 @@ {{- range .Fields}} {{- if .Form}} - + {{- if .CheckDataSource}} {{- else }} {{- if eq .FieldType "bool" }} - + {{- end }} {{- if eq .FieldType "string" }} {{- if .DictType}} @@ -326,7 +329,7 @@ {{- end }} {{- if eq .FieldType "time.Time" }} - + {{- end }} {{- if eq .FieldType "float64" }} @@ -440,6 +443,11 @@ import ArrayCtrl from '@/components/arrayCtrl/arrayCtrl.vue' import { getDictFunc, formatDate, formatBoolean, filterDict ,filterDataSource, returnArrImg, onDownloadFile } from '@/utils/format' import { ElMessage, ElMessageBox } from 'element-plus' import { ref, reactive } from 'vue' + +import { useI18n } from 'vue-i18n' // added by mohamed hassan to support multilanguage +const i18n = useI18n() // added by mohamed hassan to support multilanguage +const { t } = useI18n() // added by mohamed hassan to support multilanguage + {{- if .AutoCreateBtnAuth }} // 引入按钮权限标识 import { useBtnAuth } from '@/utils/btnAuth' @@ -544,7 +552,7 @@ const rule = reactive({ {{- if eq .FieldType "string" }} { whitespace: true, - message: '不能只输入空格', + message: t('general.noOnlySpace'), trigger: ['input', 'blur'], } {{- end }} @@ -558,11 +566,11 @@ const searchRule = reactive({ createdAt: [ { validator: (rule, value, callback) => { if (searchInfo.value.startCreatedAt && !searchInfo.value.endCreatedAt) { - callback(new Error('请填写结束日期')) + callback(new Error(t('general.placeInputEndData'))) } else if (!searchInfo.value.startCreatedAt && searchInfo.value.endCreatedAt) { - callback(new Error('请填写开始日期')) + callback(new Error(t('general.placeInputStartData'))) } else if (searchInfo.value.startCreatedAt && searchInfo.value.endCreatedAt && (searchInfo.value.startCreatedAt.getTime() === searchInfo.value.endCreatedAt.getTime() || searchInfo.value.startCreatedAt.getTime() > searchInfo.value.endCreatedAt.getTime())) { - callback(new Error('开始日期应当早于结束日期')) + callback(new Error(t('general.startDataMustBeforeEndData'))) } else { callback() } @@ -573,11 +581,11 @@ const searchRule = reactive({ {{- if eq .FieldType "time.Time" }} {{.FieldJson }} : [{ validator: (rule, value, callback) => { if (searchInfo.value.start{{.FieldName}} && !searchInfo.value.end{{.FieldName}}) { - callback(new Error('请填写结束日期')) + callback(new Error(t('general.placeInputEndData'))) } else if (!searchInfo.value.start{{.FieldName}} && searchInfo.value.end{{.FieldName}}) { - callback(new Error('请填写开始日期')) + callback(new Error(t('general.placeInputStartData'))) } else if (searchInfo.value.start{{.FieldName}} && searchInfo.value.end{{.FieldName}} && (searchInfo.value.start{{.FieldName}}.getTime() === searchInfo.value.end{{.FieldName}}.getTime() || searchInfo.value.start{{.FieldName}}.getTime() > searchInfo.value.end{{.FieldName}}.getTime())) { - callback(new Error('开始日期应当早于结束日期')) + callback(new Error(t('general.startDataMustBeforeEndData'))) } else { callback() } @@ -690,9 +698,9 @@ const handleSelectionChange = (val) => { // 删除行 const deleteRow = (row) => { - ElMessageBox.confirm('确定要删除吗?', '提示', { - confirmButtonText: '确定', - cancelButtonText: '取消', + ElMessageBox.confirm(t('general.deleteConfirm'), t('general.hint'), { + confirmButtonText: t('general.confirm'), + cancelButtonText: t('general.cancel'), type: 'warning' }).then(() => { delete{{.StructName}}Func(row) @@ -701,16 +709,16 @@ const deleteRow = (row) => { // 多选删除 const onDelete = async() => { - ElMessageBox.confirm('确定要删除吗?', '提示', { - confirmButtonText: '确定', - cancelButtonText: '取消', + ElMessageBox.confirm(t('general.deleteConfirm'), t('general.hint'), { + confirmButtonText: t('general.confirm'), + cancelButtonText: t('general.cancel'), type: 'warning' }).then(async() => { const {{.PrimaryField.FieldJson}}s = [] if (multipleSelection.value.length === 0) { ElMessage({ type: 'warning', - message: '请选择要删除的数据' + message: t('general.selectDataToDelete') }) return } @@ -752,7 +760,7 @@ const delete{{.StructName}}Func = async (row) => { if (res.code === 0) { ElMessage({ type: 'success', - message: '删除成功' + message: t('general.deleteSuccess') }) if (tableData.value.length === 1 && page.value > 1) { page.value-- @@ -835,7 +843,7 @@ const enterDialog = async () => { if (res.code === 0) { ElMessage({ type: 'success', - message: '创建/更改成功' + message: t('general.createUpdateSuccess') }) closeDialog() getTableData() @@ -896,4 +904,16 @@ const closeDetailShow = () => { margin-bottom: 0; } {{end}} - \ No newline at end of file + +{{- else}} + + + +{{- end}} diff --git a/server/resource/plugin/server/api/api.go.template b/server/resource/plugin/server/api/api.go.template index fe618caf5..03321c74f 100644 --- a/server/resource/plugin/server/api/api.go.template +++ b/server/resource/plugin/server/api/api.go.template @@ -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) } diff --git a/server/resource/plugin/server/model/model.go.template b/server/resource/plugin/server/model/model.go.template index d496049af..153ab3ba1 100644 --- a/server/resource/plugin/server/model/model.go.template +++ b/server/resource/plugin/server/model/model.go.template @@ -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 }} diff --git a/server/resource/plugin/server/model/request/request.go.template b/server/resource/plugin/server/model/request/request.go.template index 8460695c5..cf2a56944 100644 --- a/server/resource/plugin/server/model/request/request.go.template +++ b/server/resource/plugin/server/model/request/request.go.template @@ -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}} } diff --git a/server/resource/plugin/server/router/router.go.template b/server/resource/plugin/server/router/router.go.template index 429f7bf12..cc5cd2677 100644 --- a/server/resource/plugin/server/router/router.go.template +++ b/server/resource/plugin/server/router/router.go.template @@ -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}} } diff --git a/server/resource/plugin/server/service/service.go.template b/server/resource/plugin/server/service/service.go.template index 94bc95d0d..96a027e69 100644 --- a/server/resource/plugin/server/service/service.go.template +++ b/server/resource/plugin/server/service/service.go.template @@ -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,16 +21,16 @@ type {{.Abbreviation}} struct {} {{- else}} {{- $db = printf "global.MustGetGlobalDBByDBName(\"%s\")" .BusinessDB }} {{- end}} - +{{- if not .OnlyTemplate }} // Create{{.StructName}} 创建{{.Description}}记录 -// Author [piexlmax](https://github.com/piexlmax) +// Author [yourname](https://github.com/yourname) func (s *{{.Abbreviation}}) Create{{.StructName}}({{.Abbreviation}} *model.{{.StructName}}) (err error) { err = {{$db}}.Create({{.Abbreviation}}).Error return err } // Delete{{.StructName}} 删除{{.Description}}记录 -// Author [piexlmax](https://github.com/piexlmax) +// Author [yourname](https://github.com/yourname) func (s *{{.Abbreviation}}) Delete{{.StructName}}({{.PrimaryField.FieldJson}} string{{- if .AutoCreateResource -}},userID uint{{- end -}}) (err error) { {{- if .AutoCreateResource }} err = {{$db}}.Transaction(func(tx *gorm.DB) error { @@ -47,7 +49,7 @@ func (s *{{.Abbreviation}}) Delete{{.StructName}}({{.PrimaryField.FieldJson}} st } // Delete{{.StructName}}ByIds 批量删除{{.Description}}记录 -// Author [piexlmax](https://github.com/piexlmax) +// Author [yourname](https://github.com/yourname) func (s *{{.Abbreviation}}) Delete{{.StructName}}ByIds({{.PrimaryField.FieldJson}}s []string {{- if .AutoCreateResource }},deleted_by uint{{- end}}) (err error) { {{- if .AutoCreateResource }} err = {{$db}}.Transaction(func(tx *gorm.DB) error { @@ -66,21 +68,21 @@ func (s *{{.Abbreviation}}) Delete{{.StructName}}ByIds({{.PrimaryField.FieldJson } // Update{{.StructName}} 更新{{.Description}}记录 -// Author [piexlmax](https://github.com/piexlmax) +// Author [yourname](https://github.com/yourname) func (s *{{.Abbreviation}}) Update{{.StructName}}({{.Abbreviation}} model.{{.StructName}}) (err error) { err = {{$db}}.Model(&model.{{.StructName}}{}).Where("{{.PrimaryField.ColumnName}} = ?",{{.Abbreviation}}.{{.PrimaryField.FieldName}}).Updates(&{{.Abbreviation}}).Error return err } // Get{{.StructName}} 根据{{.PrimaryField.FieldJson}}获取{{.Description}}记录 -// Author [piexlmax](https://github.com/piexlmax) +// Author [yourname](https://github.com/yourname) func (s *{{.Abbreviation}}) Get{{.StructName}}({{.PrimaryField.FieldJson}} string) ({{.Abbreviation}} model.{{.StructName}}, err error) { err = {{$db}}.Where("{{.PrimaryField.ColumnName}} = ?", {{.PrimaryField.FieldJson}}).First(&{{.Abbreviation}}).Error return } // Get{{.StructName}}InfoList 分页获取{{.Description}}记录 -// Author [piexlmax](https://github.com/piexlmax) +// Author [yourname](https://github.com/yourname) func (s *{{.Abbreviation}}) Get{{.StructName}}InfoList(info request.{{.StructName}}Search) (list []model.{{.StructName}}, total int64, err error) { limit := info.PageSize offset := info.PageSize * (info.Page - 1) @@ -153,3 +155,8 @@ func (s *{{.Abbreviation}})Get{{.StructName}}DataSource() (res map[string][]map[ return } {{- end }} +{{- end }} + +func (s *{{.Abbreviation}})Get{{.StructName}}Public() { + +} \ No newline at end of file diff --git a/server/resource/plugin/web/api/api.js.template b/server/resource/plugin/web/api/api.js.template index cf9d55305..208f386e4 100644 --- a/server/resource/plugin/web/api/api.js.template +++ b/server/resource/plugin/web/api/api.js.template @@ -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', + }) +} \ No newline at end of file diff --git a/server/resource/plugin/web/form/form.vue.template b/server/resource/plugin/web/form/form.vue.template index 9f896c509..dee365c5f 100644 --- a/server/resource/plugin/web/form/form.vue.template +++ b/server/resource/plugin/web/form/form.vue.template @@ -1,4 +1,5 @@ {{- $top := . -}} +{{- if not .OnlyTemplate}} {{- else if eq .FieldType "array" }} - + @@ -261,11 +263,11 @@ {{- end }} {{- end }} {{- end }} - + @@ -284,10 +286,10 @@ @@ -302,7 +304,7 @@ {{- else }} {{- if eq .FieldType "bool" }} - + {{- end }} {{- if eq .FieldType "string" }} {{- if .DictType}} @@ -327,7 +329,7 @@ {{- end }} {{- if eq .FieldType "time.Time" }} - + {{- end }} {{- if eq .FieldType "float64" }} @@ -372,7 +374,7 @@ {{- range .Fields}} {{- if .Desc }} - + {{- if and (ne .FieldType "picture" ) (ne .FieldType "pictures" ) (ne .FieldType "file" ) (ne .FieldType "array" ) }} {{"{{"}} detailFrom.{{.FieldJson}} {{"}}"}} {{- else }} @@ -460,6 +462,9 @@ import ImportExcel from '@/components/exportExcel/importExcel.vue' import ExportTemplate from '@/components/exportExcel/exportTemplate.vue' {{- end}} +import { useI18n } from 'vue-i18n' // added by mohamed hassan to support multilanguage +const i18n = useI18n() // added by mohamed hassan to support multilanguage +const { t } = useI18n() // added by mohamed hassan to support multilanguage defineOptions({ name: '{{.StructName}}' @@ -546,7 +551,7 @@ const rule = reactive({ {{- if eq .FieldType "string" }} { whitespace: true, - message: '不能只输入空格', + message: t('general.noOnlySpace'), trigger: ['input', 'blur'], } {{- end }} @@ -560,11 +565,11 @@ const searchRule = reactive({ createdAt: [ { validator: (rule, value, callback) => { if (searchInfo.value.startCreatedAt && !searchInfo.value.endCreatedAt) { - callback(new Error('请填写结束日期')) + callback(new Error(t('general.placeInputEndData'))) } else if (!searchInfo.value.startCreatedAt && searchInfo.value.endCreatedAt) { - callback(new Error('请填写开始日期')) + callback(new Error(t('general.placeInputStartData'))) } else if (searchInfo.value.startCreatedAt && searchInfo.value.endCreatedAt && (searchInfo.value.startCreatedAt.getTime() === searchInfo.value.endCreatedAt.getTime() || searchInfo.value.startCreatedAt.getTime() > searchInfo.value.endCreatedAt.getTime())) { - callback(new Error('开始日期应当早于结束日期')) + callback(new Error(t('general.startDataMustBeforeEndData'))) } else { callback() } @@ -575,11 +580,11 @@ const searchRule = reactive({ {{- if eq .FieldType "time.Time" }} {{.FieldJson }} : [{ validator: (rule, value, callback) => { if (searchInfo.value.start{{.FieldName}} && !searchInfo.value.end{{.FieldName}}) { - callback(new Error('请填写结束日期')) + callback(new Error(t('general.placeInputEndData'))) } else if (!searchInfo.value.start{{.FieldName}} && searchInfo.value.end{{.FieldName}}) { - callback(new Error('请填写开始日期')) + callback(new Error(t('general.placeInputStartData'))) } else if (searchInfo.value.start{{.FieldName}} && searchInfo.value.end{{.FieldName}} && (searchInfo.value.start{{.FieldName}}.getTime() === searchInfo.value.end{{.FieldName}}.getTime() || searchInfo.value.start{{.FieldName}}.getTime() > searchInfo.value.end{{.FieldName}}.getTime())) { - callback(new Error('开始日期应当早于结束日期')) + callback(new Error(t('general.startDataMustBeforeEndData'))) } else { callback() } @@ -692,9 +697,9 @@ const handleSelectionChange = (val) => { // 删除行 const deleteRow = (row) => { - ElMessageBox.confirm('确定要删除吗?', '提示', { - confirmButtonText: '确定', - cancelButtonText: '取消', + ElMessageBox.confirm(t('general.deleteConfirm'), t('general.hint'), { + confirmButtonText: t('general.confirm'), + cancelButtonText: t('general.cancel'), type: 'warning' }).then(() => { delete{{.StructName}}Func(row) @@ -703,16 +708,16 @@ const deleteRow = (row) => { // 多选删除 const onDelete = async() => { - ElMessageBox.confirm('确定要删除吗?', '提示', { - confirmButtonText: '确定', - cancelButtonText: '取消', + ElMessageBox.confirm(t('general.deleteConfirm'), t('general.hint'), { + confirmButtonText: t('general.confirm'), + cancelButtonText: t('general.cancel'), type: 'warning' }).then(async() => { const {{.PrimaryField.FieldJson}}s = [] if (multipleSelection.value.length === 0) { ElMessage({ type: 'warning', - message: '请选择要删除的数据' + message: t('general.selectDataToDelete') }) return } @@ -724,7 +729,7 @@ const onDelete = async() => { if (res.code === 0) { ElMessage({ type: 'success', - message: '删除成功' + message: t('general.deleteSuccess') }) if (tableData.value.length === {{.PrimaryField.FieldJson}}s.length && page.value > 1) { page.value-- @@ -754,7 +759,7 @@ const delete{{.StructName}}Func = async (row) => { if (res.code === 0) { ElMessage({ type: 'success', - message: '删除成功' + message: t('general.deleteSuccess') }) if (tableData.value.length === 1 && page.value > 1) { page.value-- @@ -837,7 +842,7 @@ const enterDialog = async () => { if (res.code === 0) { ElMessage({ type: 'success', - message: '创建/更改成功' + message: t('general.createUpdateSuccess') }) closeDialog() getTableData() @@ -900,3 +905,15 @@ const closeDetailShow = () => { } {{end}} +{{- else}} + + + +{{- end}} \ No newline at end of file diff --git a/server/router/example/exa_file_upload_and_download.go b/server/router/example/exa_file_upload_and_download.go index 19d983c31..84f6ecdb0 100644 --- a/server/router/example/exa_file_upload_and_download.go +++ b/server/router/example/exa_file_upload_and_download.go @@ -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 } } diff --git a/server/router/system/sys_user.go b/server/router/system/sys_user.go index 35fc741aa..6c14b8200 100644 --- a/server/router/system/sys_user.go +++ b/server/router/system/sys_user.go @@ -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) // 分页获取用户列表 diff --git a/server/service/example/exa_file_upload_download.go b/server/service/example/exa_file_upload_download.go index 15e2d70cb..85b7d3387 100644 --- a/server/service/example/exa_file_upload_download.go +++ b/server/service/example/exa_file_upload_download.go @@ -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 +} diff --git a/server/service/system/auto_code_history.go b/server/service/system/auto_code_history.go index 8d1ec4ba4..d9b74ef47 100644 --- a/server/service/system/auto_code_history.go +++ b/server/service/system/auto_code_history.go @@ -6,6 +6,7 @@ import ( "fmt" "github.com/flipped-aurora/gin-vue-admin/server/utils/ast" "github.com/pkg/errors" + "os" "path" "path/filepath" "strconv" @@ -17,7 +18,7 @@ import ( model "github.com/flipped-aurora/gin-vue-admin/server/model/system" request "github.com/flipped-aurora/gin-vue-admin/server/model/system/request" "github.com/flipped-aurora/gin-vue-admin/server/utils" - + "github.com/tidwall/sjson" "go.uber.org/zap" ) @@ -174,10 +175,46 @@ func (s *autoCodeHistory) RollBack(ctx context.Context, info request.SysAutoHist return errors.Wrapf(err, "[src:%s][dst:%s]文件移动失败!", value, removePath) } } // 移动文件 + err = global.GVA_DB.WithContext(ctx).Model(&model.SysAutoCodeHistory{}).Where("id = ?", info.ID).Update("flag", 1).Error if err != nil { return errors.Wrap(err, "更新失败!") } + + localPath := path.Join(global.GVA_CONFIG.AutoCode.Root, global.GVA_CONFIG.AutoCode.Server, "resource", "lang") + files, err := s.readJSONFiles(localPath) + if err != nil { + return err + } + if info.DeleteMenu { + for _, file := range files { + err := s.reWriteI18nJson(file, "menu", history.Package, history.StructName) + if err != nil { + return err + } + } + } + + if info.DeleteApi { + for _, file := range files { + err := s.reWriteI18nJson(file, "api", history.Package, history.StructName) + if err != nil { + return err + } + } + } + + localPath = path.Join(global.GVA_CONFIG.AutoCode.Root, global.GVA_CONFIG.AutoCode.Web, "locales") + files, err = s.readJSONFiles(localPath) + if err != nil { + return err + } + for _, file := range files { + err := s.reWriteI18nJson(file, "web", history.Package, history.StructName) + if err != nil { + return err + } + } return nil } @@ -215,3 +252,75 @@ func (s *autoCodeHistory) DropTable(BusinessDb, tableName string) error { return global.GVA_DB.Exec("DROP TABLE " + tableName).Error } } + +func (s *autoCodeHistory) readJSONFiles(dir string) ([]string, error) { + var files []string + err := filepath.Walk(dir, func(path string, info os.FileInfo, err error) error { + if err != nil { + return err + } + if !info.IsDir() && filepath.Ext(path) == ".json" { + files = append(files, path) + } + return nil + }) + if err != nil { + return nil, err + } + return files, nil +} + +func (s *autoCodeHistory) reWriteI18nJson(file string, flag string, packageName, structName string) error { + data, err := os.ReadFile(file) + if err != nil { + return err + } + originJson := string(data) + switch flag { + case "api": + var err error + originJson, err = sjson.Delete(originJson, fmt.Sprintf("system.api.group.%s%s", packageName, structName)) + if err != nil { + return err + } + originJson, err = sjson.Delete(originJson, fmt.Sprintf("system.api.desc.add%s%s", packageName, structName)) + if err != nil { + return err + } + originJson, err = sjson.Delete(originJson, fmt.Sprintf("system.api.desc.delete%s%s", packageName, structName)) + if err != nil { + return err + } + originJson, err = sjson.Delete(originJson, fmt.Sprintf("system.api.desc.batch%s%s", packageName, structName)) + if err != nil { + return err + } + originJson, err = sjson.Delete(originJson, fmt.Sprintf("system.api.desc.update%s%s", packageName, structName)) + if err != nil { + return err + } + originJson, err = sjson.Delete(originJson, fmt.Sprintf("system.api.desc.find%s%s", packageName, structName)) + if err != nil { + return err + } + originJson, err = sjson.Delete(originJson, fmt.Sprintf("system.api.desc.list%s%s", packageName, structName)) + if err != nil { + return err + } + case "menu": + originJson, err = sjson.Delete(originJson, fmt.Sprintf("system.menu.%s%s", packageName, structName)) + if err != nil { + return err + } + case "web": + originJson, err = sjson.Delete(originJson, fmt.Sprintf("%s.%s", packageName, structName)) + if err != nil { + return err + } + } + err = os.WriteFile(file, []byte(originJson), 0666) + if err != nil { + return err + } + return nil +} diff --git a/server/service/system/auto_code_template.go b/server/service/system/auto_code_template.go index 817a1505a..f0dd5f86a 100644 --- a/server/service/system/auto_code_template.go +++ b/server/service/system/auto_code_template.go @@ -87,7 +87,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 { @@ -130,7 +130,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: "批量删除"}, @@ -255,8 +255,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() @@ -284,28 +286,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 } diff --git a/server/service/system/sys_api.go b/server/service/system/sys_api.go index 5620ef635..02e9cae84 100644 --- a/server/service/system/sys_api.go +++ b/server/service/system/sys_api.go @@ -245,6 +245,10 @@ func (apiService *ApiService) GetAllApis(authorityID uint) (apis []system.SysApi } err = global.GVA_DB.Order("id desc").Find(&apis).Error if parentAuthorityID == 0 || !global.GVA_CONFIG.System.UseStrictAuth { + for i := range apis { + apis[i].Description = global.Translate(apis[i].Description) + apis[i].ApiGroup = global.Translate(apis[i].ApiGroup) + } return } paths := CasbinServiceApp.GetPolicyPathByAuthorityId(authorityID) @@ -253,6 +257,8 @@ func (apiService *ApiService) GetAllApis(authorityID uint) (apis []system.SysApi for i := range apis { for j := range paths { if paths[j].Path == apis[i].Path && paths[j].Method == apis[i].Method { + apis[i].Description = global.Translate(apis[i].Description) + apis[i].ApiGroup = global.Translate(apis[i].ApiGroup) authApis = append(authApis, apis[i]) } } diff --git a/server/service/system/sys_authority.go b/server/service/system/sys_authority.go index d064127d5..674a1fc4c 100644 --- a/server/service/system/sys_authority.go +++ b/server/service/system/sys_authority.go @@ -203,7 +203,9 @@ func (authorityService *AuthorityService) GetAuthorityInfoList(authorityID uint) } else { err = db.Preload("DataAuthorityId").Where("parent_id = ?", "0").Find(&authorities).Error } - + for i := range authorities { + authorities[i].AuthorityName = global.Translate(authorities[i].AuthorityName) + } for k := range authorities { err = authorityService.findChildrenAuthority(&authorities[k]) } diff --git a/server/service/system/sys_menu.go b/server/service/system/sys_menu.go index bcca109c7..4fff0a829 100644 --- a/server/service/system/sys_menu.go +++ b/server/service/system/sys_menu.go @@ -175,8 +175,11 @@ func (menuService *MenuService) getBaseMenuTreeMap(authorityID uint) (treeMap ma } err = db.Find(&allMenus).Error - for _, v := range allMenus { - treeMap[v.ParentId] = append(treeMap[v.ParentId], v) + + for i := range allMenus { + titleKey, params := getTitleAndRemainder(allMenus[i].Title) + allMenus[i].Title = global.Translate(titleKey) + params + treeMap[allMenus[i].ParentId] = append(treeMap[allMenus[i].ParentId], allMenus[i]) } return treeMap, err } diff --git a/server/service/system/sys_user.go b/server/service/system/sys_user.go index 0f47f6afe..96410f797 100644 --- a/server/service/system/sys_user.go +++ b/server/service/system/sys_user.go @@ -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 diff --git a/server/source/system/api.go b/server/source/system/api.go index 77406d2f7..99cf2012f 100644 --- a/server/source/system/api.go +++ b/server/source/system/api.go @@ -57,6 +57,7 @@ func (i *initApi) InitializeData(ctx context.Context) (context.Context, error) { {ApiGroup: "system.api.group.systemUser", Method: "POST", Path: "/user/changePassword", Description: "system.api.desc.changePassword"}, {ApiGroup: "system.api.group.systemUser", Method: "POST", Path: "/user/setUserAuthority", Description: "system.api.desc.modifyUserRole"}, {ApiGroup: "system.api.group.systemUser", Method: "POST", Path: "/user/resetPassword", Description: "system.api.desc.resetUserPassword"}, + {ApiGroup: "system.api.group.systemUser", Method: "PUT", Path: "/user/setSelfSetting", Description: "system.api.desc.resetUserWeb"}, {ApiGroup: "system.api.group.api", Method: "POST", Path: "/api/createApi", Description: "system.api.desc.createAPI"}, {ApiGroup: "system.api.group.api", Method: "POST", Path: "/api/deleteApi", Description: "system.api.desc.deleteAPI"}, @@ -99,6 +100,7 @@ func (i *initApi) InitializeData(ctx context.Context) (context.Context, error) { {ApiGroup: "system.api.group.fileUploadDownload", Method: "POST", Path: "/fileUploadAndDownload/deleteFile", Description: "system.api.desc.deleteFile"}, {ApiGroup: "system.api.group.fileUploadDownload", Method: "POST", Path: "/fileUploadAndDownload/editFileName", Description: "system.api.desc.editFileNameOrRemark"}, {ApiGroup: "system.api.group.fileUploadDownload", Method: "POST", Path: "/fileUploadAndDownload/getFileList", Description: "system.api.desc.getUploadFileList"}, + {ApiGroup: "system.api.group.fileUploadDownload", Method: "POST", Path: "/fileUploadAndDownload/importURL", Description: "system.api.desc.importURL"}, {ApiGroup: "system.api.group.systemService", Method: "POST", Path: "/system/getServerInfo", Description: "system.api.desc.getServerInfo"}, {ApiGroup: "system.api.group.systemService", Method: "POST", Path: "/system/getSystemConfig", Description: "system.api.desc.getConfigFileContent"}, diff --git a/server/source/system/casbin.go b/server/source/system/casbin.go index 92b83c1f0..bafd9ec12 100644 --- a/server/source/system/casbin.go +++ b/server/source/system/casbin.go @@ -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"}, diff --git a/server/utils/verify.go b/server/utils/verify.go index 59609079a..43a86725f 100644 --- a/server/utils/verify.go +++ b/server/utils/verify.go @@ -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()}} diff --git a/web/openDocument.js b/web/openDocument.js index a9e65554c..1693eeebd 100644 --- a/web/openDocument.js +++ b/web/openDocument.js @@ -7,7 +7,6 @@ var child_process = require('child_process') var url = 'https://www.gin-vue-admin.com' var cmd = '' -console.log(process.platform) switch (process.platform) { case 'win32': cmd = 'start' diff --git a/web/package.json b/web/package.json index aacbec819..3aa7aa2cb 100644 --- a/web/package.json +++ b/web/package.json @@ -1,6 +1,6 @@ { "name": "gin-vue-admin", - "version": "2.7.3", + "version": "2.7.4", "private": true, "scripts": { "serve": "node openDocument.js && vite --host --mode development", @@ -10,60 +10,62 @@ "fix-memory-limit": "cross-env LIMIT=4096 increase-memory-limit" }, "dependencies": { - "@element-plus/icons-vue": "^2.1.0", - "@vue-office/docx": "^1.3.0", - "@vue-office/excel": "^1.4.5", - "@vue-office/pdf": "^1.5.3", - "@vueuse/core": "^10.7.2", + "@element-plus/icons-vue": "^2.3.1", + "@vue-office/docx": "^1.6.2", + "@vue-office/excel": "^1.7.11", + "@vue-office/pdf": "^2.0.2", + "@vueuse/core": "^11.0.3", "@wangeditor/editor": "^5.1.23", "@wangeditor/editor-for-vue": "^5.1.12", - "axios": "^1.4.0", - "core-js": "^3.31.1", + "axios": "^1.7.7", + "chokidar": "^4.0.0", + "core-js": "^3.38.1", "default-passive-events": "^2.0.0", - "echarts": "5.4.3", - "element-plus": "^2.7.4", - "highlight.js": "^11.8.0", + "echarts": "5.5.1", + "element-plus": "^2.8.1", + "highlight.js": "^11.10.0", "js-cookie": "^3.0.5", - "marked": "4.3.0", + "marked": "14.1.1", + "marked-highlight": "^2.1.4", "mitt": "^3.0.1", "nprogress": "^0.2.0", "path": "^0.12.7", - "pinia": "^2.1.4", - "qs": "^6.11.2", + "pinia": "^2.2.2", + "qs": "^6.13.0", "screenfull": "^6.0.2", - "sortablejs": "^1.15.2", + "sortablejs": "^1.15.3", "spark-md5": "^3.0.2", - "tailwindcss": "^3.3.3", - "vite-auto-import-svg": "^1.0.0", - "vue": "^3.4.21", - "vue-echarts": "^6.7.2", - "vue-router": "^4.3.2", + "tailwindcss": "^3.4.10", + "vite-auto-import-svg": "^1.1.0", + "vue": "^3.5.7", + "vue-echarts": "^7.0.3", + "vue-router": "^4.4.3", "vuedraggable": "^4.1.0", "vue-i18n": "^9.4.1" }, "devDependencies": { - "@babel/eslint-parser": "^7.22.9", - "@vitejs/plugin-legacy": "^4.1.0", - "@vitejs/plugin-vue": "^4.2.3", + "@babel/eslint-parser": "^7.25.1", + "@vitejs/plugin-legacy": "^5.4.2", + "@vitejs/plugin-vue": "^5.1.3", "@vue/cli-plugin-babel": "~5.0.8", "@vue/cli-plugin-eslint": "~5.0.8", "@vue/cli-plugin-router": "~5.0.8", "@vue/cli-plugin-vuex": "~5.0.8", "@vue/cli-service": "~5.0.8", - "@vue/compiler-sfc": "^3.3.4", - "babel-plugin-import": "^1.13.6", - "chalk": "^4.1.2", - "dotenv": "^16.3.1", - "eslint": "^8.49.0", - "eslint-plugin-vue": "^9.15.1", - "sass": "^1.54.0", - "terser": "^5.19.1", - "unplugin-auto-import": "^0.16.6", - "unplugin-vue-components": "^0.25.1", - "vite": "^4.4.6", - "vite-plugin-banner": "^0.7.0", + "@vue/compiler-sfc": "^3.5.1", + "babel-plugin-import": "^1.13.8", + "chalk": "^5.3.0", + "dotenv": "^16.4.5", + "eslint": "^9.9.1", + "eslint-plugin-vue": "^9.28.0", + "sass": "^1.78.0", + "terser": "^5.31.6", + "unplugin-auto-import": "^0.18.2", + "unplugin-vue-components": "^0.27.4", + "vite": "^5.4.3", + "vite-plugin-banner": "^0.8.0", "vite-plugin-importer": "^0.2.5", - "vite-plugin-vue-devtools": "^7.3.7", + "vite-plugin-vue-devtools": "^7.4.4", "@intlify/unplugin-vue-i18n": "^1.2.0", "@intlify/vue-i18n-loader": "^4.2.0" } diff --git a/web/src/api/authority.js b/web/src/api/authority.js index 040127320..61b22067a 100644 --- a/web/src/api/authority.js +++ b/web/src/api/authority.js @@ -19,7 +19,7 @@ export const deleteAuthority = (data) => { return service({ url: '/authority/deleteAuthority', method: 'post', - data + data, }) } diff --git a/web/src/api/fileUploadAndDownload.js b/web/src/api/fileUploadAndDownload.js index 0a5d0211d..2bff5bb47 100644 --- a/web/src/api/fileUploadAndDownload.js +++ b/web/src/api/fileUploadAndDownload.js @@ -42,3 +42,16 @@ export const editFileName = (data) => { data }) } + +/** + * 导入URL + * @param data + * @returns {*} + */ +export const importURL = (data) => { + return service({ + url: '/fileUploadAndDownload/importURL', + method: 'post', + data + }) +} diff --git a/web/src/api/user.js b/web/src/api/user.js index f1f3638ab..2b357d031 100644 --- a/web/src/api/user.js +++ b/web/src/api/user.js @@ -126,6 +126,22 @@ export const setSelfInfo = (data) => { }) } +// @Tags SysUser +// @Summary 设置自身界面配置 +// @Security ApiKeyAuth +// @accept application/json +// @Produce application/json +// @Param data body model.SysUser true "设置自身界面配置" +// @Success 200 {string} string "{"success":true,"data":{},"msg":"修改成功"}" +// @Router /user/setSelfSetting [put] +export const setSelfSetting = (data) => { + return service({ + url: '/user/setSelfSetting', + method: 'put', + data: data + }) +} + // @Tags User // @Summary 设置用户权限 // @Security ApiKeyAuth diff --git a/web/src/components/upload/common.vue b/web/src/components/upload/common.vue index 39308060f..97255da11 100644 --- a/web/src/components/upload/common.vue +++ b/web/src/components/upload/common.vue @@ -6,6 +6,7 @@ :on-error="uploadError" :on-success="uploadSuccess" :show-file-list="false" + multiple class="upload-btn" > 普通上传 diff --git a/web/src/config.json b/web/src/config.json deleted file mode 100644 index 9dc37a14a..000000000 --- a/web/src/config.json +++ /dev/null @@ -1,10 +0,0 @@ -{"weakness":false, - "grey":false, - "primaryColor":"#3b82f6", - "showTabs":true, - "darkMode":"auto", - "layout_side_width":220, - "layout_side_collapsed_width":60, - "layout_side_item_height":44, - "show_watermark":false, - "side_mode":"normal"} diff --git a/web/src/core/config.js b/web/src/core/config.js index 836cde319..65c80f27d 100644 --- a/web/src/core/config.js +++ b/web/src/core/config.js @@ -1,7 +1,7 @@ /** * 网站配置文件 */ -import chalk from "chalk"; +const greenText = (text) => `\x1b[32m${text}\x1b[0m`; const config = { appName: 'Gin-Vue-Admin', @@ -12,72 +12,19 @@ const config = { export const viteLogo = (env) => { if (config.showViteLogo) { - const chalk = require('chalk') - console.log( - chalk.green( - `> 欢迎使用Gin-Vue-Admin,开源地址:https://github.com/flipped-aurora/gin-vue-admin` - ) - ) - console.log( - chalk.green( - `> 当前版本:v2.7.3` - ) - ) - console.log( - chalk.green( - `> 加群方式:微信:shouzi_1994 QQ群:470239250` - ) - ) - console.log( - chalk.green( - `> 项目地址:https://github.com/flipped-aurora/gin-vue-admin` - ) - ) - console.log( - chalk.green( - `> 插件市场:https://plugin.gin-vue-admin.com` - ) - ) - console.log( - chalk.green( - `> GVA讨论社区:https://support.qq.com/products/371961` - ) - ) - console.log( - chalk.green( - `> 默认自动化文档地址:http://127.0.0.1:${env.VITE_SERVER_PORT}/swagger/index.html` - ) - ) - console.log( - chalk.green( - `> 默认前端文件运行地址:http://127.0.0.1:${env.VITE_CLI_PORT}` - ) - ) - - console.log( - chalk.green( - `--------------------------------------版权声明--------------------------------------` - ) - ) - - console.log( - chalk.green( - `** 版权所有方:flipped-aurora开源团队 **` - ) - ) - - console.log( - chalk.green( - `** 版权持有公司:北京翻转极光科技有限责任公司 **` - ) - ) - - console.log( - chalk.green( - `** 剔除授权标识需购买商用授权:https://gin-vue-admin.com/empower/index.html **` - ) - ) - console.log('\n') + console.log(greenText(`> 欢迎使用Gin-Vue-Admin,开源地址:https://github.com/flipped-aurora/gin-vue-admin`)); + console.log(greenText(`> 当前版本:v2.7.4`)); + console.log(greenText(`> 加群方式:微信:shouzi_1994 QQ群:470239250`)); + console.log(greenText(`> 项目地址:https://github.com/flipped-aurora/gin-vue-admin`)); + console.log(greenText(`> 插件市场:https://plugin.gin-vue-admin.com`)); + console.log(greenText(`> GVA讨论社区:https://support.qq.com/products/371961`)); + console.log(greenText(`> 默认自动化文档地址:http://127.0.0.1:${env.VITE_SERVER_PORT}/swagger/index.html`)); + console.log(greenText(`> 默认前端文件运行地址:http://127.0.0.1:${env.VITE_CLI_PORT}`)); + console.log(greenText(`--------------------------------------版权声明--------------------------------------`)); + console.log(greenText(`** 版权所有方:flipped-aurora开源团队 **`)); + console.log(greenText(`** 版权持有公司:北京翻转极光科技有限责任公司 **`)); + console.log(greenText(`** 剔除授权标识需购买商用授权:https://gin-vue-admin.com/empower/index.html **`)); + console.log('\n'); } } diff --git a/web/src/core/gin-vue-admin.js b/web/src/core/gin-vue-admin.js index 2f2647a67..30b6318cb 100644 --- a/web/src/core/gin-vue-admin.js +++ b/web/src/core/gin-vue-admin.js @@ -10,7 +10,7 @@ export default { register(app) console.log(` 欢迎使用 Gin-Vue-Admin - 当前版本:v2.7.3 + 当前版本:v2.7.4 加群方式:微信:shouzi_1994 QQ群:622360840 项目地址:https://github.com/flipped-aurora/gin-vue-admin 插件市场:https://plugin.gin-vue-admin.com diff --git a/web/src/core/global.js b/web/src/core/global.js index db550b4aa..7a4cfa11e 100644 --- a/web/src/core/global.js +++ b/web/src/core/global.js @@ -16,20 +16,27 @@ const createIconComponent = (name) => ({ }) const registerIcons = async(app) => { - const iconModules = import.meta.glob('@/assets/icons/**/*.svg') - for (const path in iconModules) { + const iconModules = import.meta.glob('@/assets/icons/**/*.svg') // 系统目录 svg 图标 + const pluginIconModules = import.meta.glob('@/plugin/**/assets/icons/**/*.svg') // 插件目录 svg 图标 + const mergedIconModules = Object.assign({}, iconModules, pluginIconModules); // 合并所有 svg 图标 + for (const path in mergedIconModules) { + let pluginName = "" + if (path.startsWith("/src/plugin/")) { + pluginName = `${path.split('/')[3]}-` + } const iconName = path.split('/').pop().replace(/\.svg$/, '') // 如果iconName带空格则不加入到图标库中并且提示名称不合法 if (iconName.indexOf(' ') !== -1) { - console.error(`icon ${iconName}.svg includes whitespace`) + console.error(`icon ${iconName}.svg includes whitespace in ${path}`) continue } + const key = `${pluginName}${iconName}` const iconComponent = createIconComponent(iconName) config.logs.push({ - 'key': iconName, + 'key': key, 'label': iconName, }) - app.component(iconName, iconComponent) + app.component(key, iconComponent) } } diff --git a/web/src/locales/ar.json b/web/src/locales/ar.json index aca1d87f5..51b99ca9b 100644 --- a/web/src/locales/ar.json +++ b/web/src/locales/ar.json @@ -1,301 +1,338 @@ { - "api": { - "group": "مجموعة", - "setupSuccess": "تم إعداد api بنجاح!" - }, - "authority": { - "addRole": "أضف دورًا", - "authorityNote": "ملاحظة: يمكنك تبديل الأدوار عن طريق سحب الصورة الرمزية في الزاوية اليمنى العليا", - "copyRole": "نسخ الدور", - "editRole": "تحرير الدور", - "parentRole": "الدور الأساسي", - "positiveIntNote": "الرجاء إدخال عدد صحيح موجب", - "resourcePermissions": "أذونات الموارد", - "roleAPI": "دور API", - "roleConfig": "تكوين الدور", - "roleDeleteConfirm": "سيؤدي هذا الإجراء إلى حذف الدور نهائيا، هل تريد المتابعة؟", - "roleID": "معرف الدور", - "roleId0Error": "لا يمكن أن يكون معرف الحرف 0", - "roleIdNote": "الرجاء إدخال معرف الدور", - "roleMenu": "قائمة الدور", - "roleName": "اسم الدور", - "roleNameNote": "الرجاء إدخال اسم دور", - "roleSelectMethod": "الرجاء تحديد طريقة الطلب", - "rootRole": "دور الجذر", - "setPermissions": "تعيين الأذونات" - }, - "autoCode": { - "actionBar": "شريط الإجراءات:", - "addField": "إضافة حقل", - "autoAPIDBCreate": "إنشاء api التلقائي", - "autoAPIDBTip": "ملاحظة: تسجيل API التي تم إنشاؤها تلقائيا في قاعدة البيانات", - "autoMoveFiles": "نقل الملفات تلقائيا", - "autoMoveFilesTip": "ملاحظة: ترحيل الملفات التي تم إنشاؤها تلقائيا إلى الموقع المطابق لتكوين ymal", - "codeGenDownload": "تم إنشاء التعليمات البرمجية التنفيذ التلقائي بنجاح ويتم تحميل", - "codeGenMoveSuccess": "يتم إنشاء التعليمات البرمجية التنفيذ التلقائي بنجاح، و النقل التلقائي بنجاح", - "codePreview": "معاينة التعليمات البرمجية", - "columnName": "حقول قاعدة البيانات", - "comment": "", - "componentContent": "", - "confirmDelete": "", - "copy": "", - "createUsingTable": "Create using this table", - "dbName": "قاعدة البيانات", - "dictionary": "", - "entFileName": "", - "entStructAbbreviation": "", - "entStructDesc": "", - "entStructName": "", - "errNoFields": "", - "errSameFiledName": "", - "errSameStructDescAbbr": "", - "existDB": "إضغط هنا لإنشاء الكود من قاعدة بيانات موجوده", - "field": "", - "fieldDataType": "", - "fieldDesc": "", - "fieldIndex": "", - "fieldJson": "", - "fieldLen": "", - "fieldName": "", - "fileName": "", - "fileNameNote": "", - "generateCode": "", - "moveDown": "", - "moveUp": "", - "selectDB": "إختار قاعدة البيانات", - "selectTable": "إختار الجدول", - "structAbbreviation": "Struct abbreviation", - "structAbbreviationNote": "", - "structChineseName": "", - "structChineseNameNote": "", - "structName": "Struct Name", - "structNameNote": "The first letter is automatically converted to uppercase", - "table": "", - "tableName": "إسم الجدول", - "tableNameNote": "Specify the table name (not required)" - }, - "autoCodeAdmin": { - "deleteHistoryConfirm": "هذه العملية ستحذف هذا التاريخ، هل تريد المتابعة؟", - "notRolledBack": "لم يتراجع", - "reuse": "الارسال المتعدد", - "rollBack": "العوده", - "rollBackMark": "علامة الاستعادة", - "rollbackConfirm": "سيؤدي هذا الإجراء إلى حذف الملفات التي تم إنشاؤها تلقائيا و APIs، هل تريد المتابعة؟", - "rollbackSuccess": "نجاح الاستعادة", - "rolledBack": "التراجع" - }, - "datas": { - "datasNote": "يتم استخدام هذه الوظيفة فقط لإنشاء جدول علاقات many2many للأدوار والأدوار، ويجب أيضا دمج الاستخدام المحدد مع الجدول لتنفيذ العمل، للحصول على التفاصيل، راجع نموذج التعليمات البرمجية (مثال العميل)", - "resourceSetupSuccess": "تم إعداد المورد بنجاح", - "thisRole": "هذا الدور", - "thisRoleAndSubRoles": "هذا الدور و الأدوار الفرعية" - }, - "error": { - "message1": "وقد امتص الصفحة بعيدا من قبل قوى غامضة، يرجى الاتصال بنا لإصلاحه", - "message2": "المشكلة الشائعة هي أن القائمة لم يتم تعيين لوحة معلومات، يمكنك تعيين لوحة المعلومات بنفسك أو تعديل المسار الافتراضي" - }, - "fieldDialog": { - "associativeDictionary": "قواميس اقتران", - "autoFill": "التعبئة التلقائية", - "boolean": "منطقيه", - "dataTypeNote": "طول نوع قاعدة البيانات", - "entColumnName": "الرجاء إدخال حقل قاعدة البيانات", - "entFieldDataType": "الرجاء تحديد نوع بيانات الحقل", - "entFieldDesc": "الرجاء إدخال اسم الحقل الصيني", - "entFieldJson": "الرجاء إدخال json تنسيق الحقل", - "entFieldName": "الرجاء إدخال الاسم الإنجليزي للحقل", - "float": "نوع الفاصلة العائمة", - "integer": "", - "note": "", - "selectDataType": "", - "selectDictionary": "", - "selectSearchType": "", - "string": "", - "time": "" - }, - "general": { - "add": "إضافة", - "addSuccess": "تمت الإضافة بنجاح!", - "cancel": "إلغاء الأمر", - "close": "غلق", - "confirm": "تأكيد", - "copy": "نسخ", - "copySuccess": "تم النسخ بنجاح!", - "createdAt": "تاريخ الإنشاء", - "delete": "حذف", - "deleteSuccess": "نجاح الحذف!", - "edit": "تعديل", - "editSuccess": "تم التحرير بنجاح!", - "enable": "مفتوح", - "hint": "ملحوظة", - "langSwitch": "!!تم تغيير اللغة بنجاح", - "no": "لا", - "operations": "العمليات", - "pleaseSelect": "من فضلك إختار", - "searchCriteria": "معايير البحث", - "selectAll": "اختر الكل", - "setupSuccess": "تم الإعداد بنجاح!!", - "undeleted": "إلغاء الحذف", - "updateSuccess": "تم التحديث بنجاح!!", - "warning": "تحذير", - "yes": "نعم" - }, - "historyComponent": { - "closeAll": "إغلاق الكل", - "closeLeft": "إغلاق الجانب الأيسر", - "closeOther": "إغلاق أخرى", - "closeRight": "إغلاق الجانب الأيمن" - }, - "init": { - "beta": "تجريبي", - "confirm": "تأكيد", - "dbHost": "عنوان الخادم", - "dbName": "إسم قاعدة البيانات", - "dbPassword": "كلمة المرور", - "dbPort": "رقم المنفذ", - "dbType": "نوع قاعدة البيانات", - "dbUser": "إسم المستخدم", - "dbUsername": "اسم المستخدم", - "enterDBAddress": "الرجاء إدخال رابط قاعدة البيانات", - "enterDBHost": "أدخل عنوان خادم قاعدة البيانات", - "enterDBName": "أدخل إسم قاعدة البيانات", - "enterDBPassword": "أدخل كلمة مرور مستخدم قاعدة البيانات", - "enterDBPort": "أدخل رقم منفذ قاعدة البيانات", - "enterDBUser": "أدخل كلمة إسم مستخدم قاعدة البيانات", - "enterDBUsername": "", - "initNow": "بداء التهيئة", - "language": "", - "note": "تعليمات التهيئة", - "note1": "1.يجب ان تكون على دراية بإستخدام GoLang و Vue.", - "note2": "2.من فضلك تأكد من قرءاة ", - "note3": "3.Please confirm that you understand the subsequent configuration process.", - "note4": "4.", - "note5": "Note: The development team does not provide free services for the content written in the document.", - "pleaseWait": "جارى تهيئة قاعدة البيانات, من فضلك إنتظر", - "readDocs": "قرأة الإرشادات" - }, - "layout": { - "currentRole": "الدور الحالي:", - "loading": "جارى التحميل", - "logout": "تسجيل الخروج", - "personalInfo": "معلومات شخصية", - "switchTo": "التبديل إلى:" - }, - "login": { - "entPassword": "أدخل كلمة المرور", - "entUserName": "أدخل اسم المستخدم", - "entVerificationCode": "أدخل رمز التأكيد", - "errInit": "تم تهية قاعدة البيانات مسبقا، لاداعى للتهيئة مجددا", - "errLogin": "من فضلك ادخل بيانات دخول صحيحة", - "errPassword": "ادخل كلمة مرور صحيحة", - "errUserName": "ادخل اسم مستخدم صحيح", - "errVerificationCode": "رمز تأكيد خطاء", - "init": "التهيئة", - "language": "اللغات", - "login": "الدخول للنظام" - }, - "menus": { - "addMenu": "إضافة قائمة", - "addMenuParameters": "أضف معلمات القائمة", - "addParameter": "أضف معلمات", - "addRootMenu": "إضافة قائمة الجذر", - "addSubMenu": "إضافة قائمة فرعية", - "clickMe": "انقر فوق لي لضبط", - "closeTabNote": "ما إذا كان سيتم إغلاق علامة التبويب تلقائيًا", - "deleteAllRolesConfirm": "سيؤدي هذا الإجراء إلى حذف جميع الأدوار بشكل دائم ضمن هذه القائمة ، هل تريد المتابعة؟", - "displayName": "اسم العرض", - "editMenu": "عدل القائمة", - "enterFilePathNote": "الرجاء إدخال مسار الملف", - "enterMenuDisplayNameNote": "الرجاء إدخال اسم عرض القائمة", - "enterMenuNameNote": "الرجاء إدخال اسم القائمة", - "filePath": "مسار الملف", - "hide": "يخفي", - "icon": "أيقونة", - "keepAliveNote": "ما إذا كان KeepAlive يخزن الصفحات مؤقتًا أم لا", - "newMenuNote": "قائمة جديدة ، تحتاج إلى تكوين الأذونات في إدارة الأدوار لاستخدامها", - "parameterType": "نوع المعلمة", - "parameterValue": "قيمة المعلمة", - "paremeterKey": "مفتاح المعلمة", - "parent": "عقدة الأم", - "parentId": "معرف العقدة الأم", - "rootDirctory": "دليل الجذر", - "rootMenu": "القائمة الرئيسية", - "routeName": "اسم الطريق", - "routeNameNote": "اسم فريد باللغة الإنجليزية", - "routePath": "مسار الطريق", - "routePathNote": "يوصى بلصق المعلمات في الخلف فقط", - "show": "عرض", - "sort": "ترتيب", - "sortTags": "علامة الفرز", - "subMenuNote": "إذا كانت القائمة تحتوي على قوائم فرعية ، فقم بإنشاء صفحة توجيه ثانوية لعرض جهاز التوجيه أو", - "visibility": "سواء للاختباء", - "visibilityNote": "سواء للاختباء في القائمة", - "home": "", - "menuSetupSuccess": "", - "setAsHome": "", - "": "" - }, - "setting": { - "": "", - "businessBlack": "", - "simpleWhite": "" - }, - "system": { - "": "", - "envValues": "", - "multiLogin": "", - "ossType": "", - "portValue": "", - "systemConfig": "" - }, - "user": { - "addUser": "إضافة مستخدم", - "anotherUserEdit": "يوجد حاليا مستخدم تحرير", - "avatar": "الصورة الرمزية", - "deleteUserConfrim": "هل أنت متأكد أنك تريد حذف هذا المستخدم", - "email": "بريد", - "mediaLibrary": "اختر من مكتبة الوسائط", - "nickName": "اسم الشهرة", - "nickNameNote": "الرجاء إدخال اسم المستخدم المستعار", - "password": "كلمة المرور", - "passwordLenNote": "الحد الأدنى 6 أحرف", - "passwordNote": "الرجاء إدخال كلمة مرور المستخدم", - "phone": "رقم التليفون", - "resetPassword": "إعادة تعيين كلمة المرور", - "resetPasswordConfrim": "ما إذا كان سيتم إعادة تعيين كلمة مرور هذا المستخدم إلى 123456", - "roleSetNote": "تم تعيين الدور بنجاح", - "userAddedNote": "تم إنشاؤه بنجاح", - "userEditedNote": "تم تحريره بنجاح", - "userName": "اسم االمستخدم", - "userNameLenNote": "5 أحرف على الأقل", - "userNameNote": "الرجاء إدخال اسم المستخدم", - "userRole": "دور المستخدم", - "userRoleNote": "الرجاء تحديد دور المستخدم" - }, - "view": { - "dashboard": { - "about": "معلومات عنا", - "codeGen": "مولد الأكواد", - "dashboardCharts": { - "accesssTrends": "اتجاهات الوصول", - "month": "شهر" - }, - "dashboardTable": { - "changeLog": "سجل التغيير" - }, - "formCreator": "منشئ النموذج", - "instructionalUse": "تعليمات التشغيل:", - "menuManage": "إدارة القائمة", - "note": "مشمس اليوم، 0°C - 10°C، الطقس البارد، وإيلاء الاهتمام لإضافة الملابس.", - "pluginRepo": "مستودع البرنامج المساعد:", - "positiveRatings": "تقييمات إيجابية", - "quickEntry": "دخول سريع", - "roleManage": "إدارة الأدوار", - "statistics": "إحصائيات", - "title": "صباح الخير، أيها المشرف، من فضلك ابدأ اليوم", - "todaysTraffic": "حركة المرور اليوم", - "totalNumberOfUsers": "إجمالي عدد المستخدمين", - "userManage": "إدارةالمستخدم" - } - } + "api": { + "group": "مجموعة", + "setupSuccess": "تم إعداد api بنجاح!" + }, + "authority": { + "addRole": "أضف دورًا", + "authorityNote": "ملاحظة: يمكنك تبديل الأدوار عن طريق سحب الصورة الرمزية في الزاوية اليمنى العليا", + "copyRole": "نسخ الدور", + "editRole": "تحرير الدور", + "parentRole": "الدور الأساسي", + "positiveIntNote": "الرجاء إدخال عدد صحيح موجب", + "resourcePermissions": "أذونات الموارد", + "roleAPI": "دور API", + "roleConfig": "تكوين الدور", + "roleDeleteConfirm": "سيؤدي هذا الإجراء إلى حذف الدور نهائيا، هل تريد المتابعة؟", + "roleID": "معرف الدور", + "roleId0Error": "لا يمكن أن يكون معرف الحرف 0", + "roleIdNote": "الرجاء إدخال معرف الدور", + "roleMenu": "قائمة الدور", + "roleName": "اسم الدور", + "roleNameNote": "الرجاء إدخال اسم دور", + "roleSelectMethod": "الرجاء تحديد طريقة الطلب", + "rootRole": "الدور الجذري / الدور الحالي في الوضع الصارم", + "setPermissions": "تعيين الأذونات" + }, + "autoCode": { + "actionBar": "شريط الإجراءات:", + "addField": "إضافة حقل", + "autoAPIDBCreate": "إنشاء api التلقائي", + "autoAPIDBTip": "ملاحظة: تسجيل API التي تم إنشاؤها تلقائيا في قاعدة البيانات", + "autoMoveFiles": "نقل الملفات تلقائيا", + "autoMoveFilesTip": "ملاحظة: ترحيل الملفات التي تم إنشاؤها تلقائيا إلى الموقع المطابق لتكوين ymal", + "codeGenDownload": "تم إنشاء التعليمات البرمجية التنفيذ التلقائي بنجاح ويتم تحميل", + "codeGenMoveSuccess": "يتم إنشاء التعليمات البرمجية التنفيذ التلقائي بنجاح، و النقل التلقائي بنجاح", + "codePreview": "معاينة التعليمات البرمجية", + "columnName": "حقول قاعدة البيانات", + "comment": "وصف حقل قاعدة البيانات", + "componentContent": "محتوى المكون", + "confirmDelete": "هل أنت متأكد من الحذف؟", + "copy": "نسخ", + "createUsingTable": "استخدام هذا الجدول لإنشاء", + "dbName": "اسم قاعدة البيانات", + "dictionary": "قاموس", + "entFileName": "اسم الملف: sysXxxxXxxx", + "entStructAbbreviation": "يرجى إدخال اختصار الهيكل", + "entStructDesc": "يرجى إدخال وصف الهيكل", + "entStructName": "يرجى إدخال اسم الهيكل", + "errNoFields": "يرجى ملء حقل واحد على الأقل", + "errSameFiledName": "يوجد حقل بنفس اسم الهيكل", + "errSameStructDescAbbr": "لا يمكن أن يكون اسم الهيكل واختصاره متماثلين", + "existDB": "إضغط هنا لإنشاء الكود من قاعدة بيانات موجوده", + "field": "حقل", + "fieldDataType": "نوع البيانات", + "fieldDesc": "وصف الحقل", + "fieldIndex": "فهرس الحقل", + "fieldJson": "حقل JSON", + "fieldLen": "طول الحقل", + "fieldName": "اسم الحقل", + "fileName": "اسم الملف", + "fileNameNote": "اسم الملف الافتراضي (يوصى بتنسيق الجمل، الحرف الأول صغير، مثل sysXxxXxxx)", + "generateCode": "توليد الكود", + "moveDown": "تحريك لأسفل", + "moveUp": "تحريك لأعلى", + "selectDB": "إختار قاعدة البيانات", + "selectTable": "إختار الجدول", + "structAbbreviation": "اختصار الهيكل", + "structAbbreviationNote": "سيتم استخدام الاختصار كاسم كائن الإدخال ومجموعة التوجيه", + "structChineseName": "وصف الهيكل", + "structChineseNameNote": "يستخدم كالوصف التلقائي لواجهة برمجة التطبيقات", + "structName": "اسم الهيكل", + "structNameNote": "يتم تحويل الحرف الأول تلقائيًا إلى حرف كبير", + "table": "جدول", + "tableName": "إسم الجدول", + "tableNameNote": "حدد اسم الجدول (غير مطلوب)" + }, + "autoCodeAdmin": { + "deleteHistoryConfirm": "هذه العملية ستحذف هذا التاريخ، هل تريد المتابعة؟", + "notRolledBack": "لم يتراجع", + "reuse": "الارسال المتعدد", + "rollBack": "العوده", + "rollBackMark": "علامة الاستعادة", + "rollbackConfirm": "سيؤدي هذا الإجراء إلى حذف الملفات التي تم إنشاؤها تلقائيا و APIs، هل تريد المتابعة؟", + "rollbackSuccess": "نجاح الاستعادة", + "rolledBack": "التراجع" + }, + "datas": { + "datasNote": "يتم استخدام هذه الوظيفة فقط لإنشاء جدول علاقات many2many للأدوار والأدوار، ويجب أيضا دمج الاستخدام المحدد مع الجدول لتنفيذ العمل، للحصول على التفاصيل، راجع نموذج التعليمات البرمجية (مثال العميل)", + "resourceSetupSuccess": "تم إعداد المورد بنجاح", + "thisRole": "هذا الدور", + "thisRoleAndSubRoles": "هذا الدور و الأدوار الفرعية" + }, + "error": { + "message1": "وقد امتص الصفحة بعيدا من قبل قوى غامضة، يرجى الاتصال بنا لإصلاحه", + "message2": "المشكلة الشائعة هي أن القائمة لم يتم تعيين لوحة معلومات، يمكنك تعيين لوحة المعلومات بنفسك أو تعديل المسار الافتراضي" + }, + "fieldDialog": { + "associativeDictionary": "قواميس اقتران", + "autoFill": "التعبئة التلقائية", + "boolean": "منطقيه", + "dataTypeNote": "طول نوع قاعدة البيانات", + "entColumnName": "الرجاء إدخال حقل قاعدة البيانات", + "entFieldDataType": "الرجاء تحديد نوع بيانات الحقل", + "entFieldDesc": "الرجاء إدخال اسم الحقل الصيني", + "entFieldJson": "الرجاء إدخال json تنسيق الحقل", + "entFieldName": "الرجاء إدخال الاسم الإنجليزي للحقل", + "float": "نوع الفاصلة العائمة", + "integer": "عدد صحيح", + "note": "سيتم إنشاء id و created_at و updated_at و deleted_at تلقائيًا. يرجى عدم إنشائها بشكل مت��رر. إذا كانت الحالة LIKE عند البحث، فإن السلاسل فقط مدعومة", + "selectDataType": "يرجى اختيار نوع البيانات", + "selectDictionary": "يرجى اختيار القاموس", + "selectSearchType": "يرجى اختيار شرط البحث في الحقل", + "string": "نص", + "time": "وقت" + }, + "general": { + "add": "إضافة", + "addSuccess": "تمت الإضافة بنجاح!", + "back": "عودة", + "cancel": "إلغاء الأمر", + "change": "تغيير", + "close": "غلق", + "collapse": "طي", + "confirm": "تأكيد", + "copy": "نسخ", + "copySuccess": "تم النسخ بنجاح!", + "createDate": "تاريخ الإنشاء", + "createUpdateSuccess": "تم الإنشاء/التحديث بنجاح", + "createdAt": "تاريخ الإنشاء", + "delete": "حذف", + "deleteConfirm": "هل أنت متأكد أنك تريد الحذف؟", + "deleteSuccess": "نجاح الحذف!", + "desc": "عرض التفاصيل", + "description": "وصف", + "edit": "تعديل", + "editSuccess": "تم التحرير بنجاح!", + "enable": "مفتوح", + "endData": "تاريخ الانتهاء", + "expand": "توسيع", + "filter": "تصفية", + "hint": "ملحوظة", + "langSwitch": "!!تم تغيير اللغة بنجاح", + "max": "القيمة القصوى", + "min": "القيمة الدنيا", + "no": "لا", + "noOnlySpace": "لا يمكن إدخال مسافات فقط", + "operations": "العمليات", + "order": "علامة الترتيب", + "placeInputEndData": "يرجى إدخال تاريخ الانتهاء", + "placeInputStartData": "يرجى إدخال تاريخ البدء", + "pleaseEnter": "يرجى إدخال", + "pleaseSelect": "من فضلك إختار", + "popUpOperation": "عملية منبثقة", + "request": "طلب", + "reset": "إعادة تعيين", + "save": "حفظ", + "search": "بحث", + "searchCriteria": "معايير البحث", + "searchDesc": "نطاق البحث هو من تاريخ البدء (شامل) إلى تاريخ الانتهاء (غير شامل)", + "selectAll": "اختر الكل", + "selectData": "اختر التاريخ", + "selectDataToDelete": "يرجى اختيار البيانات المراد حذفها", + "selectDate": "اختر التاريخ", + "setupSuccess": "تم الإعداد بنجاح!!", + "startData": "تاريخ البدء", + "startDataMustBeforeEndData": "يجب أن يكون تاريخ البدء قبل تاريخ الانتهاء", + "undeleted": "إلغاء الحذف", + "updateSuccess": "تم التحديث بنجاح!!", + "warning": "تحذير", + "yes": "نعم" + }, + "historyComponent": { + "closeAll": "إغلاق الكل", + "closeLeft": "إغلاق الجانب الأيسر", + "closeOther": "إغلاق أخرى", + "closeRight": "إغلاق الجانب الأيمن" + }, + "init": { + "beta": "تجريبي", + "confirm": "تأكيد", + "dbHost": "عنوان الخادم", + "dbName": "إسم قاعدة البيانات", + "dbPassword": "كلمة المرور", + "dbPort": "رقم المنفذ", + "dbType": "نوع قاعدة البيانات", + "dbUser": "إسم المستخدم", + "dbUsername": "اسم المستخدم", + "enterDBAddress": "الرجاء إدخال رابط قاعدة البيانات", + "enterDBHost": "أدخل عنوان خادم قاعدة البيانات", + "enterDBName": "أدخل إسم قاعدة البيانات", + "enterDBPassword": "أدخل كلمة مرور مستخدم قاعدة البيانات", + "enterDBPort": "أدخل رقم منفذ قاعدة البيانات", + "enterDBUser": "أدخل كلمة إسم مستخدم قاعدة البيانات", + "enterDBUsername": "أدخل كلمة إسم مستخدم قاعدة البيانات", + "initNow": "بداء التهيئة", + "language": "لغة", + "note": "تعليمات التهيئة", + "note1": "1. يجب أن تكون على دراية بـ Vue و GoLang.", + "note2-1": "2. يرجى التأكد من أنك قد قرأت ", + "note2-2": " الوثائق الرسمية.", + "note2-3": "فيديو التهيئة", + "note3": "3. يرجى التأكد من أنك تفهم عملية التهيئة اللاحقة.", + "note4": "4. إذا كنت تستخدم قاعدة بيانات mysql، يرجى التأكد من أن محرك قاعدة البيانات هو ", + "note5": "ملاحظة: لا يقدم فريق التطوير خدمات مجانية للمحتوى المكتوب في الوثيقة.", + "pleaseWait": "جارى تهيئة قاعدة البيانات, من فضلك إنتظر", + "readDocs": "قرأة الإرشادات" + }, + "layout": { + "currentRole": "الدور الحالي:", + "loading": "جارى التحميل", + "logout": "تسجيل الخروج", + "personalInfo": "معلومات شخصية", + "switchTo": "التبديل إلى:" + }, + "login": { + "entPassword": "أدخل كلمة المرور", + "entUserName": "أدخل اسم المستخدم", + "entVerificationCode": "أدخل رمز التأكيد", + "errInit": "تم تهية قاعدة البيانات مسبقا، لاداعى للتهيئة مجددا", + "errLogin": "من فضلك ادخل بيانات دخول صحيحة", + "errPassword": "ادخل كلمة مرور صحيحة", + "errUserName": "ادخل اسم مستخدم صحيح", + "errVerificationCode": "رمز تأكيد خطاء", + "init": "التهيئة", + "language": "اللغات", + "login": "الدخول للنظام" + }, + "menu": { + "addButton": "إضافة زر قابل لل��حكم", + "addMenu": "إضافة قائمة", + "addMenuParameters": "إضافة معلمات القائمة", + "addParameter": "إضافة معلمات", + "addRootMenu": "إضافة قائمة جذرية", + "addSubMenu": "إضافة قائمة فرعية", + "basicPage": "هل هي صفحة أساسية؟", + "basicPageNote": "إذا اخترت نعم لهذا الخيار، فلن يتم عرض القائمة اليسرى والمعلومات العلوية.", + "buttonName": "اسم الزر", + "clickMe": "انقر لتعيين", + "closeTabNote": "ما إذا كان سيتم إغلاق علامة التبويب تلقائيًا", + "comments": "تعليقات", + "deleteAllRolesConfirm": "سيؤدي هذا الإجراء إلى حذف جميع الأدوار تحت هذه القائمة بشكل دائم، هل تريد المتابعة؟", + "displayName": "عرض I18NKey", + "editMenu": "تحرير القائمة", + "enterFilePathNote": "الرجاء إدخال مسار الملف", + "enterMenuDisplayNameNote": "الرجاء إدخال اسم عرض القائمة", + "enterMenuNameNote": "الرجاء إدخال اسم القائمة", + "filePath": "مسار الملف", + "filePathNote": "الصفحة: view/xxx/xx.vue المكون الإضافي: plugin/xx/xx.vue", + "hide": "إخفاء", + "highlightMenu": "تمييز القائمة", + "icon": "أيقونة", + "keepAliveNote": "ما إذا كان keepAlive يخزن الصفحات مؤقتًا", + "newMenuNote": "قائمة جديدة، تحتاج إلى تكوين الأذونات في إدارة الأدوار لاستخدامها", + "parameterType": "نوع المعلمة", + "parameterValue": "قيمة المعلمة", + "paremeterKey": "مفتاح المعلمة", + "parent": "الأصل", + "parentId": "معرف الأصل", + "rootDirctory": "الدليل الجذري", + "rootMenu": "القائمة الجذرية", + "routeName": "اسم المسار", + "routeNameNote": "سلسلة إنجليزية فريدة", + "routePath": "مسار المسار", + "routePathNote": "يوصى بربط المعلمات في النهاية فقط", + "show": "عرض", + "sort": "ترتيب", + "subMenuNote": "إذا كانت القائمة تحتوي على قوائم فرعية، فقم بإنشاء صفحة توجيه ثانوية أو", + "visibility": "الرؤية", + "visibilityNote": "ما إذا كان سيتم إخفاؤها في القائمة" + }, + "menus": { + "assignButton": "تعيين زر", + "home": "الصفحة الرئيسية", + "menuSetupSuccess": "تم إعداد القائمة بنجاح", + "setAsHome": "تعيين كصفحة رئيسية" + }, + "setting": { + "businessBlack": "الوضع الداكن", + "simpleWhite": "الوضع الفاتح" + }, + "system": { + "envValues": "قيم البيئة", + "multiLogin": "اعتراض تسجيل الدخول المتعدد", + "ossType": "نوع OSS", + "portValue": "قيمة المنفذ", + "systemConfig": "تكوين النظام" + }, + "user": { + "addUser": "إضافة مستخدم", + "anotherUserEdit": "يوجد حاليا مستخدم تحرير", + "avatar": "الصورة الرمزية", + "deleteUserConfrim": "هل أنت متأكد أنك تريد حذف هذا المستخدم", + "email": "بريد", + "mediaLibrary": "اختر من مكتبة الوسائط", + "nickName": "اسم الشهرة", + "nickNameNote": "الرجاء إدخال اسم المستخدم المستعار", + "password": "كلمة المرور", + "passwordLenNote": "الحد الأدنى 6 أحرف", + "passwordNote": "الرجاء إدخال كلمة مرور المستخدم", + "phone": "رقم التليفون", + "resetPassword": "إعادة تعيين كلمة المرور", + "resetPasswordConfrim": "ما إذا كان سيتم إعادة تعيين كلمة مرور هذا المستخدم إلى 123456", + "roleSetNote": "تم تعيين الدور بنجاح", + "userAddedNote": "تم إنشاؤه بنجاح", + "userEditedNote": "تم تحريره بنجاح", + "userName": "اسم االمستخدم", + "userNameLenNote": "5 أحرف على الأقل", + "userNameNote": "الرجاء إدخال اسم المستخدم", + "userRole": "دور المستخدم", + "userRoleNote": "الرجاء تحديد دور المستخدم" + }, + "view": { + "dashboard": { + "about": "معلومات عنا", + "codeGen": "مولد الأكواد", + "dashboardCharts": { + "accesssTrends": "اتجاهات الوصول", + "month": "شهر" + }, + "dashboardTable": { + "changeLog": "سجل التغيير" + }, + "formCreator": "منشئ النموذج", + "instructionalUse": "تعليمات التشغيل:", + "menuManage": "إدارة القائمة", + "note": "مشمس اليوم، 0°C - 10°C، الطقس البارد، وإيلاء الاهتمام لإضافة الملابس.", + "pluginRepo": "مستودع البرنامج المساعد:", + "positiveRatings": "تقييمات إيجابية", + "quickEntry": "دخول سريع", + "roleManage": "إدارة الأدوار", + "statistics": "إحصائيات", + "title": "صباح الخير، أيها المشرف، من فضلك ابدأ اليوم", + "todaysTraffic": "حركة المرور اليوم", + "totalNumberOfUsers": "إجمالي عدد المستخدمين", + "userManage": "إدارةالمستخدم" + } + } } diff --git a/web/src/locales/en.json b/web/src/locales/en.json index 5f0c96bff..33453f10e 100644 --- a/web/src/locales/en.json +++ b/web/src/locales/en.json @@ -52,25 +52,6 @@ "projectAddress": "Project Address:", "backToHome": "Back To Home" }, - "fieldDialog": { - "associativeDictionary": "Associative Dictionary", - "autoFill": "Auto Fill", - "boolean": "Boolean", - "dataTypeNote": "Data length", - "entColumnName": "Please enter the column name", - "entFieldDataType": "Please enter field datatype", - "entFieldDesc": "Please enter field description", - "entFieldJson": "Please enter field json name", - "entFieldName": "Please enter field name", - "float": "Float", - "integer": "Integer", - "note": "id, created_at, updated_at, deleted_at will be automatically generated. Please do not create it repeatedly. If the condition is LIKE when searching, only strings are supported", - "selectDataType": "Please select datatype", - "selectDictionary": "Please select dictionary", - "selectSearchType": "Please select field search condition", - "string": "String", - "time": "Time" - }, "general": { "add": "Add", "addSuccess": "Added successfully!", @@ -607,14 +588,22 @@ "buttonPermission" : "Create Button Permission", "createdByNote" : "Note: created_by updated_by deleted_by will be automatically added to the structure to facilitate user resource permission control.", "createResourceID" : "Create Resource ID", + "createResourceIDNote" : "Note: Using the basic template will not generate any structure and CURD. Only enter and other properties are configured to facilitate the development of non-CURD logic", + "basicTemplate" : "Basic Template", "addNewFields" : "Add New Fields", - "autoMoveFiles": "Automatically move files", - "autoMoveFilesTip": "Note: Automatically migrate the generated files to the corresponding location of the ymal configuration", - "codeGenDownload": "The automation code was created successfully and is being downloaded", - "codeGenMoveSuccess": "The automated code was created and moved successfully", - "codePreview": "Preview Code", - "columnName": "Column Name", - "comment": "Comment", + "autoMoveFiles" : "Automatically move files", + "autoMoveFilesTip" : "Note: Automatically migrate the generated files to the corresponding location of the ymal configuration", + "codeGenDownload" : "The automation code was created successfully and is being downloaded", + "codeGenMoveSuccess" : "The automated code was created and moved successfully", + "codePreview" : "Preview Code", + "columnName" : "Column Name", + "comment": "Comment", + "searchConditionNote" : "Please select the field search conditions", + "seniorEditor" : "Senior Editor", + "exportJSON" : "Export JSON", + "importJSON" : "Import JSON", + "clearTempStorage" : "Clear Temporary Storage", + "tempStorage" : "Temporary Storage", "componentContent": "Component Content", "confirmDelete": "Confirm to delete?", "copy": "Copy", @@ -636,6 +625,7 @@ "fieldDesc": "Description", "fieldIndex": "Id", "primaryKey" : "Primary Key", + "nonPrimaryKey" : "Non-primary key", "fieldJson": "Json Field", "fieldLen": "Length", "fieldName": "Field Name", @@ -650,6 +640,7 @@ "selectFieldType" : "Please select the field type", "indexType" : "Index Type", "selectIndexType" : "Please select the field index type", + "dbFieldLength" : "DB Field Length", "fileName": "File Name", "fileNameNote": "The default name of the generated file (camel case format is recommended, the first letter is lowercase, such as sysXxxXxxx)", "generateCode": "Generate Code", @@ -671,7 +662,68 @@ "selectTemplate" : "Select a template", "dbListNote2" : "Note: You need to go to db-list in advance to configure multiple databases. If this item is empty, the gva library will be used to create the automation code (global.GVA_DB). If it is filled in, the code of the specified library will be created (global.MustGetGlobalDBByDBName(dbname))", "globalModelNote" : "Note: The global.Model structure will automatically contain the primary key and soft delete related operation configurations", - "gvaStruct" : "Using the GVA structure" + "gvaStruct" : "Using the GVA structure", + "string": "String", + "richText" : "Rich Text", + "time": "Time", + "float": "Float", + "integer": "Integer", + "boolean": "Boolean", + "enum" : "Enumeration", + "singleImage" : "Single Image (string)", + "multipleImages" : "Multiple Images (json string)", + "video" : "Video (string)", + "file" : "File (json string)", + "arrays" : "Arrays", + "selectPackageNote" : "Please select package", + "useGVAStructNote" : "If you enable the GVA default structure, the ID, CreatedAt, UpdatedAt, and DeletedAt fields will be automatically added. This behavior will automatically clear the duplicate fields you have created below. Do you want to continue?", + "note" : "Note", + "primeryKeyError" : "You need to create at least one primary key to ensure the feasibility of the automation code", + "allFieldError" : "Please fill in all fields and submit", + "packageStructAbbreviationError" : "Package and structure abbreviation cannot have the same name", + "jsonImportedSuccessfully" : "JSON file imported successfully", + "invalidJsonDocumentError" : "Invalid JSON file", + "basicTemplateNote" : "Using the basic template will not generate any structure and CURD. Only enter and other properties will be configured to facilitate the development of non-CURD logic.", + "fieldDialog": { + "associativeDictionary": "Associative Dictionary", + "autoFill": "Auto Fill", + "dataTypeNote": "Data length", + "entColumnName": "Please enter the column name", + "entFieldDataType": "Please enter field datatype", + "entFieldDesc": "Please enter field description", + "entFieldJson": "Please enter field json name", + "entFieldName": "Please enter field name", + "note": "id, created_at, updated_at, deleted_at will be automatically generated. Please do not create it repeatedly. If the condition is LIKE when searching, only strings are supported", + "selectDataType": "Please select datatype", + "selectDictionary": "Please select dictionary", + "selectSearchType": "Please select field search condition", + "enumValue" : "Enumeration Values", + "typeLength" : "Type Length", + "enumExample" : "Example: 'Beijing', 'Tianjin'", + "dataTypeLength" : "Database Type Length", + "enterDefaultValueNote" : "Please enter a default value", + "frontendCreateEdit" :"Frontend Creation/Editing", + "frontendTableColmuns" : "Frontend Table Columns", + "frontendDetails" : "Frontend Details", + "sort" : "Sort", + "required" : "Required", + "canBeCleared" : "Can it be cleared?", + "hideSearch" : "Hide search conditions", + "verificationError" : "Verification failed", + "dataSourceConfigNote" : "Data source configuration (this configuration is advanced and may cause the automation code to be unavailable if the programming foundation is not solid)", + "associationMode" : "Association Mode", + "oneToOne" : "One To One", + "oneToMany" : "One To Many", + "selectDataSourceTable" : "Please select the data source table", + "selectDataToStore" : "Please select the data you want to store first", + "storage" : "Storage: ", + "type" : "Type:", + "fileDesc" : ",File Description: ", + "selectDataToDisplay" : "Please select the data you want to display first", + "display" : "Display: ", + "enumValueValidationError" : "Enumeration value validation error", + "oneToManyNote" : "In one-to-many association mode, the data type will change to array, and the backend will be represented as json, specifically in array mode. Do you want to continue?" + } }, "exportTemplate" : { "exportTemplateNote" : "This function provides synchronous table export function and asynchronous table export function for large data volume. You can choose to customize it.", diff --git a/web/src/locales/zh.json b/web/src/locales/zh.json index d21884ef3..a77fe910c 100644 --- a/web/src/locales/zh.json +++ b/web/src/locales/zh.json @@ -52,25 +52,6 @@ "projectAddress": "项目地址:", "backToHome": "返回首页" }, - "fieldDialog": { - "associativeDictionary": "关联字典", - "autoFill": "自动填充", - "boolean": "布尔值", - "dataTypeNote": "数据库类型长度", - "entColumnName": "请输入数据库字段", - "entFieldDataType": "请选择field数据类型", - "entFieldDesc": "请输入field短介绍", - "entFieldJson": "请输入field格式化json", - "entFieldName": "请输入field英文名", - "float": "浮点型", - "integer": "整型", - "note": "id , created_at , updated_at , deleted_at 会自动生成请勿重复创建。搜索时如果条件为LIKE只支持字符串", - "selectDataType": "请选择field数据类型", - "selectDictionary": "请选择字典", - "selectSearchType": "请选择Field查询条件", - "string": "字符串", - "time": "时间" - }, "general": { "add": "新增", "addSuccess": "添加成功!", @@ -607,6 +588,8 @@ "buttonPermission" : "创建按钮权限", "createdByNote" : "注:会自动在结构体添加 created_by updated_by deleted_by,方便用户进行资源权限控制", "createResourceID" : "创建资源标识", + "createResourceIDNote" : "注:使用基础模板将不会生成任何结构体和CURD,仅仅配置enter等属性方便自行开发非CURD逻辑", + "basicTemplate" : "基础模板", "addNewFields" : "新增字段", "autoMoveFiles": "自动移动文件", "autoMoveFilesTip": "注:自动迁移生成的文件到ymal配置的对应位置", @@ -614,7 +597,13 @@ "codeGenMoveSuccess": "自动化代码创建成功,自动移动成功", "codePreview": "预览代码", "columnName": "数据库字段", - "comment": "数据库字段描述", + "comment" : "数据库字段描述", + "searchConditionNote" : "请选择字段查询条件", + "seniorEditor" : "高级编辑", + "exportJSON" : "导出json", + "importJSON" : "导入json", + "clearTempStorage" : "清除暂存", + "tempStorage" : "暂存", "componentContent": "组件内容", "confirmDelete": "确定删除吗?", "copy": "复制", @@ -636,6 +625,7 @@ "fieldDesc": "中文名", "fieldIndex": "序列", "primaryKey" : "主键", + "nonPrimaryKey" : "非主键", "fieldJson": "FieldJson", "fieldLen": "数据库字段长度", "fieldName": "字段名称", @@ -650,6 +640,7 @@ "selectFieldType" : "请选择字段类型", "indexType" : "索引类型", "selectIndexType" : "请选择字段索引类型", + "dbFieldLength" : "数据库字段长度", "fileName": "文件名称", "fileNameNote": "生成文件的默认名称(建议为驼峰格式,首字母小写,如sysXxxXxxx)", "generateCode": "生成代码", @@ -671,7 +662,68 @@ "selectTemplate" : "选择模板", "dbListNote2" : "注:需要提前到db-list自行配置多数据库,此项为空则会使用gva本库创建自动化代码(global.GVA_DB),填写后则会创建指定库的代码(global.MustGetGlobalDBByDBName(dbname))", "globalModelNote" : "注:会自动在结构体global.Model其中包含主键和软删除相关操作配置", - "gvaStruct" : "使用GVA结构" + "gvaStruct" : "使用GVA结构", + "string" : "字符串", + "richText" : "富文本", + "time" : "时间", + "float" : "浮点型", + "integer" : "整型", + "boolean" : "布尔值", + "enum" : "枚举", + "singleImage" : "单图片(字符串)", + "multipleImages" : "多图片(json字符串)", + "video" : "视频(字符串)", + "file" : "文件(json字符串)", + "arrays" : "数组", + "selectPackageNote" : "请选择package", + "useGVAStructNote" : "如果您开启GVA默认结构,会自动添加ID,CreatedAt,UpdatedAt,DeletedAt字段,此行为将自动清除您目前在下方创建的重名字段,是否继续?", + "note" : "注意", + "primeryKeyError" : "您至少需要创建一个主键才能保证自动化代码的可行性", + "allFieldError" : "请填写所有字段类型后进行提交", + "packageStructAbbreviationError" : "package和结构体简称不可同名", + "jsonImportedSuccessfully" : "JSON 文件导入成功", + "invalidJsonDocumentError" : "无效的 JSON 文件", + "basicTemplateNote" : "使用基础模板将不会生成任何结构体和CURD,仅仅配置enter等属性方便自行开发非CURD逻辑", + "fieldDialog": { + "associativeDictionary": "关联字典", + "autoFill": "自动填充", + "dataTypeNote": "数据库类型长度", + "entColumnName": "请输入数据库字段", + "entFieldDataType": "请选择field数据类型", + "entFieldDesc": "请输入field短介绍", + "entFieldJson": "请输入field格式化json", + "entFieldName": "请输入field英文名", + "note": "id , created_at , updated_at , deleted_at 会自动生成请勿重复创建。搜索时如果条件为LIKE只支持字符串", + "selectDataType": "请选择field数据类型", + "selectDictionary": "请选择字典", + "selectSearchType": "请选择Field查询条件", + "enumValue" : "枚举值", + "typeLength" : "类型长度", + "enumExample" : "例:'北京','天津'", + "dataTypeLength" : "数据库类型长度", + "enterDefaultValueNote" : "请输入默认值", + "frontendCreateEdit" :"前端新建/编辑", + "frontendTableColmuns" : "前端表格列", + "frontendDetails" : "前端详情", + "sort" : "是否排序", + "required" : "是否必填", + "canBeCleared" : "是否可清空", + "hideSearch" : "隐藏查询条件", + "verificationError" : "校验失败文案", + "dataSourceConfigNote" : "数据源配置(此配置为高级配置,如编程基础不牢,可能导致自动化代码不可用)", + "associationMode" : "关联模式", + "oneToOne" : "一对一", + "oneToMany" : "一对多", + "selectDataSourceTable" : "请选择数据源表", + "selectDataToStore" : "请先选择需要存储的数据", + "storage" : "存储: ", + "type" : "类型:", + "fileDesc" : ",字段说明:", + "selectDataToDisplay" : "请先选择需要展示的数据", + "display" : "展示: ", + "enumValueValidationError" : "枚举值校验错误", + "oneToManyNote" : "一对多关联模式下,数据类型会改变为数组,后端表现为json,具体表现为数组模式,是否继续?" + } }, "exportTemplate" : { "exportTemplateNote" : "本功能提供同步的表格导出功能,大数据量的异步表格导出功能,可以选择点我定制", diff --git a/web/src/main.js b/web/src/main.js index 13c85f61e..10aa21d68 100644 --- a/web/src/main.js +++ b/web/src/main.js @@ -15,9 +15,9 @@ import run from '@/core/gin-vue-admin.js' import auth from '@/directive/auth' import { store } from '@/pinia' import App from './App.vue' +import i18n from './i18n' // added by mohamed hassan to multilangauge //消除警告 import 'default-passive-events' -import i18n from './i18n' // added by mohamed hassan to multilangauge const app = createApp(App) app.config.productionTip = false diff --git a/web/src/permission.js b/web/src/permission.js index 4938d401f..b0c39af51 100644 --- a/web/src/permission.js +++ b/web/src/permission.js @@ -85,7 +85,6 @@ router.beforeEach(async(to, from) => { } else { // 不在白名单中并且已经登录的时候 if (token) { - console.log(sessionStorage.getItem("needCloseAll")) if(sessionStorage.getItem("needToHome") === 'true') { sessionStorage.removeItem("needToHome") return { path: '/'} diff --git a/web/src/pinia/modules/app.js b/web/src/pinia/modules/app.js index ddeb7f7fa..91e222e72 100644 --- a/web/src/pinia/modules/app.js +++ b/web/src/pinia/modules/app.js @@ -1,49 +1,24 @@ import { defineStore } from 'pinia' import { ref, watchEffect, reactive } from 'vue' -import originSetting from "@/config.json" import { setBodyPrimaryColor } from '@/utils/format' export const useAppStore = defineStore('app', () => { - const theme = ref(localStorage.getItem('theme') || originSetting.darkMode || 'auto') + const device = ref("") const config = reactive({ weakness: false, grey: false, - primaryColor: '#79B6E7', + primaryColor: '#3b82f6', showTabs: true, - darkMode: 'light', + darkMode: 'auto', layout_side_width : 256, layout_side_collapsed_width : 80, layout_side_item_height : 48, - show_watermark: false, - + show_watermark: true, side_mode : 'normal' }) - // 初始化配置 - Object.keys(originSetting).forEach(key => { - config[key] = originSetting[key] - if(key === 'primaryColor'){ - setBodyPrimaryColor(originSetting[key],config.darkMode) - } - }) - - if (localStorage.getItem('darkMode')) { - config.darkMode = localStorage.getItem('darkMode') - } - - - watchEffect(() =>{ - if (theme.value === 'dark'){ - document.documentElement.classList.add('dark'); - document.documentElement.classList.remove('light'); - localStorage.setItem('theme', 'dark'); - }else{ - document.documentElement.classList.add('light'); - document.documentElement.classList.remove('dark'); - localStorage.setItem('theme', 'light'); - } - }) + const theme = ref( 'auto') const toggleTheme = (dark) => { if (dark) { @@ -55,25 +30,14 @@ export const useAppStore = defineStore('app', () => { const toggleWeakness = (e) => { config.weakness = e; - if(e) { - document.documentElement.classList.add('html-weakenss'); - }else{ - document.documentElement.classList.remove('html-weakenss'); - } } const toggleGrey = (e) => { config.grey = e; - if(e) { - document.documentElement.classList.add('html-grey'); - }else{ - document.documentElement.classList.remove('html-grey'); - } } const togglePrimaryColor = (e) => { config.primaryColor = e; - setBodyPrimaryColor(e,config.darkMode) } const toggleTabs = (e) => { @@ -86,12 +50,6 @@ export const useAppStore = defineStore('app', () => { const toggleDarkMode = (e) => { config.darkMode = e - localStorage.setItem('darkMode', e) - if(e === 'dark'){ - toggleTheme(true) - }else{ - toggleTheme(false) - } } const toggleDarkModeAuto = () =>{ @@ -124,11 +82,49 @@ export const useAppStore = defineStore('app', () => { config.side_mode = e } - if(config.darkMode === 'auto'){ - toggleDarkModeAuto() - } + watchEffect(() => { + if (theme.value === 'dark') { + document.documentElement.classList.add('dark'); + document.documentElement.classList.remove('light'); + } else { + document.documentElement.classList.add('light'); + document.documentElement.classList.remove('dark'); + } + }) + watchEffect(() => { + // 色弱模式监听处理 + if (config.weakness) { + document.documentElement.classList.add('html-weakenss'); + } else { + document.documentElement.classList.remove('html-weakenss'); + } + }) + watchEffect(() => { + // 灰色模式监听处理 + if (config.grey) { + document.documentElement.classList.add('html-grey'); + } else { + document.documentElement.classList.remove('html-grey'); + } + }) - toggleGrey(config.grey) + + + watchEffect(() => { + if(config.darkMode === 'auto'){ + toggleDarkModeAuto() + } + + if(config.darkMode === 'dark'){ + toggleTheme(true) + }else{ + toggleTheme(false) + } + }) + + watchEffect(() => { + setBodyPrimaryColor(config.primaryColor, theme.value) + }) return { theme, diff --git a/web/src/pinia/modules/router.js b/web/src/pinia/modules/router.js index 6859edbc9..a4bb9a45f 100644 --- a/web/src/pinia/modules/router.js +++ b/web/src/pinia/modules/router.js @@ -31,9 +31,7 @@ const KeepAliveFilter = (routes) => { routes && routes.forEach(item => { // 子菜单中有 keep-alive 的,父菜单也必须 keep-alive,否则无效。这里将子菜单中有 keep-alive 的父菜单也加入。 if ((item.children && item.children.some(ch => ch.meta.keepAlive) || item.meta.keepAlive)) { - const regex = /\(\) => import\("([^?]+)\??.*"\)/; - const match = String(item.component).match(regex); - const path = match ? match[1] : ""; + const path = item.meta.path keepAliveRoutersArr.push(pathInfo[path]) nameMap[item.name] = pathInfo[path] } diff --git a/web/src/pinia/modules/user.js b/web/src/pinia/modules/user.js index e20cfd6ea..d3cf53b78 100644 --- a/web/src/pinia/modules/user.js +++ b/web/src/pinia/modules/user.js @@ -7,7 +7,10 @@ import { ref, computed, watch } from 'vue' import { useRouterStore } from './router' import cookie from 'js-cookie' +import {useAppStore} from "@/pinia"; + export const useUserStore = defineStore('user', () => { + const appStore = useAppStore() const loadingInstance = ref(null) const userInfo = ref({ @@ -15,13 +18,16 @@ export const useUserStore = defineStore('user', () => { nickName: '', headerImg: '', authority: {}, - sideMode: 'dark', - baseColor: '#fff' }) const token = ref(window.localStorage.getItem('token') || cookie.get('x-token') || '') const language = ref(window.localStorage.getItem('language') || cookie.get('language') || 'en') // added by mohamed hassan to allow store selected language for multilanguage support. const setUserInfo = (val) => { userInfo.value = val + if(val.originSetting){ + Object.keys(appStore.config).forEach(key => { + appStore.config[key] = val.originSetting[key] + }) + } } const setToken = (val) => { @@ -38,10 +44,10 @@ export const useUserStore = defineStore('user', () => { return language.value } - const NeedInit = () => { + const NeedInit = async () => { token.value = '' window.localStorage.removeItem('token') - router.push({ name: 'Init', replace: true }) + await router.push({name: 'Init', replace: true}) } const ResetUserInfo = (value = {}) => { @@ -100,6 +106,7 @@ export const useUserStore = defineStore('user', () => { window.localStorage.setItem('osType', 'MAC') } + // 全部操作均结束,关闭loading并返回 loadingInstance.value.close() return true @@ -125,38 +132,8 @@ export const useUserStore = defineStore('user', () => { sessionStorage.clear() window.localStorage.removeItem('token') cookie.remove('x-token') + localStorage.removeItem('originSetting') } - /* 设置侧边栏模式*/ - const changeSideMode = async(data) => { - const res = await setSelfInfo({ sideMode: data }) - if (res.code === 0) { - userInfo.value.sideMode = data - ElMessage({ - type: 'success', - message: '设置成功' - }) - } - } - - const mode = computed(() => userInfo.value.sideMode) - const sideMode = computed(() => { - if (userInfo.value.sideMode === 'dark') { - return '#191a23' - } else if (userInfo.value.sideMode === 'light') { - return '#fff' - } else { - return userInfo.value.sideMode - } - }) - const baseColor = computed(() => { - if (userInfo.value.sideMode === 'dark') { - return '#fff' - } else if (userInfo.value.sideMode === 'light') { - return '#191a23' - } else { - return userInfo.value.baseColor - } - }) watch(() => token.value, () => { window.localStorage.setItem('token', token.value) @@ -173,11 +150,7 @@ export const useUserStore = defineStore('user', () => { LoginOut, setLanguage, // added by mohame hassan to allow store selected language for multilanguage support. getLanguage, // added by mohame hassan to allow store selected language for multilanguage support. - changeSideMode, - mode, - sideMode, setToken, - baseColor, loadingInstance, ClearStorage } diff --git a/web/src/utils/asyncRouter.js b/web/src/utils/asyncRouter.js index dfa62bbd1..26c3df0a0 100644 --- a/web/src/utils/asyncRouter.js +++ b/web/src/utils/asyncRouter.js @@ -4,6 +4,7 @@ const pluginModules = import.meta.glob('../plugin/**/*.vue') export const asyncRouterHandle = (asyncRouter) => { asyncRouter.forEach(item => { if (item.component && typeof item.component === 'string') { + item.meta.path = "/src/"+item.component if (item.component.split('/')[0] === 'view') { item.component = dynamicImport(viewModules, item.component) } else if (item.component.split('/')[0] === 'plugin') { diff --git a/web/src/utils/format.js b/web/src/utils/format.js index 2e7d183a0..8186e010c 100644 --- a/web/src/utils/format.js +++ b/web/src/utils/format.js @@ -103,7 +103,7 @@ function addOpacityToColor(u, opacity) { } -export const setBodyPrimaryColor = ( primaryColor, darkMode ) =>{ +export const setBodyPrimaryColor = (primaryColor, darkMode) =>{ let fmtColorFunc = generateAllColors if (darkMode === 'light') { @@ -126,4 +126,16 @@ const baseUrl = ref(import.meta.env.VITE_BASE_API) export const getBaseUrl = () => { return baseUrl.value === "/" ? "" : baseUrl.value -} \ No newline at end of file +} + +export const CreateUUID = () => { + let d = new Date().getTime() + if (window.performance && typeof window.performance.now === 'function') { + d += performance.now() + } + return '00000000-0000-0000-0000-000000000000'.replace(/0/g, (c) => { + const r = (d + Math.random() * 16) % 16 | 0 // d是随机种子 + d = Math.floor(d / 16) + return (c === '0' ? r : (r & 0x3 | 0x8)).toString(16) + }) +} diff --git a/web/src/view/example/upload/upload.vue b/web/src/view/example/upload/upload.vue index c32a621ad..ffa07ac71 100644 --- a/web/src/view/example/upload/upload.vue +++ b/web/src/view/example/upload/upload.vue @@ -15,9 +15,16 @@ :max-w-h="1080" @on-success="getTableData" /> + + 导入URL + diff --git a/web/src/view/init/index.vue b/web/src/view/init/index.vue index 7651c3034..419fd9ec2 100644 --- a/web/src/view/init/index.vue +++ b/web/src/view/init/index.vue @@ -195,6 +195,7 @@ const goDoc = () => { const out = ref(false) const form = reactive({ + adminPassword: '123456', dbType: 'mysql', host: '127.0.0.1', port: '3306', @@ -209,7 +210,7 @@ const changeDB = (val) => { switch (val) { case 'mysql': Object.assign(form, { - adminPassword:'', + adminPassword:'123456', reAdminPassword:'', dbType: 'mysql', host: '127.0.0.1', @@ -222,8 +223,7 @@ const changeDB = (val) => { break case 'pgsql': Object.assign(form, { - adminPassword:'', - reAdminPassword:'', + adminPassword:'123456', dbType: 'pgsql', host: '127.0.0.1', port: '5432', @@ -235,8 +235,7 @@ const changeDB = (val) => { break case 'oracle': Object.assign(form, { - adminPassword:'', - reAdminPassword:'', + adminPassword:'123456', dbType: 'oracle', host: '127.0.0.1', port: '1521', @@ -248,8 +247,7 @@ const changeDB = (val) => { break case 'mssql': Object.assign(form, { - adminPassword:'', - reAdminPassword:'', + adminPassword:'123456', dbType: 'mssql', host: '127.0.0.1', port: '1433', @@ -261,8 +259,7 @@ const changeDB = (val) => { break case 'sqlite': Object.assign(form, { - adminPassword:'', - reAdminPassword:'', + adminPassword:'123456', dbType: 'sqlite', host: '', port: '', @@ -274,8 +271,7 @@ const changeDB = (val) => { break default: Object.assign(form, { - adminPassword:'', - reAdminPassword:'', + adminPassword:'123456', dbType: 'mysql', host: '127.0.0.1', port: '3306', diff --git a/web/src/view/layout/header/index.vue b/web/src/view/layout/header/index.vue index ad33b0663..4a07c816d 100644 --- a/web/src/view/layout/header/index.vue +++ b/web/src/view/layout/header/index.vue @@ -4,7 +4,7 @@ !-->