From 6a1f89936e912eae0b986f0d3d2e7e16e201f4a1 Mon Sep 17 00:00:00 2001 From: ryan Date: Fri, 12 Jun 2026 11:00:26 +0800 Subject: [PATCH] =?UTF-8?q?=E7=99=BB=E5=BD=95=E7=95=8C=E9=9D=A2=E4=BC=98?= =?UTF-8?q?=E5=8C=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- frontend/app/favicon.ico | Bin 76088 -> 0 bytes frontend/app/icon.tsx | 31 +++ frontend/app/layout.tsx | 2 + frontend/components/auth/auth-shell.tsx | 67 +++++ frontend/components/auth/login-form.tsx | 246 +++++++++-------- frontend/components/auth/login-page.tsx | 50 ++-- frontend/components/auth/otp-form.tsx | 40 ++- frontend/components/auth/register-form.tsx | 247 +++++++++--------- frontend/components/auth/register-page.tsx | 21 +- .../components/providers/title-updater.tsx | 36 +++ frontend/components/ui/button.tsx | 7 +- frontend/proxy.ts | 2 +- internal/apps/user/errs.go | 78 +++--- 13 files changed, 474 insertions(+), 353 deletions(-) delete mode 100644 frontend/app/favicon.ico create mode 100644 frontend/app/icon.tsx create mode 100644 frontend/components/auth/auth-shell.tsx create mode 100644 frontend/components/providers/title-updater.tsx diff --git a/frontend/app/favicon.ico b/frontend/app/favicon.ico deleted file mode 100644 index ee46155f027b76ab7ed55548ea2f53f2b4da2804..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 76088 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

T`fDgqEfpLm;*h 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 diff --git a/frontend/app/icon.tsx b/frontend/app/icon.tsx new file mode 100644 index 00000000..3dca5dcc --- /dev/null +++ b/frontend/app/icon.tsx @@ -0,0 +1,31 @@ +import {ImageResponse} from 'next/og' +import {WavesIcon} from 'lucide-react' + +export const size = { + width: 32, + height: 32, +} +export const contentType = 'image/png' + +export default function Icon() { + return new ImageResponse( + ( +

+ +
+ ), + { + ...size, + } + ) +} diff --git a/frontend/app/layout.tsx b/frontend/app/layout.tsx index d36262c5..8c02df74 100644 --- a/frontend/app/layout.tsx +++ b/frontend/app/layout.tsx @@ -6,6 +6,7 @@ import {BellRingProvider} from "@/contexts/bell-ring-context"; import {NotificationSettingsProvider} from "@/contexts/notification-settings-context"; import {UserProvider} from "@/contexts/user-context"; import {AppQueryProvider} from "@/components/providers/query-provider"; +import {SiteTitleUpdater} from "@/components/providers/title-updater"; import {RobotsMeta} from "@/components/layout/robots-meta"; import "./globals.css"; @@ -36,6 +37,7 @@ export default function RootLayout({ > + diff --git a/frontend/components/auth/auth-shell.tsx b/frontend/components/auth/auth-shell.tsx new file mode 100644 index 00000000..cfbdb3b5 --- /dev/null +++ b/frontend/components/auth/auth-shell.tsx @@ -0,0 +1,67 @@ +"use client" + +import type {ReactNode} from "react" +import {motion} from "motion/react" +import {WavesIcon} from "lucide-react" + +import {cn} from "@/lib/utils" + +interface AuthShellProps { + children: ReactNode + wide?: boolean +} + +export function AuthShell({children, wide = false}: AuthShellProps) { + return ( +
+
+ ) +} + +interface AuthHeadingProps { + title: string + description: string + siteName?: string +} + +export function AuthHeading({ + title, + description, + siteName = "Wavelet", +}: AuthHeadingProps) { + return ( +
+
+ + + {siteName} +
+
+

+ {title} +

+

{description}

+
+
+ ) +} diff --git a/frontend/components/auth/login-form.tsx b/frontend/components/auth/login-form.tsx index 113c0722..41a06c7e 100644 --- a/frontend/components/auth/login-form.tsx +++ b/frontend/components/auth/login-form.tsx @@ -3,28 +3,31 @@ import {useEffect, useMemo, useRef, useState} from "react" import {useMutation, useQuery} from "@tanstack/react-query" import {useRouter, useSearchParams} from "next/navigation" -import {KeyRound} from "lucide-react" +import {EyeIcon, EyeOffIcon} from "lucide-react" import {toast} from "sonner" import Link from "next/link" import {useAuth} from "@/components/providers/auth-provider" import {Button} from "@/components/ui/button" import {Input} from "@/components/ui/input" -import {Label} from "@/components/ui/label" import {Separator} from "@/components/ui/separator" import {Spinner} from "@/components/ui/spinner" -import {Card, CardContent} from "@/components/ui/card" +import {Field, FieldGroup, FieldLabel} from "@/components/ui/field" import {CapWidget} from "@/components/auth/cap-widget" +import {AuthHeading} from "@/components/auth/auth-shell" import {OTPForm} from "./otp-form" import services from "@/lib/services" import type {LoginRequest} from "@/lib/services/auth/types" function getRedirectTarget(searchParams: ReturnType) { const callbackUrl = searchParams.get("callbackUrl") - const storedRedirect = sessionStorage.getItem("redirect_after_login") + const storedRedirect = + typeof window === "undefined" + ? null + : sessionStorage.getItem("redirect_after_login") const target = callbackUrl || storedRedirect || "/home" - if (storedRedirect) { + if (storedRedirect && typeof window !== "undefined") { sessionStorage.removeItem("redirect_after_login") } @@ -33,7 +36,7 @@ function getRedirectTarget(searchParams: ReturnType) { function persistRedirectTarget(searchParams: ReturnType) { const callbackUrl = searchParams.get("callbackUrl") - if (callbackUrl) { + if (callbackUrl && typeof window !== "undefined") { sessionStorage.setItem("redirect_after_login", callbackUrl) } } @@ -43,18 +46,23 @@ function configBool(value: string | undefined, fallback: boolean) { return value === "true" } -export function LoginForm() { +export function LoginForm({ onOTPStateChange }: { onOTPStateChange?: (show: boolean) => void }) { const router = useRouter() const searchParams = useSearchParams() const { setUser } = useAuth() const [username, setUsername] = useState("") const [password, setPassword] = useState("") + const [showPassword, setShowPassword] = useState(false) const [code, setCode] = useState("") const [showLoginCodeInput, setShowLoginCodeInput] = useState(false) const [loginCooldown, setLoginCooldown] = useState(0) const [errorMessage, setErrorMessage] = useState("") const [loginCodeTip, setLoginCodeTip] = useState(null) + useEffect(() => { + onOTPStateChange?.(showLoginCodeInput) + }, [showLoginCodeInput, onOTPStateChange]) + useEffect(() => { if (loginCooldown > 0) { const timer = setTimeout(() => setLoginCooldown(loginCooldown - 1), 1000) @@ -125,9 +133,7 @@ export function LoginForm() { if (errorMsg.startsWith("smtp_invalid:")) { const tip = errorMsg.substring("smtp_invalid:".length) - setLoginCodeTip( - {tip} - ) + setLoginCodeTip("请输入您的登录验证码。") setShowLoginCodeInput(true) setLoginCooldown(0) toast.warning(tip) @@ -217,11 +223,9 @@ export function LoginForm() { if (publicConfigQuery.isPending) { return ( - - - - - +
+ +
) } @@ -240,111 +244,123 @@ export function LoginForm() { } return ( - - -
-

- 账号登录 -

-
+
+ -
-
-
-
- - setUsername(e.target.value)} - placeholder="请输入邮箱或用户名" - autoComplete="username" - onKeyDown={(e) => e.key === "Enter" && handlePasswordLogin()} - /> -
-
- - setPassword(e.target.value)} - type="password" - placeholder="请输入密码" - autoComplete="current-password" - onKeyDown={(e) => e.key === "Enter" && handlePasswordLogin()} - /> -
- -
- - {/* Cap 人机验证 */} - {capEnabled && ( - + + + + 邮箱或用户名 * + + setUsername(e.target.value)} + placeholder="输入邮箱或用户名" + autoComplete="username" + className="h-10 text-sm [@media(max-height:700px)]:h-9" + onKeyDown={(e) => e.key === "Enter" && handlePasswordLogin()} + /> + + + + 密码 * + +
+ setPassword(e.target.value)} + type={showPassword ? "text" : "password"} + placeholder="输入您的密码" + autoComplete="current-password" + className="h-10 pr-11 text-sm [@media(max-height:700px)]:h-9" + onKeyDown={(e) => e.key === "Enter" && handlePasswordLogin()} /> - )} - - {errorMessage ? ( -
- {errorMessage} -
- ) : null} - - -
-
- - {authSources.length > 0 ? ( - <> - -
-
- {authSources.map((source) => ( - - ))} -
+
- + + + + {/* Cap 人机验证 */} + {capEnabled && ( + + )} + + {errorMessage ? ( +
+ {errorMessage} +
) : null} - {registrationEnabled && ( -
- {"Don't have an account?"}{" "} - - Sign up - + +
+ + {authSources.length > 0 ? ( +
+
+ + 或者使用 +
- )} - - +
+ {authSources.map((source) => ( + + ))} +
+
+ ) : null} + + {registrationEnabled && ( +
+ 还没有账号?{" "} + + 立即注册 + +
+ )} +
) } diff --git a/frontend/components/auth/login-page.tsx b/frontend/components/auth/login-page.tsx index b4cb0dd9..071af845 100644 --- a/frontend/components/auth/login-page.tsx +++ b/frontend/components/auth/login-page.tsx @@ -6,9 +6,9 @@ import {useRouter, useSearchParams} from "next/navigation" import {toast} from "sonner" import {Spinner} from "@/components/ui/spinner" import {LoginForm} from "@/components/auth/login-form" +import {AuthShell} from "@/components/auth/auth-shell" import {Check} from "lucide-react" -import {AuroraBackground} from "@/components/ui/aurora-background" import services from "@/lib/services" import {useAuth} from "@/components/providers/auth-provider" @@ -27,6 +27,7 @@ export function LoginPage() { const router = useRouter() const searchParams = useSearchParams() const { setUser } = useAuth() + const [showOTP, setShowOTP] = useState(false) /* 处理OAuth回调 */ const [isProcessingCallback, setIsProcessingCallback] = useState(() => { @@ -136,25 +137,8 @@ export function LoginPage() { }, [searchParams, router, resolveRedirectTarget, setUser]) return ( - - - {/*Title Do Not Remove*/} - {/*
*/} - {/*

*/} - {/* Refresh*/} - {/*

*/} - {/*
*/} - + +
{isProcessingCallback || isCheckingSession ? ( {isCheckingSession ? ( -
+
- +
-
+

正在检查登录状态

请稍候,我们正在确认当前会话...

) : loginSuccess ? ( -
+
- + -
+

登录成功

正在跳转至控制台...

) : ( -
+
- +
-
+

正在验证凭据

请稍候,我们正在为您建立安全会话...

@@ -209,11 +193,11 @@ export function LoginPage() { transition={{ duration: 0.4 }} className="w-full" > - + )} - - +
+ ) } diff --git a/frontend/components/auth/otp-form.tsx b/frontend/components/auth/otp-form.tsx index 358722ef..b50f6786 100644 --- a/frontend/components/auth/otp-form.tsx +++ b/frontend/components/auth/otp-form.tsx @@ -4,9 +4,9 @@ import * as React from "react" import {RefreshCwIcon} from "lucide-react" import {Button} from "@/components/ui/button" -import {Card, CardContent, CardDescription, CardFooter, CardHeader, CardTitle,} from "@/components/ui/card" import {Field, FieldLabel} from "@/components/ui/field" import {InputOTP, InputOTPGroup, InputOTPSeparator, InputOTPSlot,} from "@/components/ui/input-otp" +import {AuthHeading} from "@/components/auth/auth-shell" import {cn} from "@/lib/utils" interface OTPFormProps { @@ -29,17 +29,16 @@ export function OTPForm({ onSubmit, }: OTPFormProps) { return ( - - - - 验证登录 - - - {loginCodeTip} - - - - +
+ + {loginCodeTip ? ( +

{loginCodeTip}

+ ) : null} +
+
验证码 @@ -50,13 +49,13 @@ export function OTPForm({ type="button" onClick={onResend} disabled={loginCooldown > 0 || isPending} - className="gap-1 text-xs px-2 py-1 h-7" + className="h-8 text-xs" > - + {loginCooldown > 0 ? `${loginCooldown}秒后重发` : "重新发送"}
-
+
- - -
+
遇到登录问题?{" "}
- - +
+
) } diff --git a/frontend/components/auth/register-form.tsx b/frontend/components/auth/register-form.tsx index c7ea424e..c5093abf 100644 --- a/frontend/components/auth/register-form.tsx +++ b/frontend/components/auth/register-form.tsx @@ -3,22 +3,24 @@ import {useEffect, useMemo, useState} from "react" import {useMutation, useQuery} from "@tanstack/react-query" import {useRouter, useSearchParams} from "next/navigation" -import {UserPlus} from "lucide-react" import {toast} from "sonner" import Link from "next/link" import {useAuth} from "@/components/providers/auth-provider" import {Button} from "@/components/ui/button" import {Input} from "@/components/ui/input" -import {Label} from "@/components/ui/label" import {Spinner} from "@/components/ui/spinner" -import {Card, CardContent} from "@/components/ui/card" +import {Field, FieldGroup, FieldLabel} from "@/components/ui/field" +import {AuthHeading} from "@/components/auth/auth-shell" import services from "@/lib/services" import type {RegisterRequest} from "@/lib/services/auth/types" function getRedirectTarget(searchParams: ReturnType) { const callbackUrl = searchParams.get("callbackUrl") - const storedRedirect = sessionStorage.getItem("redirect_after_login") + const storedRedirect = + typeof window === "undefined" + ? null + : sessionStorage.getItem("redirect_after_login") return callbackUrl || storedRedirect || "/home" } @@ -142,11 +144,9 @@ export function RegisterForm() { if (publicConfigQuery.isPending) { return ( - - - - - +
+ +
) } @@ -155,125 +155,124 @@ export function RegisterForm() { } return ( - - -
-

- 创建账号 -

-
+
+ -
-
-
- - setUsername(e.target.value)} - placeholder="请输入用户名" - autoComplete="username" - onKeyDown={(e) => e.key === "Enter" && handleRegister()} - /> -
-
- - setNickname(e.target.value)} - placeholder="请输入昵称" - autoComplete="nickname" - onKeyDown={(e) => e.key === "Enter" && handleRegister()} - /> -
-
- - setPassword(e.target.value)} - type="password" - placeholder="请输入密码(至少 8 位)" - autoComplete="new-password" - onKeyDown={(e) => e.key === "Enter" && handleRegister()} - /> -
-
- - setEmail(e.target.value)} - placeholder="请输入电子邮箱" - autoComplete="email" - onKeyDown={(e) => e.key === "Enter" && handleRegister()} - /> -
- {emailRegisterEnabled && ( -
- -
- setCode(e.target.value)} - placeholder="请输入 6 位邮箱验证码" - maxLength={6} - className="flex-1" - onKeyDown={(e) => e.key === "Enter" && handleRegister()} - /> - -
+
+ + + 用户名 * + setUsername(e.target.value)} + placeholder="请输入用户名" + autoComplete="username" + className="h-10 text-sm [@media(max-height:700px)]:h-9" + onKeyDown={(e) => e.key === "Enter" && handleRegister()} + /> + + + + 昵称 + (可选) + + setNickname(e.target.value)} + placeholder="请输入昵称" + autoComplete="nickname" + className="h-10 text-sm [@media(max-height:700px)]:h-9" + onKeyDown={(e) => e.key === "Enter" && handleRegister()} + /> + + + 电子邮箱 * + setEmail(e.target.value)} + placeholder="请输入电子邮箱" + autoComplete="email" + className="h-10 text-sm [@media(max-height:700px)]:h-9" + onKeyDown={(e) => e.key === "Enter" && handleRegister()} + /> + + + 密码 * + setPassword(e.target.value)} + type="password" + placeholder="请输入密码(至少 8 位)" + autoComplete="new-password" + className="h-10 text-sm [@media(max-height:700px)]:h-9" + onKeyDown={(e) => e.key === "Enter" && handleRegister()} + /> + + {emailRegisterEnabled && ( + + 邮箱验证码 * +
+ setCode(e.target.value)} + placeholder="请输入 6 位邮箱验证码" + maxLength={6} + className="h-10 flex-1 text-sm [@media(max-height:700px)]:h-9" + onKeyDown={(e) => e.key === "Enter" && handleRegister()} + /> +
- )} +
+ )} +
+ + {errorMessage ? ( +
+ {errorMessage}
+ ) : null} - {errorMessage ? ( -
- {errorMessage} -
- ) : null} + +
- -
- -
- Already have an account?{" "} - - Sign in - -
- - +
+ 已经有账号?{" "} + + 返回登录 + +
+
) } diff --git a/frontend/components/auth/register-page.tsx b/frontend/components/auth/register-page.tsx index cba9b374..755bda44 100644 --- a/frontend/components/auth/register-page.tsx +++ b/frontend/components/auth/register-page.tsx @@ -1,25 +1,12 @@ "use client" -import {motion} from "motion/react" import {RegisterForm} from "@/components/auth/register-form" -import {AuroraBackground} from "@/components/ui/aurora-background" +import {AuthShell} from "@/components/auth/auth-shell" export function RegisterPage() { return ( - - - - - + + + ) } diff --git a/frontend/components/providers/title-updater.tsx b/frontend/components/providers/title-updater.tsx new file mode 100644 index 00000000..54281001 --- /dev/null +++ b/frontend/components/providers/title-updater.tsx @@ -0,0 +1,36 @@ +"use client" + +import {useQuery} from '@tanstack/react-query' +import {useEffect} from 'react' +import services from '@/lib/services' +import {usePathname} from 'next/navigation' + +export function SiteTitleUpdater() { + const pathname = usePathname() + const publicConfigQuery = useQuery({ + queryKey: ["public-config"], + queryFn: () => services.config.getPublicConfig(), + }) + + useEffect(() => { + const siteName = publicConfigQuery.data?.site_name || "Wavelet Platform" + + // Determine the page suffix based on path + let suffix = "" + if (pathname === "/login") { + suffix = " - 登录" + } else if (pathname === "/register") { + suffix = " - 注册" + } else if (pathname.startsWith("/admin")) { + suffix = " - 后台管理" + } else if (pathname === "/home") { + suffix = " - 控制台" + } else if (pathname === "/") { + suffix = "" + } + + document.title = `${siteName}${suffix}` + }, [publicConfigQuery.data?.site_name, pathname]) + + return null +} diff --git a/frontend/components/ui/button.tsx b/frontend/components/ui/button.tsx index 64ec63c8..b7826d93 100644 --- a/frontend/components/ui/button.tsx +++ b/frontend/components/ui/button.tsx @@ -1,8 +1,8 @@ import * as React from "react" -import { Slot } from "@radix-ui/react-slot" -import { cva, type VariantProps } from "class-variance-authority" +import {Slot} from "@radix-ui/react-slot" +import {cva, type VariantProps} from "class-variance-authority" -import { cn } from "@/lib/utils" +import {cn} from "@/lib/utils" const buttonVariants = cva( "cursor-pointer inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-md text-sm font-medium transition-all disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg:not([class*='size-'])]:size-4 shrink-0 [&_svg]:shrink-0 outline-none focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:ring-[3px] aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive", @@ -10,6 +10,7 @@ const buttonVariants = cva( variants: { variant: { default: "bg-primary text-primary-foreground hover:bg-primary/90", + auth: "bg-foreground text-background hover:bg-foreground/90", destructive: "bg-destructive text-white hover:bg-destructive/90 focus-visible:ring-destructive/20 dark:focus-visible:ring-destructive/40 dark:bg-destructive/60", outline: diff --git a/frontend/proxy.ts b/frontend/proxy.ts index 4bb0d6a3..f692e4cd 100644 --- a/frontend/proxy.ts +++ b/frontend/proxy.ts @@ -103,7 +103,7 @@ export function proxy(request: NextRequest) { } /* 页面请求:公共路由放行 */ - const publicRoutes = ['/', '/login', '/callback', '/privacy', '/terms'] + const publicRoutes = ['/', '/login', '/register', '/callback', '/privacy', '/terms'] const publicPrefixes = ['/docs/', '/epay/'] if (publicRoutes.includes(pathname) || publicPrefixes.some(p => pathname.startsWith(p))) { diff --git a/internal/apps/user/errs.go b/internal/apps/user/errs.go index fabd3f71..c8ed94a0 100644 --- a/internal/apps/user/errs.go +++ b/internal/apps/user/errs.go @@ -5,43 +5,43 @@ package user const ( - errBindParamsFailed = "参数绑定失败" - errInvalidParams = "无效的参数" - errPasswordLoginDisabled = "管理员关闭了密码登录" //nolint:gosec // false positive: this is an error message, not hardcoded credentials - errUsernameOrPasswordWrong = "用户名或密码错误" //nolint:gosec // false positive: this is an error message, not hardcoded credentials - errLoginEmailMissing = "该账号未绑定邮箱,请联系管理员绑定邮箱后再登录" - errNeedEmailCodePrefix = "need_email_code:" - errSMTPInvalidUseTempCodePrefix = "smtp_invalid:" - errSMTPInvalidUseTempCode = "smtp 配置无效,使用临时码登录" - errEmailCodeInvalidOrExpired = "验证码错误或已过期" - errSaveSessionFailed = "无法保存会话信息,请重试" - errRegistrationDisabled = "管理员关闭了注册" - errPasswordTooShort = "密码长度不能少于 8 位" //nolint:gosec // false positive: this is an error message, not hardcoded credentials - errEmailOrCodeRequired = "邮箱或验证码未填写" - errNewPasswordTooShort = "新密码长度不能少于 8 位" //nolint:gosec // false positive: this is an error message, not hardcoded credentials - errLoginRequired = "请先登录" - errUserNotFound = "未找到该用户" - errOldPasswordIncorrect = "原密码不正确" //nolint:gosec // false positive: this is an error message, not hardcoded credentials - errPasswordEncryptFailed = "密码加密失败,请重试" //nolint:gosec // false positive: this is an error message, not hardcoded credentials - errEmailRequired = "邮箱地址不能为空" - errUnsupportedEmailScene = "不支持的验证场景" - errEmailAlreadyRegistered = "该邮箱已被注册" - errEmailCodeCooldown = "验证码发送频繁,请稍后再试" - errEmailFormatInvalid = "邮箱格式不正确" - errEmailAlreadyBound = "该邮箱已被其他账号绑定" - errRenderEmailTemplateFailed = "渲染验证邮件模板失败:%w" - errGenerateEmailCodeFailed = "生成验证码失败,请重试" - errDispatchEmailTaskFailed = "投递验证邮件发送任务失败,请重试" - errTokenNameRequired = "令牌名称不能为空" //nolint:gosec // false positive: this is an error message, not hardcoded credentials - errAccessTokenLimitReached = "已达到访问令牌最大创建数量限制" //nolint:gosec // false positive: this is an error message, not hardcoded credentials - errGenerateTokenFailed = "生成令牌失败" //nolint:gosec // false positive: this is an error message, not hardcoded credentials - errInvalidTokenID = "无效的令牌ID" //nolint:gosec // false positive: this is an error message, not hardcoded credentials - errTokenNotFoundOrForbidden = "令牌不存在或无权操作" //nolint:gosec // false positive: this is an error message, not hardcoded credentials - errAdminTokenRequiresAdmin = "只有管理员才能创建具有管理员权限的令牌" //nolint:gosec // false positive: this is an error message, not hardcoded credentials - errTaskPayloadRequired = "任务参数不能为空" - errInvalidJSONFormat = "无效的 JSON 格式: %w" - errEmailTaskFieldsRequired = "to、subject、body 不能为空" - errParseEmailPayloadFailed = "解析邮件发送参数失败: %w" - errSMTPConfigIncomplete = "系统 SMTP 邮件服务配置不完整" - errSendMailFailed = "发送邮件失败: %w" + errBindParamsFailed = "参数绑定失败" + errInvalidParams = "无效的参数" + errPasswordLoginDisabled = "管理员关闭了密码登录" //nolint:gosec // false positive: this is an error message, not hardcoded credentials + errUsernameOrPasswordWrong = "用户名或密码错误" //nolint:gosec // false positive: this is an error message, not hardcoded credentials + errLoginEmailMissing = "该账号未绑定邮箱,请联系管理员绑定邮箱后再登录" + errNeedEmailCodePrefix = "need_email_code:" + errSMTPInvalidUseTempCodePrefix = "smtp_invalid:" + errSMTPInvalidUseTempCode = "smtp 配置无效,使用临时码登录" + errEmailCodeInvalidOrExpired = "验证码错误或已过期" + errSaveSessionFailed = "无法保存会话信息,请重试" + errRegistrationDisabled = "管理员关闭了注册" + errPasswordTooShort = "密码长度不能少于 8 位" //nolint:gosec // false positive: this is an error message, not hardcoded credentials + errEmailOrCodeRequired = "邮箱或验证码未填写" + errNewPasswordTooShort = "新密码长度不能少于 8 位" //nolint:gosec // false positive: this is an error message, not hardcoded credentials + errLoginRequired = "请先登录" + errUserNotFound = "未找到该用户" + errOldPasswordIncorrect = "原密码不正确" //nolint:gosec // false positive: this is an error message, not hardcoded credentials + errPasswordEncryptFailed = "密码加密失败,请重试" //nolint:gosec // false positive: this is an error message, not hardcoded credentials + errEmailRequired = "邮箱地址不能为空" + errUnsupportedEmailScene = "不支持的验证场景" + errEmailAlreadyRegistered = "该邮箱已被注册" + errEmailCodeCooldown = "验证码发送频繁,请稍后再试" + errEmailFormatInvalid = "邮箱格式不正确" + errEmailAlreadyBound = "该邮箱已被其他账号绑定" + errRenderEmailTemplateFailed = "渲染验证邮件模板失败:%w" + errGenerateEmailCodeFailed = "生成验证码失败,请重试" + errDispatchEmailTaskFailed = "投递验证邮件发送任务失败,请重试" + errTokenNameRequired = "令牌名称不能为空" //nolint:gosec // false positive: this is an error message, not hardcoded credentials + errAccessTokenLimitReached = "已达到访问令牌最大创建数量限制" //nolint:gosec // false positive: this is an error message, not hardcoded credentials + errGenerateTokenFailed = "生成令牌失败" //nolint:gosec // false positive: this is an error message, not hardcoded credentials + errInvalidTokenID = "无效的令牌ID" //nolint:gosec // false positive: this is an error message, not hardcoded credentials + errTokenNotFoundOrForbidden = "令牌不存在或无权操作" //nolint:gosec // false positive: this is an error message, not hardcoded credentials + errAdminTokenRequiresAdmin = "只有管理员才能创建具有管理员权限的令牌" //nolint:gosec // false positive: this is an error message, not hardcoded credentials + errTaskPayloadRequired = "任务参数不能为空" + errInvalidJSONFormat = "无效的 JSON 格式: %w" + errEmailTaskFieldsRequired = "to、subject、body 不能为空" + errParseEmailPayloadFailed = "解析邮件发送参数失败: %w" + errSMTPConfigIncomplete = "系统 SMTP 邮件服务配置不完整" + errSendMailFailed = "发送邮件失败: %w" )