Most of what the company does is back-office management projects, and the business logic of each project can be eliminated by using a common set of templates. Online Preview address

The login logic

Each system has its own login and logout logic, and what our front end needs to do is to request the background, get the login permission, bring the login permission, get user information and menu information. In vUE project development, we usually make this series of judgments in the global routing hook.

router.beforeEach(async(to, from, next) => {
  NProgress.start();
  await store.dispatch('SetConfigApi'); // get configuration await store.dispatch('SetApi'); // Set basic configuration const token = await store.dispatch('getToken'); / / access tokenif(token) {// User information does not existif(! store.getters.userInfo) { await store.dispatch('GetUser'); Const menuList = await store.dispatch('GetMenu'.localRoute); // get menu await store.dispatch('GenerateRoutes'.localRoute); router.addRoutes(store.getters.addRoutes); . }else{ next(); }}else {
    if(whitelist.includes (to.path)) {// Go to next(); }else{ window.location.href = store.getters.api.IPORTAL_LOCAL_API; NProgress.done(); }}});Copy the code

When users enter the system, they first obtain the system configuration information, which can be a front-end JSON file or a background interface. In this way, you can modify the configuration of the project flexibly, instead of packing into the project every time, you can directly modify the corresponding configuration information of the operation and maintenance boots.

Menu permissions

The previous menu route is directly written in the front end, but when we directly access this route, the user can still enter the function page; Router. AddRoutes router.

  1. The front end gets the menu list first
  2. Add the user menu routing collection through a loop based on the obtained menu list
  3. Dynamically Adding routes

Details can be viewed.

Request plan

The project request is using AXIos, and we can add an interceptor to it to handle our request, or to handle repeated requests via axios.cancelToken, as shown in the code:

// set request unity information import axios from'axios';
import store from '@/store/index.js';
import qs from 'qs';
import { messages } from './msg-box.js'; Const service = axios.create({timeout: 300000, // Set withCredentials:true// cross-domain request});let hasLogoutStatus = false; // Whether a request has a state to exit const queue = []; // request queue const CancelToken = axios.canceltoken; /** * Concatenate the request url and method; * The same 'URL + method' can be regarded as the same request * @param {Object} config request header Object */ const token = config => {return `${config.url}_${config.method}`; }; @param {Object} config */ const removeQueue = config => {/ const removeQueue = config => {for (let i = 0, size = queue.length; i < size; i++) {
    const task = queue[i];
    if(! task)return; Const isLogout = token(config).includes('logout'); // Exit the interface to skip interrupt logicif(! isLogout && hasLogoutStatus) { task.token(); queue.splice(i, 1); }else {
      const cancelMethods = ['post'.'put'.'delete']; Const {method} = config;if (cancelMethods.includes(method)) {
        if(task.token === token(config)) { task.cancel(); queue.splice(i, 1); }}}}}; /** * @param {Object} Response Error Object */ const errorHandle = response => {// eslint-disable-next-line prettier/prettier const { status, data: { message =' ' }} = response;
  let msg = message;
  if(! message) { switch (status) {case 401:
        msg = 'You do not have permission to access this operation! ';
        break;
      case 403:
        msg = 'Your login status is invalid. Please log in again. ';
        break;
      case 424:
        msg = response.data.error;
        break;
      default:
        msg = The service request is abnormal. Please refresh it and try again. ';
    }
  }
  hasLogoutStatus = status === 401 || status === 403;
  if (hasLogoutStatus) {
    messages('error', msg, () => {
      store.dispatch('Logout');
    });
  }
  messages('error', msg); }; / / request interceptor service. Interceptors. Request. Use (config = > {/ / the interrupt of the same request before removeQueue (config); CancelToken = new cancelToken (c => {queue.push({token: token(config), cancel: c}); }); // Add the token after loginif (store.getters.token) {
      config.headers['Authorization'] =
        store.getters.token.token_type + ' ' + store.getters.token.access_token;
    }
    return config;
  },
  error => {
    returnPromise.reject(error); }); / / response interceptor service. Interceptors. Response. Use (response = > {/ / after the request is completed, automatically removed from the queue removeQueue (response. Config); // Disable the global button Loading response store.dispatch('CancalLoading'); Error code processingif(response.status ! = = 200) {return Promise.reject(response);
    }
    return response;
  },
  error => {
    const { response } = error;
    if(response) {// errorHandle(response);return Promise.reject(response);
    } else{// The request timed outif (error.message.includes('timeout')) {
        console.log('Out of time');
        messages('error'.'Request timed out, please refresh or check Internet connection');
      } else{// Disconnection, can display disconnection component console.log('Disconnected');
        messages('error'.'Please check whether the network is connected'); }}});export default {
  get: (url, data = {}) => {
    return new Promise((resolve, reject) => {
      service
        .get(store.getters.api.API + url, { params: data })
        .then(response => {
          resolve(response.data);
        })
        .catch(error => {
          reject(error);
        });
    }).catch(error => {
      throw new Error(error);
    });
  },
  post: (url, data = {}) => {
    return new Promise((resolve, reject) => {
      service
        .post(store.getters.api.API + url, data, {
          headers: {
            'Content-Type': 'application/x-www-form-urlencoded; charset=utf-8'
          },
          withCredentials: true,
          transformRequest: [
            data => {
              return qs.stringify(data);
            }
          ]
        })
        .then(response => {
          resolve(response.data);
        })
        .catch(error => {
          reject(error);
        });
    }).catch(error => {
      returnPromise.reject(error); }); },... /** * blob download * @param {String} URL request address * @param {String} method Request method default 'get' * @param {Object} data request data */exportFile({ url = ' ', data = {}, method = 'get'{})return new Promise((resolve, reject) => {
      const isPost =
        method.toLocaleUpperCase() === 'POST'
          ? {
            headers: { 'Content-Type': 'application/json' },
            data
          }
          : {
            params: data
          };
      const downConfig = {
        withCredentials: true,
        responseType: 'blob'. isPost }; service // eslint-disable-next-line no-unexpected-multiline [method](store.getters.api.API + url, downConfig) .then(response => { resolve(response); }) .catch(error => { reject(error); }); }).catch(error => {returnPromise.reject(error); }); }};Copy the code

When you need to use a request, you can either reference the file http.js or hang it on the vue prototype and use this.$HTTP within the component

// user.js
import http from '@/utils/http.js';

export function getUser() {
  return http.get('/user');
}

// main.js
Vue.prototype.$http = http;
Copy the code

Button Loading

The loading effect of the button can handle scenarios where the background response time is a bit long, and the store is used to encapsulate the processing mode.

// loading.js
import Vue from 'vue';

const loading = {
  state: {},
  mutations: {
    SET_LOADING: (state, data) => {
      const isObject =
        Object.prototype.toString.call(data) === '[object Object]';
      if(! isObject)return;
      Object.keys(data).forEach(key => {
        Vue.set(state, key, data[key]);
      });
    },
    CANCAL_LOADING: state => {
      Object.keys(state).forEach(key => {
        Vue.delete(state, key);
      });
    }
  },
  actions: {
    SetLoading({ commit }, data) {
      commit('SET_LOADING', data);
    },
    CancalLoading({ commit }, data) {
      commit('CANCAL_LOADING', data); }}};exportdefault loading; / / HTTP js service. Interceptors. Response. Use (response = > {/ / close button Loading global response store. Dispatch ('CancalLoading'); . })Copy the code

Defined within the component

<el-button :loading="btn.save" @click="handleClick"> Save </el-button> computed: {btn() {
        return this.$store.state.loading;
    }
}
methods: {
    handleClick() {
        this.$store.dispatch('SetLoading', { save: true}); }}Copy the code

In this way, loading can be used perfectly without having to define each one in data.

conclusion

The above are some of the processing methods that can be used in the background system, the specific code can be viewed.

Other summary articles:

  • Webpack general packaging optimization
  • Component communication processing scheme

Welcome to pay attention to the public number, we communicate and progress together.