⚡ profile

V3-admin is a middle and background management system base solution based on Vue3, TypeScript, Element-Plus, and Vue-CLI 4.5

GitHub: github.com/v3-projects… , the production environment has been installed. Welcome to raise Issues, PR, think you can point a Star support!

1 ️ ⃣ function

- User Management - Login - Logout - Permission Authentication - Page Permissions - Directive Permissions - Multi-environment - Development - Test - Production - Global Features - SVG - Internationalization - Multi-theme switch (built-in dark theme) - Dynamic sidebar - Dynamic breadcrumbs - TAB shortcut navigation - Screenfull - Adaptive shrink sidebar - Error Pages - 401-404 - Dashboard - admin - Editor - Automatic deploymentCopy the code

2 ️ ⃣ directory

# v3-admin├ ─. Env. Development# Development environment├ ─. Env. Production# Production environment├ ─. Env. Test# Test environment├ ─. Eslintrc. Js# eslint├ ─ the deploy# Automatic deployment
├─ public
│  ├─ favicon.ico
│  ├─ index.html
├─ src
│  ├─ @types          # ts statement│ ├ ─ API# API interface│ ├ ─ assets# Static resources│ ├ ─ components# Global component│ ├ ─ config# Global configuration│ ├ ─ constant# Constant/enumeration│ ├ ─ directives# Global instruction│ ├ ─ layout# layout│ ├ ─ locales# international│ ├ ─ modelGlobal model #│ ├ ─ the plugins# plug-in│ ├ ─ the router# routing│ ├ ─ store# vuex store│ ├ ─ styles# Global style│ ├ ─ utils# Global public method│ └ ─ views# All pages│ ├ ─ App. Vue# Entry page│ ├ ─ main. Ts# Import file│ ├ ─ permission. Ts# Permission management│ └ ─ shims. Which s# Module injection├ ─ tsconfig. Json# ts compile configuration└ ─ vue. Config. Js# vue - cli configuration
Copy the code

3 ️ ⃣ installation

# Clone project
git clone https://github.com/v3-projects/v3-admin

Enter the project directory
cd v3-admin

# Install dependencies
yarn

# Start project
yarn dev
Copy the code

📚 basis

1 ️ ⃣ routing

Configuration items

// The default is false, and the route will not appear in the sidebar when set to true
hidden: true

// When setting noRedirect, the route is not clickable in the breadcrumb navigation
redirect: 'noRedirect'

// Set the name of the route. Make sure to fill in the name. Otherwise, it may cause problems to reset the route
name: 'router-name'

meta: {
  // Set the access permission for the route. Multiple access permissions are supported
  roles: ['admin'.'editor']
  // Set the name of the route to be displayed in the sidebar and breadcrumbs
  title: 'title'
  // Set the ICONS for this route, remember to import SVG to @/assets/svg-icons/ ICONS
  icon: 'svg-name'
  // The default value is true. If set to false, it will not be displayed in bread crumbs
  breadcrumb: false
  // The default is false. If set to true, it will be fixed in tag-view
  affix: true
  
  // When more than one route is declared for children under a route, the mode is automatically nested
  // If there is only one route, the child route will be displayed as the root route in the sidebar
  // To display your root route regardless of the number of children declared below the route
  // You can set alwaysShow: true to ignore the previously defined rule and show the root route all the time
  alwaysShow: true

  // When this property is set, the sidebar corresponding to the activeMenu property will be highlighted when the route is entered
  activeMenu: '/dashboard'
}
Copy the code

Dynamic routing

ConstantRoutes places routes that do not require permission determination in the resident route, such as /login, /dashboard.

AsyncRoutes Places routes that require dynamic permission judgements and are added dynamically through addRoute.

Add dynamic routing methods:

Example: create an example permission-. ts file under @/router/asyncModules

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'].// You can set roles in the root route
      alwaysShow: true // The root menu will always be displayed
    },
    children: [{path: 'page'.component: () = > import(/* webpackChunkName: "permission-page" */ '@/views/permission/page.vue'),
        name: 'PagePermission'.meta: {
          title: 'pagePermission'.roles: ['admin'] // Or set the role in the subnavigation}}, {path: 'directive'.component: () = > import(/* webpackChunkName: "permission-directive" */ '@/views/permission/directive.vue'),
        name: 'DirectivePermission'.meta: {
          title: 'directivePermission' // If no role is set, the page does not require permissions but inherits the role of the root route}}]}]export default permissionRouter
Copy the code

2️ sidebar and breadcrumbs

The sidebar

Sidebar @ / layout/components/sidebar is by reading the routing and connecting with the authority to judge and dynamically generated (in other words, routing in routing + have permission)

Sidebar outside the chain

You can configure an external link in the sidebar that will open a new page when you click on it, as long as you enter a valid URL in path

{
  path: 'link'.component: Layout,
  children: [{path: 'https://github.com/v3-projects/v3-admin'.meta: { title: 'link'.icon: 'link' },
      name: 'Link'}}]Copy the code

Bread crumbs

@/components/ breadcrumb is also dynamically generated based on the route. Set breadcrumb: false for the route and the route will not appear in the breadcrumb. Set redirect: ‘noRedirect’ and the route will not appear in the breadcrumb

3 ️ ⃣ permissions

During login, the user obtains the current user’s rights (roles) and compares the routing table to generate a routing table accessible to the current user. Then, the user dynamically mounts the routing table to the router through the addRoute

Role Control Rights

The control code is in @/ permission-ts, where it can be modified in response to the specific business:

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()
  // Check whether the user is logged in
  if (store.state.user.token) {
    if (to.path === '/login') {
      // If you are logged in and ready to enter the Login page, redirect to the home page
      next({ path: '/' })
      NProgress.done()
    } else {
      // Check whether the user has obtained his/her role
      if (store.state.user.roles.length === 0) {
        try {
          // Note: the role must be an array of objects! For example: ['admin'] or ['developer', 'editor']
          await store.dispatch(UserActionTypes.ACTION_GET_USER_INFO, undefined)
          if (rolesSettings.openRoles) {
            // Get the roles returned by the interface
            const roles = store.state.user.roles
            // Generate accessible routes based on roles
            store.dispatch(PermissionActionType.ACTION_SET_ROUTES, roles)
          } else {
            // If the role function is not enabled, the default role is enabled
            store.commit(UserMutationTypes.SET_ROLES, rolesSettings.defaultRoles)
            store.dispatch(PermissionActionType.ACTION_SET_ROUTES, rolesSettings.defaultRoles)
          }
          // Add accessible routes dynamically
          store.state.permission.dynamicRoutes.forEach((route) = > {
            router.addRoute(route)
          })
          // Ensure that the route has been added
          // Set replace: true, so the navigation will leave no historynext({ ... to,replace: true})}catch (err) {
          // Delete the token and redirect to the login page
          store.dispatch(UserActionTypes.ACTION_RESET_TOKEN, undefined)
          ElMessage.error(err || 'Has Error')
          next('/login')
          NProgress.done()
        }
      } else {
        next()
      }
    }
  } else {
    // If there is no token
    if(whiteList.indexOf(to.path) ! = = -1) {
      // If you are in the no-login whitelist, enter directly
      next()
    } else {
      // Other pages without access will be redirected to the login page
      next('/login')
      NProgress.done()
    }
  }
})

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

Copy the code

Cancel the role

If you do not have the concept of roles in your business scenario, you can disable roles in @/config/ Roles. When you disable roles, the system will enable the default role (usually the admin role with the highest rights), which means that every user who logs in can see all routes

interface RolesSettings {
  // Whether to enable the role function. (After the role function is enabled, the back-end needs to cooperate. The role of the current user is returned on the interface for querying user details.)
  openRoles: boolean
  // When the role function is disabled, the default role of the current login user takes effect (default is admin and has all permissions).
  defaultRoles: Array<string>}const rolesSettings: RolesSettings = {
  openRoles: true.defaultRoles: ['admin']}export default rolesSettings
Copy the code

Instruction permissions

Simple and fast implementation of button level permission judgment (registered to the global, can be used directly) :

<el-tag v-permission="['admin']">The admin is visible</el-tag>
<el-tag v-permission="['editor']">The editor is visible</el-tag>
<el-tag v-permission="['admin','editor']">Both admin and Editor are visible</el-tag>
Copy the code

However, in some cases, v-Permission is not appropriate. Examples are el-Tab or El-Table-column of an Element and other scenarios that render the DOM dynamically. You can only do this by manually setting v-if.

At this point, you can use the permission determination function

import { checkPermission } from '@/utils/permission'
Copy the code
<el-tab-pane v-if="checkPermission(['admin'])" label="Admin">The admin is visible</el-tab-pane>
<el-tab-pane v-if="checkPermission(['editor'])" label="Editor">The editor is visible</el-tab-pane>
<el-tab-pane v-if="checkPermission(['admin','editor'])" label="AdminEditor">Both admin and Editor are visible</el-tab-pane>
Copy the code

4️ uploading HTTP requests

The general process is as follows:

Graph LR page/interaction --> unified API --> encapsulated service.ts --> server

Centrally managed APIS

The import form

@/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
  })
}
Copy the code

The packaging service. The ts

@/utils/service.ts is an AXIos-based wrapper that encapsulates global Request interceptors, response interceptors, unified error handling, unified timeout handling, baseURL Settings, CancelToken, etc.

More than 5 ️ ⃣ environment

build

When a project is completed and code is packaged, there are two built-in environments:

Package the test environment
yarn build:test

# Package the formal environment
yarn build:prod
Copy the code

variable

In.env.xxx files such as.env.production, variables corresponding to the environment are configured:

# NODE_ENV=production # baseURL VUE_APP_BASE_API ='https://www.xxx.com'
Copy the code

Obtaining method:

console.log(process.env.NODE_ENV)
console.log(process.env.VUE_APP_BASE_API)
Copy the code

✈ ️ advanced

1 ️ ⃣ ESLint

Specification code is important!

  • Configuration item: In.eslintrc.jsIn the file
  • To cancel automatic verification:@/config/vue.custom.config.tsLt.lintOnSaveSet tofalse
  • The VSCode ESlint plugin is recommended. It flags non-conforming code in red when you write it, and automatically fixes simple red code when you save it. (The VSCode ESlint tutorial is available at Google)
  • Manual check:yarn lint(Execute this command before committing the code, especially if your lintOnSave is false)

2 ️ ⃣ Git Hooks

The gitHooks are configured in package.json, and the code is checked for each commit

"gitHooks": {
    "pre-commit": "lint-staged"
  },
  "lint-staged": {
    "*.{js,jsx,vue,ts,tsx}": [
      "vue-cli-service lint"."git add"]}Copy the code

3 ️ ⃣ across domains

The @/config folder stores some built-in configuration items, such as white-list routing whitelist, vue.custom.config vue. Config file configuration and so on.

There is a proxy in vue.custom. Config for reverse proxy.

For the corresponding production environment, nginx can be used as a reverse proxy.

The reverse proxy

const vueDefaultConfig = {
  / /... Other configuration
  devServer: {
    / /... Other configuration
    proxy: {
      '/api/': {
        target: 'http://xxxxxx/api/'.ws: true.pathRewrite: {
          '^/api/': ' '
        },
        changeOrigin: true.secure: false}}}}module.exports = vueDefaultConfig
Copy the code

CORS

There is no difference between the front-end and normal sending request writing, and the workload is basically here on the back end.

After the implementation of CORS, whether the development environment or production environment, can be convenient to call the interface.

4 ️ ⃣ SVG

@/assets/svg-icons/ ICONS

use

There is no need to introduce components into the page and they can be used directly

<! -- name = SVG file name -->
<! -- class can modify the default style -->
<svg-icon name="user" font-size="20px" class="icon" />
Copy the code

Download icon

Recommend iconfont

5️ Automatic deployment

Js file, and then run the yarn deploy command to automatically publish the packaged dist file to the corresponding server

Note: The user name and password in this file are sensitive information, do not upload to the remote warehouse, this is important!

6️ New theme (dark theme as an example)

New theme style file

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

Registering a new topic

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

❓ FaQs

1️ All errors are reported

A quick Google search will resolve 99% of the errors

The other 1% can group ask me, and THEN I secretly go to Google

2️ Dependence fails

  • Do not use CNPM
  • Recommended use yarn
  • Try to remove node_modules and rely on it again
  • Google it

3️ After switching to browserHistory on the route mode, the blank page is refreshed

Will @ / config/vue. Custom. Config. PublicPath value from ts file. / modify /

☕ other

1️ stand on the shoulders of giants

  • vue-element-admin
  • vue3-composition-admin
  • d2-admin
  • vue-vben-admin

2️ communication (water blowing) group

No one cares about the exchange (blowing water) group: 1014374415