Nest.js从0到1搭建博客系统---React登录页面以及对接口(13)

你是这个时代的探索者,你的每一个代码都照亮了未知的领域。无论前方有多少挑战,你都不会孤单,因为你手中的键盘是你的朋友,你的伙伴。💼

登录页面

  • 适配手机端

api 目录结构

interface/index.ts

ts 复制代码
// 基础响应类型
export interface IBaseResult {
  code: number;
  message: string;
  timestamp: number;
}
// 分页请求参数
export interface IReqPage {
  pageNum: number;
  pageSize: number;
}

interface/user.ts

ts 复制代码
import { IBaseResult } from ".";
// 登录请求参数
export interface ISignin {
  username: string;
  password: string;
  remember?: boolean;
}
// token
export interface IToken {
  access_token?: string;
  refresh_token?: string;
}
// 登录响应结果
export interface IResultLogin extends IBaseResult {
  data?: IToken;
}

userApi.ts

ts 复制代码
import { IResultLogin, ISignin } from "@/apis/interface/user"
import { http } from "@/http"
// 登录接口
export const useSigninApi = (params: ISignin) => {
  return http.post<IResultLogin>('/api/v1/auth/signin', params)
}

services/UserService.ts

ts 复制代码
/*
 * @Author: vhen
 * @Date: 2024-01-18 19:27:12
 * @LastEditTime: 2024-01-30 08:01:58
 * @Description: 现在的努力是为了小时候吹过的牛逼!
 * @FilePath: \react-vhen-blog-admin\src\services\UserService.ts
 *
 */

import { atom } from 'jotai';
import { atomWithStorage } from 'jotai/utils';

import { ISignin } from "@/apis/interface/user";
import { useSigninApi } from '@/apis/userApi';


// 设置token
const tokenData = atomWithStorage<any>('userToken', {
  access_token: '',
  refresh_token: ''
});

const tokenInfo = atom(
  get => get(tokenData),
  async (_get, set, userParams: ISignin) => {
    const res = await useSigninApi(userParams);
    set(tokenData, res.data);
    return res;
  },
)
// 记住登录用户
const loginData = atomWithStorage<any | null>('loginInfo', null)
const loginInfo = atom(
  get => get(loginData),
  async (_get, set, info: ISignin | null) => {
    set(loginData, info);
    return info;
  },
)

export {
  loginInfo, tokenInfo
};

登录调接口

LoginForm.tsx组件

tsx 复制代码
import { LockOutlined, UserOutlined } from '@ant-design/icons';
import { Button, Checkbox, Form, Input, notification } from 'antd';
import { useAtom } from 'jotai';
import { useEffect, useState } from 'react';
import { useNavigate } from "react-router-dom";

import { ISignin } from "@/apis/interface/user";
import { loginInfo, tokenInfo } from '@/services/UserService';
import { Encrypt } from '@/utils/crypto';

const LoginForm: React.FC = () => {
  const [form] = Form.useForm();
  const navigate = useNavigate();
  const [loading, setLoading] = useState<boolean>(false);
  const [, setUserToken] = useAtom(tokenInfo)
  const [userInfo, setLoginInfo] = useAtom(loginInfo)
  const initLoginInfo = () => {
    if (userInfo) {
      form.setFieldsValue({
        username: userInfo.username,
        password: userInfo.password,
        remember: userInfo.remember
      })
    }
  }
  //  登录
  const handlerLogin = async (loginForm: ISignin) => {
    try {
      setLoading(true)
      if (loginForm.remember) {
        setLoginInfo(loginForm)
      } else {
        setLoginInfo(null)
      }
      loginForm.password = Encrypt(loginForm.password)
      const { code } = await setUserToken(loginForm)
      if (code === 1) {
        notification.success({
          message: '温馨提示',
          description: '登录成功',
        })
        navigate('/home')
      }
    } finally {
      setLoading(false);
    }
  }

  useEffect(() => {
    initLoginInfo()
  })
  return (
    <Form form={form} className='w-full' initialValues={{ remember: false }}
      autoComplete="off" onFinish={handlerLogin}>
      <Form.Item name="username" rules={[{ required: true, message: "请输入用户名" }]}>
        <Input prefix={<UserOutlined />} placeholder="请输入用户名" />
      </Form.Item>
      <Form.Item name="password" rules={[{ required: true, message: "请输入密码" }]}>
        <Input.Password prefix={<LockOutlined />} placeholder="请输入密码" />
      </Form.Item>
      <Form.Item >
        <div className='flex justify-between'>
          <Form.Item name="remember" valuePropName="checked" noStyle>
            <Checkbox>记住我</Checkbox>
          </Form.Item>
          <a className="login-form-forgot" href="#!">
            忘记密码?
          </a>
        </div>
      </Form.Item>
      <Form.Item>
        <Button type="primary" loading={loading} htmlType="submit" className="w-full">
          登录
        </Button>
      </Form.Item>
    </Form>
  )
}

export default LoginForm;

index.module.scss

scss 复制代码
.login{
  display: flex;
  align-items: center;
  justify-content: flex-end;
  background-image: url(../../assets/images/login_bg.jpg);
  background-repeat: no-repeat;
  background-size: cover;
  min-height: 100vh;
  padding-right: 260px;
  &-title{
    padding-bottom: 30px;
    font-size: 18px;
    text-align: center;
    font-weight: bold;
    color: #000;
  }
  &-form{
    display: flex;
    flex-direction: column;
    width: 400px;
    padding: 50px 20px 20px;
    background: #fff;
    border-radius: 20px;
    box-shadow: 0 5px 15px #0000000d;
    box-sizing: border-box;
    min-height: 300px;
  }
}
@media screen and (max-width:992px) {
  .login{
    padding: 0 20px;
    justify-content:center;
  }
}
@media screen and (min-width:993px) and (max-width:1500px) {
  .login{
   padding-right: 120px;
  }
}

index.tsx

tsx 复制代码
import LoginForm from "./components/LoginForm";
import style from './index.module.scss';

const Login: React.FC = () => {

  return (
    <div className={style.login}>
      <div className={style['login-form']}>
        <div className={style['login-title']} >欢迎来到 React-Vhen-Blog-Admin</div>

        <LoginForm />
        {/* <Divider plain>其他登录方式</Divider> */}
      </div>
    </div>
  )
}

export default Login;
  • 测试正常登录
  • 账号密码错误

结束语

如有不足之处,望海涵,欢迎关注一起学习,一起成长

相关推荐
Hao_Harrision9 分钟前
50天50个小项目 (React19 + Tailwindcss V4) ✨ | DragNDrop(拖拽占用组件)
前端·react.js·typescript·tailwindcss·vite7
小鱼小鱼干41 分钟前
【Gemini简直无敌了】掌间星河:通过MediaPipe实现手势控制粒子
react.js·gemini
San30.43 分钟前
深度驱动:React Hooks 核心之 `useState` 与 `useEffect` 实战详解
前端·javascript·react.js
huohuopro1 小时前
LangChain | LangGraph V1教程 #3 从路由器到ReAct架构
前端·react.js·langchain
打小就很皮...2 小时前
React 实现富文本(使用篇&Next.js)
前端·react.js·富文本·next.js
开发者小天3 小时前
react的拖拽组件库dnd-kit
前端·react.js·前端框架
全栈前端老曹4 小时前
【ReactNative】核心组件与 JSX 语法
前端·javascript·react native·react.js·跨平台·jsx·移动端开发
xiaoxue..5 小时前
React 之 Hooks
前端·javascript·react.js·面试·前端框架
风止何安啊6 小时前
🚀别再卷 Redux 了!Zustand 才是 React 状态管理的躺平神器
前端·react.js·面试
咸鱼加辣9 小时前
【前端框架】react
前端·react.js·前端框架