小白学前端--第六天(2026/2/7)智慧商城项目-1 (登录界面搭建)
呜呜,应该早一点测试好了QAQ
经历了上一次项目后端接口挂了的经验,这回我选取了一个之前我用vue做过的项目后端接口
接口文档链接如下:wiki - 智慧商城-实战项目
好,那让我们开始今天的搭建吧!
智慧商城项目
零、修改准备
昨天的工作没有白费哦,只需稍作修改就可以适配啦。
首先我们来调整一下request的接口基地址:
//axios
import axios from "axios";
const request= axios.create({
baseURL:'http://smart-shop.itheima.net/index.php?s=/api',//需填写
timeout:5000
})
request.interceptors.request.use((config)=>{
return config
},(error)=>{
return Promise.reject(error)
})
request.interceptors.response.use((response)=>{
return response.data
},(error)=>{
return Promise.reject(error)
})
export {request}
然后查看文档可知,要发的信息长这个样子
要配置一个header,里面要有platform,所以我们继续添加一个请求头
//axios
import axios from "axios";
const request= axios.create({
baseURL:'http://smart-shop.itheima.net/index.php?s=/api',//需填写
timeout:5000
})
request.interceptors.request.use((config)=>{
// 必传 platform
config.headers = config.headers || {};
config.headers.platform = config.headers.platform || "H5";
return config
},(error)=>{
return Promise.reject(error)
})
request.interceptors.response.use((response)=>{
return response.data
},(error)=>{
return Promise.reject(error)
})
export {request}
token的话加后面再加
一、登录界面(续)
没看前面的建议补一下前面的准备阶段哦~
小白学前端--第五天(2026/2/6)电商后台管理-1 (登录页面)-CSDN博客
1.业务逻辑实现(续)
通过观察请求body里面的格式我们可以发现,请求要传一个对象form,里面必须要有四个字段:smsCode,mobile,isParty和partyData 所以我们小小的改动一下Login表单里的字段名称
{
"form": {
"smsCode": "609649",
"mobile": "18917286702",
"isParty": false,
"partyData": {}
}
}
将username和password的name改成mobile字段和smsCode字段,然后再onFinish函数中传过去form,Login的index.js如下:
import React from "react";
import { Form, Input, Button, Typography, Space, Checkbox, Divider } from "antd";
import { UserOutlined, LockOutlined } from "@ant-design/icons";
import "./index.scss";
import bg from "@/assets/Login/login-bg.png";
import { fetchLogin } from "@/store/modules/user";
import { useDispatch } from "react-redux";
const { Title, Text, Link } = Typography;
const Login = () => {
const dispatch =useDispatch()
const onFinish = (value) => {
//异步触发action dispatch
const data={
form: {
...value,
isParty: false,
partyData: {},
},
}
dispatch(fetchLogin(data))
}
return (
{/* 背景图层 */}
{ backgroundImage: `url(${bg})` }} />
{/* 整体背景虚化层(只糊背景,不糊内容) */}
{/* 轻微遮罩层(更有层次) */}
{/* 内容层 */}
{/* 左侧宣传 */}
Smart Mall Admin
智慧商城管理系统 · 高效运营 · 数据驱动
✔ 商品全生命周期管理
✔ 实时订单与库存监控
✔ 精准数据分析与运营决策
{/* 右侧登录 */}
您好!欢迎登录智慧商城
);
};
export default Login;
(顺便改动了一些样式)
让我们再运行一下结果:

这边看到返回200登录成功啦!大家也可以试试自己的登录信息,用户名随便,密码是246810即可哦~
那么接下来就是把我们拿到的token本地化存储,并进行小小的优化啦~
2.优化处理
首先,我们现在utils里面创建一个token.js文件专门管理token有关的操作
之后进行本地化存储
const TOKEN_KEY = "my_smartshop_token";
export const getToken = () => localStorage.getItem(TOKEN_KEY) || "";
export const setToken = (token) => localStorage.setItem(TOKEN_KEY, token);
export const removeToken = () => localStorage.removeItem(TOKEN_KEY);
token_key是标识符,大家可以用下划线命名法命名,不过不要过于简单,容易跟其他程序的Token_key叫一个名就不好了。
然后再request.js里面的请求拦截器里面配置一下请求头,有token再携带token,因为像购物
const token = getToken();
if (token) {
config.headers["Access-Token"] = token;
}
接下来在user.js里面的 fetchLogin加入setToken,已有的token可以暂时不用先注释掉,加上message组件做一个提示,更好的显示登录状态是否成功
user.js如下:
import { createSlice } from "@reduxjs/toolkit";
import { loginAPI } from "@/apis/user";
import { setToken } from "@/utils/token";
import { message } from "antd";
const userStore = createSlice({
name: "user", //
//将这个模块里面的变量放在initialState里面
initialState: {
// token:'',
},
//reducer负责同步修改方法,注意必须是同步哦
reducers: {
// setToken(state,payload)//payload 是专门用于传递「要更新的 token
// // 数据 / 信息」的参数,是状态更新时的数据载体。
// {
// state.token=payload
// }
}
})
const userReducer = userStore.reducer//导出reducer
// const {setToken} = userStore.actions//导出action
const fetchLogin = (loginForm) => {
return async (dispatch) => {
const res = await loginAPI(loginForm)
setToken(res.data.token)
if (res.status === 200) {
setToken(res.data.token);
message.success("登录成功");
return true; // 登录成功,返回 true
}
else {
message.error("登录失败,请检查用户名和密码");
return false; // 登录失败,返回 false
}
}
}
export { setToken, fetchLogin }
export default userReducer
通过true和false返回值决定是否跳转。
在完善onFinish的时候有个要点要注意,因为dispatch是异步更新,所以必须要等到函数执行完才能进行判断是否登录成功。所以要用到async和await机制。
onFinish函数更新如下:
const onFinish = async (value) => {
//异步触发action dispatch
const data={
form: {
...value,
isParty: false,
partyData: {},
},
}
const res = await dispatch(fetchLogin(data))
if (res) {
// 登录成功,执行后续操作,例如跳转到主页
navigate("/");
} else {
// 登录失败
}
}
最后我们跑一下,检验一下是否能够成功跳转以及拿到本地的Token

打开F12的应用程序可以看到token已经拿到了,不会随着刷新而消失了
想了想还是把token字段存在user.js里面吧,重命名一下防止setToken冲突。
import { createSlice } from "@reduxjs/toolkit";
import { loginAPI } from "@/apis/user";
import { setToken as setTokenLocal } from "@/utils/token";
import { message } from "antd";
const userStore = createSlice({
name: "user", //
//将这个模块里面的变量放在initialState里面
initialState: {
token: '',
},
//reducer负责同步修改方法,注意必须是同步哦
reducers: {
setToken(state, payload)//payload 是专门用于传递「要更新的 token
// 数据 / 信息」的参数,是状态更新时的数据载体。
{
state.token = payload
}
}
})
const userReducer = userStore.reducer//导出reducer
const { setToken } = userStore.actions//导出action
const fetchLogin = (loginForm) => {
return async (dispatch) => {
const res = await loginAPI(loginForm)
setToken(res.data.token)
if (res.status === 200) {
setToken(res.data.token);
setTokenLocal(res.data.token); // 将 token 存储到 localStorage
message.success("登录成功");
return true; // 登录成功,返回 true
}
else {
message.error("登录失败,请检查用户名和密码");
return false; // 登录失败,返回 false
}
}
}
export { setToken, fetchLogin }
export default userReducer
可以看到刷新之后redux里面也会有token,说明我们配置本地token已经成功了!

最后检查一下失败情况(输入非246810密码即可),也可以正常实现。

美美提交,我会把代码提交到我的gitCode上公开,大家可以免费查看学习哦~
项目地址:https://gitcode.com/2401_86252365/react









