Vue e e-commerce practice project

Today's goal

1. Realize the basic layout of the background home page 2. Realize the left menu bar 3. Display user list 4. Add users

1. Basic layout of background home page

Open home Vue components, 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>
    <!-- Main structure -->
    <el-main>Main</el-main>
  </el-container>
</el-container>

By default, the class name with the same name as the element UI component can help us quickly add styles to the corresponding components, 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

<template>
    <el-container class="home-container">
      <!-- Head area -->
      <el-header>
        <div>
          <!-- dark horse logo -->
          <img src="../assets/heima.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">
            <!-- First level menu -->
            <el-submenu index="1">
              <!-- First level 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>Single vegetable</span>
                </template>
              </el-menu-item>
            </el-submenu>

          </el-menu>
        </el-aside>
        <!-- Main structure -->
        <el-main>Main</el-main>
      </el-container>
    </el-container>
</template>

3.axios request interceptor

In addition to the login interface, token permission verification is required in the background. We can add a token by adding an axios request interceptor to ensure that we have the permission to obtain data In main JS, add the following code before mounting axios to vue prototype

//Before the request reaches the server, the callback function in use will be called to add the request header information
axios.interceptors.request.use(config=>{
  //For the request header object, add the Authorization field of token authentication
  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 the left menu data in the created phase
    this.getMenuList()
  },
  methods: {
    logout() {
      window.sessionStorage.clear()
      this.$router.push('/login')
    },
    async getMenuList() {
      // Send request to get 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>

Rendering the left menu through v-for double loop

<el-menu
  background-color="#333744"
  text-color="#fff"
  active-text-color="#ffd04b">
  <!-- First level menu -->
  <el-submenu :index="item.id+''" v-for="item in menuList" :key="item.id">
    <!-- First level 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 the style of the active submenu

By changing the active text color property of El menu, you can set the text color of the active item clicked in the sidebar menu By changing the class name of the i tag in the menu item template, you can set the icon in the menu bar on the left. We need to use the third-party Font Icon in the project Add a data in obikonsj:

iconsObj: {
        '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:

In order to keep the left menu open only one at a time and display the submenus, we can add a property unique opened in El menu Or you can set it by data binding (at this time, true is considered a bool value instead of a string): unique opened = "true"

6. Make the telescopic function of the side menu bar

Add a div above the menu bar

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

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

|||

7. Add child routes on the background home page

Add a child routing component welcome vue In router JS, and set routing rules and default redirection of child routes Open home Vue, add a route placeholder in the main structure

After making the Welcome sub route, we need to transform all the side bar secondary menus into sub route links We only need to set the router attribute of El menu to true. At this time, when we click the secondary menu, it will be based on the index of the menu Property, such as: / 110, It is not appropriate to use index id as the jump path. We can rebind the value of index as: index = "/" + subitem path”

8. Complete the main area of the user list

New user list component user / users vue In router JS to import the child routing component users Vue and set routing rules

When clicking the secondary menu, the secondary submenu is not highlighted. We need to highlight the function being used We can set the index of the active menu by setting the default active attribute of El menu However, the default active attribute cannot be written dead and is fixed to a menu value So we can first add click events to all secondary menus and take the path value as the parameter of the method @click="saveNavState('/'+subItem.path)" Save the path to sessionStorage in the saveNavState method saveNavState( path ){ //Save the clicked secondary menu information when clicking the secondary menu window.sessionStorage.setItem("activePath",path); this.activePath = path; } Then add an activePath binding data to the data and set the default active property of El menu to activePath Finally, assign the data in sessionStorage to activePath in created this.activePath = window.sessionStorage.getItem("activePath")

9. Draw the basic structure of user list

A. Use the element UI breadcrumb component to complete the top navigation path (copy the breadcrumb code and import the components breadcrumb and breadcrumbitem in element.js) B. Use the element UI card component to complete the main table (copy the card component code and import the component card in element.js), and then use the element UI input box to complete the search box and search button, At this time, we need to use the grid layout to divide the structure (copy the card component code, import the component Row and col in element.js), and then use El button to make the add user button

<div>
    <h3>User list component</h3>
    <!-- Breadcrumb 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 the 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

<script>
export default {
  data() {
    return {
      //Get parameters for querying user information
      queryInfo: {
        query: '',
        pagenum: 1,
        pagesize: 2
      },
      //Save the requested user list data
      userList:[],
      total:0
    }
  },
  created() {
    this.getUserList()
  },
  methods: {
    async getUserList() {
      //Send request to get user list data
      const { res: data } = await this.$http.get('users', {
        params: this.queryInfo
      })
      //If the returned status is abnormal, an error is reported and returned
      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 data
      this.userList = res.data.users;
      this.total = res.data.total;
    }
  }
}
</script>

11. Display user list data

Use the table to display the user list data, and use the element UI table component to complete the list display data (copy the table code and import the components table and tablecolumn in element.js) When rendering the presentation state, the scope slot is used to obtain the data of each row Then use the switch switch component to display the status information (copy the switch component code and import the component switch in element.js) When rendering the operation column, the scope slot is also used for rendering, The operation column contains modify, delete and assign role buttons. When we put the mouse over the assign role button We hope to have some text prompts. At this time, we need to use the text prompt component (copy the text prompt component code and import the component tooltip in element.js) to include the role assignment button The code structure is as follows:

<!-- 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. Pagination of user list

A. Use the table to display the user list data. You can 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 Triggered on change) 
@current-change(Triggered when the page number changes)
:current-page(Set current page number)
:page-size(Set the number of data pieces 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 the event handler functions @ size change and @ current change for two events

handleSizeChange(newSize) {
  //Triggered when pagesize changes. When pagesize changes, we should
  //Request data with the latest pagesize and display the data
  //   console.log(newSize)
  this.queryInfo.pagesize = newSize;
  //Send the request again according to pagesize to request the latest data
  this.getUserList();  
},
handleCurrentChange( current ) {
  //Triggered when the page number changes. When the current changes, we should
  //Request data with the latest current page number and display the data
  //   console.log(current)
  this.queryInfo.pagenum = current;
  //Send the request again according to pagenum to request the latest data
  this.getUserList();  
}

13. User implementation status

When the user clicks the switch component in the list, the user's state should change accordingly. A. First, listen to the event that the user clicks the switch component, and pass the data of the scope slot as an event parameter

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

B. Send request completion status change in event

async userStateChanged(row) {
  //Send request for status modification
  const { data: res } = await this.$http.put(
    `users/${row.id}/state/${row.mg_state}`
  )
  //If the returned status is abnormal, an error is reported and returned
  if (res.meta.status !== 200) {
    row.mg_state = !row.mg_state
    return this.$message.error('Failed to modify status')
  }
  this.$message.success('Update status succeeded')
},

14. Realize the search function

Add data binding and click event of search button (when the user clicks the search button, call getUserList method to re request user list data according to the content of text box) After we enter the content in the input box and click search, we will search according to the search keyword. We hope to provide an X to delete the search keyword and re obtain all the user list data. We only need to add the clear attribute to the text box and add the clear event, and re request the data in the clear event

<el-col :span="7">
    <el-input placeholder="Please enter the content" v-model="queryInfo.query" clearable @clear="getUserList">
        <el-button slot="append" icon="el-icon-search" @click="getUserList"></el-button>
    </el-input>
</el-col>

15. Add users

A. When we click the add user button, a Dialog box will pop up to realize the function of adding users. First, we need to copy the code of the Dialog box component and add it in element JS file

B. Next, we need to add a click event for the "add user" button. In the event, set addDialogVisible to true to display the dialog box

C. Change the content in the Dialog component

<!-- Dialog components  :visible.sync(Sets whether the dialog box is displayed) width(Sets the width of the dialog box)
:before-close(Event triggered before the dialog box closes) -->
<el-dialog title="Add user" :visible.sync="addDialogVisible" width="50%">
    <!-- Dialog body area -->
    <el-form :model="addForm" :rules="addFormRules" ref="addFormRef" label-width="70px">
        <el-form-item label="user name" prop="username">
            <el-input v-model="addForm.username"></el-input>
        </el-form-item>
        <el-form-item label="password" prop="password">
            <el-input v-model="addForm.password"></el-input>
        </el-form-item>
        <el-form-item label="mailbox" prop="email">
            <el-input v-model="addForm.email"></el-input>
        </el-form-item>
        <el-form-item label="Telephone" prop="mobile">
            <el-input v-model="addForm.mobile"></el-input>
        </el-form-item>
    </el-form>
    <!-- Bottom area of dialog box -->
    <span slot="footer" class="dialog-footer">
        <el-button @click="addDialogVisible = false">Cancel</el-button>
        <el-button type="primary" @click="addDialogVisible = false">determine</el-button>
    </span>
</el-dialog>

D. Add data binding and validation rules:

data() {
  //Rules for validating mailboxes
  var checkEmail = (rule, value, cb) => {
    const regEmail = /^\w+@\w+(\.\w+)+$/
    if (regEmail.test(value)) {
      return cb()
    }
    //Returns an error message
    cb(new Error('Please enter a legal email address'))
  }
  //Rules for verifying mobile phone numbers
  var checkMobile = (rule, value, cb) => {
    const regMobile = /^1[34578]\d{9}$/
    if (regMobile.test(value)) {
      return cb()
    }
    //Returns an error message
    cb(new Error('Please enter a valid mobile phone number'))
  }
  return {
    //Get parameters for querying user information
    queryInfo: {
      // Query criteria
      query: '',
      // Current number of pages, i.e. page number
      pagenum: 1,
      // Number of data pieces displayed per page
      pagesize: 2
    },
    //Save the requested user list data
    userList: [],
    total: 0,
    //Show add user pop-up
    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 user name', trigger: 'blur' },
        {
          min: 3,
          max: 10,
          message: 'User name in 3~10 Between characters',
          trigger: 'blur'
        }
      ],
      password: [
        { required: true, message: 'Please input a password', trigger: 'blur' },
        {
          min: 6,
          max: 15,
          message: 'User name in 6~15 Between characters',
          trigger: 'blur'
        }
      ],
      email: [
          { required: true, message: 'Please enter email address', trigger: 'blur' },
          { validator:checkEmail, message: 'The email format is incorrect, please re-enter', trigger: 'blur'}
      ],
      mobile: [
          { required: true, message: 'Please enter your mobile phone number', trigger: 'blur' },
          { validator:checkMobile, message: 'The mobile phone number is incorrect, please re-enter', trigger: 'blur'}
      ]
    }
  }
}

E. Resets the form when the dialog box is closed Add the @ close event to the El dialog, and add the code to reset the form in the event

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

F. Click OK in the dialog box to send a request to complete the operation of adding users First, add a click event to the OK button, and complete the business logic code in the click event

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

Today's goal

1. Modify user and delete user

2. Push code to code cloud

3. Permission list

4. Role list

5. Assign roles

1. Modify user information

A. Bind the click event for the Modify button in the user list B. Add and modify the user dialog box in the page and modify the properties of the dialog box C. Query the user data to be modified according to the id

//Displays the dialog box for editing users
async showEditDialog(id) {
    //Send a request to obtain user information according to the id
    const { data: res } = await this.$http.get('users/' + id)
    //Judge if the addition fails, give a prompt
    if (res.meta.status !== 200) return this.$message.error('Failed to get user information')
    //Save the obtained data to the data editForm
    this.editForm = res.data
    //Show pop ups
    this.editDialogVisible = true
}

D. In the pop-up window, add and modify the form of user information and respond to data binding and data verification

<!-- Dialog body area -->
<el-form :model="editForm" :rules="editFormRules" ref="editFormRef" label-width="70px">
    <el-form-item label="user name">
        <el-input v-model="editForm.username" disabled></el-input>
    </el-form-item>
    <el-form-item label="mailbox" prop="email">
        <el-input v-model="editForm.email"></el-input>
    </el-form-item>
    <el-form-item label="Telephone" prop="mobile">
        <el-input v-model="editForm.mobile"></el-input>
    </el-form-item>
</el-form>

Data binding and validation:

//Controls whether the modify user dialog box is displayed
editDialogVisible: false,
//Modify user's form data
editForm: {
    username: '',
    email: '',
    mobile: ''
},
//Modify the validation rule object of the form
editFormRules: {
    email: [
        { required: true, message: 'Please enter email address', trigger: 'blur' },
        {
        validator: checkEmail,
        message: 'The email format is incorrect, please re-enter',
        trigger: 'blur'
        }
    ],
    mobile: [
        { required: true, message: 'Please enter your mobile phone number', trigger: 'blur' },
        {
        validator: checkMobile,
        message: 'The mobile phone number is incorrect, please re-enter',
        trigger: 'blur'
        }
    ]
}

E. Listen to the dialog box closing event and reset the form after the dialog box is closed

<el-dialog title="Modify user" :visible.sync="editDialogVisible" width="50%" @close="editDialogClosed">

editDialogClosed(){
    //After the dialog box closes, reset the representation
    this.$refs.editFormRef.resetFields()
}

F. When the user clicks the OK button, send a request to complete the modification after the data is verified successfully

editUser() {
    //After the user clicks the OK button in the modify form, verify the form data
    this.$refs.editFormRef.validate(async valid => {
    if (!valid) return this.$message.error('Please complete the user information')
    //Send a request to complete the operation of modifying the user
    const { data: res } = await this.$http.put(
        'users/' + this.editForm.id,
        this.editForm
    )
    //Judge if the modification fails, give a prompt
    if (res.meta.status !== 200) return this.$message.error('Failed to modify user')
    //Prompt for successful modification
    this.$message.success('User modified successfully')
    //close dialog boxes
    this.editDialogVisible = false
    //Re request the latest data
    this.getUserList()
    })
}

2. Delete user

When clicking the delete button, we should jump out of the prompt message box and let the user confirm the deletion operation. If you want to use the confirmation cancellation prompt box, we need to mount the prompt message box to vue first. A. Import the MessageBox component and mount the MessageBox component to the instance. Vue.prototype.$confirm = MessageBox.confirm B. Add an event to the delete button in the user list, pop up the confirm cancel window in the event handling function, and finally send the request to delete the user according to the id

async removeUserById(id){
    //Click OK to cancel to delete the user
    const confirmResult = await this.$confirm('Do you want to permanently delete this user','Delete prompt',{
    confirmButtonText:'confirm deletion',
    cancelButtonText:'cancel',
    type:'warning'
    }).catch(err=>err)
    //If the user clicks confirm, the confirm result is' confirm '
    //If the user clicks cancel, confirmResult will get the error message 'Cancel' of catch
    if(confirmResult != "confirm"){
        return this.$message.info("The deletion has been cancelled")
    }
    //Send a request to complete the deletion operation according to the id
    const {data:res} = await this.$http.delete('users/'+id)
    //Judge if the deletion fails, give a prompt
    if (res.meta.status !== 200) return this.$message.error('Failed to delete user')
    //Prompt for successful modification
    this.$message.success('User deleted successfully')
    //Re request the latest data
    this.getUserList()
}

3. Push code

Create a user sub branch and push the code to the code cloud A. Create user sub branch git checkout -b user B. Add the code to the staging area git add C. Submit the code and comment git commit -m 'add complete user list function' D. Push the local user branch to the code cloud git push -u origin user E. Merge the user branch code into the master: Switch to master git checkout master Merge user git merge user F. Push the code of the local master branch to the code cloud git push

Create rights sub branch A. Create rights sub branch git checkout -b rights B. Push the local rights branch to the code cloud git push -u origin rights

4. Permission list

A. Add permission list route

Create a rights management component (Rights.vue) and run it in router JS add the corresponding routing rule

import Rights from './components/power/Rights.vue'
......
      path: '/home', component: Home, redirect: '/welcome', children: [
        { path: "/welcome", component: Welcome },
        { path: "/users", component: Users },
        { path: "/rights", component: Rights }
      ]
......

B. Add breadcrumbs navigation

At rights Add breadcrumb component to Vue to show navigation path

C. Display data

Add a rightsList data in data, provide a getRightsList method in methods to send request to get permission list data, and call this method in created to get data.

<el-table :data="rightsList" stripe>
    <el-table-column type="index"></el-table-column>
    <el-table-column label="Permission name" prop="authName"></el-table-column>
    <el-table-column label="route" prop="path"></el-table-column>
    <el-table-column label="privilege level" prop="level">
        <template slot-scope="scope"> 
            <el-tag v-if="scope.row.level === 0">First level authority</el-tag>
            <el-tag v-if="scope.row.level === 1" type="success">Secondary authority</el-tag>
            <el-tag v-if="scope.row.level === 2" type="warning">Three level authority</el-tag>
        </template>
    </el-table-column>
</el-table>
<script>
export default {
    data(){
        return {
            //Permissions in list form
            rightsList:[]
        }
    },
    created(){
        this.getRightsList();
    },
    methods:{
        async getRightsList(){
            const {data:res} = await this.$http.get('rights/list')
            //If the returned status is abnormal, an error is reported and returned
            if (res.meta.status !== 200)
                return this.$message.error('Failed to get permission list')
            //If the return status is normal, save the requested data in data
            this.rightsList = res.data
        }
    }
}
</script>

5. Role list

A. Add role list route

Add the role list sub component (power/Roles.vue) and add the corresponding rules

path: '/home', component: Home, redirect: '/welcome', children: [
        { path: "/welcome", component: Welcome },
        { path: "/users", component: Users },
        { path: "/rights", component: Rights },
        { path: "/roles", component: Roles  }
      ]

B. Add breadcrumbs navigation

In roles Add breadcrumb component to Vue to show navigation path

C. Display data

Add a roleList data in data, provide a getRoleList method in methods to send request to get permission list data, and call this method in created to get data.

<!-- Role list area -->
<!-- row-key="id" It is a new feature provided in March 2019,
if there's nested data, rowKey is required.
If this is a nested data, rowkey Is a property that must be added -->
<el-table row-key="id" :data="roleList" border>
    <!-- Add expanded column -->
    <el-table-column type="expand"></el-table-column>
    <el-table-column type="index"></el-table-column>
    <el-table-column label="Role name" prop="roleName"></el-table-column>
    <el-table-column label="Role description" prop="roleDesc"></el-table-column>
    <el-table-column label="operation" width="300px">
        <template slot-scope="scope"> 
            <el-button size="mini" type="primary" icon="el-icon-edit">edit</el-button>
            <el-button size="mini" type="danger" icon="el-icon-delete">delete</el-button>
            <el-button size="mini" type="warning" icon="el-icon-setting">Assign permissions</el-button>
        </template>
    </el-table-column>
</el-table>

<script>
export default {
    data(){
        return {
            roleList:[]
        }
    },created(){
        this.getRoleList();
    },methods:{
        async getRoleList(){
            const {data:res} = await this.$http.get('roles')
            //If the returned status is abnormal, an error is reported and returned
            // if (res.meta.status !== 200)
            //     return this.$message.error('failed to get role list ')
            // //If the return status is normal, save the requested data in data
            // this.roleList = res.data
            console.log(res.data)
            this.roleList = res.data;
        }
    }
}
</script>

D. Supplementary notes

I have learned similar methods before, such as adding roles, deleting roles and editing roles. Please refer to the previously written code and interface documents to complete the effect.

E. Generate permission list

Generate permission drop-down list using triple nested for loop

<!-- Add expanded column -->
<el-table-column type="expand">
    <template slot-scope="scope">
        <el-row :class="['bdbottom',i1===0?'bdtop':'']" v-for="(item1,i1) in scope.row.children" :key="item1.id">
            <!-- Render first level permissions -->
            <el-col :span="5">
                <el-tag>
                    {{item1.authName}}
                </el-tag>
                <i class="el-icon-caret-right"></i>
            </el-col>
            <!-- Rendering Level 2 and 3 permissions -->
            <el-col :span="19">
                <!-- adopt for Loop nested rendering secondary permissions  -->
                <el-row :class="[i2===0?'':'bdtop' ]" v-for="(item2,i2) in item1.children" :key="item2.id">
                    <el-col :span="6">
                        <el-tag type="success">{{item2.authName}}</el-tag>
                        <i class="el-icon-caret-right"></i>
                    </el-col>
                    <el-col :span="18">
                        <el-tag type="warning" v-for="(item3) in item2.children" :key="item3.id">
                            {{item3.authName}}
                        </el-tag>
                    </el-col>
                </el-row>
            </el-col>
        </el-row>
    </template>
</el-table-column>

F. Beautification style

By setting global The #app style min width: 1366px in CSS solves the problem of three-level permission line breaking , by adding display: flex, align items: Center to the first level permission El row, the problem of vertical centering of the first level permission can be solved. The second level permission is also added similarly, because multiple contents need to be added, this style can be set to one vcenter{display:flex;align-items:center}

G. Add permission delete function

Add the closable attribute to the El tag of each permission. Yes, an "X" icon appears on the right side of the permission Add rightscope.byid to remove.scope (handle the event again) removeRightById(scope.row,item2.id) removeRightById(scope.row,item3.id)

async removeRightById(role,rightId){
    //The pop-up window prompts the user whether to delete it
    const confirmResult = await this.$confirm('Do you want to delete this permission','Delete prompt',{
        confirmButtonText:'confirm deletion',
        cancelButtonText:'cancel',
        type:'warning'
    }).catch(err=>err)
    //If the user clicks confirm, the confirm result is' confirm '
    //If the user clicks cancel, confirmResult will get the error message 'Cancel' of catch
    if(confirmResult != "confirm"){
        return this.$message.info("The deletion has been cancelled")
    }

    //The user clicks OK, which means he really wants to delete it
    //After sending the delete request, the returned data is the latest role permission information
    const {data:res} = await this.$http.delete(`roles/${role.id}/rights/${rightId}`)
    if (res.meta.status !== 200)
        return this.$message.error('Failed to delete role permissions')

    //There is no need to reload all permissions
    //You only need to update the existing role permissions
    role.children = res.data
    // this.getRoleList();

}

H. Complete the permission assignment function

Add an event to the assign permission button first < El button size = "mini" type = "warning" icon = "El icon setting" @ click = "showSetRightDialog" > assign permissions Request permission tree data in the showSetRightDialog function and display the dialog box

async showSetRightDialog() {
    //When you click the assign permission button, the corresponding dialog box will be displayed
    this.setRightDialogVisible = true;
    //Get data for all permissions
    const {data:res} = await this.$http.get('rights/tree')
    //If the returned status is abnormal, an error is reported and returned
    if (res.meta.status !== 200)
        return this.$message.error('Failed to get permission tree')
    //If the return status is normal, save the requested data in data
    this.rightsList = res.data
}

Add the assign permission dialog box and add the binding data setRightDialogVisible

This is a message. Cancel confirmation

1. Complete the pop-up window of tree structure

In element JS, and register the Tree

<!-- Assign permissions dialog box -->
<el-dialog title="Assign permissions" :visible.sync="setRightDialogVisible" width="50%" @close="setRightDialogClose">
    <!-- Tree component
    show-checkbox:Show check boxes
    node-key:Set the value corresponding to the selected node
    default-expand-all:Expand all nodes by default
    :default-checked-keys Sets the array of default selected items
    ref:Set reference -->
    <el-tree :data="rightsList" :props="treeProps" show-checkbox node-key="id" default-expand-all :default-checked-keys="defKeys" ref="treeRef"></el-tree>
    <span slot="footer" class="dialog-footer">
        <el-button @click="setRightDialogVisible = false">Cancel</el-button>
        <el-button type="primary" @click="allotRights">determine</el-button>
    </span>
</el-dialog>

<script>
export default {
  data() {
    return {
      //Role list data
      roleList: [],
      //Controls the display of the assign permissions dialog box
      setRightDialogVisible: false,
      //Permission tree data
      rightsList: [],
      //Property binding object of tree control
      treeProps: {
        //Set the tree node text through label to display authName
        label: 'authName',
        //Set to display the child node information through the children attribute
        children: 'children'
      },
      //Sets the default selection in the tree control
      defKeys: [],
      //Save the role id being operated
      roleId:''
    }
  },
  created() {
    this.getRoleList()
  },
  methods: {
    async getRoleList() {
      const { data: res } = await this.$http.get('roles')
      //If the returned status is abnormal, an error is reported and returned
      if (res.meta.status !== 200)
        return this.$message.error('Failed to get role list')
      //If the return status is normal, save the requested data in data
      // this.roleList = res.data
      console.log(res.data)
      this.roleList = res.data
    },
    async removeRightById(role, rightId) {
      //The pop-up window prompts the user whether to delete it
      const confirmResult = await this.$confirm(
        'Do you want to delete this permission',
        'Delete prompt',
        {
          confirmButtonText: 'confirm deletion',
          cancelButtonText: 'cancel',
          type: 'warning'
        }
      ).catch(err => err)
      //If the user clicks confirm, the confirm result is' confirm '
      //If the user clicks cancel, confirmResult will get the error message 'Cancel' of catch
      if (confirmResult != 'confirm') {
        return this.$message.info('The deletion has been cancelled')
      }

      //The user clicks OK, which means he really wants to delete it
      //After sending the delete request, the returned data is the latest role permission information
      const { data: res } = await this.$http.delete(
        `roles/${role.id}/rights/${rightId}`
      )
      if (res.meta.status !== 200)
        return this.$message.error('Failed to delete role permissions')

      //There is no need to reload all permissions
      //You only need to update the existing role permissions
      role.children = res.data
      // this.getRoleList();
    },
    async showSetRightDialog(role) {
      //Add role The ID is saved for use when saving rights are limited
      this.roleId = role.id;  
      //Get data for all permissions
      const { data: res } = await this.$http.get('rights/tree')
      //If the returned status is abnormal, an error is reported and returned
      if (res.meta.status !== 200) return this.$message.error('Failed to get permission tree')
      //If the return status is normal, save the requested data in data
      this.rightsList = res.data

      //Call getLeafKeys to recurse and add three-level permissions to the array
      this.getLeafKeys(role, this.defKeys)
      //When you click the assign permission button, the corresponding dialog box will be displayed
      this.setRightDialogVisible = true
      console.log(this.defKeys)
    },
    getLeafKeys(node, arr) {
      //This function will obtain all three-level permission IDs of the current role and add them to defKeys
      //If the current node does not contain the children attribute, it indicates that the node is a three-level permission
      if (!node.children) {
        return arr.push(node.id)
      }
      //Recursive call
      node.children.forEach(item => this.getLeafKeys(item, arr))
    },
    setRightDialogClose() {
      //When the user closes the tree permission dialog box, all selected states are cleared
      this.defKeys = []
    },
    async allotRights() {
      //When the user clicks OK in the tree permission dialog box, the user selected
      //Permission to send request for update

      //Get all selected and semi selected contents
      const keys = [
        ...this.$refs.treeRef.getCheckedKeys(),
        ...this.$refs.treeRef.getHalfCheckedKeys()
      ]
      //Convert an array to a concatenated string
      const idStr = keys.join(',')

      //Send request to complete update
      const { data: res } = await this.$http.post(
        `roles/${this.roleId}/rights`,
        { rids:idStr }
      )
      if (res.meta.status !== 200)
        return this.$message.error('Failed to assign permissions')

      this.$message.success("Permission assignment succeeded")
      this.getRoleList();
      //close dialog boxes
      this.setRightDialogVisible = false;
    }
  }
}
</script>

6. Assign roles

Open users Vue, which completes the function of assigning roles A. Add assigned role dialog box

<!-- Assign role dialog box -->
<el-dialog title="Assign roles" :visible.sync="setRoleDialogVisible" width="50%">
    <div>
    <p>Current user:{{userInfo.username}}</p>
    <p>Current role:{{userInfo.role_name}}</p>
    <p>Assign new roles:</p>
    </div>
    <span slot="footer" class="dialog-footer">
    <el-button @click="setRoleDialogVisible = false">Cancel</el-button>
    <el-button type="primary" @click="setRoleDialogVisible = false">determine</el-button>
    </span>
</el-dialog>

B. Add a click event to the assign role button. After clicking, a dialog box pops up for role assignment

<!-- 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' @click="setRole(scope.row)"></el-button>
</el-tooltip>

data(){
    ......
    //Controls the display of the assign role dialog box
    setRoleDialogVisible:false,
    //Save the information of the user who is operating
    userInfo:{},
    //Save all role information
    rolesList:[],
    //Save the role id selected by the user
    selectedRoleId:''
},
methods:{
    ......
    async setRole( userInfo ){
      //Save it for later use
      this.userInfo = userInfo;
      //Get all role information for use in the drop-down list
      //Send a request to complete the deletion operation according to the id
      const { data: res } = await this.$http.get('roles')
      //Judge if the deletion fails, give a prompt
      if (res.meta.status !== 200) return this.$message.error('Failed to get role list')

      this.rolesList = res.data;
      //Show the assign role dialog box
      this.setRoleDialogVisible = true;


    }
}

C. In element JS, and register Select, Option

<!-- Role selection drop-down box
v-model: Set after the user selects the role id Binding data
-->
<el-select v-model="selectedRoleId" placeholder="Please select a role">
<!-- :label Display text,:value Selected value -->
<el-option v-for="item in rolesList" :key="item.id" :label="item.roleName" :value="item.id">
</el-option>
</el-select>

D. When the user clicks OK in the dialog box, the operation of assigning roles is completed

<!-- Assign role dialog box -->
<el-dialog title="Assign roles" :visible.sync="setRoleDialogVisible" width="50%" @close="setRoleDialogClosed">
    <div>
    <p>Current user:{{userInfo.username}}</p>
    <p>Current role:{{userInfo.role_name}}</p>
    <p>Assign new roles:
        <!-- Role selection drop-down box
        v-model: Set the after the user selects the role id Binding data
        -->
        <el-select v-model="selectedRoleId" placeholder="Please select a role">
        <!-- :label Display text,:value Selected value -->
        <el-option v-for="item in rolesList" :key="item.id" :label="item.roleName" :value="item.id">
        </el-option>
        </el-select>
    </p>
    </div>
    <span slot="footer" class="dialog-footer">
    <el-button @click="setRoleDialogVisible = false">Cancel</el-button>
    <el-button type="primary" @click="saveRoleInfo">determine</el-button>
    </span>
</el-dialog>


methods:{
    .......
    async saveRoleInfo(){
      //When the user clicks the OK button
      //Judge whether the user has selected the role to be assigned
      if(!this.selectedRoleId){
        return this.$message.error('Please select the role to be assigned')
      }
      //Send a request to complete the assignment of roles
      const {data:res} = await this.$http.put(`users/${this.userInfo.id}/role`,{rid:this.selectedRoleId})

      //Judge if the deletion fails, give a prompt
      if (res.meta.status !== 200)
        return this.$message.error('Failed to assign role')

      this.$message.success('Role assignment succeeded')
      this.getUserList();
      //close dialog boxes
      this.setRoleDialogVisible = false
    },
    setRoleDialogClosed(){
      //Reset the contents of the drop-down box when the dialog box is closed
      this.selectedRoleId = ''
      this.userInfo = {}
    }
}

7. Push the code to the code cloud

A. Push the code to the temporary storage area git add B. Submit the code to the warehouse git commit -m 'completed the permission function development' C. Push the rights branch code to the code cloud git push D. Merge code into master git checkout master git merge rights E. Push master code to code cloud git push

Today's goal

1. Complete commodity classification

2. Complete parameter management

1. Commodity classification

A. New branch goods_cate

New branch goods_ Cat and push to the code cloud git checkout -b goods_cate git push -u origin goods_cate

B. Create child route

Create sub level routing components of categories and set routing rules

import Cate from './components/goods/Cate.vue'

path: '/home', component: Home, redirect: '/welcome', children: [
    { path: "/welcome", component: Welcome },
    { path: "/users", component: Users },
    { path: "/rights", component: Rights },
    { path: "/roles", component: Roles  },
    { path: "/categories", component: Cate  }
]

C. Add component basic layout

At cate Add breadcrumb navigation in Vue component and add category button in card view

<template>
    <div>
        <h3>Commodity classification</h3>
        <!-- Breadcrumb navigation -->
        <el-breadcrumb separator="/">
            <el-breadcrumb-item :to="{ path: '/home' }">home page</el-breadcrumb-item>
            <el-breadcrumb-item>Commodity management</el-breadcrumb-item>
            <el-breadcrumb-item>Commodity classification</el-breadcrumb-item>
        </el-breadcrumb>
        <!-- Card view area -->
        <el-card>
            <!-- Add category button area -->
            <el-row>
                <el-col>
                    <el-button type="primary">Add classification</el-button>
                </el-col>
            </el-row>
            <!-- Classification table  -->

            <!-- paging -->
        </el-card>
    </div>
</template>

D. Request classification data

Request classification data and save the data in data

<script>
export default {
  data() {
    return {
      // Commodity classification data list
      cateList: [],
      //Conditions for querying classified data
      queryInfo: {
        type: 3,
        pagenum: 1,
        pagesize: 5
      },
      //Total number of data saved
      total: 0
    }
  },
  created() {
    this.getCateList()
  },
  methods: {
    async getCateList() {
      //Get commodity classification data
      const { data: res } = await this.$http.get('categories', {
        params: queryInfo
      })

      if (res.meta.status !== 200) {
        return this.$message.error('Failed to get commodity list data')
      }
      //Assign data list to cateList
      this.cateList = res.data.result
      //Total number of data saved
      this.total = res.data.total
      //   console.log(res.data);
    }
  }
}
</script>

E. Using plug-ins to display data

Use the third-party plug-in Vue table with tree grid to display classified data 1). In the vue console, click dependency - > install dependency - > Run dependency - > Enter vue table with tree gird - > click Install 2). Open main JS, import Vue table with tree grid import TreeTable from 'vue-table-with-tree-grid' ..... Vue.config.productionTip = false

//Global registration component
Vue.component('tree-table', TreeTable)
3).Use components to display classified data
<!-- Classification table
:data(set up data sources) :columns(Set column configuration information in the table) :selection-type(Is there a check box)
:expand-type(Expand data) show-index(Set index column) index-text(Set index column header)
border(Add vertical border) :show-row-hover(Whether mouse over highlighting) -->
<tree-table :data="cateList" :columns="columns" :selection-type="false"
:expand-type="false" show-index index-text="#" border :show-row-hover="false">

</tree-table>

Add to data columns:
columns: [
    {label:'Classification name',prop:'cat_name'}
]

F. Custom data column

Use Vue table with tree grid to define template columns and add custom columns

//First add a column in columns
columns: [
    {label:'Classification name',prop:'cat_name'},
    //type:'template' (set this column as a template column), template:'isok' (set the name of this column template as isok)
    {label:'Is it valid',prop:'',type:'template',template:'isok'},
    {label:'sort',prop:'',type:'template',template:'order'},
    {label:'operation',prop:'',type:'template',template:'opt'}
]

<!-- Set the corresponding template column according to the valid region: slot="isok"(And columns Set in template agreement) -->
<template slot="isok" slot-scope="scope">
  <i class="el-icon-success" v-if="scope.row.cat_deleted === false" style="color:lightgreen"></i>
  <i class="el-icon-error" v-else style="color:red"></i>
</template>
<!-- sort -->
<template slot="order" slot-scope="scope">
  <el-tag size="mini" v-if="scope.row.cat_level===0">class a</el-tag>
  <el-tag size="mini" type="success" v-else-if="scope.row.cat_level===1">second level</el-tag>
  <el-tag size="mini" type="warning" v-else>Tertiary</el-tag>
</template>

<!-- operation -->
<template slot="opt" slot-scope="scope">
  <el-button size="mini" type="primary" icon="el-icon-edit">edit</el-button>
  <el-button size="mini" type="danger" icon="el-icon-delete">delete</el-button> 
</template>

G. Complete paging function

<!-- paging -->
<el-pagination @size-change="handleSizeChange" @current-change="handleCurrentChange" :current-page="queryInfo.pagenum" :page-sizes="[3, 5, 10, 15]" :page-size="queryInfo.pagesize" layout="total, sizes, prev, pager, next, jumper" :total="total">
</el-pagination>

//Add corresponding event function
methods:{
  .......
  handleSizeChange(newSize){
    //Triggered when pagesize changes
    this.queryInfo.pagesize = newSize;
    this.getCateList();
  },
  handleCurrentChange(newPage){
    //Triggered when pagenum changes
    this.queryInfo.pagenum = newPage;
    this.getCateList();
  }
}

H. Finish adding categories

......
<!-- Add category button area -->
<el-row>
  <el-col>
    <el-button type="primary" @click="showAddCateDialog">Add classification</el-button>
  </el-col>
</el-row>
......
<!-- Add classification dialog box -->
<el-dialog title="Add classification" :visible.sync="addCateDialogVisible" width="50%"  @close="addCateDialogClosed">
  <!-- Add classification form -->
  <el-form :model="addCateForm" :rules="addCateFormRules" ref="addCateFormRuleForm" label-width="100px">
    <el-form-item label="Classification name" prop="cat_name">
      <el-input v-model="addCateForm.cat_name"></el-input>
    </el-form-item>
    <el-form-item label="Parent classification" prop="cat_pid">

    </el-form-item>
  </el-form>
  <span slot="footer" class="dialog-footer">
    <el-button @click="addCateDialogVisible = false">Cancel</el-button>
    <el-button type="primary" @click="addCate">determine</el-button>
  </span>
</el-dialog>


//Used to show or hide the add classification dialog box
addCateDialogVisible: false,
//Add classified form data object
addCateForm:{
  //Classification name
  cat_name:'',
  //Add the parent id of the classification, 0 means the parent is 0 Add primary classification
  cat_pid:0,
  //Add a level of classification, 0 means add a level of classification
  cat_level:0
},
//Add classification verification rule
addCateFormRules:{
  //Validation rules
  cat_name:[ {required:true , message:'Please enter the classification name',trigger:'blur'} ]
},
//Save the list of 1 and 2 parent classifications
parentCateList:[]
.......
showAddCateDialog() {
  //Call getParentCateList to get the classification list
  this.getParentCateList()
  //The add classification dialog box is displayed
  this.addCateDialogVisible = true
},
async getParentCateList(){
  //Get parent classification data list
  const { data: res } = await this.$http.get('categories', {
    params: {type:2}
  })

  if (res.meta.status !== 200) {
    return this.$message.error('Failed to get commodity classification list data')
  }
  this.parentCateList = res.data
}

Add cascading menu to display parent classification First import the Cascader component and register Then add the use cascading menu component:

<el-form-item label="Parent classification" prop="cat_pid">
  <!-- expandTrigger='hover'(Mouse over trigger cascade) v-model(Set cascading menu binding data) :options(Specify cascading menu data source)  :props(Rules used to configure data display) 
  clearable(Provide“ X"No. complete the function of deleting text) change-on-select(Can I select any level of menu) -->
  <el-cascader expandTrigger='hover' v-model="selectedKeys" :options="parentCateList" :props="cascaderProps" @change="parentCateChange" clearable change-on-select></el-cascader>
</el-form-item>

Add data
//How to display data in the configuration cascade menu
cascaderProps:{
  value:'cat_id',
  label:'cat_name',
  children:'children',
  expandTrigger:'hover'
},
//Bind the classification value selected by the user
selectedKeys:[]
.....
methods:{
  .....
  parentCateChange(){
    //Triggered when the selection item in the cascade menu changes
    console.log(this.selectedKeys)
    //If the user selects a parent classification
    if(this.selectedKeys.length > 0){
      //Set the last item in the array as the parent classification
      this.addCateForm.cat_pid = this.selectedKeys[this.selectedKeys.length - 1]
      //level should also change with it
      this.addCateForm.cat_level = this.selectedKeys.length
      return
    }else{
      this.addCateForm.cat_pid = 0
      this.addCateForm.cat_level = 0
      return
    }
  },
  addCateDialogClosed(){
    //Reset the form when the add classification dialog box is closed
    this.$refs.addCateFormRef.resetFields()
    this.selectedKeys = [];
    this.addCateForm.cat_pid = 0
    this.addCateForm.cat_level = 0
  },
  addCate() {
    //Click OK to finish adding classification
    console.log(this.addCateForm)
    this.$refs.addCateFormRef.validate(async valid => {
      if (!valid) return
      //Send request to finish adding classification
      const { data: res } = await this.$http.post(
        'categories',
        this.addCateForm
      )

      if (res.meta.status !== 201) {
        return this.$message.error('Failed to add classification')
      }

      this.$message.success('Classification added successfully')
      this.getCateList()
      this.addCateDialogVisible = false
    })
  }
}

1. Push code

After making and adding categories, submit the code to the warehouse and push it to the code cloud to add goods_ Merge the cat branch into the master git add . git commit -m 'complete product classification' git push git checkout master git merge goods_cate

2. Parameter management

Parameters can only be set for three-level classification content. Parameters are divided into dynamic parameters and static parameter attributes

A. Add child component

Add params Vue sub components, and in router JS and set the routing rules

import Params from './components/goods/Params.vue'
......
path: '/home', component: Home, redirect: '/welcome', children: [
  { path: "/welcome", component: Welcome },
  { path: "/users", component: Users },
  { path: "/rights", component: Rights },
  { path: "/roles", component: Roles  },
  { path: "/categories", component: Cate  },
  { path: "/params", component: Params  }
]

B. Complete the basic layout of components

Complete params Basic layout of Vue components The warning message uses El alert, which is displayed in element JS introduces the component and registers it

<template>
    <div>
        <h3>Classification parameters</h3>
        <!-- Breadcrumb navigation -->
        <el-breadcrumb separator="/">
            <el-breadcrumb-item :to="{ path: '/home' }">home page</el-breadcrumb-item>
            <el-breadcrumb-item>Commodity management</el-breadcrumb-item>
            <el-breadcrumb-item>Classification parameters</el-breadcrumb-item>
        </el-breadcrumb>
        <!-- Card view area -->
        <el-card>
            <!-- Warning area :closable="false"(Show or not“ X"number) show-icon(Display icon) -->
            <el-alert title="Note: only relevant parameters can be set for the third level classification" type="warning" :closable="false" show-icon>
            </el-alert>

            <!-- Select commodity classification area -->
            <el-row class="cat_opt">
                <el-col>
                    <span>Select product category:</span>
                    <!-- Select the cascading selection box for the product category -->
                </el-col>
                <el-col></el-col>
            </el-row>
        </el-card>
    </div>
</template>

C. Complete cascade selection box

Complete the cascading selection box of commodity classification

<!-- Select commodity classification area -->
<el-row class="cat_opt">
    <el-col>
        <span>Select product category:</span>
        <!-- Select the cascading selection box for the product category -->
        <el-cascader expandTrigger='hover' v-model="selectedCateKeys" :options="cateList" :props="cateProps" @change="handleChange" clearable></el-cascader>
    </el-col>
    <el-col></el-col>
</el-row>
......
<script>
export default {
  data() {
    return {
        //Classification list
        cateList:[],
        //The category id selected by the user in the cascade drop-down menu
        selectedCateKeys:[],
        //How to display data in the configuration cascade menu
        cateProps: {
            value: 'cat_id',
            label: 'cat_name',
            children: 'children'
        }
    }
  },
  created() {
      this.getCateList()
  },
  methods: {
      async getCateList(){
        //Get a list of all product categories
        const { data: res } = await this.$http.get('categories')

        if (res.meta.status !== 200) {
            return this.$message.error('Failed to get classification data')
        }
        //Assign data list to cateList
        this.cateList = res.data
        // //Total number of data saved
        // this.total = res.data.total
        //   console.log(res.data);
      },
      handleChange(){
        //Triggered when the user selects a content change in the cascade menu
        console.log(this.selectedCateKeys);
      }
  }
}
</script>

D. Display parameters

Display dynamic parameter data and static attribute data

<!-- tab Tab area -->
<el-tabs v-model="activeName" @tab-click="handleTabClick">
  <!-- Add panel of dynamic parameters and change the tab to many -->
  <el-tab-pane label="dynamic parameter " name="many">
    <el-button size="mini" type="primary" :disabled="isButtonDisabled">Add parameter</el-button>
    <!-- Dynamic parameter table -->
    <el-table :data="manyTableData" border stripe>
      <!-- Expand row -->
      <el-table-column type="expand"></el-table-column>
      <!-- Index column -->
      <el-table-column type="index"></el-table-column>
      <el-table-column label="Parameter name" prop="attr_name"></el-table-column>
      <el-table-column label="operation">
        <template slot-scope="scope">
          <el-button size="mini" type="primary" icon="el-icon-edit">edit</el-button>
          <el-button size="mini" type="danger" icon="el-icon-delete">delete</el-button>
        </template>
      </el-table-column>
    </el-table>
  </el-tab-pane>
  <!-- Add a panel with static properties and change the tab to only -->
  <el-tab-pane label="Static properties" name="only">
    <el-button size="mini" type="primary" :disabled="isButtonDisabled">Add attribute</el-button>
    <!-- Static attribute table -->
    <el-table :data="onlyTableData" border stripe>
      <!-- Expand row -->
      <el-table-column type="expand"></el-table-column>
      <!-- Index column -->
      <el-table-column type="index"></el-table-column>
      <el-table-column label="Attribute name" prop="attr_name"></el-table-column>
      <el-table-column label="operation">
        <template slot-scope="scope">
          <el-button size="mini" type="primary" icon="el-icon-edit">edit</el-button>
          <el-button size="mini" type="danger" icon="el-icon-delete">delete</el-button>
        </template>
      </el-table-column>
    </el-table>
  </el-tab-pane>

</el-tabs>


<script>
export default {
  data() {
    return {
      ......
      //Tab activate the displayed tab items
      activeName: 'many',
      //Used to save dynamic parameter data
      manyTableData: [],
      //Used to save static attribute data
      onlyTableData: []  
    }
  methods: {
    .......
    async handleChange() {
      //Triggered when the user selects a content change in the cascade menu
      console.log(this.selectedCateKeys)
      //Send a request and obtain parameter data according to the three-level classification and panel selected by the user
      const { data: res } = await this.$http.get(
        `categories/${this.cateId}/attributes`,
        { params: { sel: this.activeName } }
      )
      if (res.meta.status !== 200) {
        return this.$message.error('Failed to get parameter list data')
      }

      console.log(res.data)
      if (this.activeName === 'many') {
        //Dynamic parameters are obtained
        this.manyTableData = res.data
      } else if (this.activeName === 'only') {
        //Get static properties
        this.onlyTableData = res.data
      }
    },
    handleTabClick() {
      console.log(this.activeName)
      this.handleChange()
    }
  },
  computed: {
    //Add a calculation attribute to get whether the button is disabled or not
    isButtonDisabled() {
      return this.selectedCateKeys.length !== 3
    },
    //Get the selected three-level classification id
    cateId() {
      if (this.selectedCateKeys.length === 3) {
        return this.selectedCateKeys[this.selectedCateKeys.length - 1]
      }
      return null
    }
  }

E. Add parameter

Finish adding parameters or attributes

<!-- Add parameter or property dialog box -->
<el-dialog :title="'add to'+titleText" :visible.sync="addDialogVisible" width="50%" @close="addDialogClosed">
  <!-- Add form -->
  <el-form :model="addForm" :rules="addFormRules" ref="addFormRef" label-width="100px">
    <el-form-item :label="titleText" prop="attr_name">
      <el-input v-model="addForm.attr_name"></el-input>
    </el-form-item>
  </el-form>
  <span slot="footer" class="dialog-footer">
    <el-button @click="addDialogVisible = false">Cancel</el-button>
    <el-button type="primary" @click="addParams">determine</el-button>
  </span>
</el-dialog>

export default {
  data() {
    return {
      .......
      //Controls the addition of parameters Display or hide of the properties dialog box
      addDialogVisible: false,
      //Form data object for adding parameters
      addForm: {
        attr_name: ''
      },
      //Add form validation rule
      addFormRules: {
        attr_name: [{ required: true, message: 'Please enter a name', trigger: 'blur' }]
      }
    }
  },methods: {
    .......
    addParams() {
      //When the user clicks OK in the dialog box, the form will be verified
      this.$refs.addFormRef.validate(async valid => {
        //Failed verification, return
        if (!valid) return
        //If the verification is passed, send the request to complete the addition of parameters or attributes
        const { data: res } = this.$http.post(`categories/${this.cateId}/attributes`,
          { 
            attr_name: this.addForm.attr_name, 
            attr_sel: this.activeName,
            attr_vals: "a,b,c" 
          }
        )

        console.log(res)
        if (res.meta.status !== 201) {
          return this.$message.error('add to' + this.titleText + 'Data failure')
        }
        this.$message.success('add to' + this.titleText + 'Data success')
        this.addDialogVisible = false
        this.getCateList()
      })
    }
  }

F. Edit parameters

Finish editing parameters or attributes

<!-- Modify parameters or properties dialog box -->
<el-dialog :title="'modify'+titleText" :visible.sync="editDialogVisible" width="50%" @close="editDialogClosed">
  <!-- Add form -->
  <el-form :model="editForm" :rules="editFormRules" ref="editFormRef" label-width="100px">
    <el-form-item :label="titleText" prop="attr_name">
      <el-input v-model="editForm.attr_name"></el-input>
    </el-form-item>
  </el-form>
  <span slot="footer" class="dialog-footer">
    <el-button @click="editDialogVisible = false">Cancel</el-button>
    <el-button type="primary" @click="editParams">determine</el-button>
  </span>
</el-dialog>

export default {
  data() {
    return {
      .......
      //Control and modify parameters Show or hide the properties dialog box
      editDialogVisible:false,
      //Modify parameters Form in properties dialog box
      editForm:{
        attr_name:''
      },
      //Modify the validation rules of the form
      editFormRules:{
        attr_name:[
          { required: true, message: 'Please enter a name', trigger: 'blur' }
        ]
      }
    }
  },methods: {
    .......
    async showEditDialog(attr_id){
      //Initiate a request to obtain the parameter data to be modified
      const {data:res} = await this.$http.get(`categories/${this.cateId}/attributes/${attr_id}`,
      {params:{ attr_sel:this.activeName }})
      if (res.meta.status !== 200) {
        return this.$message.error('Failed to get parameter data')
      }
      this.editForm = res.data;
      //Display modified parameters properties dialog 
      this.editDialogVisible = true;
    },
    editDialogClosed(){
      //Modify parameters when closing Properties dialog box
      this.$refs.editFormRef.resetFields()
    },
    editParams(){
      //validate form 
      this.$refs.editFormRef.validate(async valid => {
        if(!valid) return;

        //Send request to complete modification
        const {data:res} = await this.$http.put(`categories/${this.cateId}/attributes/${this.editForm.attr_id}`,
        {attr_name:this.editForm.attr_name,attr_sel:this.activeName})

        if (res.meta.status !== 200) {
          return this.$message.error('Failed to get parameter data')
        }
        this.$message.success('modify' + this.titleText + 'Data success')
        this.editDialogVisible = false
        this.handleChange();
      })
    }
  }

G. Delete parameter

Delete parameter or attribute

Add events to the two delete buttons
<el-button size="mini" type="danger" icon="el-icon-delete" @click="removeParams(scope.row.attr_id)">delete</el-button>
<el-button size="mini" type="danger" icon="el-icon-delete" @click="removeParams(scope.row.attr_id)">delete</el-button>

Add the corresponding event handler function
async removeParams(attr_id){
  //Delete the corresponding parameter or attribute according to the id
  //The pop-up window prompts the user whether to delete it
  const confirmResult = await this.$confirm(
    'Would you like to delete this'+this.titleText,
    'Delete prompt',
    {
      confirmButtonText: 'confirm deletion',
      cancelButtonText: 'cancel',
      type: 'warning'
    }
  ).catch(err => err)
  //If the user clicks confirm, the confirm result is' confirm '
  //If the user clicks cancel, confirmResult will get the error message 'Cancel' of catch
  if (confirmResult != 'confirm') {
    return this.$message.info('The deletion has been cancelled')
  }

  //If you don't cancel, you just want to delete. Send a request to complete the deletion
  const {data:res} = await this.$http.delete(`categories/${this.cateId}/attributes/${attr_id}`)

  if (res.meta.status !== 200) {
    return this.$message.error('Failed to delete parameter data')
  }
  this.$message.success('delete' + this.titleText + 'Data success')
  this.handleChange()
}

Added by skope on Thu, 24 Feb 2022 11:43:37 +0200