diff --git a/internal/dto/user.go b/internal/dto/user.go index bcc7bd0..14592b3 100644 --- a/internal/dto/user.go +++ b/internal/dto/user.go @@ -1,100 +1,100 @@ package dto type UserDto struct { - ID uint `json:"id"` // 用户ID - Username string `json:"username"` // 用户名 - Nickname string `json:"nickname"` - AvatarUrl string `json:"avatar_url"` // 头像URL - Email string `json:"email"` // 邮箱 - Gender string `json:"gender"` - Role string `json:"role"` - Language string `json:"language"` // 语言 + ID uint `json:"id"` // 用户ID + Username string `json:"username"` // 用户名 + Nickname string `json:"nickname"` + AvatarUrl string `json:"avatar_url"` // 头像URL + Email string `json:"email"` // 邮箱 + Gender string `json:"gender"` + Role string `json:"role"` + Language string `json:"language"` // 语言 } type UserOidcConfigDto struct { - Name string `json:"name"` // OIDC配置名称 - DisplayName string `json:"display_name"` // OIDC配置显示名称 - Icon string `json:"icon"` // OIDC配置图标URL - LoginUrl string `json:"login_url"` // OIDC登录URL + Name string `json:"name"` // OIDC配置名称 + DisplayName string `json:"display_name"` // OIDC配置显示名称 + Icon string `json:"icon"` // OIDC配置图标URL + LoginUrl string `json:"login_url"` // OIDC登录URL } type UserLoginReq struct { - Username string `json:"username"` // username or email - Password string `json:"password"` + Username string `json:"username"` // username or email + Password string `json:"password"` } type UserLoginResp struct { - Token string `json:"token"` - RefreshToken string `json:"refresh_token"` - User UserDto `json:"user"` + Token string `json:"token"` + RefreshToken string `json:"refresh_token"` + User UserDto `json:"user"` } type UserRegisterReq struct { - Username string `json:"username"` // 用户名 - Nickname string `json:"nickname"` // 昵称 - Password string `json:"password"` // 密码 - Email string `json:"-" binding:"-"` + Username string `json:"username"` // 用户名 + Nickname string `json:"nickname"` // 昵称 + Password string `json:"password"` // 密码 + Email string `json:"-" binding:"-"` } type UserRegisterResp struct { - Token string `json:"token"` // 访问令牌 - RefreshToken string `json:"refresh_token"` // 刷新令牌 - User UserDto `json:"user"` // 用户信息 + Token string `json:"token"` // 访问令牌 + RefreshToken string `json:"refresh_token"` // 刷新令牌 + User UserDto `json:"user"` // 用户信息 } type VerifyEmailReq struct { - Email string `json:"email"` // 邮箱地址 + Email string `json:"email"` // 邮箱地址 } type VerifyEmailResp struct { - Success bool `json:"success"` // 验证码发送成功与否 + Success bool `json:"success"` // 验证码发送成功与否 } type OidcLoginReq struct { - Name string `json:"name"` // OIDC配置名称 - Code string `json:"code"` // OIDC授权码 - State string `json:"state"` + Name string `json:"name"` // OIDC配置名称 + Code string `json:"code"` // OIDC授权码 + State string `json:"state"` } type OidcLoginResp struct { - Token string `json:"token"` - RefreshToken string `json:"refresh_token"` - User UserDto `json:"user"` + Token string `json:"token"` + RefreshToken string `json:"refresh_token"` + User UserDto `json:"user"` } type ListOidcConfigResp struct { - OidcConfigs []UserOidcConfigDto `json:"oidc_configs"` // OIDC配置列表 + OidcConfigs []UserOidcConfigDto `json:"oidc_configs"` // OIDC配置列表 } type GetUserReq struct { - UserID uint `json:"user_id"` + UserID uint `json:"user_id"` } type GetUserByUsernameReq struct { - Username string `json:"username"` + Username string `json:"username"` } type GetUserResp struct { - User UserDto `json:"user"` // 用户信息 + User UserDto `json:"user"` // 用户信息 } type UpdateUserReq struct { - ID uint `json:"id"` - Username string `json:"username"` - Nickname string `json:"nickname"` - AvatarUrl string `json:"avatar_url"` - Gender string `json:"gender"` + ID uint `json:"id"` + Username string `json:"username"` + Nickname string `json:"nickname"` + AvatarUrl string `json:"avatar_url"` + Gender string `json:"gender"` } type UpdateUserResp struct { - User *UserDto `json:"user"` // 更新后的用户信息 + User *UserDto `json:"user"` // 更新后的用户信息 } type UpdatePasswordReq struct { - OldPassword string `json:"old_password"` - NewPassword string `json:"new_password"` + OldPassword string `json:"old_password"` + NewPassword string `json:"new_password"` } type ResetPasswordReq struct { - Email string `json:"-" binding:"-"` - NewPassword string `json:"new_password"` + Email string `json:"-" binding:"-"` + NewPassword string `json:"new_password"` } diff --git a/web/src/components/auth/common/current-logged.tsx b/web/src/components/auth/common/current-logged.tsx index 2f9914d..87053fb 100644 --- a/web/src/components/auth/common/current-logged.tsx +++ b/web/src/components/auth/common/current-logged.tsx @@ -8,33 +8,49 @@ import { useTranslations } from "next-intl"; import { useRouter, useSearchParams } from "next/navigation"; import React from "react"; import { SectionDivider } from '@/components/common/section-divider'; +import { LogOut } from "lucide-react"; +import { userLogout } from "@/api/user"; +import { toast } from "sonner"; export function CurrentLogged() { const t = useTranslations("Login"); const router = useRouter() const searchParams = useSearchParams() const redirectBack = searchParams.get("redirect_back") || "/" - const { user } = useAuth(); + const { user, logout } = useAuth(); const handleLoggedContinue = () => { router.push(redirectBack); } + + const handleLogOut = () => { + userLogout().then(() => { + logout(); + toast.success(t("logout_success")); + }) + } + if (!user) return null; return ( -
+
{t("currently_logged_in")} -
-
- - - {getFallbackAvatarFromUsername(user.nickname || user.username)} - +
+
+
+ + + {getFallbackAvatarFromUsername(user.nickname || user.username)} + +
+
+ {formatDisplayName(user)} + + {user.email} + +
-
- {formatDisplayName(user)} - - {user.email} - +
+
diff --git a/web/src/components/auth/login/login-form.tsx b/web/src/components/auth/login/login-form.tsx index a24888f..f4cabcc 100644 --- a/web/src/components/auth/login/login-form.tsx +++ b/web/src/components/auth/login/login-form.tsx @@ -25,6 +25,7 @@ import { useAuth } from "@/contexts/auth-context" import { registerPath, resetPasswordPath } from "@/hooks/use-route" import { CurrentLogged } from "@/components/auth/common/current-logged" import { SectionDivider } from "@/components/common/section-divider" +import { Avatar, AvatarFallback, AvatarImage } from "@/components/ui/avatar" export function LoginForm({ className, @@ -103,9 +104,9 @@ export function LoginForm({ - {t("with_oidc")} + {user ? t("bind_oidc") : t("with_oidc")}
-
+
{/* OIDC 登录选项 */} {oidcConfigs.length > 0 && (
@@ -130,10 +131,10 @@ export function LoginForm({ )} {/* 分隔线 */} {oidcConfigs.length > 0 && ( - {t("or_continue_with_local_account")} + {t("or_continue_with_local_account")} )} {/* 邮箱密码登录 */} -
+
{t("no_account")}{" "} - + {t("register")}
@@ -211,20 +212,10 @@ function LoginWithOidc({ asChild > - {`${displayName} { - e.currentTarget.style.display = 'none'; - }} - /> + + + + {displayName} diff --git a/web/src/components/auth/register/register-form.tsx b/web/src/components/auth/register/register-form.tsx index 3b89039..fc7a81f 100644 --- a/web/src/components/auth/register/register-form.tsx +++ b/web/src/components/auth/register/register-form.tsx @@ -109,10 +109,10 @@ export function RegisterForm({ -
- {t("register_a_new_account")} +
+ {t("register_a_new_account")} -
+
{/* 用户名 */}
@@ -152,17 +152,21 @@ export function RegisterForm({ value={email} onChange={e => setEmail(e.target.value)} /> - +
{/* 邮箱验证码 */}
- setVerifyCode(value)} - /> +
+ setVerifyCode(value)} + /> + +
+
{captchaProps &&
diff --git a/web/src/components/console/user-security/index.tsx b/web/src/components/console/user-security/index.tsx index 303dd19..51861d1 100644 --- a/web/src/components/console/user-security/index.tsx +++ b/web/src/components/console/user-security/index.tsx @@ -73,7 +73,7 @@ export function UserSecurityPage() { {t("forgot_password_or_no_password")}
- +
@@ -83,13 +83,14 @@ export function UserSecurityPage() {
setEmail(e.target.value)} /> - +
-
+
setVerifyCode(value)} /> - +
+
) diff --git a/web/src/locales/zh-CN.json b/web/src/locales/zh-CN.json index 39db21d..45838d6 100644 --- a/web/src/locales/zh-CN.json +++ b/web/src/locales/zh-CN.json @@ -128,6 +128,7 @@ } }, "Login": { + "bind_oidc": "绑定第三方账号", "captcha_error": "验证错误,请重试。", "continue": "继续", "currently_logged_in": "当前已登录为", @@ -137,7 +138,7 @@ "login_success": "登录成功!", "login_failed": "登录失败", "welcome": "欢迎回来", - "with_oidc": "使用第三方身份提供者", + "with_oidc": "使用第三方账号", "or_continue_with_local_account": "或使用用户名和密码", "email_or_username": "邮箱或用户名", "password": "密码",