Vue3 后台管理系统模板

Vue3 后台管理系统模板

gie仓库地址

一个基于 Vue3 + TypeScript + Element Plus 的后台管理系统模板,集成了动态路由和权限管理功能。

技术栈

  • Vue 3.2
  • TypeScript 4.5
  • Vue Router 4
  • Vuex 4
  • Element Plus 2.9
  • Axios
  • Less

功能特性

  • 🚀 基于 Vue3 最新技术栈开发
  • 📦 使用 TypeScript 进行开发,提供更好的类型检查和开发体验
  • 🔐 完整的权限管理解决方案,支持动态路由和按钮级权限控制
  • 🎨 使用 Element Plus 组件库,提供美观的 UI 界面
  • 📱 响应式设计,支持多种设备访问
  • 🔧 支持 PWA,可离线访问
  • 📝 集成 ESLint + Prettier,统一代码风格

项目结构

复制代码
src/
├── assets/         # 静态资源
├── components/     # 公共组件
├── hooks/          # Vue3 组合式 API 钩子
├── network/        # 网络请求相关
├── plugins/        # 插件
├── router/         # 路由配置
├── store/          # Vuex 状态管理
├── utils/          # 工具函数
└── views/          # 页面组件

安装和使用

环境要求

  • Node.js >= 14.0.0
  • npm >= 6.0.0

安装依赖

bash 复制代码
npm install

开发环境运行

bash 复制代码
npm run serve

生产环境构建

bash 复制代码
npm run build

代码检查

bash 复制代码
npm run lint

权限管理

本项目实现了完整的权限管理功能,包括动态路由和按钮级权限控制。以下是详细的实现说明:

1. 权限管理架构

权限管理主要包含以下几个部分:

  • 路由权限控制
  • 菜单权限控制
  • 按钮级权限控制
  • 数据权限控制

2. 实现细节

2.1 路由权限控制
  1. 路由守卫实现

    • router/index.ts 中实现全局路由守卫
    • 检查用户是否登录(通过 token)
    • 动态添加路由配置
  2. 动态路由生成

    • 用户登录后获取权限菜单数据
    • 通过 addDynamicRoutes 工具函数动态生成路由
    • 支持路由懒加载,提高性能
  3. 路由配置示例

typescript 复制代码
// 路由守卫实现
router.beforeEach((to, from, next) => {
  const token = localStorage.getItem('token');
  if (!token && to.meta.check) {
    next({ name: 'login' });
    return;
  }
  // 动态添加路由
  if (token && !layoutRoute.children.length) {
    const menus = JSON.parse(localStorage.getItem('menus') || '[]');
    addDynamicRoutes(router, menus);
    next({ ...to, replace: true });
    return;
  }
  next();
});
2.2 菜单权限控制
  1. 菜单数据结构

    • 支持多级菜单
    • 包含路径、名称、组件、元数据等信息
    • 支持菜单图标、权限标识等扩展属性
  2. 菜单渲染

    • 根据用户权限动态生成菜单
    • 支持菜单缓存,提高性能
    • 支持菜单排序和分组
2.3 按钮级权限控制
  1. 权限指令实现

    • 通过自定义指令 v-permission 控制按钮显示
    • 支持权限表达式,如:v-permission="['add', 'edit']"
    • 支持权限组合判断
  2. 使用示例

vue 复制代码
<template>
  <el-button v-permission="['add']">添加</el-button>
  <el-button v-permission="['edit']">编辑</el-button>
  <el-button v-permission="['delete']">删除</el-button>
</template>
2.4 数据权限控制
  1. 数据过滤

    • 根据用户角色过滤数据
    • 支持数据范围控制
    • 支持字段级权限控制
  2. 实现方式

    • 在 API 请求中添加权限参数
    • 后端根据权限参数过滤数据
    • 前端处理权限数据展示

3. 权限管理流程

  1. 登录流程

    • 用户输入账号密码登录
    • 获取用户 token 和权限信息
    • 存储权限信息到本地存储
  2. 权限验证流程

    • 路由跳转时验证权限
    • 动态生成路由和菜单
    • 控制按钮和数据的访问权限
  3. 权限更新流程

    • 支持动态更新权限
    • 支持权限缓存清理
    • 支持权限实时生效

4. 安全考虑

  1. 前端安全

    • 敏感信息加密存储
    • 路由权限双重验证
    • XSS 防护
  2. 后端安全

    • 接口权限验证
    • 数据权限过滤
    • 防 SQL 注入

接口封装

本项目采用统一的接口封装方案,提供了完整的请求拦截、响应拦截和错误处理机制。以下是详细的实现说明:

1. 接口封装架构

接口封装主要包含以下几个部分:

  • 请求实例配置
  • 请求拦截器
  • 响应拦截器
  • 接口模块化
  • 统一错误处理

2. 实现细节

2.1 请求实例配置
typescript 复制代码
const service = axios.create({
    baseURL: "/api/pc",
    timeout: 40000,
    headers: {
        "Access-Control-Allow-Origin": "*",
        "Connection": "Keep-Alive",
        "Content-Type": "application/json; charset = utf-8"
    }
})
2.2 请求拦截器
typescript 复制代码
service.interceptors.request.use(
    config => {
        const token = localStorage.getItem("token");
        if (token) {
            config.headers["access-token"] = token
        }
        return config;
    }
)
2.3 响应拦截器
typescript 复制代码
service.interceptors.response.use(
    (res) => {
        const code = res.data.code
        if (code == 100) {
            router.push({ name: "login" });
        } else if (code == 1) {
            ElMessage({
                message: res.data.msg,
                type: 'warning'
            });
        }
        return res
    }, (error) => {
        return Promise.reject(error);
    }
)
2.4 接口模块化
  1. 目录结构

    src/network/
    ├── index.ts # 请求配置和拦截器
    └── apis/ # 接口模块
    ├── home.ts # 首页相关接口
    ├── work.ts # 工作相关接口
    └── user.ts # 用户相关接口

  2. 接口定义示例

typescript 复制代码
// apis/home.ts
export default {
    // 获取首页数据
    getHomeData: (params: any) => ({
        url: '/home/data',
        method: 'get',
        params
    }),
    // 更新首页数据
    updateHomeData: (data: any) => ({
        url: '/home/update',
        method: 'post',
        data
    })
}
  1. 接口调用示例
typescript 复制代码
import getData from '@/network';

// 获取首页数据
const getHomeData = async () => {
    try {
        const res = await getData('home/getHomeData', { page: 1 });
        return res.data;
    } catch (error) {
        console.error('获取首页数据失败:', error);
    }
}

3. 接口封装特点

  1. 统一配置

    • 统一的 baseURL 配置
    • 统一的超时时间设置
    • 统一的请求头配置
  2. 自动处理

    • 自动添加 token
    • 自动处理登录过期
    • 自动处理错误提示
  3. 模块化管理

    • 按功能模块划分接口
    • 支持接口自动导入
    • 支持接口命名空间
  4. 类型支持

    • 完整的 TypeScript 类型支持
    • 接口参数类型检查
    • 响应数据类型定义

4. 错误处理机制

  1. 请求错误处理

    • 网络错误处理
    • 超时错误处理
    • 请求取消处理
  2. 响应错误处理

    • 状态码错误处理
    • 业务错误处理
    • 登录过期处理
  3. 错误提示

    • 统一的错误提示组件
    • 可配置的错误提示方式
    • 支持自定义错误处理

5. 使用建议

  1. 接口定义

    • 使用 TypeScript 定义接口类型
    • 添加详细的接口注释
    • 遵循统一的命名规范
  2. 接口调用

    • 使用 async/await 处理异步
    • 添加适当的错误处理
    • 注意请求参数的合法性
  3. 性能优化

    • 合理使用请求缓存
    • 避免重复请求
    • 控制并发请求数量

贡献指南

欢迎提交 Issue 和 Pull Request 来帮助改进项目。

权限说明

javascript 复制代码
    <!-- 路由格式 -->
    使用方式,登录后后端返回数据格式,根据这个格式,把所有路径路由配置放在这里,读取的时候让后台判断,返回那些路径,与后端沟通好.
    <!-- 把路由配置放在这里 -->
    parentId: id;
    index: index;
    title:一级路由名称
    icon:图标 我用的是iconfont 的图标 根据自己情况替换就行了;
    type: group;
    children: [ //子级路由
    index:index;
    title:二级路由名称
    path:path;
    name:name;
    component:文件读取路径 读取pages 文件 路径// 看不明白的就把这里的路径和pages 下的路径对比一下就明白了
    menuType:menuType;
    meta:   路由原信息
    ] ;
    "nav": [
        {
            "parentId": "1",
            "index": "1",
            "title": "首页",
            "icon": "icon-shouye",
            "type": "group",
            "children": [
                {
                    "index": "1-1",
                    "title": "首页",
                    "name": "home",
                    "path": "/home",
                    "component": "shouYe/index",
                    "menuType": 0,
                    "meta": {
                        "selectIndex": "1-1",
                        "check": true
                    }
                }
            ]
        },
        {
            "parentId": "2",
            "index": "2",
            "title": "设备管理",
            "icon": "icon-shebei",
            "type": "group",
            "children": [
                {
                    "index": "2-1",
                    "title": "设备列表",
                    "name": "shebei",
                    "path": "/shebei",
                    "component": "shebei/shebei",
                    "menuType": 0,
                    "meta": {
                        "selectIndex": "2-1",
                        "check": true
                    }
                }
            ]
        },
        {
            "parentId": "3",
            "index": "3",
            "title": "模块管理",
            "icon": "icon-mokuai",
            "type": "group",
            "children": [
                {
                    "index": "3-1",
                    "title": "模块列表",
                    "name": "mokuai",
                    "path": "/mokuai",
                    "component": "mokuai/Mokuai",
                    "menuType": 0,
                    "meta": {
                        "selectIndex": "3-1",
                        "check": true
                    }
                }
            ]
        },
        {
            "parentId": "4",
            "index": "4",
            "title": "标靶检测",
            "icon": "icon-mubiaobachang1",
            "type": "group",
            "children": [
                {
                    "index": "4-1",
                    "title": "报警列表",
                    "name": "jingIndex",
                    "path": "/jingIndex",
                    "component": "biaoba/index",
                    "menuType": 0,
                    "meta": {
                        "selectIndex": "4-1",
                        "check": true
                    }
                },
                {
                    "index": "4-2",
                    "title": "标靶检测",
                    "name": "biaoba",
                    "path": "/biaoba",
                    "component": "biaoba/biaoba",
                    "menuType": 0,
                    "meta": {
                        "selectIndex": "4-2",
                        "check": true
                    }
                },
                {
                    "index": "4-3",
                    "title": "标靶报警",
                    "name": "baojing",
                    "path": "/baojing",
                    "component": "biaoba/baojing",
                    "menuType": 0,
                    "meta": {
                        "selectIndex": "4-3",
                        "check": true
                    }
                },
                {
                    "index": "4-4",
                    "title": "报警等级",
                    "name": "dengji",
                    "path": "/dengji",
                    "component": "biaoba/dengji",
                    "menuType": 0,
                    "meta": {
                        "selectIndex": "4-4",
                        "check": true
                    }
                }
            ]
        }
    ]

许可证

MIT

相关推荐
崔庆才丨静觅5 小时前
hCaptcha 验证码图像识别 API 对接教程
前端
passerby60616 小时前
完成前端时间处理的另一块版图
前端·github·web components
掘了6 小时前
「2025 年终总结」在所有失去的人中,我最怀念我自己
前端·后端·年终总结
崔庆才丨静觅6 小时前
实用免费的 Short URL 短链接 API 对接说明
前端
崔庆才丨静觅6 小时前
5分钟快速搭建 AI 平台并用它赚钱!
前端
崔庆才丨静觅7 小时前
比官方便宜一半以上!Midjourney API 申请及使用
前端
Moment7 小时前
富文本编辑器在 AI 时代为什么这么受欢迎
前端·javascript·后端
崔庆才丨静觅7 小时前
刷屏全网的“nano-banana”API接入指南!0.1元/张量产高清创意图,开发者必藏
前端
剪刀石头布啊7 小时前
jwt介绍
前端
爱敲代码的小鱼7 小时前
AJAX(异步交互的技术来实现从服务端中获取数据):
前端·javascript·ajax