基于 Arco-Design 的B端管理后台起始模板, 使用 vue3 + vite + typescript 构建。 https://appnify.app.juetan.cn/
 
 
 
 
 
 
Go to file
绝弹 3f0c83a83b
自动部署 / build (push) Failing after 24s Details
feat: 替换为aconify组件库
2024-03-11 21:34:53 +08:00
.gitea feat: 替换为aconify组件库 2024-03-11 21:34:53 +08:00
.github feat: 添加企业微信通知 2024-01-16 14:17:16 +08:00
.vscode feat: 设置进度条颜色跟随主色 2023-09-22 20:37:14 +08:00
public feat: 优化编辑器逻辑 2024-02-23 16:14:31 +08:00
scripts feat: 替换为aconify组件库 2024-03-11 21:34:53 +08:00
src feat: 替换为aconify组件库 2024-03-11 21:34:53 +08:00
.env feat: 优化布局 2024-02-27 23:40:10 +08:00
.env.production feat: 优化路由加载机制 2024-01-12 11:29:00 +08:00
.eslintrc feat: 添加unplugin-vue-router插件 2023-10-13 17:25:23 +08:00
.gitignore feat: 首次提交 2023-07-08 14:18:41 +08:00
.npmrc feat: 首次提交 2023-07-08 14:18:41 +08:00
.prettierrc feat: 第三方库作为VUE插件进行初始化 2024-01-30 10:02:28 +08:00
Dockerfile feat: 优化路由加载机制 2024-01-12 11:29:00 +08:00
README.md feat: 优化表格参数 2024-02-29 23:27:11 +08:00
index.html feat: 替换为aconify组件库 2024-03-11 21:34:53 +08:00
package.json feat: 替换为aconify组件库 2024-03-11 21:34:53 +08:00
pnpm-lock.yaml feat: 调整路由以文件夹为单位 2024-01-11 17:36:46 +08:00
tsconfig.json feat: 调整路由以文件夹为单位 2024-01-11 17:36:46 +08:00
tsconfig.node.json feat: 添加文件图标 2023-11-02 22:04:40 +08:00
uno.config.ts feat: 替换为aconify组件库 2024-03-11 21:34:53 +08:00
vite.config.ts feat: 替换为aconify组件库 2024-03-11 21:34:53 +08:00

README.md

介绍

基于 vue3 + vite + typescript 的 B 端管理后台模板,提供路由自动生成、轻量 CRUD 表格组件和 API 接口自动生成等功能。

功能

  • 基于文件的路由系统,自动生成路由项/菜单项/面包屑
  • Typescript 支持,内置和扩展众多类型定义,文档在手可触
  • 根据 openapi 自动生成数据类型、请求函数
  • 轻量化的封装表单、CRUD 表格,开箱即用
  • 内置 VITE 插件,输出版本/打包信息,支持根据不同后缀打包
  • 轻量的字典常量定义助手函数
  • 常用 API/组件自动导入,同时带类型提示
  • 图标/样式一个类名搞定
  • 遵循 Conventional Changelog 规范, 自动生成版本记录文档
  • 内置常用 VsCode 代码片段和推荐扩展,提升开发效率
  • 支持路由动态打包、路由权限、路由缓存和动态首页
  • 支持 Docker 部署,包含优化过的 Dockerfile 配置

快速开始

  1. 确保本地安装有如下软件(推荐最新版本)。提示Pnpm 在 NodeJS v16+ 版本可通过 corepack enable 命令开启,低版本请通过 npm install pnpm 命令安装。
git           # 地址https://git-scm.com/
node + pnpm   # 地址https://nodejs.org/en
  1. 拉取模板
npx degit https://github.com/appnify/starter-vue
  1. 安装依赖
pnpm install
  1. 启动项目,默认 3020 端口。
pnpm dev

使用文档

本仓库仅是一个起始模板,具体项目请根据需求改造。

路由菜单

基于 vite-plugin-pages 插件。根据 src/pages 目录生成路由数组,然后根据路由数组自动生成菜单数组,导航时根据菜单层级自动生成导航面包屑。

根据 src/pages 目录生成路由数组,包含以下以下规则:

  • 以文件夹为路由,读取该文件夹下 index.vue 的信息作为路由信息,其他文件会跳过,可以包含子文件夹作为嵌套路由
  • 在 src/pages 的文件夹层级,作为菜单层级,路由层级最终只有 2 层(配合 keep-alive 缓存)
  • 在 src/pages 目录下,以 _ 开头的文件夹作为 1 级路由,其他作为 2 级路由,也就是应用路由
  • 子文件夹下,只有 index.vue 文件有效,其他文件会忽略,这些文件可以作为子组件使用
  • components 目录会被忽视。
  • xxx.xx.xx 文件会被忽视,例如 index.my.vue 文件。

对应目录下的 index.vue 文件中定义如下路由配置:

<route lang="json">
{
  // 其他 Route 参数
  "meta": {
    // 请看下面
  }
}
</route>

目前支持的参数,如下:

interface RouteMeta {
  /**
   * 页面标题
   * @description
   * 菜单和导航面包屑等地方会用到
   */
  title?: string;
  /**
   * 页面图标
   * @description
   * 使用 icon-park-outline 图标集的图标类名
   */
  icon?: string;
  /**
   * 显示顺序
   * @description
   * 在菜单中的显示顺序,越小越靠前
   */
  sort?: number;
  /**
   * 是否隐藏
   * @description
   * - false  // 不隐藏(默认)
   * - true   // 在路由和菜单中隐藏,即忽略且不打包
   * - 'menu' // 在菜单中隐藏,通过其他方式访问
   * - 'prod' // 在生产环境下隐藏
   */
  hide?: boolean | 'menu' | 'prod';
  /**
   * 所需权限
   * @example
   * ```js
   * ['system:user']
   * ```
   */
  auth?: string[];
  /**
   * 是否缓存
   * @description
   * 是否使用 keep-alive 缓存
   */
  cache?: boolean;
  /**
   * 组件名字
   * @description
   * 组件名字,当 cache为true 时必须
   */
  name?: string;
  /**
   * 是否显示loading
   * @description
   * 可以自定义 loading 文本
   */
  loading?: boolean | string;
  /**
   * 链接
   * @description
   * ```js
   * 'https://juetan.cn'
   * ```
   */
  link?: string;
}

嵌套布局

默认情况下,嵌套路由会使用父级 index.vue 作为布局文件,如果不需要布局,只需在父级路由指定 component 为 null 即可,如下:

{
  "component": null,
  "meta": {}
}

这样,其层级仅作为菜单层级,在路由上表现为扁平。

路由权限

在每个路由的 index.vue 文件中,通过 meta.auth 字段指定访问该路由所需的权限,示例如下:

{
  "meta": {
    "auth": ["system:user", "system:menu"]
  }
}

默认全部需要登陆才可访问,其中有 2 个比较特殊的权限:

  • * 表示无需登陆即可访问,适合挂一些比较通用的页面。
  • unlogin 表示未登录才可以访问。例如登录页,登陆后访问该页面会被拒绝。

用户登陆后获取的权限,应存储在 userStore.auth 字段中,在路由的 beforeEach 守卫中,会比较两个是否匹配,匹配上则继续,否则会显示如下 403 页面:

动态路由

相比于比较流行的加法挂载,我更倾向于减法挂载。即默认加载完所有路由,在 beforeEach 钩子根据权限移除不必要的路由。

动态首页

在作为首页路由的 index.vue 文件中,指定 alias 为 '/' 即可,默认是 home/index.vue 文件。如需动态更新首页,在 beforeEach 获取完菜单信息,通过 removeRoute 移除旧的首页路由,通过 addRoute 添加新的首页路由即可。

路由缓存

在路由的 index.vue 文件,首先指定好组件的名字,再通过 cache 字段开启缓存,示例如下:

<script>
  defineOptions({
    name: 'MyPage',
  });
</script>
<route> { "meta": { // 组件名字 "name": "MyPage", // 开启缓存 "cache": true } } </route>

条件加载

基于 plugin 内置 VITE 插件,主要用于输出编译信息以及根据不同文件后缀进行打包。在项目根目录下的 .env 配置文件中,可指定以下属性:

VITE_EXTENSION = my

配置后,构建时将首先尝试加载 index.my.vue 文件,不存在时回退至 index.vue 文件。默认开发环境下为 dev, 其他环境为 prod这在本地临时开发或根据微差异化打包时非常有用。

图标样式

基于 UnoCSS 插件,可使用类似 TailwindCSS 的原子样式快速开发,同时默认安装 icon-park-outline 图标库,只需引用类名即可得到 SVG 图标。这在路由菜单等需要动态渲染时非常有用,同时所有样式类和图标类都是按需打包的,示例:

<i class="text-sm icon-park-outline-home" />

接口请求

基于 typescript-swagger-api 库,根据 openapi 结构自动生成请求接口和数据类型。生成的内容位于 src/api/service 目录下,包含以下内容:

  • 请求数据类型(typescript)
  • 请求客户端(axios/fetch, 默认 axios)
  • 请求基类(对象)。

如需自定义生成模板,可查阅 scripts/openapi 目录下的模板内容。生成的接口类型包含完整的入参和出参类型提示。

此外,在 src/api/instance/useRequest.ts 文件中还定义了一个 useRequest 函数,可对请求状态进行管理,示例:

const state = useRequest(api.user.getUsers);

// 返回的数据
state.data;

// 是否请求中
state.loading;

// 请求异常
state.error;

字典枚举

字典枚举可能包含多种需求,例如根据值获取标签、生成下拉框选项、根据值获取其他内容(如颜色)等。在 src/utils/defineConstants.ts 文件中,定义了一个简易的字典枚举值助手函数,解决以上问题,且提供类型提示,示例如下:

enum MediaEnum {
  VIDEO = 1,
  IMAGE = 2,
}

const media = defineConstants([
  {
    value: MediaEnum.VIDEO,
    label: '视频',
    color: 'red',
  },
  {
    value: MediaEnum.IMAGE,
    label: '图片',
    color: 'blue',
  },
]);

// 根据value值获取其他属性值, 第2个参数可选(默认label)
media.fmt(1); // 视频

// 获取某个属性值组成的数组默认value
media.val(); // [1, 2]

增删改查

在 src/components 目录中,封装有 form 组件和 table 组件,主要用于 CRUD 的常规操作,这里演示基本的使用方法。

<template>
  <table ref="tableRef" v-bind="table" />
</template>
<script>
  import { Table, useTable } from '@/components';

  const table = useTable({
    // 数据源配置,可以是数组或返回对象的异步函数
    data: async (search, paging) => {
      return { data, total };
    },

    // 表格列配置
    columns: [
      {
        title: '用户名',
        dataIndex: 'name',
      },
    ],

    // 分页配置
    pagination: {
      showTotal: true,
    },

    // 查询配置类型为useForm的入参
    search: {
      items: [
        {
          field: 'username',
          label: '用户名',
          type: 'input',
        },
      ],
    },

    // 新增表单弹窗的配置类型为useFormModal的入参
    create: {
      title: '新增用户',
      items: [
        {
          field: 'username',
          label: '用户名',
          type: 'input',
        },
      ],
      submit: async ({ model }) => {
        return api.xx(model);
      },
    },

    // 修改表单弹窗的配置类型为useFormModal的入参
    modify: {
      title: '修改用户',
      items: [
        {
          field: 'username',
          label: '用户名',
          type: 'input',
        },
      ],
      submit: async ({ model }) => {
        return api.xx(model);
      },
    },
  });
</script>

提示:以上每个参数都有类型提示,原组件每个参数都可透传,封装遵循扩展而非限制原则。

自动导入

基于 unplugin-auto-import 和 unplugin-vue-components 插件,主要用于 vue 等常用 API 的自动导入;以及 arco-design 等常用组件的导入,示例如下:

<template>
  <!-- ArcoDesign组件无需导入即可使用且有类型提示 -->
  <a-table :data="data"></a-table>
</template>

<script lang="ts">
  // vue的API无需导入即可使用且有类型提示
  const data = ref([]);
</script>

如需自定义其他 API 的自动导入,请查阅vite.config.ts文件中的配置。

代码片段

基于 VsCode 的 snippet 功能,在 .vscode/components.code-snippets 文件中定义有常用组件和 API 的模板。所有代码片段均以 g(generate) 开头,对于快速 CRUD 或新建页面等非常有用,示例:

  1. 在文件内,如输入如下内容并回车:
groutemeta
  1. 将会生成如下的内容:
<route lang="json">
{
  "meta": {
    "order": 10020,
    "titble": "测试页面",
    "icon": "icon-park-outline-home"
  }
}
</route>

版本记录

基于 release-it 库,运行 pnpm release 命令时,将根据你的选择执行各种操作,如需自定义 CHANGELOG.md 的生成模板或进行其他自定义配置,请查阅 /scripts/release 目录下的内容。包含功能如下:

  • 提升 package.json 的 version 字段
  • 给 git 打版本标签,例如 v1.0.1
  • 根据符合 Conventional Changelog 规范的 git 提交信息,在CHANGELOG.md文件中生成版本记录。
  • 自动推送到 npm/github/gitlab 中

状态管理

基于 pinia 库,使用 pinia-plugin-persistedstate 插件持久化部分应用配置。需要注意的是useXxStore 不能在 app.use(store) 之前调用,否则插件会失效。

工具类库

日常开发难免用到各种工具库,但直接使用的话难免有不符合项目需求的时候。例如 dayjs 的本地化语言、相对时间插件等都要配置,散落在项目的各个角落并不是个好习惯。

建议在 src/libs 进行二次封装后,再在项目中使用,不仅统一调用还便于管理,方便后续的优化升级。本项目内置开发中常用的类库,如下:

说明
lodash-es 常用函数集,例如深克隆、防抖、节流等
axios HTTP 请求库
dayjs 日期时间处理库
numeral 数值处理库,如数值转时间、数值转文件大小等
nprogress 进度条
@vueuse/core 基于 Vue Composition API 的工具库,响应式存储数据、监听事件等

最后

本仓库还在优化中,如果你在使用过程中遇到问题,欢迎在 issue 中提问。