返回 导航

Vue.js

hangge.com

Vue.js - 后台管理系统模板项目推荐1(Vue Vben Admin,综合天花板、企业级首选)

作者:hangge | 2026-09-14 09:13
    在企业级后台管理系统、OA 系统、数据中台、权限管理平台开发中,如果从零搭建项目架构、封装通用组件、配置路由权限、适配样式主题,会耗费开发者大量时间精力。目前开源社区诞生了大量优质的 Vue 后台管理模板,均已封装路由管理、权限控制、动态菜单、Mock 数据、全局样式、常用业务组件等通用能力,支持快速二次开发,大幅提升项目落地效率。本文将为大家推荐一个主流且优质的后台管理系统模板项目:Vue Vben Admin

一、Vue Vben Admin(企业级首选、综合天花板)

1,基本介绍

(1)vue-vben-admin(简称 Vben Admin)是一个基于 Vue3ViteTypeScript 的现代化企业级中后台管理系统前端解决方案,由 vbenjs 团队开发维护,GitHub 星标超 30k+,是 Vue3 生态中架构先进、功能完备、开箱即用的中大型后台开发框架。

(2)简单说 vue-vben-admin 不是现成业务系统,而是一个高度工程化的后台开发脚手架,集成了中后台所需的所有核心能力,同时支持多 UI 组件库切换,帮助团队快速搭建高质量、可维护的企业级管理平台。

2,核心技术栈

技术项 版本 / 选型 核心价值
核心框架 Vue3Composition API+setup 语法糖) 更好的代码组织、逻辑复用、类型推导,性能优化显著
构建工具 Vite 极速冷启动、热更新,开发效率提升 5-10 倍,构建速度更快
语言 TypeScript(强制类型校验) 减少类型错误,提升代码可维护性,大型项目更稳健
UI 组件系统 核心使用 Ant Design Vue,同时支持多种可选 UI 库(AntD NextElement PlusNaive UITDesign 等) 可自由切换组件库,无需重写业务逻辑,适配不同团队技术偏好
样式方案 Tailwind CSS v4 原子化 CSS,开发速度快,样式一致性好,体积小
状态管理 PiniaVue 官方推荐) 更简洁 API,更好的 TypeScript 支持,无嵌套模块限制
路由 Vue Router 4.x 更好的 Vue3 集成,支持 Composition API,动态路由更灵活
架构模式 Monorepopnpm workspace 代码组织更高效,支持多包管理,方便组件复用和版本控制
网络请求 Axios(深度封装) 完善的请求拦截、错误处理、类型定义、取消请求等功能

3,项目优缺点

(1)优点:
  • 架构极致解耦,模块化、规范化程度极高,支持大型团队协作开发
  • 内置完善的 AI 业务适配能力,完美支持 RAG 知识库、大数据量预览、流式响应场景
  • 支持多 UI 框架切换,组件复用性强,自定义拓展成本极低
  • 完善的权限体系、细粒度按钮权限、动态路由、菜单缓存功能
  • 文档详尽、社区活跃、问题迭代速度快
(2)缺点:
  • 功能丰富导致项目体积稍大,新手入门有一定学习成本,小型轻量化项目略显冗余

4,准备工作

(1)首先需求安装 Node.js,并且官方要求 Node.js 22.18.0 及以上版本。我们只需要访问其官网下载安装即可。

(2)同时项目只支持使用 pnpm 进行依赖安装,我们还需要执行如下命令安装 pnpm
npm i -g pnpm

(3)安装完毕可以通过 pnpm -v 命令进行验证:

5,下载项目

(1)在 CMD 终端种执行如下命令克隆代码,然后进入项目:
git clone https://github.com/vbenjs/vue-vben-admin.git
cd vue-vben-admin

(2)整个项目的目录结构如下:
.
├── README.md # 项目说明文档
├── apps # 项目应用目录
│   ├── backend-mock # 后端模拟服务应用
│   ├── web-antd # 基于 Ant Design Vue 的前端应用(功能最全的示例前端)
│   ├── web-antdv-next # 基于 Ant Design Vue Next 的前端应用
│   ├── web-ele # 基于 Element Plus 的前端应用
│   ├── web-naive # 基于 Naive UI 的前端应用
│   └── web-tdesign # 基于 TDesign 的前端应用
├── cspell.json # CSpell 配置文件
├── docs # 项目文档目录
├── eslint.config.mjs # ESLint 配置文件
├── lefthook.yml # Git Hook 配置文件
├── internal # 内部工具目录
│   ├── lint-configs # 代码检查配置
│   │   ├── commitlint-config # Commitlint 配置
│   │   ├── eslint-config # ESLint 配置
│   │   ├── oxfmt-config # Oxfmt 配置
│   │   ├── oxlint-config # Oxlint 配置
│   │   └── stylelint-config # Stylelint 配置
│   ├── node-utils # Node.js 工具
│   ├── tsconfig # 通用 tsconfig 配置
│   └── vite-config # 通用 Vite 配置
├── oxfmt.config.ts # Oxfmt 配置入口
├── oxlint.config.ts # Oxlint 配置文件
├── package.json # 项目依赖配置
├── packages # 项目包目录
│   ├── @core # 核心包
│   │   ├── base # 基础包
│   │   │   ├── design # 设计相关
│   │   │   ├── icons # 图标
│   │   │   ├── shared # 共享
│   │   │   └── typings # 类型定义
│   │   ├── composables # 组合式 API
│   │   ├── preferences # 偏好设置
│   │   └── ui-kit # UI 组件集合
│   │       ├── layout-ui # 布局 UI
│   │       ├── menu-ui # 菜单 UI
│   │       ├── shadcn-ui # shadcn UI
│   │       └── tabs-ui # 标签页 UI
│   ├── constants # 常量
│   ├── effects # 副作用相关包
│   │   ├── access # 访问控制
│   │   ├── plugins # 第三方大型依赖插件
│   │   ├── common-ui # 通用 UI
│   │   ├── hooks # 组合式 API
│   │   ├── layouts # 布局
│   │   └── request # 请求
│   ├── icons # 图标
│   ├── locales # 国际化
│   ├── preferences # 偏好设置
│   ├── stores # 状态管理
│   ├── styles # 样式
│   ├── types # 类型定义
│   └── utils # 工具
├── playground # 演示目录
├── pnpm-lock.yaml # pnpm 锁定文件
├── pnpm-workspace.yaml # pnpm 工作区配置文件
├── scripts # 脚本目录
│   ├── deploy # 部署相关脚本
│   ├── turbo-run # Turbo 运行脚本
│   └── vsh # VSH 脚本
├── stylelint.config.mjs # Stylelint 配置文件
├── turbo.json # Turbo 配置文件
├── vben-admin.code-workspace # VS Code 工作区配置文件
└── vitest.config.ts # Vitest 配置文件

(3)然后再项目目录下执行如下命令安装依赖:
pnpm install

6,启动项目

(1)执行如下命令可启动开发服务器。该命令执行后会提示选择运行哪个版本应用(Ant Design VueElement PlusNaive UITDesign 等)
pnpm dev

(2)我们也可直接指定启动命令,例如下面命令直接开启 Ant Design Vue 版本。
pnpm dev:antd

(3)使用浏览器访问,默认显示登录页:

(4)登录后内页显示效果如下:

(5)切换成浅色模式效果如下:

7,打包与部署

(1)运行下面命令执行多应用打包。生成结果会输出到各应用的 dist/ 目录。部署时可直接使用打包结果。
pnpm build

(2)项目内置 build:docker 脚本,可构建本地 Docker 镜像(需先安装 Docker)。执行命令如下:
提示:这将启动一个 Nginx 容器托管前端应用。可在仓库中自行编写 Dockerfile 以定制镜像。
pnpm run build:docker
docker run -p 80:80 vben-admin:latest

附:项目常用功能与主要代码详解

1,登录/登出

(1)前端登录通常在 src/views/_core/authentication/login.vue 中实现。使用内置的 AuthenticationLogin 组件配合 PiniaauthStore 完成表单提交:
<template>
  <AuthenticationLogin
    :loading="authStore.loginLoading"
    @submit="authStore.authLogin"
  />
</template>
<script setup lang="ts">
import { useAuthStore } from '@/store/modules/auth';
const authStore = useAuthStore();
</script>

(2)其中 authStore.authLogin 方法会调用后端登录接口(如 axios.post('/login',credentials)),并在成功后保存用户信息和权限,然后跳转到首页。
 
(3)登出可调用 authStore.logout() 清除登录状态并跳转到登录页。

2,权限控制 (RBAC)

(1)路由配置中可以通过 meta.authority 指定可访问该路由的角色。例如:
// 示例:只有管理员可访问的路由
{
  path: '/admin',
  name: 'AdminPage',
  component: () => import('@/views/AdminPage.vue'),
  meta: { authority: ['admin'] },
}

(2)登录成功后,会根据后台返回的用户角色列表(如 userInfo.roles = ['admin','user'])过滤路由,将符合条件的路由动态加入到路由表。这样不同角色登录后可见不同的菜单。
 
(3)框架还支持设置 menuVisibleWithForbidden: true 实现“菜单可见但页面禁止访问”跳转 403 页面。

3,动态路由

(1)新增路由时,可在对应应用的 src/router/routes/modules/ 目录下创建模块文件:
import type { RouteRecordRaw } from 'vue-router';

const routes: RouteRecordRaw[] = [
  {
    meta: {
      icon: 'lucide:home',
      title: '测试模块',
    },
    name: 'Test',
    path: '/test',
    children: [
      {
        name: 'TestPage1',
        path: '/test/page1',
        component: () => import('#/views/test/page1/index.vue'),
        meta: {
          icon: 'lucide:file-text',
          title: 'Page 1',
        },
      },
      {
        name: 'TestPage2',
        path: '/test/page2',
        component: () => import('#/views/test/page2/index.vue'),
        meta: {
          icon: 'lucide:file',
          title: 'Page 2',
        },
      },
    ],
  },
];

export default routes;

(2)效果如下:

4,表单与表格

(1)我们除了可以直接使用原生写法来使用 Ant Design Vue 提供的表单和表格组件外,vben-admin 封装了 useVbenFormuseVbenVxeGrid 两个强大的 Hook,可以声明式配置表单和表格。
传统 Ant Design 声明式 Vben
手动写 <a-form-item> 配置 schema 数组
手动绑定 v-model 自动处理表单值
手写分页逻辑 内置 proxyConfig 自动请求
手写 loading 状态 自动管理

(2)下面是一个使用 useVbenForm 实现的表单样例:
<script lang="ts" setup>
import { ref } from 'vue';

import { Page } from '@vben/common-ui';

import { message } from 'ant-design-vue';

import { useVbenForm } from '#/adapter/form';

// 表单 Schema 配置 - 声明式定义表单字段
const formSchema = [
  {
    component: 'Input',
    fieldName: 'username',
    label: '用户名',
    rules: 'required',
    componentProps: {
      placeholder: '请输入用户名',
    },
  },
  {
    component: 'InputPassword',
    fieldName: 'password',
    label: '密码',
    rules: 'required',
    componentProps: {
      placeholder: '请输入密码',
    },
  },
  {
    component: 'Input',
    fieldName: 'email',
    label: '邮箱',
    rules: 'required',
    componentProps: {
      placeholder: '请输入邮箱',
    },
  },
  {
    component: 'Select',
    fieldName: 'role',
    label: '角色',
    componentProps: {
      placeholder: '请选择角色',
      options: [
        { label: '管理员', value: 'admin' },
        { label: '普通用户', value: 'user' },
        { label: '访客', value: 'guest' },
      ],
    },
  },
  {
    component: 'RadioGroup',
    fieldName: 'status',
    label: '状态',
    defaultValue: 1,
    componentProps: {
      optionType: 'button',
      buttonStyle: 'solid',
      options: [
        { label: '启用', value: 1 },
        { label: '禁用', value: 0 },
      ],
    },
  },
  {
    component: 'RangePicker',
    fieldName: 'dateRange',
    label: '生效日期',
  },
  {
    component: 'Textarea',
    fieldName: 'remark',
    label: '备注',
    componentProps: {
      placeholder: '请输入备注信息',
      rows: 4,
    },
  },
];

// 使用 useVbenForm 创建表单
const [Form, formApi] = useVbenForm({
  schema: formSchema,
  showDefaultActions: false,
});

// 表单提交
const loading = ref(false);
async function handleSubmit() {
  const { valid } = await formApi.validate();
  if (!valid) return;

  loading.value = true;
  const values = await formApi.getValues();

  setTimeout(() => {
    loading.value = false;
    message.success('提交成功!');
    console.log('表单数据:', values);
  }, 1000);
}

// 重置表单
function handleReset() {
  formApi.resetForm();
  message.info('表单已重置');
}
</script>

<template>
  <Page title="BasicForm 表单演示">
    <div class="p-6">
      <a-card title="用户信息表单">
        <Form />
        <div class="mt-4 flex gap-2">
          <a-button type="primary" :loading="loading" @click="handleSubmit">
            提交
          </a-button>
          <a-button @click="handleReset">
            重置
          </a-button>
        </div>
      </a-card>
    </div>
  </Page>
</template>

(3)下面是使用 useVbenVxeGrid 实现的表格样例:
<script lang="ts" setup>
import type { VxeTableGridOptions } from '#/adapter/vxe-table';

import { Page } from '@vben/common-ui';

import { message } from 'ant-design-vue';

import { useVbenVxeGrid } from '#/adapter/vxe-table';

// 表格列配置
const columns = [
  { field: 'id', title: 'ID', width: 80 },
  { field: 'name', title: '姓名', width: 150 },
  { field: 'email', title: '邮箱', minWidth: 200 },
  { field: 'phone', title: '电话', width: 150 },
  {
    field: 'status',
    title: '状态',
    width: 100,
    cellRender: { name: 'CellTag' },
  },
  { field: 'createTime', title: '创建时间', width: 180 },
  {
    field: 'operation',
    title: '操作',
    width: 150,
    fixed: 'right',
    cellRender: {
      name: 'CellOperation',
      attrs: { onClick: onActionClick },
    },
  },
];

// 搜索表单配置
const searchFormSchema = [
  {
    component: 'Input',
    fieldName: 'name',
    label: '姓名',
    componentProps: { placeholder: '请输入姓名' },
  },
  {
    component: 'Select',
    fieldName: 'status',
    label: '状态',
    componentProps: {
      placeholder: '请选择状态',
      allowClear: true,
      options: [
        { label: '启用', value: 1 },
        { label: '禁用', value: 0 },
      ],
    },
  },
];

// 模拟数据
const mockData = Array.from({ length: 50 }, (_, i) => ({
  id: i + 1,
  name: `用户${i + 1}`,
  email: `user${i + 1}@example.com`,
  phone: `138${String(i).padStart(8, '0')}`,
  status: i % 2 === 0 ? 1 : 0,
  createTime: new Date(Date.now() - i * 86400000).toLocaleString(),
}));

// 使用 useVbenVxeGrid 创建表格
const [Grid, gridApi] = useVbenVxeGrid({
  formOptions: {
    schema: searchFormSchema,
    submitOnChange: true,
  },
  gridOptions: {
    columns,
    height: 'auto',
    keepSource: true,
    proxyConfig: {
      ajax: {
        query: async ({ page }, formValues) => {
          let filtered = [...mockData];
          if (formValues?.name) {
            filtered = filtered.filter((item) => item.name.includes(formValues.name));
          }
          if (formValues?.status !== undefined) {
            filtered = filtered.filter((item) => item.status === formValues.status);
          }
          const start = (page.currentPage - 1) * page.pageSize;
          const end = start + page.pageSize;
          return {
            items: filtered.slice(start, end),
            total: filtered.length,
          };
        },
      },
    },
    rowConfig: { keyField: 'id' },
    toolbarConfig: {
      custom: true,
      export: true,
      refresh: true,
      search: true,
      zoom: true,
    },
  } as VxeTableGridOptions,
});

// 操作按钮点击事件
function onActionClick(e: { code: string; row: any }) {
  if (e.code === 'edit') {
    message.info(`编辑: ${e.row.name}`);
  } else if (e.code === 'delete') {
    message.warning(`删除: ${e.row.name}`);
  }
}
</script>

<template>
  <Page title="BasicTable 表格演示" auto-content-height>
    <Grid table-title="用户列表" class="h-full">
      <template #toolbar-tools>
        <a-button type="primary" @click="gridApi.query()">
          刷新
        </a-button>
      </template>
    </Grid>
  </Page>
</template>
评论

全部评论(0)

回到顶部