新闻详情

新闻详情

首页 / 资讯中心 / 详情

umi后台管理项目实战:从工程搭建到生产构建

发布时间:2026/10/1 8:32:09来源:尧图网络
umi后台管理项目实战:从工程搭建到生产构建
1. 引言本文以 umi 为技术底座完整讲解一个后台管理项目的实战落地过程覆盖从基本工程搭建、登录注册、菜单权限配置、页面跳转、用户操作埋点到开发调试与生产构建的完整链路。通过本文你可以掌握一套可复用的 umi 后台管理项目开发范式。2. 基本工程搭建2.1 初始化项目umi 提供了官方脚手架可以快速生成一个带路由、布局和权限模型的基础工程。推荐使用 pnpm 作为包管理器初始化命令如下# 使用 pnpm 创建 umi 项目 pnpm create umi 选择需要的功能antd、dva、qiankun、pro-layout 等 进入项目目录 cd my-admin 安装依赖 pnpm install 启动开发服务 pnpm start初始化完成后项目会生成src、config、public等目录其中config/config.ts是核心配置文件负责路由、插件和构建相关的全局配置。2.2 目录结构规划一个清晰的后台管理项目目录结构可以显著降低后续维护成本。推荐按业务模块划分src/ ├── pages/ # 页面组件按路由组织 ├── components/ # 通用业务组件 ├── layouts/ # 全局布局 ├── services/ # 接口请求层 ├── models/ # 全局状态管理 ├── utils/ # 工具函数 ├── constants/ # 常量定义 └── access.ts # 权限定义2.3 配置路由与布局umi 采用约定式路由与配置式路由相结合的方式。后台管理项目通常使用配置式路由以便统一管理菜单和权限。在config/routes.ts中定义路由结构export default [ { path: /user, layout: false, routes: [ { path: /user/login, component: ./User/Login }, { path: /user/register, component: ./User/Register }, ], }, { path: /, component: /layouts/BasicLayout, routes: [ { path: /dashboard, name: 工作台, icon: DashboardOutlined, component: ./Dashboard }, { path: /system, name: 系统管理, icon: SettingOutlined }, ], }, ];3. 登录注册3.1 登录页实现登录页是后台管理系统的入口。使用 antd 的Form组件实现表单校验配合ProForm可以进一步简化开发。核心逻辑包括表单校验、调用登录接口、存储 Token、跳转首页。import { ProForm, ProFormText } from ant-design/pro-components; import { history } from umi; import { login } from /services/auth; const LoginPage () { const handleSubmit async (values: { username: string; password: string }) { const { token } await login(values); localStorage.setItem(token, token); history.push(/dashboard); }; return ( ProForm onFinish{handleSubmit} ProFormText nameusername label用户名 rules{[{ required: true }]} / ProFormText.Password namepassword label密码 rules{[{ required: true }]} / /ProForm ); }; export default LoginPage;3.2 注册页与验证码注册页通常需要额外的校验逻辑例如确认密码、图形验证码或短信验证码。建议将验证码逻辑封装为独立组件便于复用const CaptchaInput ({ onSend }: { onSend: (phone: string) Promisevoid }) { const [countdown, setCountdown] useState(0); const handleSend async (phone: string) { await onSend(phone); setCountdown(60); const timer setInterval(() { setCountdown((prev) { if (prev 1) { clearInterval(timer); return 0; } return prev - 1; }); }, 1000); }; return ( Space Input placeholder手机号 / Button disabled{countdown 0} onClick{() handleSend()} {countdown 0 ? ${countdown}s 后重发 : 发送验证码} /Button /Space ); };3.3 Token 管理与请求拦截登录成功后需要统一管理 Token。推荐在request.ts中封装请求拦截器自动携带 Token并统一处理 401 未授权场景import { request } from umi; import { history } from umi; const authRequest request.extend({ requestInterceptors: [(url, options) { const token localStorage.getItem(token); if (token) { options.headers { ...options.headers, Authorization: Bearer ${token} }; } return { url, options }; }], responseInterceptors: [(response) { if (response.status 401) { localStorage.removeItem(token); history.push(/user/login); } return response; }], }); export default authRequest;4. 菜单权限配置4.1 权限模型设计后台管理系统的权限通常分为菜单权限和操作权限两层。菜单权限决定用户能看到哪些页面操作权限决定用户能执行哪些按钮操作。推荐使用基于角色的权限模型RBAC用户系统使用者可关联一个或多个角色。角色权限的集合例如管理员、运营、访客。菜单/操作具体的页面入口或按钮动作。4.2 动态路由与菜单生成umi 支持通过access.ts定义权限规则并结合initialState实现动态菜单。登录后从接口获取用户权限列表动态生成菜单// access.ts export default function access(initialState: { currentUser?: API.CurrentUser }) { const { currentUser } initialState || {}; return { canAdmin: currentUser currentUser.roles.includes(admin), canEdit: currentUser currentUser.permissions.includes(edit), }; }// 动态菜单配置 const menuData [ { path: /dashboard, name: 工作台, icon: DashboardOutlined }, { path: /system/user, name: 用户管理, icon: UserOutlined, access: canAdmin }, { path: /system/role, name: 角色管理, icon: TeamOutlined, access: canAdmin }, { path: /system/menu, name: 菜单管理, icon: MenuOutlined, access: canAdmin }, ];4.3 按钮级权限控制除了菜单权限后台管理还经常需要控制页面内的按钮是否可见。可以通过自定义 Hook 或高阶组件实现import { useAccess } from umi; const UserTable () { const access useAccess(); return ( Table columns{[ { title: 用户名, dataIndex: username }, { title: 操作, render: (_, record) ( Space {access.canEdit Button typelink编辑/Button} {access.canAdmin Button typelink danger删除/Button} /Space ) } ]} / ); };5. 页面跳转5.1 声明式跳转umi 提供Link组件和history对象两种跳转方式。声明式跳转适合菜单、面包屑等静态场景import { Link } from umi; const Breadcrumb () ( Link to/system/user用户管理/Link );5.2 编程式跳转在表单提交、按钮点击等交互场景中通常使用编程式跳转并支持携带查询参数import { history } from umi; // 跳转到详情页并携带 id history.push(/system/user/detail?id${userId}); // 带 state 跳转适合传递复杂对象 history.push(/system/user/detail, { userId, from: list }); // 返回上一页 history.back();5.3 路由守卫与重定向未登录用户访问受保护页面时需要自动重定向到登录页。umi 的wrappers机制可以方便地实现路由守卫。下面给出一个更完整的守卫实现支持免登录白名单、登录后重定向回原页面以及全局路由鉴权配置// wrappers/auth.tsx import { Redirect, useLocation } from umi; import { isLogin } from /utils/auth; // 免登录白名单这些页面无需登录即可访问 const WHITE_LIST [/user/login, /user/register, /user/forgot]; const AuthWrapper ({ children }: { children: React.ReactNode }) { const location useLocation(); // 白名单页面直接放行 if (WHITE_LIST.includes(location.pathname)) { return {children}/; } // 未登录则重定向到登录页并携带来源路径登录成功后跳回原页面 if (!isLogin()) { const redirect encodeURIComponent(location.pathname location.search); return Redirect to{/user/login?redirect${redirect}} /; } return {children}/; }; export default AuthWrapper;// utils/auth.ts export const TOKEN_KEY token; export const isLogin () Boolean(localStorage.getItem(TOKEN_KEY)); export const getToken () localStorage.getItem(TOKEN_KEY); export const setToken (token: string) localStorage.setItem(TOKEN_KEY, token); export const clearToken () localStorage.removeItem(TOKEN_KEY);// 路由配置中应用守卫 { path: /dashboard, component: ./Dashboard, wrappers: [/wrappers/auth], }登录成功后根据redirect参数跳回原页面实现免登录重定向闭环// 登录页提交成功后 const { token } await login(values); setToken(token); const redirect new URLSearchParams(location.search).get(redirect); history.push(redirect || /dashboard);6. 页面用户操作埋点6.1 埋点方案设计用户操作埋点用于采集用户在页面上的行为数据为产品决策提供依据。常见的埋点类型包括页面浏览PV/UV、停留时长、来源页面。按钮点击按钮名称、所在页面、点击次数。表单提交提交成功率、失败原因。搜索行为关键词、搜索结果数量。6.2 统一埋点工具封装建议封装统一的埋点工具函数避免在每个页面重复写上报逻辑// utils/tracker.ts interface TrackEvent { event: string; page: string; params?: Recordstring, unknown; } export const track ({ event, page, params }: TrackEvent) { // 上报到埋点服务 fetch(/api/track, { method: POST, body: JSON.stringify({ event, page, params, timestamp: Date.now(), userId: localStorage.getItem(userId), }), }); };6.3 页面浏览埋点页面浏览埋点可以在路由切换时统一触发。umi 提供了onRouteChange配置可以在路由变化时执行埋点逻辑// app.tsx import { track } from /utils/tracker; export function onRouteChange({ location }: { location: { pathname: string } }) { track({ event: page_view, page: location.pathname, }); }6.4 按钮点击埋点按钮点击埋点可以通过封装高阶组件或自定义 Hook 实现减少业务代码侵入// hooks/useTrack.ts import { track } from /utils/tracker; export const useTrack (page: string) { const trackClick (event: string, params?: Recordstring, unknown) { track({ event, page, params }); }; return { trackClick }; }; // 页面中使用 const { trackClick } useTrack(/system/user); const handleDelete (id: number) { trackClick(user_delete, { id }); // 执行删除逻辑 };7. 开发调试7.1 本地开发代理开发阶段前后端分离需要配置代理解决跨域问题。在config/config.ts中配置proxyexport default { proxy: { /api: { target: http://localhost:8080, changeOrigin: true, pathRewrite: { ^/api: }, }, }, };7.2 调试工具与日志开发调试时合理使用浏览器 DevTools 和日志输出可以快速定位问题。建议在utils/logger.ts中封装分级日志工具// utils/logger.ts const isDev process.env.NODE_ENV development; export const logger { info: (...args: unknown[]) { if (isDev) console.info([INFO], ...args); }, warn: (...args: unknown[]) { if (isDev) console.warn([WARN], ...args); }, error: (...args: unknown[]) { console.error([ERROR], ...args); }, };7.3 状态调试使用 dva 或 valtio 等状态管理方案时可以借助 Redux DevTools 或自定义中间件查看状态变化。推荐在开发环境开启状态日志方便追踪数据流// models/user.ts export default { namespace: user, state: { list: [], loading: false }, reducers: { save(state, { payload }) { logger.info(user/save, payload); return { ...state, ...payload }; }, }, };8. 开发生产构建8.1 环境变量管理不同环境开发、测试、生产通常需要不同的接口地址和配置。umi 支持通过.env文件管理环境变量# .env.development API_BASE_URLhttp://localhost:8080/api .env.production API_BASE_URLhttps://api.example.com/api// 代码中读取环境变量 const apiBase process.env.API_BASE_URL;8.2 生产构建配置生产构建需要关注代码压缩、资源分包、CDN 路径等。umi 默认集成了 webpack 优化但部分场景需要手动调整export default { define: { process.env.API_BASE_URL: process.env.API_BASE_URL, }, hash: true, // 生成带 hash 的资源文件名 publicPath: process.env.NODE_ENV production ? https://cdn.example.com/ : /, chunks: [vendors, umi], chainWebpack(config) { config.optimization.splitChunks({ cacheGroups: { vendors: { name: vendors, test: /[\\/]node_modules[\\/]/, priority: 10, chunks: all, }, }, }); }, };8.3 构建与部署生产构建命令为pnpm build构建产物输出到dist目录。部署时需要注意将dist目录部署到 Nginx 或对象存储。配置 SPA 路
网站建设高端定制企业官网
RELATED

相关资讯

更多精彩内容,欢迎继续阅读

较早相关资讯

最新相关资讯

RT-2:把机器人动作当成“外语单词“——让网络知识直接长成操作技能 2026/10/1 10:13:24

RT-2:把机器人动作当成“外语单词“——让网络知识直接长成操作技能

RT-2:把机器人动作当成"外语单词"——让网络知识直接长成操作技能 原文:RT-2: Vision-Language-Action Models Transfer Web Knowledge to Robotic Control 作者:Anthony Brohan, Noah Brown, Justice Carbajal … Brianna Zitkovich(Google DeepMind,作者按字母…

阅读更多 →
视频生成ai哪个好?稿定AI!!技术原理与场景化应用实践 2026/10/1 10:13:18

视频生成ai哪个好?稿定AI!!技术原理与场景化应用实践

稿定AI视频生成的技术实现稿定AI视频生成基于自研的时空扩散架构,结合了多模态语义编码与潜空间压缩技术。核心创新点在于轻量化时序注意力模块,通过分组注意力机制降低显存占用,使消费级GPU也能完成短时长视频推理。操作流程分四步。第一步&…

阅读更多 →
机器学习网络入侵检测系统实战:从数据准备到部署全记录 2026/10/1 10:13:18

机器学习网络入侵检测系统实战:从数据准备到部署全记录

前段时间接了一个安全方向的项目,客户要求做一套网络入侵检测系统,但明确不想继续依赖传统规则库,而是希望用机器学习从流量数据里识别异常行为。这个需求听起来不复杂,实际落地时从数据、特征、模型到部署全流程踩了不少坑。我把…

阅读更多 →
为什么很多企业的年度预算总不准?问题不在预算,而在规划机制 2026/10/1 10:13:11

为什么很多企业的年度预算总不准?问题不在预算,而在规划机制

“你是否也在经历这些预算之痛?年度预算花了三个月编制完成,刚过一季度,偏差就已经超过15%。销售说市场变了,采购说价格涨了,生产说产能跟不上——而财务部门只能拿着过时的数据,一遍遍解释实际经营为什么和…

阅读更多 →
搜索系列 · 第 02 篇——架构拆解:从节点到分片路由 2026/10/1 10:13:11

搜索系列 · 第 02 篇——架构拆解:从节点到分片路由

节点角色 集群发现 分片路由 近实时引擎目 录一、导读 二、Lucene 索引与近实时引擎 2.1 段(Segment)与提交 2.2 近实时刷新(Refresh) 2.3 段合并与 flush 三、节点角色与集群组织 3.1 节点角色 3.2 集群发现 四、分片路由与协…

阅读更多 →
CTF题目《UnserializeThree》(BUUCTF Web 困难 反序列化) 2026/10/1 10:13:11

CTF题目《UnserializeThree》(BUUCTF Web 困难 反序列化)

DASCTF 上传题(Hack Me)—— phar 反序列化 getshell 详细题解 面向零基础读者的一步步解析。每一步都会先说明「看到什么」,再说明「为什么这样做」,最后给出「具体怎么做」。 〇、先看结论(TL;DR) 考点&…

阅读更多 →

今日资讯

本周资讯

本月资讯

看完文章仍有疑问?

联系尧图顾问,获取一对一建站咨询

立即免费咨询 📞 400-888-8888
📞 ✉