Vue Project Actual Warfare - E-commerce Background Management System (next day)

Attachment: https://gitee.com/zhoulililia/vue_shop

1. Background home page basic layout opens Home.vue component, layout:

<el-container class="home-container">
  <!-- Head area -->
  <el-header>Header<el-button type="info" @click="logout"> Sign out </el-button></el-header>
  <!-- Page Body Area -->
  <el-container>
    <!-- sidebar -->
    <el-aside width="200px">Aside</el-aside>
    <!-- Principal structure -->
    <el-main>Main</el-main>
  </el-container>
</el-container>

By default, a class name with the same name as an element-ui component can help us quickly style the corresponding component, such as:

.home-container {
  height: 100%;
}
.el-header{
  background-color:#373D41;
}
.el-aside{
  background-color:#333744;
}
.el-main{
  background-color:#eaedf1;
}

2. Top layout, Sidebar layout

Element-ui, notice to element. Some of the primary keys introduced on demand in JS

<template>
    <el-container class="home-container">
      <!-- Head area -->
      <el-header>
        <div>
          <!-- logo -->
          <img src="../assets/logo.png" alt="">
          <!-- Top Title -->
          <span>E-commerce Background Management System</span>
        </div>
        <el-button type="info" @click="logout"> Sign out </el-button>
      </el-header>
      <!-- Page Body Area -->
      <el-container>
        <!-- sidebar -->
        <el-aside width="200px">
          <!-- Sidebar Menu -->
          <el-menu
            background-color="#333744"
            text-color="#fff"
            active-text-color="#ffd04b">
            <!-- Level 1 Menu -->
            <el-submenu index="1">
              <!-- Level 1 Menu Template -->
              <template slot="title">
                <!-- Icon -->
                <i class="el-icon-location"></i>
                <!-- text -->
                <span>Navigation One</span>
              </template>
              <!-- Secondary Submenu -->
              <el-menu-item index="1-4-1">
                <!-- Secondary Menu Template -->
                <template slot="title">
                  <!-- Icon -->
                  <i class="el-icon-location"></i>
                  <!-- text -->
                  <span>Submenu One</span>
                </template>
              </el-menu-item>
            </el-submenu>
            
          </el-menu>
        </el-aside>
        <!-- Principal structure -->
        <el-main>Main</el-main>
      </el-container>
    </el-container>
</template>

3.axios request interceptor

Background requires token privilege validation in addition to the login interface. We can add token by adding axios request interceptor to ensure we have access to data in main. Add code to JS to add the following code before mounting axios to the vue prototype

//The request calls this callback function in use to add the request header information before reaching the server
axios.interceptors.request.use(config=>{
  //For the request header object, add the Autohorization field for token validation
  config.headers.Authorization = window.sessionStorage.getItem("token")
  return config
})

4. Request Sidebar Data

<script>
export default {
  data() {
    return {
      // Left menu data
      menuList: null
    }
  },
  created() {
    // Request left menu data during the create phase
    this.getMenuList()
  },
  methods: {
    logout() {
      window.sessionStorage.clear()
      this.$router.push('/login')
    },
    async getMenuList() {
      // Send a request for left menu data
      const { data: res } = await this.$http.get('menus')
      if (res.meta.status !== 200) return this.$message.error(res.meta.msg)

      this.menuList = res.data
      console.log(res)
    }
  }
}
</script>

Render left menu with v-for double loop

<el-menu
  background-color="#333744"
  text-color="#fff"
  active-text-color="#ffd04b">
  <!-- Level 1 Menu -->
  <el-submenu :index="item.id+''" v-for="item in menuList" :key="item.id">
    <!-- Level 1 Menu Template -->
    <template slot="title">
      <!-- Icon -->
      <i class="el-icon-location"></i>
      <!-- text -->
      <span>{{item.authName}}</span>
    </template>
    <!-- Secondary Submenu -->
    <el-menu-item :index="subItem.id+''" v-for="subItem in item.children" :key="subItem.id">
      <!-- Secondary Menu Template -->
      <template slot="title">
        <!-- Icon -->
        <i class="el-icon-location"></i>
        <!-- text -->
        <span>{{subItem.authName}}</span>
      </template>
    </el-menu-item>
  </el-submenu>
</el-menu>

5. Set Activation Submenu Style

By changing the active-text-color property of el-menu, you can set the text color of the active item clicked on the sidebar menu. By changing the class name of the i tag in the menu item template, you can set the icon of the left menu bar. We need to add an iconsObj to the data in the project using a third-party font icon:

            iconsObj:{
                //An id corresponds to an icon
                    '125':'iconfont icon-user',
                    '103':'iconfont icon-tijikongjian',
                    '101':'iconfont icon-shangpin',
                    '102':'iconfont icon-danju',
                    '145':'iconfont icon-baobiao'
            },

Then bind the icon class name to the data in iconsObj:

To keep the left menu open only one at a time, displaying its sub-menus, we can add a property unique-opened to the el-menu or set it with data binding (true is considered a bool value, not a string at this time):unique-opened="true"

6. Make Side Menu Bar Scalable Add a div above the menu bar

        <!-- sidebar,Width is set by folding or not -->
        <el-aside :width="isCollapse ? '64px':'200px'">
          <!-- Scalable Sidebar Button -->
          <div class="toggle-button" @click="toggleCollapse">|||</div>
          <!-- Sidebar menu,:collapse="isCollapse"(Set fold menu to bound isCollapse Value),:collapse-transition="false"(Turn off the default fold animation) -->
          <el-menu
          :collapse="isCollapse"
          :collapse-transition="false"
          ......

Then add styles to the div and events to the div:

<div class="toggle-button" @click="this.isCollapse ? '64px':'200px'">|||</div>

7. Add subrouting to background home page

New subrouting component Welcome.vue

<template>
    <div>
        <h3>Welcome</h3>
    </div>
</template>

In router. Import subrouting components into JS and set routing rules and default redirection of subrouting to open Home.vue, adds a routing placeholder to the main's body structure

import Welcome from '../components/Welcome.vue'

const router = new VueRouter({
    routes: [{
        path: '/',
        redirect: '/login'
    }, {
        path: '/login',
        component: Login
    }, {
        path: '/home',
        component: Home,
        redirect: '/welcome',
        children: [
            { path: '/welcome', component: Welcome },
//Here
        ]
    }]
})

After making the Welcome subrouting, we need to transform all the sidebar secondary menus into subrouting links. We just need to set the router property of el-menu to true. When we click on the secondary menu, we will make the route jump according to the index property of the menu, for example: /110, it is not appropriate to use the index id as the route of the jump. We can rebind index to index='/'+subItem.path'

<!-- Level 2 Menu -->
<el-menu-item :index="'/'+subItem.path" v-for="subItem in item.children" :key="subItem.id"      @click="saveNavState('/'+subItem.path)">

8. Complete the user list body area

Create a new user list component user/Users.vue in router. Import subrouting component Users in js. Vue and set routing rules

Because user is a sub-component of re/home to be placed in child ren and welcome

const router = new VueRouter({
    routes: [{
        path: '/',
        redirect: '/login'
    }, {
        path: '/login',
        component: Login
    }, {
        path: '/home',
        component: Home,
        redirect: '/welcome',
        children: [
            { path: '/welcome', component: Welcome },
            { path: '/users', component: Users },
        ]
    }]
})

When clicking on Level 2 menu, the clicked Level 2 submenu is not highlighted. We need to highlight the function being used

We can set the index of the current activation menu by setting the default-active property of el-menu

But the default-active attribute cannot be written to death, fixed to a menu value

So we can first add a click event to all the secondary menus and use the path value as a parameter of the method

@click="saveNavState('/'+subItem.path)"

Save path to sessionStorage in saveNavState method

        //Save Link Activation State
        saveNavState(activePath) {
            window.sessionStorage.setItem('activePath',activePath)
            this.activePath = activePath
        }

Then add an activePath binding data to the data and set the default-active property of el-menu to activePath

Finally in created

    created(){
        this.getMenuList()
        this.activePath = window.sessionStorage.getItem('activePath')
    },

9. Draw the basic structure of the user list

A. Complete the top navigation path using the element-ui crumb component (copy the crumb code, import the component Breadcrumb, BreadcrumbItem in element.js)

B. Use the element-ui card component to complete the body table (copy the card component code, import the component card in the element.js), and then use the element-ui input box to complete the search box and search buttons.

At this point we need to use a raster layout to divide the structure (copy the card component code, import the component Row, Col in element.js), and then use el-button to make the Add User button

<div>
    <h3>User List Component</h3>
    <!-- Crumb navigation -->
    <el-breadcrumb separator="/">
        <el-breadcrumb-item :to="{ path: '/home' }">home page</el-breadcrumb-item>
        <el-breadcrumb-item>user management</el-breadcrumb-item>
        <el-breadcrumb-item>User List</el-breadcrumb-item>
    </el-breadcrumb>
    <!-- Card View Area -->
    <el-card>
        <!-- Search and Add Areas -->
        <el-row :gutter="20">
            <el-col :span="7">
                <el-input placeholder="Please enter content">
                    <el-button slot="append" icon="el-icon-search"></el-button>
                </el-input> 
            </el-col>
            <el-col :span="4">
                <el-button type="primary">Add User</el-button>
            </el-col>
        </el-row> 
    </el-card>
</div>

10. Request user list data (you can leave a message if needed, depending on the api interface documentation)

<script>
export default {
  data() {
    return {
      //Parameters to obtain query user information
      queryInfo: {
        query: '',
        pagenum: 1,
        pagesize: 2
      },
      //Save the user list data requested back
      userList:[],
      total:0
    }
  },
  created() {
    this.getUserList()
  },
  methods: {
    async getUserList() {
      //Send a request to get user list data
      const { res: data } = await this.$http.get('users', {
        params: this.queryInfo
      })
      //Error and return if return status is abnormal
      if (res.meta.status !== 200)
        return this.$message.error('Failed to get user list')
      //If the return status is normal, save the requested data in the data
      this.userList = res.data.users;
      this.total = res.data.total;
    }
  }
}
</script>

11. Show user list data

Use tables to display user list data, use element-ui table component to complete list display data (copy table code, import component Table, TableColumn in element.js)

When rendering the presentation state, the domain slot is used to get the data for each row

Then use the switch switch switch component to display status information (copy the switch component code and import the component switch in element.js)

When rendering operation columns, scope slots are also used to render them.

The action column contains the Modify, Delete, Assign Roles button when we hover over the Assign Roles button

Hopefully there will be some text prompts, at this point we need to use the text prompt component (copy the text prompt component code, import the component Tooltip in element.js) to include the Assign Roles button

<!-- User List(form)region -->
<el-table :data="userList" border stripe>
    <el-table-column type="index"></el-table-column>
    <el-table-column label="Full name" prop="username"></el-table-column>
    <el-table-column label="mailbox" prop="email"></el-table-column>
    <el-table-column label="Telephone" prop="mobile"></el-table-column>
    <el-table-column label="role" prop="role_name"></el-table-column>
    <el-table-column label="state">
        <template slot-scope="scope">
            <el-switch v-model="scope.row.mg_state"></el-switch>
        </template>
    </el-table-column>
    <el-table-column label="operation" width="180px">
        <template slot-scope="scope">
            <!-- modify -->
            <el-button type="primary" icon="el-icon-edit" size='mini'></el-button>
            <!-- delete -->
            <el-button type="danger" icon="el-icon-delete" size='mini'></el-button>
            <!-- Assign Roles -->
            <el-tooltip class="item" effect="dark" content="Assign Roles" placement="top" :enterable="false">
                <el-button type="warning" icon="el-icon-setting" size='mini'></el-button>
            </el-tooltip>
        </template>
    </el-table-column>
</el-table>

12. Paging User List

A. Use tables to display user list data, and use the paging component to complete the list paging display data (copy the paging component code and import the component Pagination in element.js)

B. Change binding data in components

<!-- Paging Navigation Area 
@size-change(pagesize Trigger on change) 
@current-change(Triggered when page number changes)
:current-page(Set Current Page Number)
:page-size(Set the number of data bars per page)
:total(Set Total Pages) -->
            <el-pagination @size-change="handleSizeChange" @current-change="handleCurrentChange" :current-page="queryInfo.pagenum" :page-sizes="[1, 2, 5, 10]" :page-size="queryInfo.pagesize" layout="total, sizes, prev, pager, next, jumper" :total="total">
            </el-pagination>

C. Add event handlers for two events @size-change, @current-change

        //Listen for pagesize change events
        handleSizeChange(newSize) {
            // console.log(newSize);
            this.queryInfo.pagesize = newSize
            this.getUserList();
        },
        //Listen for page number value change events
        handleCurrentChange(newPage) {
            // console.log(newPage);
            this.queryInfo.pagenum = newPage
            this.getUserList();
        },

13. Update user status

When a user clicks on the switch component in the list, the user's state should change with it.

A. First listen for user clicks on the switch component and pass the data from the scope slot as an event parameter

<el-switch v-model="scope.row.mg_state" @change="userStateChanged(scope.row)"></el-switch>

B. Send changes to request completion status in an event.

        //Listen for changes in switch state
        async userStateChanged(userinfo) {
            console.log(userinfo);
            const {data:res} =  await this.$http.put(`users/${userinfo.id}/state/${userinfo.mg_state}`)
            if(res.meta.status !==200) {
                row.mg_state = !row.mg_state
                return this.$message.error('Failed to modify state!')
            }
             this.$message.success('Update Status Successful')
        }

14. Implement search

Add data binding v-model, add click event of search button (call getUserList method to re-request user list data based on text box content when user clicks search button)

When we enter the content in the input box and click Search, we will search by the search keyword. We want to be able to provide an X to delete the search keyword and retrieve all the user list data. Just add the clearable attribute to the text box and the clear event, and request the data again in the clear event.

  <!-- Search and Add Areas -->
    <el-row :gutter="30">
        <el-col :span="9">
         <el-input placeholder="Please enter content" v-model="queryInfo.query" clearable @clear='getUserList'>
            <el-button slot="append" icon="el-icon-search" @click="getUserList"></el-button>
         </el-input>
        </el-col>
        <el-col :span="4">
            <el-button type="primary">Add User</el-button>
        </el-col>
    </el-row>

15. Implement Add Users

A. When we click the Add User button, a dialog box pops up to add users. First, we need to copy the code of the dialog box components and at element. Introducing Dialog components into JS files

B. Next we'll add a click event for the Add User button, where addDialogVisible is set to true, which displays the dialog box

C. Change the content in the Dialog component

<!-- Add User Dialog -->
     <el-dialog
       title="Add User"
       :visible.sync="addDialogVisible"
       width="50%"
       @close="addDialogClosed"
       >
       <!-- Content Theme Area -->
       <el-form :model="addForm" status-icon :rules="addFormRules" ref="addFormRef" label-width="70px">
    <el-form-item label="User name" prop="username">
       <el-input v-model="addForm.username" autocomplete="off"></el-input>
    </el-form-item>
    <el-form-item label="Password" prop="password">
       <el-input v-model="addForm.password" autocomplete="off"></el-input>
    </el-form-item>
    <el-form-item label="mailbox" prop="email">
       <el-input v-model="addForm.email" autocomplete="off"></el-input>
    </el-form-item>
    <el-form-item label="Mobile phone" prop="mobile">
       <el-input v-model="addForm.mobile" autocomplete="off"></el-input>
    </el-form-item>
       </el-form>
       <!-- Bottom Zone -->
       <span slot="footer" class="dialog-footer">
         <el-button @click="addDialogVisible = false">Cancel</el-button>
         <el-button type="primary" @click="addUser">Determine</el-button>
       </span>
     </el-dialog>

D. Add data binding and validation rules:

Mailboxes and mobile phones are validated with regular expressions using the method of creating new objects as follows

data() {
  //Rules for validating mailboxes
  var checkEmail = (rule, value, cb) => {
    const regEmail = /^\w+@\w+(\.\w+)+$/
    if (regEmail.test(value)) {
      return cb()
    }
    //Return an error prompt
    cb(new Error('Please enter a valid mailbox'))
  }
  //Rules for verifying mobile phone numbers
  var checkMobile = (rule, value, cb) => {
    const regMobile = /^1[34578]\d{9}$/
    if (regMobile.test(value)) {
      return cb()
    }
    //Return an error prompt
    cb(new Error('Please enter a valid mobile number'))
  }
  return {
    //Parameters to obtain query user information
    queryInfo: {
      // Query Conditions
      query: '',
      // Current number of pages, that is, page number
      pagenum: 1,
      // Number of data bars per page
      pagesize: 2
    },
    //Save the user list data requested back
    userList: [],
    total: 0,
    //Whether to display the Add User pop-up window
    addDialogVisible: false,
    // Add User's Form Data
    addForm: {
      username: '',
      password: '',
      email: '',
      mobile: ''
    },
    // Add Validation Rule Object for Form
    addFormRules: {
      username: [
        { required: true, message: 'Please enter a user name', trigger: 'blur' },
        {
          min: 3,
          max: 10,
          message: 'User name at 3~10 Between characters',
          trigger: 'blur'
        }
      ],
      password: [
        { required: true, message: 'Please input a password', trigger: 'blur' },
        {
          min: 6,
          max: 15,
          message: 'User name at 6~15 Between characters',
          trigger: 'blur'
        }
      ],
      email: [
          { required: true, message: 'Please enter your mailbox', trigger: 'blur' },
          { validator:checkEmail, message: 'Mailbox format is incorrect, please re-enter', trigger: 'blur'}
      ],
      mobile: [
          { required: true, message: 'Please enter your mobile number', trigger: 'blur' },
          { validator:checkMobile, message: 'Incorrect mobile number, please re-enter', trigger: 'blur'}
      ]
    }
  }
}

E. Reset the form when closing the dialog

Add the @close event to el-dialog and the code to reset the form to it

methods:{
  ....
  addDialogClosed(){
      //After the dialog closes, reset the expression
      this.$refs.addFormRef.resetFields();
  }
}

F. Click the OK button in the dialog box to send a request to complete adding the user

First add a click event to the OK button to complete the business logic code in the click event

methods:{
  ....
  addUser(){
      //Click the OK button to add a new user
      //Call validate for form validation
      this.$refs.addFormRef.validate( async valid => {
          if(!valid) return this.$message.error("Please fill in the complete user information");
          //Send a request to complete adding users
          const {data:res} = await this.$http.post("users",this.addForm)
          //Judge that if adding fails, prompt
          if (res.meta.status !== 200)
              return this.$message.error('Failed to add user')
          //Add Success Tips
          this.$message.success("Successfully added user")
          //close dialog boxes
          this.addDialogVisible = false
          //Re-request the latest data
          this.getUserList()
      })
  }
}

Keywords: Javascript Vue html tab

Added by sangamon on Sat, 15 Jan 2022 21:57:51 +0200