diff --git a/src/modules/common/controller/account.go b/src/modules/common/controller/account.go index 07831e8c..15eeeef3 100644 --- a/src/modules/common/controller/account.go +++ b/src/modules/common/controller/account.go @@ -4,8 +4,10 @@ import ( "ems.agt/src/framework/config" commonConstants "ems.agt/src/framework/constants/common" tokenConstants "ems.agt/src/framework/constants/token" - ctxUtils "ems.agt/src/framework/utils/ctx" + "ems.agt/src/framework/i18n" + "ems.agt/src/framework/utils/ctx" tokenUtils "ems.agt/src/framework/utils/token" + "ems.agt/src/framework/vo" "ems.agt/src/framework/vo/result" libAccount "ems.agt/src/lib_features/account" commonModel "ems.agt/src/modules/common/model" @@ -34,15 +36,16 @@ type AccountController struct { // // POST /login func (s *AccountController) Login(c *gin.Context) { + language := ctx.AcceptLanguage(c) var loginBody commonModel.LoginBody if err := c.ShouldBindJSON(&loginBody); err != nil { - c.JSON(400, result.CodeMsg(400, "parameter error")) + c.JSON(400, result.CodeMsg(400, i18n.TKey(language, "app.common.err400"))) return } // 当前请求信息 - ipaddr, location := ctxUtils.IPAddrLocation(c) - os, browser := ctxUtils.UaOsBrowser(c) + ipaddr, location := ctx.IPAddrLocation(c) + os, browser := ctx.UaOsBrowser(c) // 校验验证码 err := s.accountService.ValidateCaptcha( @@ -51,19 +54,19 @@ func (s *AccountController) Login(c *gin.Context) { ) // 根据错误信息,创建系统访问记录 if err != nil { - msg := err.Error() + " " + loginBody.Code + msg := i18n.TKey(language, err.Error()) s.sysLogLoginService.CreateSysLogLogin( - loginBody.Username, commonConstants.STATUS_NO, msg, + loginBody.Username, commonConstants.STATUS_NO, msg+loginBody.Code, ipaddr, location, os, browser, ) - c.JSON(200, result.ErrMsg(err.Error())) + c.JSON(200, result.ErrMsg(msg)) return } // 登录用户信息 loginUser, err := s.accountService.LoginByUsername(loginBody.Username, loginBody.Password) if err != nil { - c.JSON(200, result.ErrMsg(err.Error())) + c.JSON(200, result.ErrMsg(i18n.TKey(language, err.Error()))) return } @@ -75,8 +78,9 @@ func (s *AccountController) Login(c *gin.Context) { } else { s.accountService.UpdateLoginDateAndIP(&loginUser) // 登录成功 + msg := i18n.TKey(language, "app.common.loginSuccess") s.sysLogLoginService.CreateSysLogLogin( - loginBody.Username, commonConstants.STATUS_YES, "Login Successful", + loginBody.Username, commonConstants.STATUS_YES, msg, ipaddr, location, os, browser, ) } @@ -93,9 +97,10 @@ func (s *AccountController) Login(c *gin.Context) { // // GET /getInfo func (s *AccountController) Info(c *gin.Context) { - loginUser, err := ctxUtils.LoginUser(c) + language := ctx.AcceptLanguage(c) + loginUser, err := ctx.LoginUser(c) if err != nil { - c.JSON(401, result.CodeMsg(401, err.Error())) + c.JSON(401, result.CodeMsg(401, i18n.TKey(language, err.Error()))) return } @@ -103,6 +108,12 @@ func (s *AccountController) Info(c *gin.Context) { isAdmin := config.IsAdmin(loginUser.UserID) roles, perms := s.accountService.RoleAndMenuPerms(loginUser.UserID, isAdmin) + loginUser.User.NickName = i18n.TKey(language, loginUser.User.NickName) + loginUser.User.Remark = i18n.TKey(language, loginUser.User.Remark) + loginUser.User.Dept.DeptName = i18n.TKey(language, loginUser.User.Dept.DeptName) + for ri := range loginUser.User.Roles { + loginUser.User.Roles[ri].RoleName = i18n.TKey(language, loginUser.User.Roles[ri].RoleName) + } c.JSON(200, result.OkData(map[string]any{ "user": loginUser.User, "roles": roles, @@ -114,11 +125,25 @@ func (s *AccountController) Info(c *gin.Context) { // // GET /getRouters func (s *AccountController) Router(c *gin.Context) { - userID := ctxUtils.LoginUserToUserID(c) + userID := ctx.LoginUserToUserID(c) // 前端路由,管理员拥有所有 isAdmin := config.IsAdmin(userID) buildMenus := s.accountService.RouteMenus(userID, isAdmin) + + // 闭包函数处理多语言 + language := ctx.AcceptLanguage(c) + var converI18n func(language string, arr *[]vo.Router) + converI18n = func(language string, arr *[]vo.Router) { + for i := range *arr { + (*arr)[i].Meta.Title = i18n.TKey(language, (*arr)[i].Meta.Title) + if len((*arr)[i].Children) > 0 { + converI18n(language, &(*arr)[i].Children) + } + } + } + converI18n(language, &buildMenus) + c.JSON(200, result.OkData(buildMenus)) } @@ -126,21 +151,25 @@ func (s *AccountController) Router(c *gin.Context) { // // POST /logout func (s *AccountController) Logout(c *gin.Context) { - tokenStr := ctxUtils.Authorization(c) + language := ctx.AcceptLanguage(c) + msg := i18n.TKey(language, "app.common.logoutSuccess") + tokenStr := ctx.Authorization(c) if tokenStr != "" { // 存在token时记录退出信息 userName := tokenUtils.Remove(tokenStr) if userName != "" { // 当前请求信息 - ipaddr, location := ctxUtils.IPAddrLocation(c) - os, browser := ctxUtils.UaOsBrowser(c) + ipaddr, location := ctx.IPAddrLocation(c) + os, browser := ctx.UaOsBrowser(c) + // 创建系统访问记录 退出成功 + s.sysLogLoginService.CreateSysLogLogin( - userName, commonConstants.STATUS_YES, "Exit successful", + userName, commonConstants.STATUS_YES, msg, ipaddr, location, os, browser, ) } } - c.JSON(200, result.OkMsg("Exit successful")) + c.JSON(200, result.OkMsg(msg)) } diff --git a/src/modules/common/controller/common.go b/src/modules/common/controller/common.go index 3ce08516..4ba37768 100644 --- a/src/modules/common/controller/common.go +++ b/src/modules/common/controller/common.go @@ -57,5 +57,15 @@ func (s *CommontController) I18n(c *gin.Context) { // GET /sys-conf func (s *CommontController) SysConfig(c *gin.Context) { data := s.commontService.SystemConfigInfo() + + // 闭包函数处理多语言 + language := ctx.AcceptLanguage(c) + converI18n := func(language string, arr *map[string]string) { + for k, v := range *arr { + (*arr)[k] = i18n.TKey(language, v) + } + } + converI18n(language, &data) + c.JSON(200, result.OkData(data)) } diff --git a/src/modules/common/controller/file.go b/src/modules/common/controller/file.go index c160867b..352fee79 100644 --- a/src/modules/common/controller/file.go +++ b/src/modules/common/controller/file.go @@ -7,6 +7,8 @@ import ( "strings" "ems.agt/src/framework/constants/uploadsubpath" + "ems.agt/src/framework/i18n" + "ems.agt/src/framework/utils/ctx" "ems.agt/src/framework/utils/file" "ems.agt/src/framework/vo/result" @@ -25,9 +27,10 @@ type FileController struct{} // // GET /download/:filePath func (s *FileController) Download(c *gin.Context) { + language := ctx.AcceptLanguage(c) filePath := c.Param("filePath") if len(filePath) < 8 { - c.JSON(400, result.CodeMsg(400, "parameter error")) + c.JSON(400, result.CodeMsg(400, i18n.TKey(language, "app.common.err400"))) return } // base64解析出地址 @@ -68,16 +71,17 @@ func (s *FileController) Download(c *gin.Context) { // // POST /upload func (s *FileController) Upload(c *gin.Context) { + language := ctx.AcceptLanguage(c) // 上传的文件 formFile, err := c.FormFile("file") if err != nil { - c.JSON(400, result.CodeMsg(400, "parameter error")) + c.JSON(400, result.CodeMsg(400, i18n.TKey(language, "app.common.err400"))) return } // 子路径 subPath := c.PostForm("subPath") if _, ok := uploadsubpath.UploadSubpath[subPath]; !ok { - c.JSON(400, result.CodeMsg(400, "parameter error")) + c.JSON(400, result.CodeMsg(400, i18n.TKey(language, "app.common.err400"))) return } @@ -101,6 +105,7 @@ func (s *FileController) Upload(c *gin.Context) { // // POST /chunkCheck func (s *FileController) ChunkCheck(c *gin.Context) { + language := ctx.AcceptLanguage(c) var body struct { // 唯一标识 Identifier string `json:"identifier" binding:"required"` @@ -109,7 +114,7 @@ func (s *FileController) ChunkCheck(c *gin.Context) { } err := c.ShouldBindJSON(&body) if err != nil { - c.JSON(400, result.CodeMsg(400, "parameter error")) + c.JSON(400, result.CodeMsg(400, i18n.TKey(language, "app.common.err400"))) return } @@ -126,6 +131,7 @@ func (s *FileController) ChunkCheck(c *gin.Context) { // // POST /chunkMerge func (s *FileController) ChunkMerge(c *gin.Context) { + language := ctx.AcceptLanguage(c) var body struct { // 唯一标识 Identifier string `json:"identifier" binding:"required"` @@ -136,11 +142,11 @@ func (s *FileController) ChunkMerge(c *gin.Context) { } err := c.ShouldBindJSON(&body) if err != nil { - c.JSON(400, result.CodeMsg(400, "parameter error")) + c.JSON(400, result.CodeMsg(400, i18n.TKey(language, "app.common.err400"))) return } if _, ok := uploadsubpath.UploadSubpath[body.SubPath]; !ok { - c.JSON(400, result.CodeMsg(400, "parameter error")) + c.JSON(400, result.CodeMsg(400, i18n.TKey(language, "app.common.err400"))) return } @@ -164,6 +170,7 @@ func (s *FileController) ChunkMerge(c *gin.Context) { // // POST /chunkUpload func (s *FileController) ChunkUpload(c *gin.Context) { + language := ctx.AcceptLanguage(c) // 切片编号 index := c.PostForm("index") // 切片唯一标识 @@ -171,7 +178,7 @@ func (s *FileController) ChunkUpload(c *gin.Context) { // 上传的文件 formFile, err := c.FormFile("file") if index == "" || identifier == "" || err != nil { - c.JSON(400, result.CodeMsg(400, "parameter error")) + c.JSON(400, result.CodeMsg(400, i18n.TKey(language, "app.common.err400"))) return } diff --git a/src/modules/common/controller/register.go b/src/modules/common/controller/register.go index 97526d0d..484a47fe 100644 --- a/src/modules/common/controller/register.go +++ b/src/modules/common/controller/register.go @@ -2,7 +2,8 @@ package controller import ( commonConstants "ems.agt/src/framework/constants/common" - ctxUtils "ems.agt/src/framework/utils/ctx" + "ems.agt/src/framework/i18n" + "ems.agt/src/framework/utils/ctx" "ems.agt/src/framework/utils/regular" "ems.agt/src/framework/vo/result" commonModel "ems.agt/src/modules/common/model" @@ -32,32 +33,33 @@ type RegisterController struct { // // GET /register func (s *RegisterController) Register(c *gin.Context) { + language := ctx.AcceptLanguage(c) var registerBody commonModel.RegisterBody if err := c.ShouldBindJSON(®isterBody); err != nil { - c.JSON(400, result.ErrMsg("parameter error")) + c.JSON(400, result.CodeMsg(400, i18n.TKey(language, "app.common.err400"))) return } // 判断必传参数 if !regular.ValidUsername(registerBody.Username) { // 账号不能以数字开头,可包含大写小写字母,数字,且不少于5位 - c.JSON(200, result.ErrMsg("The account cannot start with a number and can contain uppercase and lowercase letters, numbers, and no less than 5 digits")) + c.JSON(200, result.ErrMsg(i18n.TKey(language, "register.errUsername"))) return } if !regular.ValidPassword(registerBody.Password) { // 登录密码至少包含大小写字母、数字、特殊符号,且不少于6位 - c.JSON(200, result.ErrMsg("The login password should contain at least uppercase and lowercase letters, numbers, special symbols, and no less than 6 digits")) + c.JSON(200, result.ErrMsg(i18n.TKey(language, "register.errPasswd"))) return } if registerBody.Password != registerBody.ConfirmPassword { // 用户确认输入密码不一致 - c.JSON(200, result.ErrMsg("The user confirmed that the input password is inconsistent")) + c.JSON(200, result.ErrMsg(i18n.TKey(language, "register.errPasswdNotEq"))) return } // 当前请求信息 - ipaddr, location := ctxUtils.IPAddrLocation(c) - os, browser := ctxUtils.UaOsBrowser(c) + ipaddr, location := ctx.IPAddrLocation(c) + os, browser := ctx.UaOsBrowser(c) // 校验验证码 err := s.registerService.ValidateCaptcha( @@ -77,13 +79,13 @@ func (s *RegisterController) Register(c *gin.Context) { userID, err := s.registerService.ByUserName(registerBody.Username, registerBody.Password, registerBody.UserType) if err == nil { - msg := registerBody.Username + " registered success " + userID + msg := i18n.TTemplate(language, "register.successMsg", map[string]any{"name": registerBody.Username, "id": userID}) s.sysLogLoginService.CreateSysLogLogin( registerBody.Username, commonConstants.STATUS_YES, msg, ipaddr, location, os, browser, ) // 注册成功 - c.JSON(200, result.OkMsg("registered success")) + c.JSON(200, result.OkMsg(i18n.TKey(language, "register.success"))) return } c.JSON(200, result.ErrMsg(err.Error())) diff --git a/src/modules/common/service/account.impl.go b/src/modules/common/service/account.impl.go index b9d96e3c..31e95718 100644 --- a/src/modules/common/service/account.impl.go +++ b/src/modules/common/service/account.impl.go @@ -45,18 +45,18 @@ func (s *AccountImpl) ValidateCaptcha(code, uuid string) error { } if code == "" || uuid == "" { // 验证码信息错误 - return fmt.Errorf("captcha message error") + return fmt.Errorf("captcha.err") } verifyKey := cachekey.CAPTCHA_CODE_KEY + uuid captcha, _ := redis.Get("", verifyKey) if captcha == "" { // 验证码已失效 - return fmt.Errorf("captcha is no longer valid") + return fmt.Errorf("captcha.errValid") } redis.Del("", verifyKey) if captcha != code { // 验证码错误 - return fmt.Errorf("captcha error") + return fmt.Errorf("captcha.err") } return nil } @@ -74,14 +74,14 @@ func (s *AccountImpl) LoginByUsername(username, password string) (vo.LoginUser, // 查询用户登录账号 sysUser := s.sysUserService.SelectUserByUserName(username) if sysUser.UserName != username { - return loginUser, fmt.Errorf("user does not exist or wrong password") + return loginUser, fmt.Errorf("login.errNameOrPasswd") } if sysUser.DelFlag == common.STATUS_YES { // 对不起,您的账号已被删除 - return loginUser, fmt.Errorf("sorry, your account has been deleted") + return loginUser, fmt.Errorf("login.errDelFlag") } if sysUser.Status == common.STATUS_NO { - return loginUser, fmt.Errorf("sorry, your account has been disabled") + return loginUser, fmt.Errorf("login.errStatus") } // 检验用户密码 @@ -89,7 +89,7 @@ func (s *AccountImpl) LoginByUsername(username, password string) (vo.LoginUser, if !compareBool { redis.SetByExpire("", retrykey, retryCount+1, lockTime) // 用户不存在或密码错误 - return loginUser, fmt.Errorf("user does not exist or wrong password") + return loginUser, fmt.Errorf("login.errNameOrPasswd") } else { // 清除错误记录次数 s.ClearLoginRecordCache(username) @@ -136,9 +136,13 @@ func (s *AccountImpl) ClearLoginRecordCache(username string) bool { // passwordRetryCount 密码重试次数 func (s *AccountImpl) passwordRetryCount(username string) (string, int64, time.Duration, error) { + // 从数据库配置获取登录次数和错误锁定时间 + maxRetryCountStr := s.sysConfigService.SelectConfigValueByKey("sys.user.maxRetryCount") + lockTimeStr := s.sysConfigService.SelectConfigValueByKey("sys.user.lockTime") + // 验证登录次数和错误锁定时间 - maxRetryCount := config.Get("user.password.maxRetryCount").(int) - lockTime := config.Get("user.password.lockTime").(int) + maxRetryCount := parse.Number(maxRetryCountStr) + lockTime := parse.Number(lockTimeStr) // 验证缓存记录次数 retrykey := cachekey.PWD_ERR_CNT_KEY + username retryCount, err := redis.Get("", retrykey) @@ -147,9 +151,9 @@ func (s *AccountImpl) passwordRetryCount(username string) (string, int64, time.D } // 是否超过错误值 retryCountInt64 := parse.Number(retryCount) - if retryCountInt64 >= int64(maxRetryCount) { - // 密码输入错误 %d 次,帐户锁定 %d 分钟 - errorMsg := fmt.Errorf("password entered incorrectly %d times, account locked for %d minutes", maxRetryCount, lockTime) + if retryCountInt64 >= maxRetryCount { + // 密码输入错误多次,帐户已被锁定 + errorMsg := fmt.Errorf("login.errRetryPasswd") return retrykey, retryCountInt64, time.Duration(lockTime) * time.Minute, errorMsg } return retrykey, retryCountInt64, time.Duration(lockTime) * time.Minute, nil