✨✨✨ V3-Admin 使用文檔

⚡ 簡介

v3-admin 是一箇中後臺管理系統基礎解決方案,基於 Vue三、TypeScript、Element-Plus 和 Vue-Cli 4.5css

GitHub地址:github.com/v3-projects… ,已上生產環境。歡迎各位提 Issues、PR,以爲能夠的點個 Star 支持一下!html

1️⃣ 功能

- 用戶管理
  - 登陸
  - 註銷
	
- 權限驗證
  - 頁面權限
  - 指令權限

- 多環境
  - development
  - test
  - production
  
- 全局功能
  - svg
  - 國際化
  - 多主題切換(內置黑暗主題)
  - 動態側邊欄
  - 動態麪包屑
  - 標籤頁快捷導航
  - Screenfull 全屏
  - 自適應收縮側邊欄

- 錯誤頁面
  - 401
  - 404

- Dashboard
  - admin
  - editor

- 自動部署
複製代碼

2️⃣ 目錄

# v3-admin
├─ .env.development   # 開發環境
├─ .env.production    # 生產環境
├─ .env.test          # 測試環境
├─ .eslintrc.js       # eslint
├─ deploy             # 自動部署
├─ public
│  ├─ favicon.ico
│  ├─ index.html
├─ src
│  ├─ @types          # ts 聲明
│  ├─ api             # api 接口
│  ├─ assets          # 靜態資源
│  ├─ components      # 全局組件
│  ├─ config          # 全局配置
│  ├─ constant        # 常量/枚舉
│  ├─ directives      # 全局指令
│  ├─ layout          # 佈局
│  ├─ locales         # 國際化
│  ├─ model           # 全局 model
│  ├─ plugins         # 插件
│  ├─ router          # 路由
│  ├─ store           # vuex store
│  ├─ styles          # 全局樣式
│  ├─ utils           # 全局公共方法
│  └─ views           # 全部頁面
│  ├─ App.vue         # 入口頁面
│  ├─ main.ts         # 入口文件
│  ├─ permission.ts   # 權限管理
│  └─ shims.d.ts      # 模塊注入
├─ tsconfig.json      # ts 編譯配置
└─ vue.config.js      # vue-cli 配置
複製代碼

3️⃣ 安裝

# 克隆項目
git clone https://github.com/v3-projects/v3-admin

# 進入項目目錄
cd v3-admin

# 安裝依賴
yarn

# 啓動項目
yarn dev
複製代碼

📚 基礎

1️⃣ 路由

配置項

// 默認false,設置 true 的時候該路由不會在側邊欄出現
hidden: true

// 設置 noRedirect 的時候該路由在麪包屑導航中不可被點擊
redirect: 'noRedirect'

// 設定路由的名字,必定要填寫否則重置路由可能會出問題
name: 'router-name'

meta: {
  // 設置該路由進入的權限,支持多個權限疊加
  roles: ['admin', 'editor']
  // 設置該路由在側邊欄和麪包屑中展現的名字
  title: 'title'
  // 設置該路由的圖標,記得將 svg 導入 @/assets/svg-icons/icons
  icon: 'svg-name'
  // 默認true,若是設置爲false,則不會在麪包屑中顯示
  breadcrumb: false
  // 默認false,若是設置爲true,它則會固定在 tags-view 中
  affix: true
  
  // 當一個路由下面的 children 聲明的路由大於1個時,自動會變成嵌套的模式
  // 只有一個時,會將那個子路由當作根路由顯示在側邊欄
  // 若想無論路由下面的 children 聲明的個數都顯示你的根路由
  // 能夠設置alwaysShow: true,這樣就會忽略以前定義的規則,一直顯示根路由
  alwaysShow: true

  // 當設置了該屬性,進入路由時,則會高亮 activeMenu 屬性對應的側邊欄
  activeMenu: '/dashboard'
}
複製代碼

動態路由

constantRoutes 把不須要判斷權限的路由放置在常駐路由裏面,如 /login/dashboard前端

asyncRoutes 放置需求動態判斷權限並經過 addRoute 動態添加的路由。vue

添加動態路由方法:node

案例:在 @/router/asyncModules 下面建立例如 permission.ts 文件webpack

import { RouteRecordRaw } from 'vue-router'
import Layout from '@/layout/index.vue'

const permissionRouter: Array<RouteRecordRaw> = [
  {
    path: '/permission',
    component: Layout,
    name: 'Permission',
    redirect: '/permission/directive',
    meta: {
      title: 'permission',
      icon: 'lock',
      roles: ['admin', 'editor'], // 能夠在根路由中設置角色
      alwaysShow: true // 將始終顯示根菜單
    },
    children: [
      {
        path: 'page',
        component: () => import(/* webpackChunkName: "permission-page" */ '@/views/permission/page.vue'),
        name: 'PagePermission',
        meta: {
          title: 'pagePermission',
          roles: ['admin'] // 或者在子導航中設置角色
        }
      },
      {
        path: 'directive',
        component: () => import(/* webpackChunkName: "permission-directive" */ '@/views/permission/directive.vue'),
        name: 'DirectivePermission',
        meta: {
          title: 'directivePermission' // 若是未設置角色,則表示:該頁面不須要權限,但會繼承根路由的角色
        }
      }
    ]
  }
]

export default permissionRouter
複製代碼

2️⃣ 側邊欄和麪包屑

側邊欄

sidebar1.png sidebar2.png

側邊欄 @/layout/components/sidebar 是經過讀取路由並結合權限判斷而動態生成的(換句話說就是常駐路由 + 有權限的路由)ios

側邊欄外鏈

能夠在側邊欄中配置一個外鏈,只要你在 path 中填寫了合法的 url 路徑,當你點擊側邊欄的時候就會幫你新開這個頁面nginx

{
  path: 'link',
  component: Layout,
  children: [
    {
      path: 'https://github.com/v3-projects/v3-admin',
      meta: { title: 'link', icon: 'link' },
      name: 'Link'
    }
  ]
}
複製代碼

麪包屑

breadcrumb.png

麪包屑 @/components/bread-crumb 也是根據路由動態生成的,爲路由設置 breadcrumb: false 時該路由將不會出如今麪包屑中,設置 redirect: 'noRedirect' 時該路由在麪包屑中不能被點擊git

3️⃣ 權限

登陸時經過獲取當前用戶的權限(角色)去比對路由表,生成當前用戶具備的權限可訪問的路由表,經過 addRoute 動態掛載到 router 上github

角色控制權限

控制代碼都在 @/permission.ts 中,這裏可根據具體的業務作響應的修改:

import NProgress from 'nprogress'
import 'nprogress/nprogress.css'
import router from '@/router'
import { RouteLocationNormalized } from 'vue-router'
import { useStore } from './store'
import { UserActionTypes } from './store/modules/user/action-types'
import { PermissionActionType } from './store/modules/permission/action-types'
import { UserMutationTypes } from './store/modules/user/mutation-types'
import { ElMessage } from 'element-plus'
import { whiteList } from './config/white-list'
import rolesSettings from './config/roles'

NProgress.configure({ showSpinner: false })

router.beforeEach(async(to: RouteLocationNormalized, _: RouteLocationNormalized, next: any) => {
  NProgress.start()
  const store = useStore()
  // 判斷該用戶是否登陸
  if (store.state.user.token) {
    if (to.path === '/login') {
      // 若是登陸,並準備進入 login 頁面,則重定向到主頁
      next({ path: '/' })
      NProgress.done()
    } else {
      // 檢查用戶是否已得到其權限角色
      if (store.state.user.roles.length === 0) {
        try {
          // 注意:角色必須是一個對象數組! 例如: ['admin'] 或 ['developer', 'editor']
          await store.dispatch(UserActionTypes.ACTION_GET_USER_INFO, undefined)
          if (rolesSettings.openRoles) {
            // 獲取接口返回的 roles
            const roles = store.state.user.roles
            // 根據角色生成可訪問的 routes
            store.dispatch(PermissionActionType.ACTION_SET_ROUTES, roles)
          } else {
            // 沒有開啓角色功能,則啓用默認角色
            store.commit(UserMutationTypes.SET_ROLES, rolesSettings.defaultRoles)
            store.dispatch(PermissionActionType.ACTION_SET_ROUTES, rolesSettings.defaultRoles)
          }
          // 動態地添加可訪問的 routes
          store.state.permission.dynamicRoutes.forEach((route) => {
            router.addRoute(route)
          })
          // 確保添加路由已完成
          // 設置 replace: true, 所以導航將不會留下歷史記錄
          next({ ...to, replace: true })
        } catch (err) {
          // 刪除 token,並重定向到登陸頁面
          store.dispatch(UserActionTypes.ACTION_RESET_TOKEN, undefined)
          ElMessage.error(err || 'Has Error')
          next('/login')
          NProgress.done()
        }
      } else {
        next()
      }
    }
  } else {
    // 若是沒有 token
    if (whiteList.indexOf(to.path) !== -1) {
      // 若是在免登陸的白名單中,則直接進入
      next()
    } else {
      // 其餘沒有訪問權限的頁面將被重定向到登陸頁面
      next('/login')
      NProgress.done()
    }
  }
})

router.afterEach(() => {
  NProgress.done()
})

複製代碼

取消角色

假如你的業務場景中沒有 角色 的概念,那麼在 @/config/roles 裏能夠關閉角色功能,關閉後系統將啓用默認角色(通常爲最高權限的 admin 角色),即每一個登陸的用戶均可見全部路由

interface RolesSettings {
  // 是否開啓角色功能(開啓後須要後端配合,在查詢用戶詳情接口返回當前用戶的所屬角色)
  openRoles: boolean
  // 當角色功能關閉時,當前登陸用戶的默認角色將生效(默認爲admin,擁有全部權限)
  defaultRoles: Array<string>
}

const rolesSettings: RolesSettings = {
  openRoles: true,
  defaultRoles: ['admin']
}

export default rolesSettings
複製代碼

指令權限

簡單快速的實現按鈕級別的權限判斷(已註冊到全局,可直接使用):

<el-tag v-permission="['admin']">admin可見</el-tag>
<el-tag v-permission="['editor']">editor可見</el-tag>
<el-tag v-permission="['admin','editor']">admin和editor均可見</el-tag>
複製代碼

但在某些狀況下,不適合使用 v-permission。例如:Element 的 el-tab 或 el-table-column 以及其它動態渲染 dom 的場景。你只能經過手動設置 v-if 來實現。

這時候可使用權限判斷函數

import { checkPermission } from '@/utils/permission'
複製代碼
<el-tab-pane v-if="checkPermission(['admin'])" label="Admin">admin可見</el-tab-pane>
<el-tab-pane v-if="checkPermission(['editor'])" label="Editor">editor可見</el-tab-pane>
<el-tab-pane v-if="checkPermission(['admin','editor'])" label="AdminEditor">admin和editor均可見</el-tab-pane>
複製代碼

4️⃣ 發送HTTP請求

大體的流程以下:

graph LR
頁面/交互 --> 統一管理的API --> 封裝的service.ts --> 服務器

統一管理的 API

import 形式

@/api/login.ts

import { request } from '@/utils/service'

interface UserRequestData {
  username: string
  password: string
}

export function accountLogin(data: UserRequestData) {
  return request({
    url: 'user/login',
    method: 'post',
    data
  })
}
複製代碼

封裝的 service.ts

@/utils/service.ts 是基於 axios 的封裝,封裝了全局 request 攔截器、response 攔截器、統一的錯誤處理、統一作了超時處理、baseURL設置、CancelToken 等。

5️⃣ 多環境

構建

項目開發完成,打包代碼時,內置兩種環境:

# 打包測試環境
yarn build:test

# 打包正式環境
yarn build:prod
複製代碼

變量

.env.production.env.xxx 文件中,配置了該環境對應的變量:

# 當前運行的環境
NODE_ENV=production
# 當前環境對應接口的 baseURL
VUE_APP_BASE_API = 'https://www.xxx.com'
複製代碼

獲取方式:

console.log(process.env.NODE_ENV)
console.log(process.env.VUE_APP_BASE_API)
複製代碼

✈️ 進階

1️⃣ ESLint

規範代碼很重要!

  • 配置項:在 .eslintrc.js 文件中
  • 取消自動校驗:@/config/vue.custom.config.ts 中將 lintOnSave 設置爲 false
  • 推薦 VSCode 的 ESlint 插件,它可在寫代碼時,將不符合規範的代碼標紅,而且在你保存代碼是自動修復一些簡單的標紅的代碼(VSCode 配置 ESlint 教程可自行 Google)
  • 手動校驗:yarn lint(提交代碼前執行該命令,特別是在你 lintOnSave 爲 false 的狀況下)

2️⃣ Git Hooks

package.json 中配置了 gitHooks,每次 commit 時都將檢測代碼

"gitHooks": {
    "pre-commit": "lint-staged"
  },
  "lint-staged": {
    "*.{js,jsx,vue,ts,tsx}": [
      "vue-cli-service lint",
      "git add"
    ]
  }
複製代碼

3️⃣ 跨域

@/config 文件夾下存放了內置的一些配置項,好比 white-list 路由白名單,vue.custom.config vue.config 文件配置等。

其中的 vue.custom.config 裏就有 proxy 進行反向代理。

與之對應的生產環境,則可使用 nginx 來作反向代理。

反向代理

const vueDefaultConfig = {
  // ...其餘配置
  devServer: {
    // ...其餘配置
    proxy: {
      '/api/': {
        target: 'http://xxxxxx/api/',
        ws: true,
        pathRewrite: {
          '^/api/': ''
        },
        changeOrigin: true,
        secure: false
      }
    }
  }
}

module.exports = vueDefaultConfig
複製代碼

CORS

這種方案對於前端來講沒有什麼工做量,和正常發送請求寫法上沒有任何區別,工做量基本都在後端這裏。

實現 CORS 以後,不論是開發環境仍是生產環境,都能方便的調用接口。

4️⃣ SVG

全局 @/components/svg-icon 組件,圖標存放在 @/assets/svg-icons/icons

使用方式

無需在頁面中引入組件,可直接使用

<!-- name 爲 svg 文件名 -->
<!-- class 可修改默認樣式 -->
<svg-icon name="user" font-size="20px" class="icon" />
複製代碼

下載 icon

推薦 iconfont

5️⃣ 自動部署

deploy/index.js 文件裏填寫服務器的IP、端口、用戶名、密碼等信息,再執行 yarn deploy 命令便可自動發佈打包好的 dist 文件到對應的服務器

注意:該文件中的用戶名密碼等信息爲敏感信息,勿上傳到遠程倉庫,這一點很重要!

6️⃣ 新增主題(黑暗主題爲例)

新增主題樣式文件

  • src/style/theme/dark/index.scss
  • src/style/theme/dark/setting.scss

註冊新的主題

  • src/style/theme/register.scss
  • src/config/theme.ts

❓ 常見問題

1️⃣ 全部的報錯

Google 一下能夠解決 99% 的報錯

剩下 1% 能夠加羣問我,而後我偷偷去 Google

2️⃣ 依賴失敗

  • 不要使用 cnpm
  • 推薦用 yarn
  • 嘗試刪除 node_modules 後再次依賴
  • Google 一下

3️⃣ 路由模式切換爲 browserHistory 後,刷新出現空白頁面

@/config/vue.custom.config.ts 文件中 publicPath 的值從 ./ 修改成 /

☕ 其餘

1️⃣ 站在巨人的肩膀上

2️⃣ 交流(吹水)羣

無人問津的交流(吹水)羣:1014374415

v3-admin.png

相關文章
相關標籤/搜索