E-commerce project 02

###1. The basic layout of the background homepage
Open the Home.vue component and perform the layout:

<el-container class="home-container">
  <!-- 头部区域 -->
  <el-header>Header<el-button type="info" @click="logout"> 退出 </el-button></el-header>
  <!-- 页面主体区域 -->
  <el-container>
    <!-- 侧边栏 -->
    <el-aside width="200px">Aside</el-aside>
    <!-- 主体结构 -->
    <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 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

<template>
    <el-container class="home-container">
      <!-- 头部区域 -->
      <el-header>
        <div>
          <!-- 黑马logo -->
          <img src="../assets/heima.png" alt="">
          <!-- 顶部标题 -->
          <span>电商后台管理系统</span>
        </div>
        <el-button type="info" @click="logout"> 退出 </el-button>
      </el-header>
      <!-- 页面主体区域 -->
      <el-container>
        <!-- 侧边栏 -->
        <el-aside width="200px">
          <!-- 侧边栏菜单 -->
          <el-menu
            background-color="#333744"
            text-color="#fff"
            active-text-color="#ffd04b">
            <!-- 一级菜单 -->
            <el-submenu index="1">
              <!-- 一级菜单模板 -->
              <template slot="title">
                <!-- 图标 -->
                <i class="el-icon-location"></i>
                <!-- 文本 -->
                <span>导航一</span>
              </template>
              <!-- 二级子菜单 -->
              <el-menu-item index="1-4-1">
                <!-- 二级菜单模板 -->
                <template slot="title">
                  <!-- 图标 -->
                  <i class="el-icon-location"></i>
                  <!-- 文本 -->
                  <span>子菜单一</span>
                </template>
              </el-menu-item>
            </el-submenu>
            
          </el-menu>
        </el-aside>
        <!-- 主体结构 -->
        <el-main>Main</el-main>
      </el-container>
    </el-container>
</template>

###3.axios request interceptor
In addition to the login interface, the background requires token permission verification. We can add token by adding the axios request interceptor to ensure that we have the permission to obtain data
. Add the code in main.js, in Add the following code before mounting axios to the vue prototype

//请求在到达服务器之前,先会调用use中的这个回调函数来添加请求头信息
axios.interceptors.request.use(config=>{
  //为请求头对象,添加token验证的Authorization字段
  config.headers.Authorization = window.sessionStorage.getItem("token")
  return config
})

###4. Request sidebar data

<script>
export default {
  data() {
    return {
      // 左侧菜单数据
      menuList: null
    }
  },
  created() {
    // 在created阶段请求左侧菜单数据
    this.getMenuList()
  },
  methods: {
    logout() {
      window.sessionStorage.clear()
      this.$router.push('/login')
    },
    async getMenuList() {
      // 发送请求获取左侧菜单数据
      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 the left menu through the v-for double loop

<el-menu
  background-color="#333744"
  text-color="#fff"
  active-text-color="#ffd04b">
  <!-- 一级菜单 -->
  <el-submenu :index="item.id+''" v-for="item in menuList" :key="item.id">
    <!-- 一级菜单模板 -->
    <template slot="title">
      <!-- 图标 -->
      <i class="el-icon-location"></i>
      <!-- 文本 -->
      <span>{
   
   {item.authName}}</span>
    </template>
    <!-- 二级子菜单 -->
    <el-menu-item :index="subItem.id+''" v-for="subItem in item.children" :key="subItem.id">
      <!-- 二级菜单模板 -->
      <template slot="title">
        <!-- 图标 -->
        <i class="el-icon-location"></i>
        <!-- 文本 -->
        <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 activated item clicked in the sidebar menu.
By changing the class of the i tag in the menu item template (template) Name, you can set the icons in the left menu bar, we need to use third-party font icons
in the project Add an iconsObj to the data:

iconsObj: {
        '125':'iconfont icon-user',
        '103':'iconfont icon-tijikongjian',
        '101':'iconfont icon-shangpin',
        '102':'iconfont icon-danju',
        '145':'iconfont icon-baobiao'
      }

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

In order to keep the left menu only open one at a time and display the sub-menus in it, we can add an attribute unique-opened to el-menu
or set it by data binding (at this time, true is considered to be a bool value, and Not a string) :unique-opened="true"

###6. Make the side menu bar flexible function
Add a div above the menu bar

        <!-- 侧边栏,宽度根据是否折叠进行设置 -->
        <el-aside :width="isCollapse ? '64px':'200px'">
          <!-- 伸缩侧边栏按钮 -->
          <div class="toggle-button" @click="toggleCollapse">|||</div>
          <!-- 侧边栏菜单,:collapse="isCollapse"(设置折叠菜单为绑定的 isCollapse 值),:collapse-transition="false"(关闭默认的折叠动画) -->
          <el-menu
          :collapse="isCollapse"
          :collapse-transition="false"
          ......

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

###7. Add child routing on the background homepage Add
new child routing component Welcome.vue
Import the child routing component in router.js, and set the routing rules and the default redirection of the child routing.
Open Home.vue, in Add a routing placeholder to the main structure of main

After making the Welcome child routing, we need to transform all the sidebar secondary menus into child routing links.
We only need to set the router attribute of el-menu to true. At this time, when we click on the secondary When the menu is in the menu, it will
route and jump according to the index attribute of the menu , such as: /110, it is
not appropriate to use index id as the jump path, we can rebind the index value to: index="'/'+ subItem.path"

###8. Complete the main area of ​​the
user list Create a new user list component user/
Users.vue, import the child routing component Users.vue in router.js, and set routing rules

When the secondary menu is clicked, the secondary submenu that is clicked is not highlighted, we need to highlight the function being used.
We can set the index of the currently active menu by setting the default-active attribute of el-menu
but The default-active attribute can't be hard-coded , it is fixed to a certain menu value,
so we can add click events to all secondary menus first, and use the path value as the method parameter
@click=”saveNavState('/'+subItem.path )"
in the saveNavState method to save the path to sessionStorage
saveNavState( path ){ //Save the clicked second-level menu information when clicking the second-level menu window.sessionStorage.setItem("activePath",path); this.activePath = path; } Then add an activePath binding data to the data, and set the default-active attribute of el-menu to activePath. Finally, in created, assign the data in sessionStorage to activePath this.activePath = window.sessionStorage.getItem(" activePath")






###9. Draw the basic structure of the user list
A. Use the element-ui breadcrumb component to complete the top navigation path (copy the breadcrumb code, import the components Breadcrumb, BreadcrumbItem in element.js)
B. Use the element-ui card component to complete the main body Form (copy the card component code, 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, in element Import components Row, Col) in .js, and then use el-button to make buttons for adding users

<div>
    <h3>用户列表组件</h3>
    <!-- 面包屑导航 -->
    <el-breadcrumb separator="/">
        <el-breadcrumb-item :to="{ path: '/home' }">首页</el-breadcrumb-item>
        <el-breadcrumb-item>用户管理</el-breadcrumb-item>
        <el-breadcrumb-item>用户列表</el-breadcrumb-item>
    </el-breadcrumb>
    <!-- 卡片视图区域 -->
    <el-card>
        <!-- 搜索与添加区域 -->
        <el-row :gutter="20">
            <el-col :span="7">
                <el-input placeholder="请输入内容">
                    <el-button slot="append" icon="el-icon-search"></el-button>
                </el-input> 
            </el-col>
            <el-col :span="4">
                <el-button type="primary">添加用户</el-button>
            </el-col>
        </el-row> 
    </el-card>
</div>

###10. Request user list data

<script>
export default {
  data() {
    return {
      //获取查询用户信息的参数
      queryInfo: {
        query: '',
        pagenum: 1,
        pagesize: 2
      },
      //保存请求回来的用户列表数据
      userList:[],
      total:0
    }
  },
  created() {
    this.getUserList()
  },
  methods: {
    async getUserList() {
      //发送请求获取用户列表数据
      const { res: data } = await this.$http.get('users', {
        params: this.queryInfo
      })
      //如果返回状态为异常状态则报错并返回
      if (res.meta.status !== 200)
        return this.$message.error('获取用户列表失败')
      //如果返回状态正常,将请求的数据保存在data中
      this.userList = res.data.users;
      this.total = res.data.total;
    }
  }
}
</script>

###11. Display user list data
Use a table to display user list data, and use element-ui table component to complete the list display data (copy the table code, import the components Table, TableColumn in element.js)
When rendering the display state, Will use the scope slot to get the data of each row and
then use the switch switch component to display the status information (copy the switch component code, import the component Switch in element.js),
and when the operation column is rendered, the scope slot is also used for rendering ,
In the operation bar contains the modify, delete, and assign role buttons. When we put the mouse on 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, in the element Import the component Tooltip in .js), and include the assigned role button. The
code structure is as follows:

<!-- 用户列表(表格)区域 -->
<el-table :data="userList" border stripe>
    <el-table-column type="index"></el-table-column>
    <el-table-column label="姓名" prop="username"></el-table-column>
    <el-table-column label="邮箱" prop="email"></el-table-column>
    <el-table-column label="电话" prop="mobile"></el-table-column>
    <el-table-column label="角色" prop="role_name"></el-table-column>
    <el-table-column label="状态">
        <template slot-scope="scope">
            <el-switch v-model="scope.row.mg_state"></el-switch>
        </template>
    </el-table-column>
    <el-table-column label="操作" width="180px">
        <template slot-scope="scope">
            <!-- 修改 -->
            <el-button type="primary" icon="el-icon-edit" size='mini'></el-button>
            <!-- 删除 -->
            <el-button type="danger" icon="el-icon-delete" size='mini'></el-button>
            <!-- 分配角色 -->
            <el-tooltip class="item" effect="dark" content="分配角色" 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. Implement user list paging
A. Use a table to display user list data, you can use the paging component to complete the list paging display data (copy the paging component code, import the component Pagination in element.js)
B. Change the binding in the component Set data

<!-- 分页导航区域 
@size-change(pagesize改变时触发) 
@current-change(页码发生改变时触发)
:current-page(设置当前页码)
:page-size(设置每页的数据条数)
:total(设置总页数) -->
            <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 two event handlers @size-change, @current-change

handleSizeChange(newSize) {
  //pagesize改变时触发,当pagesize发生改变的时候,我们应该
  //以最新的pagesize来请求数据并展示数据
  //   console.log(newSize)
  this.queryInfo.pagesize = newSize;
  //重新按照pagesize发送请求,请求最新的数据
  this.getUserList();  
},
handleCurrentChange( current ) {
  //页码发生改变时触发当current发生改变的时候,我们应该
  //以最新的current页码来请求数据并展示数据
  //   console.log(current)
  this.queryInfo.pagenum = current;
  //重新按照pagenum发送请求,请求最新的数据
  this.getUserList();  
}

###13. Realize to update the user status
When the user clicks the switch component in the list, the user's status should change accordingly.
A. First, listen to the event that the user clicks on the switch component, and pass the data of the scope slot as the event parameter

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

B. Send request completion status changes in the event

async userStateChanged(row) {
  //发送请求进行状态修改
  const { data: res } = await this.$http.put(
    `users/${row.id}/state/${row.mg_state}`
  )
  //如果返回状态为异常状态则报错并返回
  if (res.meta.status !== 200) {
    row.mg_state = !row.mg_state
    return this.$message.error('修改状态失败')
  }
  this.$message.success('更新状态成功')
},

###14. Realize the search function
Add data binding, add the click event of the search button (when the user clicks the search button, call the getUserList method to request the user list data again according to the content of the text box)
When we enter the content in the input box and After clicking search, it will be searched according to the search keyword. We hope 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 add the clear event, and then request the data again in the clear event. Can

<el-col :span="7">
    <el-input placeholder="请输入内容" v-model="queryInfo.query" clearable @clear="getUserList">
        <el-button slot="append" icon="el-icon-search" @click="getUserList"></el-button>
    </el-input>
</el-col>

###15. Implement adding users
A. When we click the Add User button, a dialog box pops up to realize the function of adding users. First, we need to copy the code of the dialog component and introduce the Dialog component in the element.js file

B. Next, we need to add a click event for the "Add User" button, in the event addDialogVisible is set to true, that is, the dialog box is displayed

C. Change the content in the Dialog component

<!-- 对话框组件  :visible.sync(设置是否显示对话框) width(设置对话框的宽度)
:before-close(在对话框关闭前触发的事件) -->
<el-dialog title="添加用户" :visible.sync="addDialogVisible" width="50%">
    <!-- 对话框主体区域 -->
    <el-form :model="addForm" :rules="addFormRules" ref="addFormRef" label-width="70px">
        <el-form-item label="用户名" prop="username">
            <el-input v-model="addForm.username"></el-input>
        </el-form-item>
        <el-form-item label="密码" prop="password">
            <el-input v-model="addForm.password"></el-input>
        </el-form-item>
        <el-form-item label="邮箱" prop="email">
            <el-input v-model="addForm.email"></el-input>
        </el-form-item>
        <el-form-item label="电话" prop="mobile">
            <el-input v-model="addForm.mobile"></el-input>
        </el-form-item>
    </el-form>
    <!-- 对话框底部区域 -->
    <span slot="footer" class="dialog-footer">
        <el-button @click="addDialogVisible = false">取 消</el-button>
        <el-button type="primary" @click="addDialogVisible = false">确 定</el-button>
    </span>
</el-dialog>

D. Add data binding and verification rules:

data() {
  //验证邮箱的规则
  var checkEmail = (rule, value, cb) => {
    const regEmail = /^\w+@\w+(\.\w+)+$/
    if (regEmail.test(value)) {
      return cb()
    }
    //返回一个错误提示
    cb(new Error('请输入合法的邮箱'))
  }
  //验证手机号码的规则
  var checkMobile = (rule, value, cb) => {
    const regMobile = /^1[34578]\d{9}$/
    if (regMobile.test(value)) {
      return cb()
    }
    //返回一个错误提示
    cb(new Error('请输入合法的手机号码'))
  }
  return {
    //获取查询用户信息的参数
    queryInfo: {
      // 查询的条件
      query: '',
      // 当前的页数,即页码
      pagenum: 1,
      // 每页显示的数据条数
      pagesize: 2
    },
    //保存请求回来的用户列表数据
    userList: [],
    total: 0,
    //是否显示添加用户弹出窗
    addDialogVisible: false,
    // 添加用户的表单数据
    addForm: {
      username: '',
      password: '',
      email: '',
      mobile: ''
    },
    // 添加表单的验证规则对象
    addFormRules: {
      username: [
        { required: true, message: '请输入用户名称', trigger: 'blur' },
        {
          min: 3,
          max: 10,
          message: '用户名在3~10个字符之间',
          trigger: 'blur'
        }
      ],
      password: [
        { required: true, message: '请输入密码', trigger: 'blur' },
        {
          min: 6,
          max: 15,
          message: '用户名在6~15个字符之间',
          trigger: 'blur'
        }
      ],
      email: [
          { required: true, message: '请输入邮箱', trigger: 'blur' },
          { validator:checkEmail, message: '邮箱格式不正确,请重新输入', trigger: 'blur'}
      ],
      mobile: [
          { required: true, message: '请输入手机号码', trigger: 'blur' },
          { validator:checkMobile, message: '手机号码不正确,请重新输入', trigger: 'blur'}
      ]
    }
  }
}

E. When the dialog box is closed, reset the form.
Add @close event to el-dialog and add the code to reset the form in the event

methods:{
  ....
  addDialogClosed(){
      //对话框关闭之后,重置表达
      this.$refs.addFormRef.resetFields();
  }
}

F. Click the OK button 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(){
      //点击确定按钮,添加新用户
      //调用validate进行表单验证
      this.$refs.addFormRef.validate( async valid => {
          if(!valid) return this.$message.error("请填写完整用户信息");
          //发送请求完成添加用户的操作
          const {data:res} = await this.$http.post("users",this.addForm)
          //判断如果添加失败,就做提示
          if (res.meta.status !== 200)
              return this.$message.error('添加用户失败')
          //添加成功的提示
          this.$message.success("添加用户成功")
          //关闭对话框
          this.addDialogVisible = false
          //重新请求最新的数据
          this.getUserList()
      })
  }
}

Guess you like

Origin blog.csdn.net/weixin_48116269/article/details/109126319