| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330 |
- "use client";
- import {LockOutlined, UserOutlined} from "@ant-design/icons";
- import type {ProFormInstance} from "@ant-design/pro-components";
- import {LoginFormPage, ProConfigProvider, ProFormCheckbox, ProFormText,} from "@ant-design/pro-components";
- import {App, Divider, Spin, theme} from "antd";
- import {deleteCookie, getCookie, setCookie} from "cookies-next";
- import {useRouter} from "next/navigation";
- import Image from "next/image";
- import {useEffect, useRef, useState} from "react";
- import {LoginReq} from "../_modules/definies";
- import {decrypt, displayModeIsDark, encrypt, watchDarkModeChange,} from "../_modules/func";
- type Captcha = {
- img: string;
- uuid: string;
- };
- //cookies 记住的用户名 key
- const cookie_username_key = "mortnon_username";
- //cookies 记住的密码 key
- const cookie_password_key = "mortnon_password";
- //浅色背景图
- const backgroudLight = "/bg3.jpg";
- //深色前景图
- const backgroundDark = "/bg-dark.jpg";
- export default function Login() {
- const {message} = App.useApp();
- //验证码数据
- const [captcha, setCaptcha] = useState({} as Captcha);
- //是否展示验证码框
- const [showCaptcha, setShowCaptcha] = useState(false);
- //验证码加载状态
- const [isLoadingImg, setIsLoadingImg] = useState(true);
- //获取验证码
- const getCaptcha = async () => {
- try {
- const response = await fetch("/api/captchaImage");
- if (response.ok) {
- const data = await response.json();
- setShowCaptcha(data.captchaEnabled);
- if (data.captchaEnabled) {
- const imagePrefix = "data:image/gif;base64,";
- const captchaData: Captcha = {
- img: imagePrefix + data.img,
- uuid: data.uuid,
- };
- setCaptcha(captchaData);
- setIsLoadingImg(false);
- }
- } else {
- }
- } catch (error) {
- } finally {
- }
- };
- //深色模式
- const [isDark, setIsDark] = useState(false);
- //背景图片
- const [background, setBackground] = useState(backgroudLight);
- useEffect(() => {
- getCaptcha();
- readUserNamePassword();
- setIsDark(displayModeIsDark());
- setBackground(displayModeIsDark() ? backgroundDark : backgroudLight);
- const unsubscribe = watchDarkModeChange((matches: boolean) => {
- setIsDark(matches);
- setBackground(matches ? backgroundDark : backgroudLight);
- });
- return () => {
- unsubscribe();
- };
- }, []);
- const router = useRouter();
- //提交登录
- const userLogin = async (values: any) => {
- const loginData: LoginReq = {
- username: values.username,
- password: values.password,
- code: values.code,
- uuid: captcha.uuid,
- };
- //是否记住密码
- const autoLogin = values.autoLogin;
- try {
- const response = await fetch("/api/login", {
- method: "POST",
- headers: {
- "Content-Type": "application/json",
- },
- body: JSON.stringify(loginData),
- credentials: "include",
- });
- //获得响应
- if (response.ok) {
- const data = await response.json();
- //登录成功
- if (data.code == 200) {
- App.useApp().message.success("登录成功");
- setCookie("token", data.token);
- //记住密码
- if (autoLogin) {
- rememberUserNamePassword(values.username, values.password);
- } else {
- removeUserNamePassword();
- }
- router.push("/");
- } else {
- App.useApp().message.open({
- type: "error",
- content: data.msg,
- });
- //异常,自动刷新验证码
- getCaptcha();
- }
- } else {
- const data = await response.json();
- App.useApp().message.open({
- type: "error",
- content: data.msg,
- });
- }
- } catch (error) {
- console.log("error:", error);
- App.useApp().message.open({
- type: "error",
- content: "登录发生异常,请重试",
- });
- } finally {
- }
- };
- //记住用户名密码到cookie
- const rememberUserNamePassword = (username: string, password: string) => {
- setCookie(cookie_username_key, encrypt(username));
- setCookie(cookie_password_key, encrypt(password));
- };
- //移除cookie中的用户名和密码
- const removeUserNamePassword = () => {
- deleteCookie(cookie_username_key);
- deleteCookie(cookie_password_key);
- };
- const loginFormRef = useRef<ProFormInstance>(null);
- //读取cookie中用户名密码,并填写到表单中
- const readUserNamePassword = () => {
- const username = getCookie(cookie_username_key);
- const password = getCookie(cookie_password_key);
- if (username !== undefined && password !== undefined) {
- if (loginFormRef) {
- if (typeof username === "string" && password === "string") {
- loginFormRef.current?.setFieldsValue({
- username: decrypt(username),
- password: decrypt(password),
- autoLogin: true,
- });
- }
- }
- }
- };
- const {token} = theme.useToken();
- return (
- <ProConfigProvider dark={isDark}>
- <div
- style={{
- backgroundColor: "white",
- height: "100vh",
- }}
- >
- <LoginFormPage
- formRef={loginFormRef}
- backgroundImageUrl={background}
- logo="https://static.dongfangzan.cn/img/mortnon.svg"
- title={(<span>MorTnon 若依后台管理</span>) as any}
- containerStyle={{
- backgroundColor: "rgba(0,0,0,0)",
- backdropFilter: "blur(4px)",
- }}
- subTitle={
- <span style={{color: "rgba(255,255,255,1)"}}>
- MorTnon,高质量的快速开发框架
- </span>
- }
- actions={
- <div
- style={{
- display: "flex",
- justifyContent: "center",
- alignItems: "center",
- }}
- >
- <p style={{color: "rgba(255,255,255,.6)"}}>
- ©{new Date().getFullYear()} Mortnon.
- </p>
- </div>
- }
- onFinish={userLogin}
- >
- <Divider>账号密码登录</Divider>
- <>
- <ProFormText
- name="username"
- fieldProps={{
- size: "large",
- prefix: (
- <UserOutlined
- style={{
- color: token.colorText,
- }}
- className={"prefixIcon"}
- />
- ),
- }}
- placeholder={"用户名"}
- rules={[
- {
- required: true,
- message: "用户名不能为空",
- },
- ]}
- />
- <ProFormText.Password
- name="password"
- fieldProps={{
- size: "large",
- prefix: (
- <LockOutlined
- style={{
- color: token.colorText,
- }}
- className={"prefixIcon"}
- />
- ),
- }}
- placeholder={"密码"}
- rules={[
- {
- required: true,
- message: "密码不能为空",
- },
- ]}
- />
- {showCaptcha && (
- <div
- style={{
- display: "flex",
- justifyContent: "center",
- flexDirection: "row",
- }}
- >
- <ProFormText
- name="code"
- fieldProps={{
- size: "large",
- prefix: (
- <UserOutlined
- style={{
- color: token.colorText,
- }}
- className={"prefixIcon"}
- />
- ),
- }}
- placeholder={"验证码"}
- rules={[
- {
- required: true,
- message: "验证码不能为空",
- },
- ]}
- />
- <div style={{margin: "0 0 0 8px"}}>
- <Spin spinning={isLoadingImg}>
- {captcha.img === undefined ? (
- <div style={{width: 80, height: 40}}></div>
- ) : (
- <Image
- src={captcha.img}
- width={80}
- height={40}
- alt="captcha"
- onClick={getCaptcha}
- />
- )}
- </Spin>
- </div>
- </div>
- )}
- </>
- <div
- style={{
- marginBlockEnd: 24,
- }}
- >
- <ProFormCheckbox noStyle name="autoLogin">
- 记住密码
- </ProFormCheckbox>
- </div>
- </LoginFormPage>
- </div>
- </ProConfigProvider>
- );
- }
|