先看几张图:
在现代前端开发中,构建一个高效灵活的后台管理系统已成为许多开发者的一个基本要求,发布构建是否够快,尤其是当项目不断迭代,代码不断增多后,是否还能高效构建。
本文将介绍一个基于React、Vite和Antd的标准后台管理系统开发模板,支持动态菜单配置和权限精确到按钮的实现。通过这个模板,开发者可以迅速搭建起一个功能完备、可扩展性强的后台管理系统,没有使用create-rect-app脚手架,完全从0开始自己搭建,使用了目前比较先进的技术。
技术栈:
react+redux+hook+vite+antd+less+axios 基于vite构建,本地开发体验很不错
非服务端渲染,仿antd-pro外观,但没有使用dva和roadhog
目录结构:
项目启动:
pnpm install // 安装依赖模块
pnpm run dev // 运行开发环境
pnpm run build // 正式打包,生成最终代码
pnpm run preview // 本地运行正式打包后的最终代码
pnpm run prettier // 一键格式化代码
启动问题:
执行 npm run build 后有提示ts错误,传入的类型和实际定义的不符
解决办法:找到getData方法的定义,入参增加any即可。
本地开发走mock:
本地使用 mockjs 进行接口拦截做本地mock数据。
正式环境需要关闭此配置。
/**
* MOCK模拟数据
* 不需要下面这些mock配置,仅本地用
* */
import Mock from "mockjs";
// @ts-ignore
import mock from "../../mock/app-data.js";
Mock.mock(/\/api.*/, (options: any) => {
const res = mock(options);
return res;
});
动态菜单配置:
接口按照此格式返回即可。
/**
* MOCK模拟数据
* 不需要下面这些mock配置,仅本地用
* 正式打包需要去掉
* */
import Mock from "mockjs";
// @ts-ignore
import mock from "../../mock/app-data.js";
Mock.mock(/\/api.*/, (options: any) => {
const res = mock(options);
return res;
});// 所有的菜单数据
const menus = [
{
id: 1,
title: "首页",
icon: "icon-home",
url: "/home",
parent: null,
desc: "首页",
sorts: 0,
conditions: 1,
},
{
id: 2,
title: "系统管理",
icon: "icon-setting",
url: "/system",
parent: null,
desc: "系统管理目录分支",
sorts: 1,
conditions: 1,
},
{
id: 3,
title: "用户管理",
icon: "icon-user",
url: "/system/useradmin",
parent: 2,
desc: "系统管理/用户管理",
sorts: 0,
conditions: 1,
},
{
id: 4,
title: "角色管理",
icon: "icon-team",
url: "/system/roleadmin",
parent: 2,
desc: "系统管理/角色管理",
sorts: 1,
conditions: 1,
},
{
id: 5,
title: "权限管理",
icon: "icon-safetycertificate",
url: "/system/poweradmin",
parent: 2,
desc: "系统管理/权限管理",
sorts: 2,
conditions: 1,
},
{
id: 6,
title: "菜单管理",
icon: "icon-appstore",
url: "/system/menuadmin",
parent: 2,
desc: "系统管理/菜单管理",
sorts: 3,
conditions: 1,
},
];// 所有的菜单数据
const menus = [
{
id: 1,
title: "首页",
icon: "icon-home",
url: "/home",
parent: null,
desc: "首页",
sorts: 0,
conditions: 1,
},
{
id: 2,
title: "系统管理",
icon: "icon-setting",
url: "/system",
parent: null,
desc: "系统管理目录分支",
sorts: 1,
conditions: 1,
},
{
id: 3,
title: "用户管理",
icon: "icon-user",
url: "/system/useradmin",
parent: 2,
desc: "系统管理/用户管理",
sorts: 0,
conditions: 1,
},
{
id: 4,
title: "角色管理",
icon: "icon-team",
url: "/system/roleadmin",
parent: 2,
desc: "系统管理/角色管理",
sorts: 1,
conditions: 1,
},
{
id: 5,
title: "权限管理",
icon: "icon-safetycertificate",
url: "/system/poweradmin",
parent: 2,
desc: "系统管理/权限管理",
sorts: 2,
conditions: 1,
},
{
id: 6,
title: "菜单管理",
icon: "icon-appstore",
url: "/system/menuadmin",
parent: 2,
desc: "系统管理/菜单管理",
sorts: 3,
conditions: 1,
},
];
登录信息保存:
登录状态保存在的localstorage内
// 用户提交登录
const onSubmit = async (): Promise<void> => {
try {
const values = await form.validateFields();
setLoading(true);
const res = await loginIn(values.username, values.password);
if (res && res.status === 200) {
message.success("登录成功");
if (rememberPassword) {
localStorage.setItem(
"userLoginInfo",
JSON.stringify({
username: values.username,
password: tools.compile(values.password), // 密码简单加密一下再存到localStorage
})
); // 保存用户名和密码
} else {
localStorage.removeItem("userLoginInfo");
}
/** 将这些信息加密后存入sessionStorage,并存入store **/
sessionStorage.setItem(
"userinfo",
tools.compile(JSON.stringify(res.data))
);
await dispatch.app.setUserInfo(res.data);
navigate("/"); // 跳转到主页
} else {
message.error(res?.message ?? "登录失败");
setLoading(false);
}
} catch (e) {
// 验证未通过
}
};
github地址:https://github.com/javaLuo/react-admin