This is the 25th day of my participation in the August Genwen Challenge.More challenges in August

Sources of learning videos (link)

Ps, blogger of Station B (Good point)

Front-end learning notes

Install the front-end Vue environment and create a Vue project

Installation node. Js

websiteaddress After installation fool operation can check whether the installation is complete (command) below is my version If the preceding version information is displayed, the installation is successful

The environment for installing vUE

The command

# Install Taobao NPM can not install, but install the domestic mirror will be faster
npm install -g cnpm --registry=https://registry.npm.taobao.org
# vue - CLI install dependency package
cnpm install --g vue-cli
This can be used to create a vue project with visualization, or not, I use the command line to create a Vue project
vue ui
Copy the code

Create the environment for vUE

The rest is just the next stepYou can see it by running it in the project directory

Set the command access in IDEA Import the project into IDEA

My other Vue installation blog is Vue Notes

Install Element-UI, Axios, QS, MockJS

# installation element - the UI
cnpm install element-ui --save
# installation axios
cnpm install axios --save
CNPM install qs --save
cnpm install qs --save
# installation mockjs
cnpm install mockjs --save-dev
Copy the code
  1. Axios: A Promise based HTTP library, Ajax
  2. Qs: Query parameter serialization and parsing library
  3. Mockjs: A tool that generates random data for us

**Mockjs ** creates a mock. Js file in the SRC directory to write random apis that don’t interact with the back end yet, so import the file in main.js with fake data The main js file

import Vue from "vue";
import App from "./App.vue";
import router from "./router";
import store from "./store";
// Introduce mock data, annotate the line when closed
require("./mock") 
Vue.config.productionTip = false;
new Vue({
  router,
  store,
  render: (h) = > h(App),
}).$mount("#app");

Copy the code

Let’s bring in element-UI, axios. Then we’ll open main.js in our project SRC directory and introduce the element-UI dependency axios.

import Element from 'element-ui'
import "element-ui/lib/theme-chalk/index.css"
import axios from 'axios'
Vue.use(Element)
Copy the code

Page routing

Login and creation of the home page

RouterThe link path management system of WebApp is to establish the mapping relationship between URL and page, mainly in SRC router index. Js is to configure the routeCreate our login page and home page

To configure the mapping between the URL and the Vue page in the routing center, refer to the default format./ SRC /router/index.js

import Vue from "vue";
import VueRouter from "vue-router";
import Login from ".. /views/Login";
Vue.use(VueRouter);
const routes = [
  {
    path: "/".name: "Home".component: () = > import('.. /views/Home.vue'),}, {path: "/login".name: "Login".component: Login
  },
];
const router = new VueRouter({
  mode: 'history'.base: process.env.BASE_URL,
  routes
});

export default router;
Copy the code

After modifying the index.js page we started the vue project

npm run serve
Copy the code

Start after the completion of the access localhost: 8081 / login page to find the page as shown below, in the Home | the About

The reason:New vue program there is no other configuration, the default is a single page application, means that this application is made by a shell page, and multiple pages, composition at the time of jump page without shell, the shell pressure surface is App. Vue login page is a fragment, we should change our App. Vue web pageApp.vue after modification

<template>
  <div id="app">
    <router-view/>
  </div>
</template>
<style lang="less">
#app {
  font-family: Avenir, Helvetica, Arial, sans-serif;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  text-align: center;
  color: #2c3e50;
}
#nav {
  padding: 30px;
  a {
    font-weight: bold;
    color: #2c3e50;

    &.router-link-exact-active {
      color: #42b983;
    }
  }
}
</style>
Copy the code

** Check ** after the modification is complete

Log in to develop

Login development process

You need to go to element-UI to find the component of the form, which is a simple login page, but the verification code of the login page needs to interact with the background. There are two main login and background interactions: 1, obtain the verification code of the login, submit the login form, and complete the login. Since the back-end code has not been written, So we’ll write the data in our mock.js to complete the interaction. Development of the APIInteractive process1. Open the login interface 2. Dynamically load the login verification code. For projects separated from the front and back ends, we do not use session for interaction. Then send the random code and the Base64 string code of the verification code picture to the front end 3. The front end submits the user name, password, verification code, and random code 4 to verify whether the background is correctRough flow chart

Login page

<template>

  <el-row type="flex" class="row-bg" justify="center">
    <el-col :xl="6" :lg="Seven">
      <h2>Welcome to FJJ Management System</h2>
      <el-image :src="require('@/assets/img.png')" style="height: 180px; width: 180px;"></el-image>
      <p>Scan the QR code to add personal wechat</p>

    </el-col>
    <el-col :span="1">
      <el-divider direction="vertical"></el-divider>
    </el-col>
    <el-col :span="6" :lg="Seven">
      <el-form :model="loginForm" :rules="rules" ref="loginForm" label-width="80px">
        <el-form-item label="Username" prop="username" style="width: 380px;">
          <el-input v-model="loginForm.username"></el-input>
        </el-form-item>
        <el-form-item label="Password" prop="password"  style="width: 380px;">
          <el-input v-model="loginForm.password" type="password"></el-input>
        </el-form-item>
        <el-form-item label="Verification code" prop="code"  style="width: 380px;">
          <el-input v-model="loginForm.code"  style="width: 172px; float: left" maxlength="5"></el-input>
          <el-image :src="captchaImg" class="captchaImg" @click="getCaptcha"></el-image>
        </el-form-item>

        <el-form-item>
          <el-button type="primary" @click="submitForm('loginForm')">Immediately create</el-button>
          <el-button @click="resetForm('loginForm')">reset</el-button>
        </el-form-item>
      </el-form>
    </el-col>
  </el-row>
</template>

<script>
export default {
  name: "Login",
  data () {
    return {
      loginForm: {
        username: ' '.password: ' '.code: ' '.token: ' '
      },
      rules: {
        username: [{required: true.message: 'Please enter a user name'.trigger: 'blur'}].password: [{required: true.message: 'Please enter your password'.trigger: 'blur'}].code: [{required: true.message: 'Please enter the verification code'.trigger: 'blur' },
          { min: 5.max: 5.message: 'Length of 5 characters'.trigger: 'blur'}},captchaImg: null}},methods: {
    submitForm (formName) {
      this.$refs[formName].validate((valid) = > {
        if (valid) {
          this.$axios.post('/login? ' ,this.loginForm).then(res= >{})}else {
          console.log('Wrong submission')
          return false
        }
      })
    },
    resetForm (formName) {
      this.$refs[formName].resetFields()
    }
  }
}
</script>

<style scoped>
.el-row {
  /*background-color: #fafafa; * /
  height: 100%;
  display: flex;
  align-items: center;
  text-align: center;
  justify-content: center;
  margin-top: 10%;
}

.el-divider {
  height: 200px;
}

.captchaImg {
  float: left;
  margin-left: 8px;
  border-radius: 4px;
}
</style>

Copy the code

The effectOur captcha hasn’t shown up yet and this is where the QR code was introduced

Verification code

At this point, our verification code is not displayed, so we use mock verification code before interacting with the background

Set it to NULL in data first** getCaptcha () method. Call the create image method **

    getCaptcha () {
      this.$axios.post('/captcha').then(res= > {
        this.loginForm.token = res.data.data.token
        this.captchaImg = res.data.data.captchaImg
      })
    }
Copy the code

After creation, don’t forget to call the method below using this method** code, only the content of export default **

<script>
export default {
  name: "Login",
  data () {
    return {
      loginForm: {
        username: ' '.password: ' '.code: ' '.token: ' '
      },
      rules: {
        username: [{required: true.message: 'Please enter a user name'.trigger: 'blur'}].password: [{required: true.message: 'Please enter your password'.trigger: 'blur'}].code: [{required: true.message: 'Please enter the verification code'.trigger: 'blur' },
          { min: 5.max: 5.message: 'Length of 5 characters'.trigger: 'blur'}},captchaImg: null}},methods: {
    submitForm (formName) {
      this.$refs[formName].validate((valid) = > {
        if (valid) {
          // eslint-disable-next-line no-unused-vars
          this.$axios.post('/login? ' ,this.loginForm).then(res= >{})}else {
          console.log('Wrong submission')
          return false
        }
      })
    },
    resetForm (formName) {
      this.$refs[formName].resetFields()
    },
    getCaptcha () {
      this.$axios.post('/captcha').then(res= > {
        // the token value is obtained from the data after the result
        // This is the result that we return in the background. If it is correct, there will be a value of data in it
        this.loginForm.token = res.data.data.token
        // Do the same with our image
        this.captchaImg = res.data.data.captchaImg
      })
    }
  },
  created() {
    this.getCaptcha()
  }
}
</script>

<style scoped>
.el-row {
  /*background-color: #fafafa; * /
  height: 100%;
  display: flex;
  align-items: center;
  text-align: center;
  justify-content: center;
  margin-top: 10%;
}

.el-divider {
  height: 200px;
}
.captchaImg {
  float: left;
  margin-left: 8px;
  border-radius: 4px;
}
</style>

Copy the code

Write data inside our mock.js

// Create the returned object
const Mock = require('mockjs')
// Get Random
const Random = Mock.Random
// Set the result to return
let Result = {
    code: 200.msg: 'Operation successful'.data: null
}
// Image request
Mock.mock('/captcha'.'post'.() = > {
    Result.data = {
        token: Random.string(32),
        captchaImg: Random.dataImage('120x40'.'jikof')}return Result
})

Copy the code

At this point our effect, the verification code is now mock generated randomly when interacting with the backend API interface can be used

Login request

/ SRC /store/index.js so that we can store the data in localStorage **

import Vue from "vue";
import Vuex from "vuex";

Vue.use(Vuex);

export default new Vuex.Store({
  state: {
    token: ' '
  },
  mutations: {
    SET_TOKEN: (state,token) = > {
      state.token = token
      localStorage.setItem("token",token)
    }
  },
  actions: {},
  modules: {},});Copy the code

In our login. vue, save our JWT to Settings and jump to the home page after successful Login The same is true for the test data of the request written for our mock. JWT cannot be put in the test for the time being, so JWT identity is not put in the test. It will be directly put in the test first and then put in the test when interacting with the background After login, go to the home page

There is only a temporary interaction with the background, so it is undefined

The minor error log summarizes the error introduced into Axios

There’s a little error here just for the record Error while using AXIos request

The solution Change it in login. vue as well The request can then be sent

Set the global AXIOS at login time

Fail to log in here to set the global because, what we need is the pop-up display error, such as authentication code error, the user name or password is not correct, etc., are not only the login interface, all interface call will have this case, all we want to be a blocker, analysis of the results returned, if it is abnormal pop-up error directly, So we can save each interface and create a file axios.js (the same as main.js) in the SRC directory

import axios from 'axios'
import router from './router'
import Element from 'element-ui'
axios.defaults.baseURL = 'http://localhost:8081'
const request = axios.create({
    timeout: 5000.headers: {
        'Content-Type': 'application/json; charset=utf-8'
    }
})

request.interceptors.request.use(config= > {
    config.headers.Authorization = localStorage.getItem('token')
    return config
})

request.interceptors.response.use(
    response= > {
        console.log('response ->' + response)

        const res = response.data

        if (res.code === 200) {
            return response
        } else{ Element.Message.error(! res.msg ?'System exception' : res.msg)
            return Promise.reject(response.data.msg)
        }
    },
    error= > {
        console.log(error)

        if (error.response.data) {
            error.massage = error.response.data.msg
        }

        if (error.response.status === 401) {
            router.push('/login')
        }

        Element.Message.error(error.massage, {duration: 3000})
        return Promise.reject(error)
    }
)

export default request

Copy the code

Pre-interception can assemble the token information of the header for all permission requests. Post-interception can call the login page if status.code and error.response.status are 401 not logged in and have no permission. We need to change the original main.js to our own Axios JS To test this, do we enter the wrong transition in mock.js first The effect

Background interface development

So I’m going to choose theta

<el-container>
  <el-header>Header</el-header>
  <el-container>
    <el-aside width="200px">Aside</el-aside>
    <el-main>Main</el-main>
  </el-container>
</el-container>
Copy the code

I’m going to create an Index page and I’m going to put it in there, so I can pull out the common ones in a second and copy the styles Add to the route The effect Add a style to set the height

Header navigation bar Settings

The Index. The vue web page

<template>
  <el-container>
    <el-aside width="200px">
      <div>The menu bar</div>
    </el-aside>
    <el-container>
      <el-header style="height: 55px;"><Strong>ManHub background management system</Strong>
        <div class="header-avatar block">
          <el-avatar  src="https://cube.elemecdn.com/0/88/03b0d39583f48206768a7534e55bcpng.png"></el-avatar>
          <el-dropdown><span class="el-dropdown-link">
            fjj<i class="el-icon-arrow-down el-icon--right"></i>
          </span>
            <el-dropdown-menu slot="dropdown">
              <router-link to="/userCenter">
                <el-dropdown-item>Personal center</el-dropdown-item>
              </router-link>
              <el-dropdown-item @click.native="logout">exit</el-dropdown-item>
            </el-dropdown-menu>
          </el-dropdown>
          <el-link href="http://markerhub.com">Web site</el-link>
        </div>
      </el-header>
      <el-main>
        <div style="margin: 0 15px;">
          <router-view></router-view>
        </div>
      </el-main>
    </el-container>
  </el-container>
</template>

<script>
export default {
  name: "Index"
}
</script>

<style scoped>
/* Dropdown box CSS */
.el-dropdown-link {
  cursor: pointer;
  color: black;
}

.el-icon-arrow-down {
  font-size: 12px;
}

/* Set the header navigation style */
.header-avatar {
  float: right;
  width: 210px;
  display: flex;
  justify-content: space-around;
  align-items: center;
  text-align: center;
}

/* Navigation bar CSS */
.el-container {
  padding: 0vh;
  margin: 0;
  height: 100vh;
}

.el-header {
  background-color: #D3DCE6;
  color: # 333;
  text-align: center;
  line-height: 60px;
}

.el-aside {
  background-color: #D3DCE6;
  color: # 333;
  text-align: center;
  line-height: 200px;
}

.el-main {
  color: # 333;
  padding-left: 20px;
}

/* Remove the underscore */ from the a tag
a {
  text-decoration: none;
}

/* Set the link to slide up to become little hands */
.el-dropdown-link {
  cursor: pointer;
  color: black;
}

/* Sets the height of the sidebar */
.el-menu-vertical-demo {
  height: 100vh;
}

/* Remove the underscore */ from the a tag
a {
  text-decoration: none;
}

</style>

Copy the code

The effect

Side navigation bar Settings

** Almost feels right, go to element-UI and add the menu bar component to home. vue, but make it a dynamic menu, so separate it out and create a new SideMenu

<template>
  <el-menu class="el-menu-vertical-demo" background-color="#545c64" text-color="#fff" active-text-color="#ffd04b">
    <router-link to="/index">
      <el-menu-item index="Index">
        <template slot="title"><i class="el-icon-s-home"></i> <span slot="title">Home page</span></template>
      </el-menu-item>
    </router-link>
    <el-submenu index="1">
      <template slot="title"><i class="el-icon-s-operation"></i> <span>System management</span></template>
      <el-menu-item index="1-1">
        <template slot="title"><i class="el-icon-s-custom"></i> <span slot="title">User management</span></template>
      </el-menu-item>
      <el-menu-item index="1-2">
        <template slot="title"><i class="el-icon-rank"></i> <span slot="title">Role management</span></template>
      </el-menu-item>
      <el-menu-item index="1-3">
        <template slot="title"><i class="el-icon-menu"></i> <span slot="title">Menu management</span></template>
      </el-menu-item>
    </el-submenu>
    <el-submenu index="2">
      <template slot="title"><i class="el-icon-s-tools"></i> <span>System tools</span></template>
      <el-menu-item index="2-2">
        <template slot="title"><i class="el-icon-s-order"></i> <span slot="title">Digital dictionary</span></template>
      </el-menu-item>
    </el-submenu>
  </el-menu>
</template>

<script>
export default {
  name: "SideMenu"
}
</script>

<style scoped>
/* Sets the height of the sidebar */
.el-menu-vertical-demo {
  height: 100vh;
}
/* Remove the underscore */ from the a tag
a {
  text-decoration: none;
}
</style>

Copy the code

At this point sidemenu. vue is added to home.vue as a component. We need to import and declare the component to use the label, so we should declare in index. vue to use the label

The effect Remove the entire frame inside home.vue, leaving only the middle contents in IndexAfter removing home.vue

<template>
  <el-container>
    <el-aside width="200px">
      <SideMenu></SideMenu>
    </el-aside>
    <el-container>
      <el-header style="height: 55px;"><Strong>ManHub background management system</Strong>
        <div class="header-avatar block">
          <el-avatar  src="https://cube.elemecdn.com/0/88/03b0d39583f48206768a7534e55bcpng.png"></el-avatar>
          <el-dropdown><span class="el-dropdown-link">
            fjj<i class="el-icon-arrow-down el-icon--right"></i>
          </span>
            <el-dropdown-menu slot="dropdown">
              <router-link to="/userCenter">
                <el-dropdown-item>Personal center</el-dropdown-item>
              </router-link>
              <el-dropdown-item @click.native="logout">exit</el-dropdown-item>
            </el-dropdown-menu>
          </el-dropdown>
          <el-link href="http://markerhub.com">Web site</el-link>
        </div>
      </el-header>
      <el-main>
        <div style="margin: 0 15px;">
          <router-view></router-view>
        </div>
      </el-main>
    </el-container>
  </el-container>
</template>

<script>
import SideMenu from "./inc/SideMenu";

export default {
  name: "Home".components: {SideMenu}
}
</script>

<style scoped>
/* Dropdown box CSS */
.el-dropdown-link {
  cursor: pointer;
  color: black;
}

.el-icon-arrow-down {
  font-size: 12px;
}

/* Set the header navigation style */
.header-avatar {
  float: right;
  width: 210px;
  display: flex;
  justify-content: space-around;
  align-items: center;
  text-align: center;
}

/* Navigation bar CSS */
.el-container {
  padding: 0vh;
  margin: 0;
  height: 100vh;
}

.el-header {
  background-color: #D3DCE6;
  color: # 333;
  text-align: center;
  line-height: 60px;
}

.el-aside {
  background-color: #D3DCE6;
  color: # 333;
  text-align: center;
  line-height: 200px;
}

.el-main {
  color: # 333;
  padding-left: 20px;
}

/* Remove the underscore */ from the a tag
a {
  text-decoration: none;
}

/* Set the link to slide up to become little hands */
.el-dropdown-link {
  cursor: pointer;
  color: black;
}

/* Sets the height of the sidebar */
.el-menu-vertical-demo {
  height: 100vh;
}

/* Remove the underscore */ from the a tag
a {
  text-decoration: none;
}
</style>

Copy the code

After removing the index.vue

<template>
<div>The middle section</div>
</template>

<script>

export default {
  name: "Index"

}
</script>

<style scoped>


</style>

Copy the code

At this point when we’re accessing Index we can’t just have the middle part without the whole frame We should use index.vue as a child route to the Home, so that when we access index the parent route will be displayedStep 1 Modify the routeSecond, modify home.vue

And then I add this, at this point, when we’re looking at the effect

Side navigation bar routing

Create several new pages, first create a folder under views, and then create a new Vue page.

Add a route to index.js At this point we’re not even going to click on the left side of user management and change the Home page The effect

Display user login information and log out to clear browser cache

The upper right corner of the management interface is written dead. Now we have logged in successfully, so we can request to obtain the current user information through the interface, so that the user information can be dynamically displayed home.vue

Write request and test data inside mock.js

// Personal center test data
Mock.mock('/sys/userInfo'.'get',() =>{
    Result.data = {
        id: '1',
        username :'Feng Jiaojiao',
        avatar: 'https://cube.elemecdn.com/0/88/03b0d39583f48206768a7534e55bcpng.png'
    }
    return Result
})
Copy the code

The effect Logged out

The mock. Js data

// Log out
Mock.mock('/logout'.'post', () = > {return Result
})
Copy the code

Personal center interface

Create a VUE for your personal center

<template>
  <div style="text-align: center;">
    <h2>Hello! {{userinfo.username}} student</h2>

    <el-form :model="passForm" status-icon :rules="rules" ref="passForm" label-width="100px">
      <el-form-item label="Old password" prop="currentPass">
        <el-input type="password" v-model="passForm.currentPass" autocomplete="off"></el-input>
      </el-form-item>
      <el-form-item label="New password" prop="password">
        <el-input type="password" v-model="passForm.password" autocomplete="off"></el-input>
      </el-form-item>
      <el-form-item label="Confirm password" prop="checkPass">
        <el-input type="password" v-model="passForm.checkPass" autocomplete="off"></el-input>
      </el-form-item>
      <el-form-item>
        <el-button type="primary" @click="submitForm('passForm')">submit</el-button>
        <el-button @click="resetForm('passForm')">reset</el-button>
      </el-form-item>
    </el-form>
  </div>
</template>
<script>
export default {
  name: 'Login',
  data () {
    var validatePass = (rule, value, callback) = > {
      if (value === ' ') {
        callback(new Error('Please enter your password again'))}else if(value ! = =this.passForm.password) {
        callback(new Error('Two input passwords are inconsistent! '))}else {
        callback()
      }
    }
    return {
      userInfo: {},passForm: {
        password: ' '.checkPass: ' '.currentPass: ' '
      },
      rules: {
        password: [{required: true.message: 'Please enter a new password'.trigger: 'blur' },
          { min: 6.max: 12.message: 'Between 6 and 12 characters long'.trigger: 'blur'}].checkPass: [{required: true.validator: validatePass, trigger: 'blur'}].currentPass: [{required: true.message: 'Please enter your current password'.trigger: 'blur' }
        ]
      }
    }
  },
  created () {
    this.getUserInfo()
  },
  methods: {
    getUserInfo () {
      this.$axios.get('/sys/userInfo').then(res= > {
        this.userInfo = res.data.data
      })
    },
    submitForm (formName) {
      this.$refs[formName].validate((valid) = > {
        if (valid) {
          const _this = this
          this.$axios.post('/sys/user/updatePass'.this.passForm).then(res= > {
            _this.$alert(res.data.msg, 'tip', {
              confirmButtonText: 'sure'.callback: action= > {
                this.$refs[formName].resetFields()
              }
            })
          })
        } else {
          console.log('error submit!! ')
          return false
        }
      })
    },
    resetForm (formName) {
      this.$refs[formName].resetFields()
    }
  }
}
</script>

<style scoped>
.el-form {
  width: 420px;
  margin: 50px auto;
}
</style>

Copy the code

You need to write this sentence in home.vue Just set our route in index

After clicking on

Dynamic menu bar development

The above code, the menu bar on the left of the data is written to death, and should not be written in the actual situation, because the menu is needed according to the logged in user’s permission to dynamic display menu, which users see menu bar may not be the same, these data need to get to the backend access should simplify the data into a json array data, The for loop is then shown as sidemenu.vue

<template>
  <el-menu class="el-menu-vertical-demo" background-color="#545c64" text-color="#fff" active-text-color="#ffd04b">
    <router-link to="/index">
      <el-menu-item index="Index">
        <template slot="title"><i class="el-icon-s-home"></i> <span slot="title">Home page</span></template>
      </el-menu-item>
    </router-link>
    <el-submenu :index="menu.name" v-for="menu in menuList" :key="menu.name">
      <template slot="title">
        <i :class="menu.icon"></i>
        <span>{{menu.title}}</span>
      </template>
      <router-link :to="item.path" v-for="item in menu.children" :key="item.path">
        <el-menu-item :index="item.name" @click="selectMenu(item)">
          <template slot="title">
            <i :class="item.icon"></i>
            <span slot="title">{{item.title}}</span>
          </template>
        </el-menu-item>
      </router-link>
    </el-submenu>

  </el-menu>
</template>

<script>
export default {
  name: "SideMenu".data() {
    return {
      menuList: [{
        name: 'SysManga'.title: 'System Administration'.icon: 'el-icon-s-operation'.path: ' '.component: ' '.children: [{
          name: 'SysUser'.title: 'User Management'.icon: 'el-icon-s-custom'.path: '/user'.children: []}]}, {name: 'SysTools'.title: 'System Tools'.icon: 'el-icon-s-tools'.path: ' '.children: [{
          name: 'SysDict'.title: 'Digital dictionary'.icon: 'el-icon-s-order'.path: '/sys/dicts'.children: []},]}],}}}</script>

<style scoped>
/* Sets the height of the sidebar */
.el-menu-vertical-demo {
  height: 100vh;
}

/* Remove the underscore */ from the a tag
a {
  text-decoration: none;
}
</style>

Copy the code

As you can see, using the for loop to display the data, all you need to do is change the menuList in the data, and the effect is exactly the same as before. Now menuList data we are write directly to the page data, generally we are request to the backend, so you need to define a mock interface, should be dynamic menu, we also want to consider the access problem, so we request data generally out dynamic menu, to access the data, such as a menu to add, Delete whether there is permission, whether can display. Mock.js

Mock.mock('/sys/menu/nav'.'get'.() = > {
/ / the menu json
 let nav = [     
  {      
     name: 'SysManga'. }, {name: 'SysTools'. }]// Permission data
          let authoritys = ['SysUser'."SysUser:save"]
          Result.data = {} 
          Result.data.nav = nav  
          Result.data.authoritys = authoritys  
          return Result       
Copy the code

The interface defined for the navigation menu should be called after the login has successfully completed, but not every time the login is opened, that is, when the browser has stored the user’s token we do not need to log in again, so we cannot put it in the login completed method. Here we need to consider the routing problem of the navigation menu. When we click the menu to route to the page, we need to declare the solution in the router: Load menu data in router.js. Router has a prefix block, which means we can make some judgments or load data before routing to the page

Add the following code to router.js: SRC /router/index.js

// Dynamic navigation bar
router.beforeEach((to, from, next) = > {
    let hasRoute = store.state.menus.hasRoute
    const token = localStorage.getItem('token')
    if (to.path === '/login') {
        next()
    } else if(! token) { next({path: '/login'})}if(token && ! hasRoute) { axios.get('/sys/menu/nav', {
            headers: {
                Authorization: localStorage.getItem('token')
            }
        }).then(res= > {
            console.log(res.data.data)
            store.commit('setMenuList', res.data.data.nav)
            store.commit('setPermList', res.data.data.authoritys)
            // Dynamically bind routes
            const newRoutes = router.options.routes
            res.data.data.nav.forEach(menu= > {
                if (menu.children) {
                    menu.children.forEach(e= > {
                        const route = menuToRoute(e)
                        if (route) {
                            newRoutes[0].children.push(route)
                        }
                    })
                }
            })
            console.log(newRoutes)
            console.log('newRoutes')
            router.addRoutes(newRoutes)
            hasRoute = true
            store.commit('changeRouteStatus', hasRoute)
        })
    }

    next()
})
const menuToRoute = (menu) = > {
    if(! menu.component) {return null
    }
    // Copy to properties
    const route = {
        path: menu.path,
        name: menu.name,
        meta: {
            icon: menu.icon,
            title: menu.title
        }
    }
    route.component = () = > import('@/views/' + menu.component + '.vue')
    console.log(route)
    console.log('route')
    return route
}
export default router

Copy the code

Router. AddRoutes (newRoutes) dynamically adds a routing object to the menu object. At the same time, there is a Menu.component in the menu object, which is the corresponding component of the connection. We need to add, say, the /sys/users link to component(sys/User). Also, in the menu object above, there is a menu.component. This is the component of the connection that we need to add. For example, the /sys/ Users link corresponds to the Component (sys/User).

 // Json for the menu
    const nav = [{
        name: 'SysManga'.title: 'System Administration'.icon: 'el-icon-s-operation'.component: ' '.path: ' '.children: [{title: 'User Management'.icon: 'el-icon-s-custom'.path: '/sys/users'.name: 'SysUser'.component: 'sys/User'.children: []}, {name: 'SysRole'.title: 'Role Management'.icon: 'el-icon-rank'.path: '/sys/roles'.component: 'sys/Role'.children: []}, {name: 'SysMenu'.title: 'Menu Management'.icon: 'el-icon-menu'.path: '/sys/menus'.component: 'sys/Menu'.children: []}]}, {name: 'SysTools'.title: 'System Tools'.icon: 'el-icon-s-tools'.path: ' '.component: ' '.children: [{title: 'Digital dictionary'.icon: 'el-icon-s-order'.path: '/sys/dicts'.component: ' '.children: []}}]]Copy the code

At the same time, in the above router, we also judged whether the menu could be loaded in advance by judging whether there was a login page and whether there was a token. At the same time, we also made a switch hasRoute to dynamically judge whether the menu had been loaded. We also need to define a few methods in store for storing data. We define a menu module, so in store we create a folder called Modules, and then new Menus.js

import Vue from 'vue'
import Vuex from 'vuex'

Vue.use(Vuex)
export default {
    state: {      // Menu bar data
        menuList: [].// Permission data
        permList: [].hasRoute: false
    }, mutations: {
        changeRouteStatus(state, hasRoute) {
            state.hasRoute = hasRoute
            sessionStorage.setItem("hasRoute", hasRoute)
        }, setMenuList(state, menus) {
            state.menuList = menus
        }, setPermList(state, authoritys) {
            state.permList = authoritys
        }
    }
}

Copy the code

Remember to import this module in store and add it to modules: SRC /store/index.js

import menus from "./modules/menus".export default new Vuex.Store({  
...  modules:
 {    menus  }})
Copy the code

In this way, our menu data can be loaded, and then SideMenu. Vue directly obtain the store menuList data to display the menu. src/views/inc/SideMenu.vue

data() {   
 return {   
      menuList: this.$store.state.menus.menuList, 
         }}
Copy the code

Results the following

Dynamic TAB page development

1. When we click the navigation menu, a corresponding TAB will be added at the top. Note that it is not allowed to be added repeatedly, and you can directly switch to this TAB when you find an existing TAB. Tabs. Vue: SRC /views/inc/Tabs. Vue: SRC /views/inc/Tabs

<template>
  <el-tabs v-model="editableTabsValue" type="card" closable @tab-remove="removeTab" @tab-click="clickTab">
    <el-tab-pane
      v-for="(item) in editableTabs"
      :key="item.name"
      :label="item.title"
      :name="item.name"
    >
    </el-tab-pane>
  </el-tabs>
</template>

<script>
export default {
  name: 'Tabs',
  data () {
    return {
      editableTabsValue: this.$store.state.menus.editableTabsValue,
      tabIndex: 2}},computed: {
    editableTabs: {
      get () {
        return this.$store.state.menus.editableTabs
      },
      set (val) {
        this.$store.state.menus.editableTabs = val
      }
    }
  },
  methods: {
    removeTab (targetName) {
      const tabs = this.editableTabs
      let activeName = this.editableTabsValue
      if (targetName === 'Index') {
        return
      }
      if (activeName === targetName) {
        tabs.forEach((tab, index) = > {
          if (tab.name === targetName) {
            const nextTab = tabs[index + 1] || tabs[index - 1]
            if (nextTab) {
              activeName = nextTab.name
            }
          }
        })
      }
      this.editableTabsValue = activeName
      this.editableTabs = tabs.filter(tab= >tab.name ! == targetName)this.$router.push({ name: activeName })
    },
    clickTab (target) {
      this.$router.push({ name: target.name })
    }
  }
}
</script>

<style scoped>

</style>

Copy the code

Computed means that computed attributes are recalculated when the values of the attributes that it depends on change, and if they are not, they are used in the cache. The logic of clickTab removeTab is simpler, especially if removeTab considers multiple cases. Modify the meun. Add editableTabsValue js and editableTabs then home page as the default page SRC/store/modules/menus. Js

  state: {
    // Menu bar data
    menuList: [].// Permission data
    permList: [].hasRoute: false.editableTabsValue: 'Index'.editableTabs: [{
      title: 'home'.name: 'Index'}},Copy the code

Then we’ll introduce our Tabs. Vue component in home. vue

# Import componentsimport Tabs from "./inc/Tabs"# declare component components: {SideMenu, Tabs}, <el-main> # use component <Tabs></Tabs> <div style="margin: 0 15px;">  
        <router-view></router-view> 
          </div>
          </el-main>
Copy the code

Current effect Having completed the first step, now we need to click on the menu navigation and add the Tabs to the Tabs list, so we should modify the sideMeun. Vue pageSince the tabs TAB list is stored in the store, we need to commit the event, so we add the addTabs method to menu.js:After refreshing the browser, the link /sys/ Users stays the same, but the Tab is missing, so we need to fix it. When the user opens the page directly by entering the link form, we can also automatically add and activate the specified Tab according to the link. So where do I add this echo method? The router? We can, but we need to make a judgment call, because every navigation click triggers the Router. Is there an easier way? Some! Since refreshing or opening a page is a one-time action, we can perform the echo action in higher level app. vue as follows:

As you can see from the code above, the addTabs method is triggered on all pages except the login page, so we can add a TAB and activate a TAB.

Personal center

Personal center page

Create UserCenCenter. Vue

<template>
  <div style="text-align: center;">
    <h2>Hello! {{userinfo.username}} student</h2>

    <el-form :model="passForm" status-icon :rules="rules" ref="passForm" label-width="100px">
      <el-form-item label="Old password" prop="currentPass">
        <el-input type="password" v-model="passForm.currentPass" autocomplete="off"></el-input>
      </el-form-item>
      <el-form-item label="New password" prop="password">
        <el-input type="password" v-model="passForm.password" autocomplete="off"></el-input>
      </el-form-item>
      <el-form-item label="Confirm password" prop="checkPass">
        <el-input type="password" v-model="passForm.checkPass" autocomplete="off"></el-input>
      </el-form-item>
      <el-form-item>
        <el-button type="primary" @click="submitForm('passForm')">submit</el-button>
        <el-button @click="resetForm('passForm')">reset</el-button>
      </el-form-item>
    </el-form>
  </div>
</template>
<script>
export default {
  name: 'Login',
  data () {
    var validatePass = (rule, value, callback) = > {
      if (value === ' ') {
        callback(new Error('Please enter your password again'))}else if(value ! = =this.passForm.password) {
        callback(new Error('Two input passwords are inconsistent! '))}else {
        callback()
      }
    }
    return {
      userInfo: {},passForm: {
        password: ' '.checkPass: ' '.currentPass: ' '
      },
      rules: {
        password: [{required: true.message: 'Please enter a new password'.trigger: 'blur' },
          { min: 6.max: 12.message: 'Between 6 and 12 characters long'.trigger: 'blur'}].checkPass: [{required: true.validator: validatePass, trigger: 'blur'}].currentPass: [{required: true.message: 'Please enter your current password'.trigger: 'blur' }
        ]
      }
    }
  },
  created () {
    this.getUserInfo()
  },
  methods: {
    getUserInfo () {
      this.$axios.get('/sys/userInfo').then(res= > {
        this.userInfo = res.data.data
      })
    },
    submitForm (formName) {
      this.$refs[formName].validate((valid) = > {
        if (valid) {
          const _this = this
          this.$axios.post('/sys/user/updatePass'.this.passForm).then(res= > {
            _this.$alert(res.data.msg, 'tip', {
              confirmButtonText: 'sure'.callback: action= > {
                this.$refs[formName].resetFields()
              }
            })
          })
        } else {
          console.log('error submit!! ')
          return false
        }
      })
    },
    resetForm (formName) {
      this.$refs[formName].resetFields()
    }
  }
}
</script>

<style scoped>
.el-form {
  width: 420px;
  margin: 50px auto;
}
</style>

Copy the code

Menu interface

The menu page

Menu management we use the Table component of the tree structure data, we just need to assemble the data according to the example, it can be displayed automaticallyThere should be a tree structure But elemenui added – no specific code SRC/views/sys/Menu. The vue

<template>
  <div>
    <el-form :inline="true" :model="formInline" ref="editForm" class="demo-form-inline">
      <el-form-item>
        <el-button type="primary" @click="dialogVisible = true">new</el-button>
      </el-form-item>
    </el-form>
    <el-table
    :data="tableData"
    style="width: 100%; margin-bottom: 20px;"
    row-key="id"
    border
    stripe
    default-expand-all
    :tree-props="{children: 'children', hasChildren: 'hasChildren'}">
    <el-table-column
      prop="name"
      label="Name"
      sortable
      width="180">
    </el-table-column>
    <el-table-column
      prop="perm"
      label="Permission code"
      sortable
      width="180">
    </el-table-column>
    <el-table-column
      prop="icon"
      label="Icon">
    </el-table-column>
      <el-table-column
        prop="type"
        label="Type">
        <template slot-scope="scope">
          <el-tag size="small" v-if="scope.row.type === 0">directory</el-tag>
          <el-tag size="small" v-else-if="scope.row.type === 1" type="success">The menu</el-tag>
          <el-tag size="small" v-else-if="scope.row.type === 2" type="info">button</el-tag>
        </template>
      </el-table-column>
      <el-table-column
        prop="path"
        label=URL "menu">
      </el-table-column>
      <el-table-column
        prop="component"
        label="Menu Component">
      </el-table-column>
      <el-table-column
        prop="orderNum"
        label="Sort number">
      </el-table-column>
      <el-table-column
        prop="statu"
        label="State">
        <template slot-scope="scope">
   <el-tag size="small" v-if="scope.row.statu === 1" type="success">normal</el-tag>
   <el-tag size="small" v-else-if="scope.row.statu === 0" type="danger">disable</el-tag>
        </template>
      </el-table-column>
      <el-table-column
        prop="icon"
        label="Operation">

        <template slot-scope="scope">
          <el-button type="text" @click="editHandle(scope.row.id)">The editor</el-button>
          <el-divider direction="vertical"></el-divider>

          <template>
            <el-popconfirm title="Is this a paragraph of content to delete?" @confirm="delHandle(scope.row.id)">
              <el-button type="text" slot="reference"  >delete</el-button>
            </el-popconfirm>
          </template>

        </template>
      </el-table-column>

  </el-table>
<! -- New dialog box -->
    <el-dialog
      title="Tip"
      :visible.sync="dialogVisible"
      width="600px"
      :before-close="handleClose">
      <el-form :model="editForm" :rules="editFormRules" ref="editForm" label-width="100px" class="demo-editForm">
        <el-form-item label="Superior menu" prop="parentId">
          <el-select v-model="editForm.parentId" placeholder="Please select superior menu">
      <template v-for="item in tableData">
        <el-option :label="item.name" :value="item.id"></el-option>
        <template v-for="chid in item.children">
          <el-option :label="chid.name" :value="chid.id"></el-option>
          <span>{{ '-  ' + chid.name}}</span>
        </template>
      </template>
          </el-select>
        </el-form-item>
        <el-form-item label="Menu name" prop="name" label-width="100px">
          <el-input v-model="editForm.name" autocomplete="off"></el-input>
        </el-form-item>

        <el-form-item label="Permission code" prop="perms" label-width="100px">
          <el-input v-model="editForm.perms" autocomplete="off"></el-input>
        </el-form-item>

        <el-form-item label="Icon" prop="icon" label-width="100px">
          <el-input v-model="editForm.icon" autocomplete="off"></el-input>
        </el-form-item>
        <el-form-item label=URL "menu" prop="path" label-width="100px">
          <el-input v-model="editForm.path" autocomplete="off"></el-input>
        </el-form-item>

        <el-form-item label="Menu Component" prop="component" label-width="100px">
          <el-input v-model="editForm.component" autocomplete="off"></el-input>
        </el-form-item>

        <el-form-item label="Type" prop="type" label-width="100px">
          <el-radio-group v-model="editForm.type">
            <el-radio :label=0>directory</el-radio>
            <el-radio :label=1>The menu</el-radio>
            <el-radio :label=2>button</el-radio>
          </el-radio-group>
        </el-form-item>
        <el-form-item label="State" prop="statu" label-width="100px">
          <el-radio-group v-model="editForm.statu">
            <el-radio :label=0>disable</el-radio>
            <el-radio :label=1>normal</el-radio>
          </el-radio-group>
        </el-form-item>

        <el-form-item label="Sort number" prop="orderNum" label-width="100px">
          <el-input-number v-model="editForm.orderNum" :min="1" label="Sort number">1</el-input-number>
        </el-form-item>

        <el-form-item>
          <el-button type="primary" @click="submitForm('editForm')">Immediately create</el-button>
          <el-button @click="resetForm('editForm')">reset</el-button>
        </el-form-item>
      </el-form>
    </el-dialog>
  </div>
</template>

<script>

export default {
  name: 'Meun',
  data () {
    return {
      dialogVisible: false.editForm: [].editFormRules: {
        parentId: [{required: true.message: 'Please select superior menu'.trigger: 'blur'}].name: [{required: true.message: 'Please enter a name'.trigger: 'blur'}].perms: [{required: true.message: 'Please enter permission code'.trigger: 'blur'}].type: [{required: true.message: 'Please select status'.trigger: 'blur'}].orderNum: [{required: true.message: 'Please fill in the sort number'.trigger: 'blur'}].statu: [{required: true.message: 'Please select status'.trigger: 'blur'}},tableData: []
    }
  },
  created () {
    this.getMenuTree()
  },
  methods: {
    getMenuTree () {
      this.$axios.get('/sys/menu/list').then(res= > {
        this.tableData = res.data.data
      })
    },
    submitForm (formName) {
      this.$refs[formName].validate((valid) = > {
        if (valid) {
          this.$axios.post('/sys/menu/' + (this.editForm.id ? 'update' : 'save'), this.editForm)
            .then(res= > {
              this.$message({
                showClose: true.message: 'Congratulations, it worked.'.type: 'success'.onClose: () = > {
                  this.getMenuTree()
                }
              })
              this.dialogVisible = false})}else {
          console.log('error submit!! ')
          return false
        }
      })
    },
    editHandle (id) {
      this.dialogVisible = true
      this.$axios.get('/sys/menu/info/' + id).then(res= > {
        console.log(res.data.data + '99999999')
        this.editForm = res.data.data
      })
    },
    resetForm (formName) {
      this.$refs[formName].resetFields()
      this.dialogVisible = false
      this.editForm = {}
    },
    handleClose () {
      this.resetForm('editForm')
    },
    delHandle (id) {
      this.$axios.post('/sys/menu/delete/' + id).then(res= > {
        this.$message({
          showClose: true.message: 'Congratulations, it worked.'.type: 'success'.onClose: () = > {
            this.getMenuTree()
          }
        })
      })
    }
  }
}
</script>
<style scoped>
</style>

Copy the code

Role management

The role page

Roles need to be associated with menu permissions, and the menu is a tree structure,

src/views/sys/Role.vue

<template>
  <div>
    <el-form :inline="true">
      <el-form-item>
        <el-input
          v-model="searchForm.name"
          placeholder="Name"
          clearable
        >
        </el-input>
      </el-form-item>

      <el-form-item>
        <el-button @click="getRoleList">search</el-button>
      </el-form-item>

      <el-form-item>
        <el-button type="primary" @click="dialogVisible = true">new</el-button>
      </el-form-item>
      <el-form-item>
        <el-popconfirm title="Is this a definitive batch delete?" @confirm="delHandle(null)">
          <el-button type="danger" slot="reference" :disabled="delBtlStatu">Batch delete</el-button>
        </el-popconfirm>
      </el-form-item>
    </el-form>
    <el-table
      ref="multipleTable"
      :data="tableData"
      tooltip-effect="dark"
      style="width: 100%"
      border
      stripe
      @selection-change="handleSelectionChange">

      <el-table-column
        type="selection"
        width="55">
      </el-table-column>

      <el-table-column
        prop="name"
        label="Name"
        width="120">
      </el-table-column>
      <el-table-column
        prop="code"
        label="Unique code"
        show-overflow-tooltip>
      </el-table-column>
      <el-table-column
        prop="remark"
        label="Description"
        show-overflow-tooltip>
      </el-table-column>

      <el-table-column
        prop="statu"
        label="State">
        <template slot-scope="scope">
          <el-tag size="small" v-if="scope.row.statu === 1" type="success">normal</el-tag>
          <el-tag size="small" v-else-if="scope.row.statu === 0" type="danger">disable</el-tag>
        </template>

      </el-table-column>
      <el-table-column
        prop="icon"
        label="Operation">

        <template slot-scope="scope">
          <el-button type="text" @click="permHandle(scope.row.id)">Assign permissions</el-button>
          <el-divider direction="vertical"></el-divider>

          <el-button type="text" @click="editHandle(scope.row.id)">The editor</el-button>
          <el-divider direction="vertical"></el-divider>

          <template>
            <el-popconfirm title="Is this a paragraph of content to delete?" @confirm="delHandle(scope.row.id)">
              <el-button type="text" slot="reference">delete</el-button>
            </el-popconfirm>
          </template>

        </template>
      </el-table-column>

    </el-table>

    <el-pagination
      @size-change="handleSizeChange"
      @current-change="handleCurrentChange"
      layout="total, sizes, prev, pager, next, jumper"
      :page-sizes="[10, 20, 50, 100]." "
      :current-page="current"
      :page-size="size"
      :total="total">
    </el-pagination>

    <! -- New dialog box -->
    <el-dialog
      title="Tip"
      :visible.sync="dialogVisible"
      width="600px"
      :before-close="handleClose">

      <el-form :model="editForm" :rules="editFormRules" ref="editForm" label-width="100px" class="demo-editForm">

        <el-form-item label="Role Name" prop="name" label-width="100px">
          <el-input v-model="editForm.name" autocomplete="off"></el-input>
        </el-form-item>

        <el-form-item label="Unique code" prop="code" label-width="100px">
          <el-input v-model="editForm.code" autocomplete="off"></el-input>
        </el-form-item>

        <el-form-item label="Description" prop="remark" label-width="100px">
          <el-input v-model="editForm.remark" autocomplete="off"></el-input>
        </el-form-item>

        <el-form-item label="State" prop="statu" label-width="100px">
          <el-radio-group v-model="editForm.statu">
            <el-radio :label=0>disable</el-radio>
            <el-radio :label=1>normal</el-radio>
          </el-radio-group>
        </el-form-item>

        <el-form-item>
          <el-button type="primary" @click="submitForm('editForm')">Immediately create</el-button>
          <el-button @click="resetForm('editForm')">reset</el-button>
        </el-form-item>
      </el-form>

    </el-dialog>

    <el-dialog
      title="Assign permissions"
      :visible.sync="permDialogVisible"
      width="600px">

      <el-form :model="permForm">

        <el-tree
          :data="permTreeData"
          show-checkbox
          ref="permTree"
          :default-expand-all=true
          node-key="id"
          :check-strictly=true
          :props="defaultProps">
        </el-tree>
      </el-form>
      <span slot="footer" class="dialog-footer">
			    <el-button @click="permDialogVisible = false">Take away</el-button>
			    <el-button type="primary" @click="submitPermFormHandle('permForm')">determine</el-button>
			</span>
    </el-dialog>
  </div>
</template>

<script>
export default {
  name: 'Role',
  data () {
    return {
      searchForm: {},
      delBtlStatu: true.total: 0.size: 10.current: 1.dialogVisible: false.editForm: {},tableData: [].editFormRules: {
        name: [{required: true.message: 'Please enter role name'.trigger: 'blur'}].code: [{required: true.message: 'Please enter unique code'.trigger: 'blur'}].statu: [{required: true.message: 'Please select status'.trigger: 'blur'}},multipleSelection: [].permDialogVisible: false.permForm: {},
      defaultProps: {
        children: 'children'.label: 'name'
      },
      permTreeData: []
    }
  },
  created () {
    this.getRoleList()

    this.$axios.get('/sys/menu/list').then(res= > {
      this.permTreeData = res.data.data
    })
  },
  methods: {
    toggleSelection (rows) {
      if (rows) {
        rows.forEach(row= > {
          this.$refs.multipleTable.toggleRowSelection(row)
        })
      } else {
        this.$refs.multipleTable.clearSelection()
      }
    },
    handleSelectionChange (val) {
      console.log('tick')
      console.log(val)
      this.multipleSelection = val

      this.delBtlStatu = val.length === 0
    },

    handleSizeChange (val) {
      console.log(` per page${val}Article `)
      this.size = val
      this.getRoleList()
    },
    handleCurrentChange (val) {
      console.log('Current page:${val}`)
      this.current = val
      this.getRoleList()
    },

    resetForm (formName) {
      this.$refs[formName].resetFields()
      this.dialogVisible = false
      this.editForm = {}
    },
    handleClose () {
      this.resetForm('editForm')
    },

    getRoleList () {
      this.$axios.get('/sys/role/list', {
        params: {
          name: this.searchForm.name,
          current: this.current,
          size: this.size
        }
      }).then(res= > {
        this.tableData = res.data.data.records
        this.size = res.data.data.size
        this.current = res.data.data.current
        this.total = res.data.data.total
      })
    },

    submitForm (formName) {
      this.$refs[formName].validate((valid) = > {
        if (valid) {
          this.$axios.post('/sys/role/' + (this.editForm.id ? 'update' : 'save'), this.editForm)
            .then(res= > {
              this.$message({
                showClose: true.message: 'Congratulations, it worked.'.type: 'success'.onClose: () = > {
                  this.getRoleList()
                }
              })

              this.dialogVisible = false
              this.resetForm(formName)
            })
        } else {
          console.log('error submit!! ')
          return false
        }
      })
    },
    editHandle (id) {
      this.$axios.get('/sys/role/info/' + id).then(res= > {
        this.editForm = res.data.data

        this.dialogVisible = true
      })
    },
    delHandle (id) {
      var ids = []

      if (id) {
        ids.push(id)
      } else {
        this.multipleSelection.forEach(row= > {
          ids.push(row.id)
        })
      }

      console.log(ids)

      this.$axios.post('/sys/role/delete', ids).then(res= > {
        this.$message({
          showClose: true.message: 'Congratulations, it worked.'.type: 'success'.onClose: () = > {
            this.getRoleList()
          }
        })
      })
    },
    permHandle (id) {
      this.permDialogVisible = true

      this.$axios.get('/sys/role/info/' + id).then(res= > {
        this.$refs.permTree.setCheckedKeys(res.data.data.menuIds)
        this.permForm = res.data.data
      })
    },

    submitPermFormHandle (formName) {
      var menuIds = this.$refs.permTree.getCheckedKeys()

      console.log(menuIds)

      this.$axios.post('/sys/role/perm/' + this.permForm.id, menuIds).then(res= > {
        this.$message({
          showClose: true.message: 'Congratulations, it worked.'.type: 'success'.onClose: () = > {
            this.getRoleList()
          }
        })
        this.permDialogVisible = false
        this.resetForm(formName)
      })
    }
  }
}
</script>

<style scoped>
.el-pagination {
  float: right;
  margin-top: 22px;
}
</style>

Copy the code

The user interface

The user page

User management has an operation called role assignment, which is similar to the operation of adding permissions to roles

<template>
  <div>
    <el-form :inline="true">
      <el-form-item>
        <el-input
          v-model="searchForm.username"
          placeholder="Username"
          clearable
        >
        </el-input>
      </el-form-item>

      <el-form-item>
        <el-button @click="getUserList">search</el-button>
      </el-form-item>

      <el-form-item>
        <el-button type="primary" @click="dialogVisible = true" v-if="hasAuth('sys:user:save')">new</el-button>
      </el-form-item>
      <el-form-item>
        <el-popconfirm title="Is this a definitive batch delete?" @confirm="delHandle(null)">
          <el-button type="danger" slot="reference" :disabled="delBtlStatu" v-if="hasAuth('sys:user:delete')">Batch delete</el-button>
        </el-popconfirm>
      </el-form-item>
    </el-form>

    <el-table
      ref="multipleTable"
      :data="tableData"
      tooltip-effect="dark"
      style="width: 100%"
      border
      stripe
      @selection-change="handleSelectionChange">

      <el-table-column
        type="selection"
        width="55">
      </el-table-column>

      <el-table-column
        label="Avatar"
        width="50">
        <template slot-scope="scope">
          <el-avatar size="small" :src="scope.row.avatar"></el-avatar>
        </template>
      </el-table-column>

      <el-table-column
        prop="username"
        label="Username"
        width="120">
      </el-table-column>
      <el-table-column
        prop="code"
        label="Role Name">
        <template slot-scope="scope">
          <el-tag size="small" type="info" v-for="item in scope.row.sysRoles">{{item.name}}</el-tag>
        </template>

      </el-table-column>
      <el-table-column
        prop="email"
        label="Email">
      </el-table-column>
      <el-table-column
        prop="phone"
        label="Mobile phone Number">
      </el-table-column>

      <el-table-column
        prop="statu"
        label="State">
        <template slot-scope="scope">
          <el-tag size="small" v-if="scope.row.statu === 1" type="success">normal</el-tag>
          <el-tag size="small" v-else-if="scope.row.statu === 0" type="danger">disable</el-tag>
        </template>

      </el-table-column>
      <el-table-column
        prop="created"
        width="200"
        label="Creation time"
      >
      </el-table-column>
      <el-table-column
        prop="icon"
        width="260px"
        label="Operation">

        <template slot-scope="scope">
          <el-button type="text" @click="roleHandle(scope.row.id)">Assign roles</el-button>
          <el-divider direction="vertical"></el-divider>

          <el-button type="text" @click="repassHandle(scope.row.id, scope.row.username)">To reset your password</el-button>
          <el-divider direction="vertical"></el-divider>

          <el-button type="text" @click="editHandle(scope.row.id)">The editor</el-button>
          <el-divider direction="vertical"></el-divider>

          <template>
            <el-popconfirm title="Is this a paragraph of content to delete?" @confirm="delHandle(scope.row.id)">
              <el-button type="text" slot="reference">delete</el-button>
            </el-popconfirm>
          </template>

        </template>
      </el-table-column>

    </el-table>

    <el-pagination
      @size-change="handleSizeChange"
      @current-change="handleCurrentChange"
      layout="total, sizes, prev, pager, next, jumper"
      :page-sizes="[10, 20, 50, 100]." "
      :current-page="current"
      :page-size="size"
      :total="total">
    </el-pagination>

    <! -- New dialog box -->
    <el-dialog
      title="Tip"
      :visible.sync="dialogVisible"
      width="600px"
      :before-close="handleClose">

      <el-form :model="editForm" :rules="editFormRules" ref="editForm">
        <el-form-item label="Username" prop="username" label-width="100px">
          <el-input v-model="editForm.username" autocomplete="off"></el-input>
          <el-alert
            title="Initial password is 888888"
            :closable="false"
            type="info"
            style="line-height: 12px;"
          ></el-alert>
        </el-form-item>

        <el-form-item label="Email"  prop="email" label-width="100px">
          <el-input v-model="editForm.email" autocomplete="off"></el-input>
        </el-form-item>
        <el-form-item label="Mobile phone Number"  prop="phone" label-width="100px">
          <el-input v-model="editForm.phone" autocomplete="off"></el-input>
        </el-form-item>

        <el-form-item label="State"  prop="statu" label-width="100px">
          <el-radio-group v-model="editForm.statu">
            <el-radio :label="0">disable</el-radio>
            <el-radio :label="1">normal</el-radio>
          </el-radio-group>
        </el-form-item>

      </el-form>
      <div slot="footer" class="dialog-footer">
        <el-button @click="resetForm('editForm')">Take away</el-button>
        <el-button type="primary" @click="submitForm('editForm')">determine</el-button>
      </div>
    </el-dialog>

    <! Assign permissions dialog box -->
    <el-dialog title="Assign roles" :visible.sync="roleDialogFormVisible" width="600px">

      <el-form :model="roleForm">
        <el-tree
          :data="roleTreeData"
          show-checkbox
          ref="roleTree"
          :check-strictly=checkStrictly
          node-key="id"
          :default-expand-all=true
          :props="defaultProps">
        </el-tree>
      </el-form>

      <div slot="footer" class="dialog-footer">
        <el-button @click="roleDialogFormVisible=false">Take away</el-button>
        <el-button type="primary" @click="submitRoleHandle('roleForm')">determine</el-button>
      </div>
    </el-dialog>
  </div>
</template>

<script>
export default {
  name: 'SysUser',
  data () {
    return {
      searchForm: {},
      delBtlStatu: true.total: 0.size: 10.current: 1.dialogVisible: false.editForm: {},tableData: [].editFormRules: {
        username: [{required: true.message: 'Please enter user name'.trigger: 'blur'}].email: [{required: true.message: 'Please enter email address'.trigger: 'blur'}].statu: [{required: true.message: 'Please select status'.trigger: 'blur'}},multipleSelection: [].roleDialogFormVisible: false.defaultProps: {
        children: 'children'.label: 'name'
      },
      roleForm: {},
      roleTreeData: [].treeCheckedKeys: [].checkStrictly: true

    }
  },
  created () {
    this.getUserList()

    this.$axios.get('/sys/role/list').then(res= > {
      this.roleTreeData = res.data.data.records
    })
  },
  methods: {
    toggleSelection (rows) {
      if (rows) {
        rows.forEach(row= > {
          this.$refs.multipleTable.toggleRowSelection(row)
        })
      } else {
        this.$refs.multipleTable.clearSelection()
      }
    },
    handleSelectionChange (val) {
      console.log('tick')
      console.log(val)
      this.multipleSelection = val

      this.delBtlStatu = val.length === 0
    },

    handleSizeChange (val) {
      console.log(` per page${val}Article `)
      this.size = val
      this.getUserList()
    },
    handleCurrentChange (val) {
      console.log('Current page:${val}`)
      this.current = val
      this.getUserList()
    },

    resetForm (formName) {
      this.$refs[formName].resetFields()
      this.dialogVisible = false
      this.editForm = {}
    },
    handleClose () {
      this.resetForm('editForm')
    },

    getUserList () {
      this.$axios.get('/sys/user/list', {
        params: {
          username: this.searchForm.username,
          current: this.current,
          size: this.size
        }
      }).then(res= > {
        this.tableData = res.data.data.records
        this.size = res.data.data.size
        this.current = res.data.data.current
        this.total = res.data.data.total
      })
    },

    submitForm (formName) {
      this.$refs[formName].validate((valid) = > {
        if (valid) {
          this.$axios.post('/sys/user/' + (this.editForm.id ? 'update' : 'save'), this.editForm)
            .then(res= > {
              this.$message({
                showClose: true.message: 'Congratulations, it worked.'.type: 'success'.onClose: () = > {
                  this.getUserList()
                }
              })

              this.dialogVisible = false})}else {
          console.log('error submit!! ')
          return false
        }
      })
    },
    editHandle (id) {
      this.$axios.get('/sys/user/info/' + id).then(res= > {
        this.editForm = res.data.data

        this.dialogVisible = true
      })
    },
    delHandle (id) {
      var ids = []

      if (id) {
        ids.push(id)
      } else {
        this.multipleSelection.forEach(row= > {
          ids.push(row.id)
        })
      }

      console.log(ids)

      this.$axios.post('/sys/user/delete', ids).then(res= > {
        this.$message({
          showClose: true.message: 'Congratulations, it worked.'.type: 'success'.onClose: () = > {
            this.getUserList()
          }
        })
      })
    },

    roleHandle (id) {
      this.roleDialogFormVisible = true

      this.$axios.get('/sys/user/info/' + id).then(res= > {
        this.roleForm = res.data.data

        const roleIds = []
        res.data.data.sysRoles.forEach(row= > {
          roleIds.push(row.id)
        })

        this.$refs.roleTree.setCheckedKeys(roleIds)
      })
    },
    submitRoleHandle (formName) {
      var roleIds = this.$refs.roleTree.getCheckedKeys()

      console.log(roleIds)

      this.$axios.post('/sys/user/role/' + this.roleForm.id, roleIds).then(res= > {
        this.$message({
          showClose: true.message: 'Congratulations, it worked.'.type: 'success'.onClose: () = > {
            this.getUserList()
          }
        })

        this.roleDialogFormVisible = false
      })
    },
    repassHandle (id, username) {
      this.$confirm('will reset user [' + username + '] password, do you want to continue? '.'tip', {
        confirmButtonText: 'sure'.cancelButtonText: 'cancel'.type: 'warning'
      }).then(() = > {
        this.$axios.post('/sys/user/repass', id).then(res= > {
          this.$message({
            showClose: true.message: 'Congratulations, it worked.'.type: 'success'.onClose: () = >{}})})})}}}</script>

<style scoped>

.el-pagination {
  float: right;
  margin-top: 22px;
}

</style>

Copy the code

Button permission control

The menu above, the role, the actions that the user has, not every user has, users without permissions we should hide the button. SRC/globalfun.js SRC/globalfun.js

import Vue from 'vue'

Vue.mixin({
  methods: {
    hasAuth (perm) {
      var authority = this.$store.state.menus.permList

      return authority.indexOf(perm) > -1}}})Copy the code

In the shelf menu, we need to frame the permission data at the same time. Now we need to use the array of permission data here, so we can pass the button whether the permission is in the permission list. The function of mixins is that multiple components can share data and methods. After being introduced into components that use mixins, methods and attributes in mixins are incorporated into the components and can be directly used to expand existing component data and methods. Import this file SRC \main.js in main.js

import gobal from "./globalFun"
Copy the code

SRC /views/sys/ menu.vue

<el-button type="primary" @click="dialogFormVisible = true" v-if="hasAuth('sys:menu:save')"> new < / el - button >Copy the code

V-if is used to determine whether the return is true.The effectThere is no new button when logging in to testAdmin time is there