preface

The dictionary module has been designed in the back end, and the corresponding interface has been completed. In the case of unseparated front and back ends, since the page is rendered by the server, a custom dictionary tag is usually used to evaluate and render dictionary data. In this case, the server can easily cache the dictionary. After the front and back ends are separated, the front and back ends interact with each other through interfaces, so dictionaries are maintained differently.

Dictionary Component design

Let’s briefly examine what the dictionary component should do.

Analyze the application scenario first

In background administration, there are three common scenarios for using dictionaries:

  1. Add/modify form, drop – down selection
  2. List page, from value to display name
  3. Search the form, drop – down selection

The use of different scenarios, for the front-end, is actually a different way of presentation. So when we make components, we can start by default with three layouts according to the scenario.

The idea of caching

There are many ways to cache, here is a brief description:

  1. After system login, all dictionary data will be returned once and cached in local cookies or VUEX.

    Advantages: Reduces server stress

    Disadvantages: A one-time return, dictionary volume, may affect the experience

  2. No caching, every time to call the interface to get data;

    Advantages: no

    Disadvantages: frequent requests, page dictionary more words, affect the experience

  3. Vuex is used to cache based on dictKey to ensure that the interface can be called only once for the same key in the same VUE instance.

    Scheme three is the approach adopted by this framework, which is not optimal. But relative to each other, it might be better than the first two. Of course, there must be other options beyond these three, which I won’t discuss here.

Component Parameter Description

Temporarily set a few commonly used parameters, may be added later

Parameter names type The default value instructions
dictKey String undefined Dictionary unique encoding (table name _ field name)
type String enum Dictionary type (enum-> enumeration dictionary type, DB -> database dictionary type,local-> local dictionary type)
value String, Number undefined The value of the binding
size String medium Corresponding to el-select size, medium, small, and mini
mode String form Form-> normal form,list-> list page,searchForm-> searchForm

Interface specification

First, a brief description of the interfaces provided by the back end

Requested address:

{{api_base_url}}/sys/dict/getByDictKey

Data type:

application/json

Example request:

{
	"dictKey": "sys_role_role_type"."type": "enum"
}
Copy the code

Sample response:

{"code": 0, // return status code 0, success "MSG ":" query success through dictionary unique code", // message description "data": {"name": "role type ", "dictKey": "Sys_role_role_type ", // dictionary unique encoding "items": [{"name":" administrator ", "dictItemValue": 10}, {"name": "process auditor ", "dictItemValue": 20}}}]Copy the code

Start coding

The directory structure

├ ─ ─ the SRC ├ ─ ─ the components/m ├ ─ ─ Dict └ ─ ─ index. The vue ├ ─ ─ store ├ ─ ─ modules └ ─ ─ Dict. Js ├ ─ ─ getters. Js └ ─ ─ index. The js ├ ─ ─ views ├── Dashboard ├─ index.vue ├─ main.jsCopy the code

File,

  • src/components/m/Dict/index.vue

A dictionary component

<template> <div class="m-dict"> <! - form layout mode - > < slot v - if = "mode = = = 'form'" v - bind: dict = "dict" > < el - select: size = "size" v - model = "mValue" v - if = "dict. The items" @change="handleChange"> <el-option v-for="item in dict.items" :key="item.dictItemValue" :label="item.name" :value="item.dictItemValue"> </el-option> </el-select> </slot> <! --> <slot v-else-if="mode==='list'" V-bind :dict="dict"> <span v-for="item in dict.items" :key="item.dictItemValue"> <el-tag :type="type" size="mini" v-if="item.dictItemValue === value">{{ item.name }}</el-tag>  </span> </slot> <! <slot V-else -if="mode==='searchForm'" V-bind :dict="dict"> <el-select :size="size" V-model ="mValue" V-if ="dict.items" @change="handleChange"> <el-option label=" all ":value="undefined"></el-option> <el-option V-for ="item in dict.items" :key="item.dictItemValue" :label="item.name" :value="item.dictItemValue"> </el-option> </el-select> </slot> </div> </template> <script> import { mapGetters } from 'vuex' export default { name: 'MDict', props: DictKey: {type: String, default: Undefined}, // Dictionary type (enum-> enumeration dictionary type,db-> database dictionary type,local-> local dictionary type) // If not, the backend check enum first, then check db type: {type: String, default: 'enum'}, // Binding value value: {type: [String, Number], default: undefined}, size: {// medium/small/mini type: String, default: 'medium'}, mode: {// form-> normal form,list-> list page,searchForm-> searchForm type: String, default: 'form' } }, data() { return { mValue: this.value } }, computed: { ... MapGetters ([' dictMap ']), / / the current dictionary dict () {return enclosing dictMap [enclosing dictKey] | | {}}}, watch: {value(n) {this.mvalue = n}}, created() {if (! Enclosing dictMap [this dictKey]) {/ / here call store/modules/dict. Js/action - > getByDictKey this.$store.dispatch('dict/getByDictKey', { dictKey: this.dictKey, type: this.type }) } }, methods: HandleChange (value) {this.$emit('input', value)}}} </script>Copy the code
  • src/store/modules/dict.js
import request from '@/utils/request'

const getDefaultState = (a)= > {
  return {
    / / dictionary map
    dictMap: {}
  }
}

const state = getDefaultState()

const mutations = {
  // Save the dictionary entry
  SAVE_DICT_ITEM: (state, data) = > {
    var obj = {}
    obj[data.dictKey] = data
    // You need to make a copy, otherwise the data changes will not be detected
    state.dictMap = Object.assign({}, state.dictMap, obj)
  },
  // Remove the dictionary entry
  DELETE_DICT_ITEM: (state, dictKey) = > {
    delete state.dictMap[dictKey]
  }
}

const actions = {
  // Get the dictionary action
  getByDictKey({ commit }, data) {
    return new Promise((resolve, reject) = > {
      if (state.dictMap[data.dictKey]) {
        resolve()
      } else {
        // Prevent multiple requests for the same key
        commit('SAVE_DICT_ITEM', {
          dictKey: data.dictKey,
          items: []})// We don't need api.service.js for now
        request({
          url: '/sys/dict/getByDictKey'.method: 'post',
          data
        }).then(res= > {
          if (res.code === 0 && res.data) {
            commit('SAVE_DICT_ITEM', res.data)
          } else {
            commit('DELETE_DICT_ITEM', data.dictKey)
          }
          resolve()
        }).catch(error= > {
          commit('DELETE_DICT_ITEM', data.dictKey)
          reject(error)
        })
      }
    })
  }
}

export default {
  namespaced: true,
  state,
  mutations,
  actions
}
Copy the code
  • src/store/getters.js

Get method for defining dictMap

const getters = {
  sidebar: state= > state.app.sidebar,
  device: state= > state.app.device,
  token: state= > state.user.token,
  avatar: state= > state.user.avatar,
  name: state= > state.user.name,
  / / here additional dictMap the get method, can use mapGetters, as shown in the SRC/components/m/Dict/index vue
  dictMap: state= > state.dict.dictMap
}
export default getters
Copy the code
  • src/store/index.js

The dict.js module is introduced here to make full use of require.contex

import Vue from 'vue'
import Vuex from 'vuex'
import getters from './getters'
// import app from './modules/app'
// import settings from './modules/settings'
// import user from './modules/user'
// Automatically register the VUEX module
const files = require.context('./modules'.true, /\.js$/)
var modules = {}
files.keys().forEach((routerPath) = > {
  const name = routerPath.replace(/^\.\/(.*)\.\w+$/.'$1')
  const value = files(routerPath)
  const fileModule = value.default
  modules[name] = fileModule
}, {})
Vue.use(Vuex)

const store = new Vuex.Store({
  modules: {
    ...modules
  },
  getters
})

export default store

Copy the code
  • src/main.js

The main entry globally registers custom components, also using require.context, the code snippet

import Vue from 'vue'

// Handles custom component global registration
const files = require.context('./components/m'.true, /\.vue$/)
files.keys().forEach((routerPath) = > {
  const componentName = routerPath.replace(/^\.\/(.*)\/index\.\w+$/.'$1')
  const value = files(routerPath)
  Vue.component('m-' + componentName.toLowerCase(), value.default)
}, {})
Copy the code
  • src/views/dashboard/index.vue

Sample usage is provided here:

Custom layout

<m-dict v-model="form.roleType" dict-key="sys_role_role_type">
    <template v-slot:default="{ dict }">
	<el-select v-model="form.roleType" v-if="dict.items">
   		<el-option
               v-for="item in dict.items"
               :key="item.dictItemValue"
               :label="item.name"
               :value="item.dictItemValue">
        </el-option>
        </el-select>
    </template>
</m-dict>
Copy the code

Form layout mode

<m-dict mode="form" v-model="form.roleType" dict-key="sys_role_role_type"></m-dict>
Copy the code

List layout mode

<m-dict mode="list" v-model="form.roleType" dict-key="sys_role_role_type"></m-dict>
Copy the code

Search for form layout patterns

<m-dict mode="searchForm" v-model="form.roleType" dict-key="sys_role_role_type"></m-dict>
Copy the code

rendering

summary

The dictionary component package in this article is still relatively rough, but it is basically enough for ordinary use. If needed in future scenarios, we will consider further expansion. For example, if the local dictionary type is reserved, the interface does not need to request the dictionary. Currently, this parameter is not implemented.

Project source code address

  • The back-end

Gitee.com/mldong/mldo…

  • The front end

Gitee.com/mldong/mldo…

Related articles

Create a suitable for their own rapid development framework – the pilot

Build a suitable for their own rapid development framework – front-end scaffolding

Build a suitable for their own rapid development framework – front-end login and routing modular

To create a suitable for their own rapid development framework – front-end section of the framework layer and CURD sample