"use client" import { getQueryVariable, validatePhoneNumber, } from "@/components/login/libs/common" import FingerprintJS from "@fingerprintjs/fingerprintjs" import { BackgroundImage, Box, Button, Flex, FloatingIndicator, Group, Input, LoadingOverlay, Modal, Paper, PasswordInput, Stack, Tabs, Text, TextInput, useComputedColorScheme, } from "@mantine/core" import { useForm } from "@mantine/form" import { useDisclosure } from "@mantine/hooks" import { useCallback, useEffect, useMemo, useState } from "react" import { getUserPermission, getVerifyCode, passwdLogin, verificationLogin, } from "./api" import QrLogin from "./feishu/qr-login" import { APP, PLATFORM, TENANT } from "./libs/common" import { DigitalIcon } from "./resource/icons/digital" import { useLoginStore } from "./store" import tabClasses from "./Tab.module.css" // import { useSearchParams } from "next/navigation" import Feishu from "./feishu/auto-login" import DarkBgImage from "./resource/images/dark-login-bg.png" import LightBgImage from "./resource/images/light-login-bg.png" import loginBg2Dark from "./resource/images/login-bg2-dark.png" import loginBg2Light from "./resource/images/login-bg2-light.png" import LogoDigImage from "./resource/images/logo-dig.png" const HeaderIcon = DigitalIcon const headerTitle = "管理系统平台" export default function LoginPage({ useUserStore }: { useUserStore: any }) { const colorScheme = useComputedColorScheme() // const params = useSearchParams().get("auto") const [loading, setLoading] = useState(false) const [error, setError] = useState(null) const [isClient, setIsClient] = useState(false) useEffect(() => { setIsClient(true) }, []) // 创建 Mantine Form 实例 const accountForm = useForm({ // 初始值 initialValues: { username: "", // 账户名 password: "", // 密码 }, // 验证规则 - 基于 rules 对象 validate: { username: (value) => { if (!value) { return "账户名不能为空" } if (value.length < 1) { return "账户名至少1个字符" } // if (value.length > 20) { // return "账户名不能超过20个字符" // } // if (!/^[a-zA-Z0-9_]+$/.test(value)) { // return "账户名只能包含字母、数字和下划线" // } return null }, password: (value) => { if (!value) { return "密码不能为空" } // if (value.length < 6) { // return "密码至少6个字符" // } // if (value.length > 30) { // return "密码不能超过30个字符" // } // if (!/(?=.*[a-z])(?=.*[A-Z])(?=.*\d)/.test(value)) { // return "密码需包含大小写字母和数字" // } return null }, }, // 验证触发时机 validateInputOnChange: true, // 输入时验证 validateInputOnBlur: true, // 失焦时验证 clearInputErrorOnChange: true, // 输入时清除错误 }) const phoneForm = useForm({ // 初始值 initialValues: { phone: "", // 手机号 code: "", // 验证码 }, // 验证规则 - 基于 rules 对象 validate: { phone: (value) => { if (!value) { return "手机号不能为空" } if (value.length !== 11) { return "手机号必须为11位" } return null }, code: (value) => { if (!value) { return "验证码不能为空" } if (value.length !== 6) { return "验证码必须为6位" } return null }, }, // 验证触发时机 validateInputOnChange: true, // 输入时验证 validateInputOnBlur: true, // 失焦时验证 clearInputErrorOnChange: true, // 输入时清除错误 }) const [opened, { open, close }] = useDisclosure(false) const [activeTab, setActiveTab] = useState("account") // const [fingerprint, setFingerprint] = useState("") const { setFingerprint } = useLoginStore() const fingerprint = useLoginStore.getState().fingerprint const fn = useCallback(async () => { const fpPromise = await FingerprintJS.load() fpPromise.get().then((result) => { const visitorId = result.visitorId setFingerprint(visitorId) }) }, [setFingerprint]) useEffect(() => { fn() }, [fn]) useEffect(() => { if (getQueryVariable("code")) { setActiveTab("feishu") } }, []) const [rootRef, setRootRef] = useState(null) const [controlsRefs, setControlsRefs] = useState< Record >({}) const setControlRef = (val: string) => (node: HTMLButtonElement) => { controlsRefs[val] = node setControlsRefs(controlsRefs) } const { setUserInfo, refreshToken } = useUserStore() // 表单提交处理 const handleAccountSubmit = accountForm.onSubmit( async (values) => { // 验证成功时的处理 setLoading(true) setError(null) try { let isAdmin = values.username === "admin" let phone = values.username.startsWith("+86") ? values.username : `+86${values.username}` const params = { account: isAdmin ? values.username : phone, password: values.password, tenant: TENANT, platform: PLATFORM, app: APP, fingerprint, } try { const res = await passwdLogin(params) const info = res.message setUserInfo(info.tenant, info.user_info, info.rbac) refreshToken({ access_token: info.access_token || "", refresh_token: info.refresh_token || "", }) const permission = await getUserPermission() console.log(permission) window.location.href = "/" } catch (error) { if (error) { const message = error instanceof Error ? error.message : "登录失败,请重试" setError(message) open() // 显示错误弹窗 return } } } catch (err) { const message = err instanceof Error ? err.message : "登录失败,请重试" setError(message) open() // 显示错误弹窗 } finally { setLoading(false) } }, (errors) => { console.log("验证错误:", errors) } ) const [codeTime, setCodeTime] = useState(0) const handleCountDown = () => { setCodeTime(60) let clean = setInterval(() => { setCodeTime((time) => { if (time === 0) { clearInterval(clean) return 0 } return time - 1 }) }, 1000) } const handleGetCode = async () => { if (!validatePhoneNumber(phoneForm.values.phone)) { setError("请输入正确的手机号") open() // 显示错误弹窗 return } else { try { handleCountDown() getVerifyCode({ phone: phoneForm.values.phone.startsWith("+86") ? phoneForm.values.phone : `+86${phoneForm.values.phone}`, }).then((res) => { if (res?.code === 200) { setError("验证码已发送") open() // 显示错误弹窗 } else { typeof res?.message === "string" && setError(res?.message || "验证码发送失败") open() // 显示错误弹窗 } }) } catch (error) { const message = error instanceof Error ? error.message : "获取验证码失败,请重试" setError(message) open() // 显示错误弹窗 } } } // 手机号登录表单提交处理 const handlePhoneSubmit = phoneForm.onSubmit( async (values) => { // 验证成功时的处理 setLoading(true) setError(null) try { const params = { phone: values.phone.startsWith("+86") ? values.phone : `+86${values.phone}`, verify_code: values.code, tenant: TENANT, platform: PLATFORM, app: APP, fingerprint, } const res = await verificationLogin(params) const info = res.message setUserInfo(info.tenant, info.user_info, info.rbac) refreshToken({ access_token: info.access_token || "", refresh_token: info.refresh_token || "", }) const permission = await getUserPermission() console.log(permission) window.location.href = "/" } catch (err) { const message = err instanceof Error ? err.message : "登录失败,请重试" setError(message) open() // 显示错误弹窗 } finally { setLoading(false) } }, (errors) => { console.log("验证错误:", errors) } ) const bgImage = useMemo( () => (colorScheme !== "dark" ? LightBgImage : DarkBgImage), [colorScheme] ) const stackBg2Image = useMemo( () => (colorScheme === "dark" ? loginBg2Dark : loginBg2Light), [colorScheme] ) const isFeishu = useMemo(() => { if (typeof window !== "undefined") return !!(window.h5sdk && window.tt) else return false }, []) return ( <> {error} {isClient && ( )} {isClient && ( )} {headerTitle} setActiveTab(value || "")}> 账户登录 手机号登录 飞书扫码
{/* 账户名输入 */} {/* 密码输入 */} {/* 登录按钮 */}
{/* 手机号输入 */} {/* 验证码输入 */} {/* 登录按钮 */}
{isClient && }
{isFeishu && ( )} ) }