Vue+JS+Element UI实战(电商项目2)

目录

1.权限管理开发

1.创建新分支

2.开发权限列表对应规格

3.权限列表的基本页面布局

 4.请求权限列表的数据

 5.权限列表数据渲染为表格

6.用户角色权限三者关系

1.权限管理业务分析

7.角色列表路由切换

8.角色列表基础布局+获取相关数据

9.渲染角色列表中的table数据

10.展开行的操作

1.渲染一级权限

2.渲染二级三级权限

3.一级权限居中问题

4.小箭头换行问题

11.tag标签添加弹出框

12.发起删除的请求

在删除后,就合上了

13.分配权限对话框,获取权限数据

14.把权限以树形结构加载到对话框

优化树形控件

15.将角色身上已有权限加入分配权限中

16.已有权限的默认勾选功能

问题:关闭后清空元素项

17.角色授权:勾选状态保存到数据库

18.完善用户列表的分配角色

19.角色列表渲染为下拉菜单

20.分配角色功能

21.提交权限管理代码

2.分类管理开发

1.创建分类管理子分支

2.商品分类路由组件的加载

3.绘制商品分类页面的基本结构

4.获取商品分类数据列表

5.商品分类数据渲染成树形table表格

1.按需渲染√和×图标,使用模板列

2.渲染排序和操作两列

6.渲染分页页码条

7.添加分类的操作

8.点击添加分类后,加载父级分类

 9.渲染父级分类的级联选择器

props

10.添加分类的表单数据​​​​​​​

11.监听添加分类对话框的关闭事件

12.具体的添加操作

13.商品分类提交到git仓库


1.权限管理开发

1.创建新分支

git branch检查当前所处分支,从master分支上创建新分支git checkout -b rights,

查看结果git branch,推送到云端进行保存git push -u origin rights。

2.开发权限列表对应规格

通过路由形式加载权限列表组件页面。

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 }
    ]

3.权限列表的基本页面布局

粘贴Users.vue的面包屑导航。

  <!-- 面包屑导航区域 -->
    <el-breadcrumb separator-class="el-icon-arrow-right">
      <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-card>

 4.请求权限列表的数据

  • 请求路径:rights/:type

  • 请求方法:get

  • 请求参数

参数名参数说明备注
type类型值 list 或 tree , list 列表显示权限, tree 树状显示权限,参数是url参数:type
  • 响应参数

参数名参数说明备注
id权限 ID
authName权限说明
level权限层级
pid权限父 ID
path对应访问路径
  • 响应数据

  type=list
{"data": [
        {
            "id": 101,
            "authName": "商品管理",
            "level": "0",
            "pid": 0,
            "path": null
        },
        {
            "id": 102,
            "authName": "订单管理",
            "level": "0",
            "pid": 0,
            "path": null
        }
    ],
    "meta": {
        "msg": "获取权限列表成功",
        "status": 200
    }}

type=tree
  { data: [
      {
        id: 101,
        authName: '商品管理',
        path: null,
        pid: 0,
        children: [
          {
            id: 104,
            authName: '商品列表',
            path: null,
            pid: 101,
            children: [
              {
                id: 105,
                authName: '添加商品',
                path: null,
                pid: '104,101'
              }
            ]
          }
        ]
      }
    ],
    meta: {
      msg: '获取权限列表成功',
      status: 200
    }}
  data () {
    return {
      // 权限列表
      rightsList: []
    }
  },
  created () {
    // 获取所有的权限
    this.getRightsList()
  },
  methods: {
    // 获取权限列表
    async getRightsList () {
      const { data: res } = await this.$http.get('rights/list')
      if (res.meta.status !== 200) {
        return this.$message.error('获取权限列表失败!')
      }
      this.rightsList = res.data
      console.log(this.rightsList)
    }
  }

 5.权限列表数据渲染为表格

import { Tag } from 'element-ui'

Vue.use(Tag)
 <!-- 卡片视图 -->
    <el-card>
      <el-table :data="rightsList" border stripe>
        <el-table-column type="index" label="#"></el-table-column>
        <el-table-column label="权限名称" prop="authName"></el-table-column>
        <el-table-column label="路径" prop="path"></el-table-column
        ><el-table-column label="权限等级" prop="level">
          <template slot-scope="scope">
            <el-tag v-if="scope.row.level === '0'">一级</el-tag>
            <el-tag type="success" v-else-if="scope.row.level === '1'"
              >二级</el-tag
            >
            <el-tag type="warning" v-else>三级</el-tag>
          </template>
        </el-table-column>
      </el-table>
    </el-card>

Element

6.用户角色权限三者关系

1.权限管理业务分析

通过权限管理模块控制不同的用户可以进行哪些操作,具体可以通过角色的方式进行控制,即每个用户分配 一个特定的角色,角色包括不同的功能权限只要用户拥有了某个角色,这个角色下的所有权限都属于这个用户

 

7.角色列表路由切换

import Roles from '@/components/power/Roles.vue'

{ path: '/roles', component: Roles }

8.角色列表基础布局+获取相关数据

角色列表接口

  • 请求路径:roles

  • 请求方法:get

  • 响应数据说明

    • 第一层为角色信息

    • 第二层开始为权限说明,权限一共有 3 层权限

    • 最后一层权限,不包含 children 属性

  • 响应数据

{
"data": [{
            "id": 30,
            "roleName": "主管",
            "roleDesc": "技术负责人",
            "children": [
                {
                    "id": 101,
                    "authName": "商品管理",
                    "path": null,
                    "children": [
                        {
                            "id": 104,
                            "authName": "商品列表",
                            "path": null,
                            "children": [
                                {
                                    "id": 105,
                                    "authName": "添加商品",
                                    "path": null
                                }]}]}]}],
"meta": {
        "msg": "获取成功",
        "status": 200
    }}
 <!-- 面包屑导航区域 -->
    <el-breadcrumb separator-class="el-icon-arrow-right">
      <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>
        <el-col>
          <el-button type="primary">添加角色</el-button>
        </el-col>
      </el-row>
      <!-- 角色列表区域 -->
    </el-card>

 data () {
    return {
      // 所有角色列表数据
      rolelist: []
    }
  },
  created () {
    this.getRolesList()
  },
  methods: {
    // 获取所有角色的列表
    async getRolesList () {
      const { data: res } = await this.$http.get('roles')
      if (res.meta.status !== 200) {
        return this.$message.error('获取角色列表失败!')
      }
      this.rolelist = res.data
      console.log(this.rolelist)// 可以打印出来获取的数据
    }
  }

9.渲染角色列表中的table数据

<!-- 角色列表区域 -->
<el-table :data="rolelist" border stripe>
  <!-- 展开列 -->
  <el-table-column type="expand"></el-table-column>
  <!-- 索引列 -->
  <el-table-column type="index"></el-table-column>
  <el-table-column label="角色名称" prop="roleName"></el-table-column>
  <el-table-column label="角色描述" prop="roleDesc"></el-table-column>
  <el-table-column label="操作" width="300px">
    <template>
      <el-button size="mini" type="primary" icon="el-icon-edit">编辑</el-button>
      <el-button size="mini" type="danger" icon="el-icon-delete">删除</el-button>
      <el-button size="mini" type="warning" icon="el-icon-setting">分配权限</el-button>
    </template>
  </el-table-column>
</el-table>

10.展开行的操作

1.渲染一级权限

<!-- 展开列 -->
<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"
    >
     <!-- 渲染一级权限 -->
     <el-col :span="5">
       <el-tag>{{ item1.authName }}</el-tag>
       <i class="el-icon-caret-right"></i>
     </el-col>
     <!-- 渲染二级和三级权限 -->
     <el-col :span="19"></el-col>
   </el-row>
   <pre>{{ scope.row }}</pre>
  </template>
</el-table-column>

.el-tag {
  margin: 7px;
}
.bdtop {
  border-top: 1px solid #eee;
}
.bdbottom {
  border-bottom: 1px solid #eee;
}

2.渲染二级三级权限

通过for循环嵌套在一级权限中,再次用for循环把二级权限渲染出来。 

 <!-- 渲染二级和三级权限 -->
              <el-col :span="19">
                <!-- 通过for循环嵌套渲染二级权限 -->
                <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
                    >
                    <i class="el-icon-caret-right"></i>
                  </el-col>
                </el-row>
              </el-col>

3.一级权限居中问题

选中对应的哪一行加flex布局。

<el-row :class="['bdbottom', i1 === 0 ? 'bdtop' : '','vcenter']" >  
<el-row :class="[i2 === 0 ? '' : 'bdtop','vcenter']">
.vcenter{
  display: flex;
  align-items: center;
}

4.小箭头换行问题

给整个页面最小宽度。

global.css 

html,
body,
#app {
  height: 100%;
  margin: 0;
  padding: 0;
  min-width: 1366px;
}

11.tag标签添加弹出框

设置closable属性可以定义一个标签是否可移除。

close:关闭 Tag 时触发的事件。

<el-tag
   type="warning"
   v-for="item3 in item2.children"
   :key="item3.id"
   closable
   @close="removeRightById()"
   >{{ item3.authName }}</el-tag >

 // 根据id删除对应的权限
    async removeRightById () {
      // 弹框提示用户是否要删除
      const confirmResult = await this.$confirm('此操作将永久删除该文件, 是否继续?', '提示', {
        confirmButtonText: '确定',
        cancelButtonText: '取消',
        type: 'warning'
      }).catch(err => err)
      if (confirmResult !== 'confirm') {
        return this.$message.info('取消了删除!')
      }
      console.log('确认了删除!')
    }
  }

Element

https://element.eleme.cn/2.5/#/que-ren-xiao-xi

12.发起删除的请求

  • 请求路径:roles/:roleId/rights/:rightId

  • 请求方法:delete

  • 请求参数

    参数名参数说明备注
    :roleId角色 ID不能为空携带在url中
    :rightId权限 ID不能为空携带在url中
  • 响应数据说明

    • 返回的data, 是当前角色下最新的权限数据

  • 响应数据

    {
        "data": [{
                "id": 101,
                "authName": "商品管理",
                "path": null,
                "children": [{
                        "id": 104,
                        "authName": "商品列表",
                        "path": null,
                        "children": [ {
                                "id": 105,
                                "authName": "添加商品",
                                "path": null
                            }, {
                                "id": 116,
                                "authName": "修改",
                                "path": null
                            }]}]}],
        "meta": {
            "msg": "取消权限成功",
            "status": 200
        }}
<!-- scope.row包含角色id,item3.id权限id -->
<el-tag
  type="warning"
  v-for="item3 in item2.children"
  :key="item3.id"
  closable
  @close="removeRightById(scope.row,item3.id)"
 >{{ item3.authName }}</el-tag>

 // 根据id删除对应的权限
    async removeRightById (role, rightId) {
      // 弹框提示用户是否要删除
      const confirmResult = await this.$confirm('此操作将永久删除该文件, 是否继续?', '提示', {
        confirmButtonText: '确定',
        cancelButtonText: '取消',
        type: 'warning'
      }).catch(err => err)
      if (confirmResult !== 'confirm') {
        return this.$message.info('取消了删除!')
      }
      // console.log('确认了删除!')
      const { data: res } = await this.$http.delete(`roles/${role.id}/rights/${rightId}`)
      if (res.meta.status !== 200) {
        return this.$message.error('删除权限失败!')
      }
      // 删除成功,可以重新刷新一下列表
      //this.getRolesList()     
     role.children = res.data
    }

在删除后,就合上了

为什么:删除完毕后,会重新获取整个数据列表,页面的table列表会被重新渲染一次,所以打开状态会立即合上。

把服务器返回值中的data重新为角色赋值,提升用户体验;不建议直接调用getRolesList函数,会整个重新渲染一次。

13.分配权限对话框,获取权限数据

<el-button size="mini" type="warning" icon="el-icon-setting"
           @click="showSetRightDialog">分配权限</el-button>

<!-- 分配权限的对话框 -->
<el-dialog title="分配权限"
      :visible.sync="setRightDialogVisble" width="50%">
   <span>这是一段信息</span>
   <span slot="footer" class="dialog-footer">
    <el-button @click="setRightDialogVisble = false">取 消</el-button>
    <el-button type="primary" @click="setRightDialogVisble = false">确 定</el-button>
   </span>
</el-dialog>

// 控制分配权限对话框的显示与隐藏
setRightDialogVisble: false,
// 所有权限的数据
rightslist: [] 

// 展示分配权限的对话框
async showSetRightDialog () {
  // 获取所有权限的数据
  const { data: res } = await this.$http.get('rights/tree')
  if (res.meta.status !== 200) {
      return this.$message.error('获取权限数据失败!')
  }
  // 把获取到的权限数据保存到data中
   this.rightslist = res.data
   console.log(this.rightslist)

   this.setRightDialogVisble = true
}

https://element.eleme.cn/2.5/#/ji-ben-yong-fa

 API:4.请求权限列表的数据

14.把权限以树形结构加载到对话框

import { Tree } from 'element-ui'

Vue.use(Tree)
<!-- 树形控件 -->
//:data:绑定数据源,:props指定属性绑定对象
<el-tree :data="rightslist" :props="treeProps"></el-tree>

// 树形控件的属性绑定对象
treeProps: {
   // 指定看到的是哪一个数据
   label: 'authName',
   children: 'children'
}  

https://element.eleme.cn/2.5/#/ji-chu-yong-fa

优化树形控件

<el-tree :data="rightslist" :props="treeProps" show-checkbox></el-tree>

https://element.eleme.cn/2.5/#/ke-xuan-ze

node-key每个树节点用来作为唯一标识的属性,整棵树应该是唯一的String
<el-tree :data="rightslist" :props="treeProps" show-checkbox node-key="id"></el-tree>

默认打开所有节点

default-expand-all是否默认展开所有节点booleanfalse
 <el-tree
        :data="rightslist"
        :props="treeProps"
        show-checkbox
        node-key="id"
        default-expand-all
      ></el-tree>

15.将角色身上已有权限加入分配权限中

default-checked-keys默认勾选的节点的 key 的数组array
<el-tree :default-checked-keys="defKeys"></el-tree>

// 默认选中的节点Id值数组
// 检验是否有效
defKeys: [105, 116]

再点击按钮的同时,立即把当前角色已有的三级权限id获取出来,都添加数组中。把整个数组通过属性绑定,交给default-checked-keys。

16.已有权限的默认勾选功能

<template  slot-scope="scope">
  <el-button @click="showSetRightDialog(scope.row)">分配权限</el-button>
</template>

// 默认选中的节点Id值数组
defKeys: []

// 展示分配权限的对话框
async showSetRightDialog (role) {
  // 递归获取三级节点的Id
  this.getLeafKeys(role, this.defKeys)
//当递归函数调用成功后,数组中保存的是已经拥有三级权限的id,然后再展开展示
  this.setRightDialogVisble = true
},
// 通过递归的形式,获取角色下所有三级权限的id,并保存到defKeys数组中
// node:节点判断是否是三级权限节点, arr:数组进行保存
getLeafKeys (node, arr) {
  // 如果当前node节点不包含children属性,则是三级节点
  if (!node.children) {
      return arr.push(node.id)
  }
  // 如果当前node节点包含children属性,则进行递归直到不包含children属性
  node.children.forEach(item =>
     this.getLeafKeys(item, arr)
  )
}

问题:关闭后清空元素项

每次点击按钮都会把当前角色已有的三级权限id保存到数组中,再关闭后并没有清空数组,就会导致数组越来越多。

<!-- 分配权限的对话框 -->
<el-dialog title="分配权限" :visible.sync="setRightDialogVisble" width="50%"
     @close="setRightDialogClosed">

// 监听分配权限对话框的关闭事件
setRightDialogClosed () {
  this.defKeys = []
}

17.角色授权:勾选状态保存到数据库

  • 请求路径:roles/:roleId/rights

  • 请求方法:post

  • 请求参数:通过 请求体 发送给后端

参数名参数说明备注
:roleId角色 ID不能为空携带在url中
rids权限 ID 列表(字符串), 分割的权限 ID 列表(获取所有被选中、叶子节点的key和半选中节点的key, 包括 1,2,3级节点)
  • 响应数据

{
    "data": null,
    "meta": {
        "msg": "更新成功",
        "status": 200
    }
}
getCheckedKeys若节点可被选择(即 show-checkbox 为 true),则返回目前被选中的节点的 key 所组成的数组(leafOnly) 接收一个 boolean 类型的参数,若为 true 则仅返回被选中的叶子节点的 keys,默认值为 false
getHalfCheckedNodes若节点可被选择(即 show-checkbox 为 true),则返回目前半选中的节点所组成的数组-

https://element.eleme.cn/2.5/#/ke-xuan-ze

  1.  确定按钮绑定单击事件处理函数allotRights( )
  2. 定义分配权限的函数allotRights( )
  3. 分配权限期间要拿到所有的keys,获取全选半选的id,
  4. 给tree加引用,获取它的引用ref
  5. 打印新数组keys,拿到id
  6. 拿到id数组后,将它变成以逗号拼接的字符串idStr
  7. 调用API接口
  8. showSetRightDialog把id保存到data中
  9. data中定义默认的id值roleId
  10. 可以把roleId放入allotRights函数中进行使用
<el-tree ref="treeRef"></el-tree>
<el-button type="primary" @click="allotRights">确 定</el-button>

// 当前即将分配权限的角色id
roleId: ''

async showSetRightDialog (role) {
      this.roleId = role.id
}

// 点击为角色分配权限
async allotRights () {
 const keys = [
  // 获取到所有已选中节点的id数组,合并两个数组
   ...this.$refs.treeRef.getCheckedKeys(),...this.$refs.treeRef.getHalfCheckedKeys()
 ]
  // console.log(keys)
  // 以逗号拼接的字符串
  const idStr = keys.join(',')
  const { data: res } = await this.$http.post(`roles/${this.roleId}/rights`, { rids: idStr })

  if (res.meta.status !== 200) {
     return this.$message.error('分配权限失败!')
  }
  this.$message.success('分配权限成功!')
  // 刷新数据列表
  this.getRolesList()
  // 把整个对话框隐藏起来
  this.setRightDialogVisble = false
}

18.完善用户列表的分配角色

弹出页面分配角色对话框,渲染用户基本信息,展示对话框的同时把所有角色信息获取

Users.vue

<!-- 分配角色按钮 -->
<el-tooltip effect="dark" content="分配角色" placement="top-start" :enterable="false"> 
   <el-button type="warning" @click="setRole(scope.row)"></el-button>
</el-tooltip>

<!-- 分配角色的对话框 -->
<el-dialog title="分配角色" :visible.sync="setRoleDialogVisble" width="50%">
  <div>
      <p>当前的用户:{{userInfo.username}}</p>
      <p>当前的角色:{{userInfo.role_name}}</p>
  </div>
  <span slot="footer" class="dialog-footer">
    <el-button @click="setRoleDialogVisble = false">取 消</el-button>
    <el-button type="primary" @click="setRoleDialogVisble = false">确 定</el-button>
  </span>
</el-dialog>


// 控制分配角色对话框的显示和隐藏
setRoleDialogVisble: false,
// 需要被分配角色的用户信息
userInfo: {},
// 所有角色的数据列表
rolesList: []

 // 展示分配角色的对话框
async setRole (userInfo) {
  this.userInfo = userInfo
  // 在展示对话框之前,获取所有角色的列表
  const { data: res } = await this.$http.get('roles')
  if (res.meta.status !== 200) {
     return this.$message.error('获取角色列表失败!')
  }
  this.rolesList = res.data
  this.setRoleDialogVisble = true
}

https://element.eleme.cn/2.5/#/ji-ben-yong-fa

19.角色列表渲染为下拉菜单

v-model的值为当前被选中的el-option的 value 属性值。

import { Select,Option } from 'element-ui'
Vue.use(Select)
Vue.use(Option)
<p>
分配新角色:
<!-- v-model:双向绑定是选中之后的值selectedRoleId -->
  <el-select v-model="selectedRoleId" placeholder="请选择">
   <el-option
      v-for="item in rolesList"
      :key="item.id"
      :label="item.roleName"
      :value="item.id">
<!-- value:选中的是主管,真正记录到v-model里面的是id的值 -->
    </el-option>
   </el-select>
</p>

// 已选中的角色Id值
selectRoleId: ''

https://element.eleme.cn/2.5/#/ji-chu-yong-fa

20.分配角色功能

  1. 确定按钮绑定点击事件saveRoleInfo
  2. 触发整个事件是要先判断有没有选中新的角色
  3. 发起put请求
  4. 对话框关闭后并没有重置选择项,监听对话框的close事件
<!-- 分配角色的对话框 -->
<el-dialog title="分配角色" @close="setRoleDialogClosed">
<el-button type="primary" @click="saveRoleInfo">确 定</el-button>

// 点击按钮,分配角色
async saveRoleInfo () {
 if (!this.selectedRoleId) {
     return this.$message.error('请选择要分配的角色!')
 }
 const { data: res } = await this.$http.put(`users/${this.userInfo.id}/role`, { rid: this.selectedRoleId })
 if (res.meta.status !== 200) {
     return this.$message.error('更新角色失败!')
 }
// 弹出成功的提示消息
 this.$message.success('更新角色成功!')
// 刷新当前用户列表
 this.getUserList()
// 隐藏分配角色的对话框
 this.setRoleDialogVisble = false
}

// 监听分配角色对话框的关闭事件
setRoleDialogClosed () {
  this.selectedRoleId = ''
  this.userInfo = {}
}
  • 请求路径:users/:id/role

  • 请求方法:put

  • 请求参数

参数名参数说明备注
id用户 ID不能为空参数是url参数:id
rid角色 id不能为空参数body参数
  • 响应参数

参数名参数说明备注
id用户 ID
role_id角色 ID
mobile手机号
email邮箱
  • 响应数据

{ "data": {
        "id": 508,
        "rid": "30",
        "username": "asdf1",
        "mobile": "123123",
        "email": "adfsa@qq.com"
    },
    "meta": {
        "msg": "设置角色成功",
        "status": 200
    }}

21.提交权限管理代码

  1. git branch  查看当前所处分支,处于rights分支
  2. git add . 所有修改后的文件添加到暂存区
  3. git commit -m "完成了权限功能的开发"  把当前所有代码提交到rights分支
  4. git push 把本地rights分支提交到远程的rights分支(不需要-u,因为远程已经有了rights分支)
  5. git checkout master 切换到master主分支
  6. git merge rights  合并rights所有的代码到master中
  7. git branch  查看当前所处分支,处于master分支
  8. git push 将本地的master分支推送到云端

2.分类管理开发

商品分类用于在购物时,快速找到所要购买的商品,可以通过电商平台主页直观的看到。

1.创建分类管理子分支

  1. git branch  当前处于master分支
  2. git checkout -b goods_cate 从主分支上分出一个子分支,创建一个子分支
  3. git branch  此时处于goods_cate子分支
  4. git push -u origin goods_cate  goods_cate推送到码云仓库中

2.商品分类路由组件的加载

components/goods/Cate.vue

router/index.js

import Cate from '@/components/goods/Cate.vue'
 {
    path: '/home',
    component: Home,
    redirect: '/welcome',
    children: [
      { path: '/categories', component: Cate }
    ]
  }

3.绘制商品分类页面的基本结构

<!-- 面包屑导航区域 -->
<el-breadcrumb separator-class="el-icon-arrow-right">
  <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>
     <el-button type="primary">添加分类</el-button>
  </el-row>
<!-- 表格 -->
<!-- 分页区域 -->
</el-card>

4.获取商品分类数据列表

  • 请求路径:categories

  • 请求方法:get

  • 请求参数

参数名参数说明备注
type[1,2,3]值:1,2,3 分别表示显示一层二层三层分类列表 【可选参数】如果不传递,则默认获取所有级别的分类
pagenum当前页码值【可选参数】如果不传递,则默认获取所有分类
pagesize每页显示多少条数据【可选参数】如果不传递,则默认获取所有分类
  • 响应参数

参数名参数说明备注
cat_id分类 ID
cat_name分类名称
cat_pid分类父 ID
cat_level分类当前层级
  • 响应数据

{ 
 "data": [{
            "cat_id": 1,
            "cat_name": "大家电",
            "cat_pid": 0,
            "cat_level": 0,
            "cat_deleted": false,
            "children": [{
                    "cat_id": 3,
                    "cat_name": "电视",
                    "cat_pid": 1,
                    "cat_level": 1,
                    "cat_deleted": false,
                    "children": [{
                            "cat_id": 6,
                            "cat_name": "曲面电视",
                            "cat_pid": 3,
                            "cat_level": 2,
                            "cat_deleted": false
                        },{
                            "cat_id": 7,
                            "cat_name": "海信",
                            "cat_pid": 3,
                            "cat_level": 2,
                            "cat_deleted": false
                           }]}]}],
 "meta": {
        "msg": "获取成功",
        "status": 200
  }}
 data () {
    return {
      // 查询条件
      querInfo: {
        type: 3,
        pagenum: 1,
        pagesize: 5
      },
      // 商品分类的数据列表,默认为空
      catelist: [],
      // 总数据条数
      total: 0
    }
  },
  created () {
    this.getCateList()
  },
  methods: {
    // 获取商品分类数据
    async getCateList () {
      const { data: res } = await this.$http.get('categories', { params: this.querInfo })
      if (res.meta.status !== 200) {
        return this.$message.error('获取商品分类失败!')
      }
      console.log(res.data)
      // 数据获取成功了,可以把数据保存到catelist上
      // 把数据列表,赋值给catelist
      this.catelist = res.data.result
      // 为总数据条数赋值
      this.total = res.data.total
    }
  }

5.商品分类数据渲染成树形table表格

vue ui可视化面板找到依赖,安装运行依赖vue-table-with-tree-grid。

main.js导入该插件,再进行全局注册

import Treetable from 'vue-table-with-tree-grid'
Vue.component('tree-table', TreeTable)
 <!-- 表格 -->
      <!-- false是布尔值,所以需要在前加冒号,代表属性绑定 -->
      <tree-table
        class="treeTable"
        :data="catelist"
        :columns="columns"
        :selection-type="false"
        :expand-type="false"
        show-index
        index-text="#"
        border
        :show-row-hover="false"
      ></tree-table>

 // 商品分类的数据列表,默认为空
      catelist: [],
      // 总数据条数
      total: 0,
      // 为table指定列的定义
      columns: [
        {
          label: '分类名称',
          prop: 'cat_name'
        }
      ]

.treeTable {
  margin-top: 15px;
}

GitHub - MisterTaki/vue-table-with-tree-grid: A table (with tree-grid) component for Vue.js 2.0. (Its style extends @iView)

vue-table-with-tree-grid/Example.vue at master · MisterTaki/vue-table-with-tree-grid · GitHub

1.按需渲染√和×图标,使用模板列

<!-- 是否有效 -->
<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>

 // 为table指定列的定义
      columns: [
        {
          label: '是否有效',
          // 表示将当前列定义为模板列
          type: 'template',
          // 表示当前这一列使用模板名称
          template: 'isok'
        }
      ]

2.渲染排序和操作两列

<!-- 排序 -->
<template slot="order" slot-scope="scope">
  <el-tag size="mini" v-if="scope.row.cat_level === 0">一级</el-tag>
  <el-tag type="success" size="mini" v-else-if="scope.row.cat_level === 1">二级</el-tag>
  <el-tag type="warning" size="mini" v-else>三级</el-tag>
</template>
<!-- 操作 -->
<template slot="opt">
  <el-button type="primary" icon="el-icon-edit" size="mini">编辑</el-button>
  <el-button type="danger" icon="el-icon-delete" size="mini">删除</el-button>
</template>

columns: [
        {
          label: '排序',
          // 表示将当前列定义为模板列
          type: 'template',
          // 表示当前这一列使用模板名称
          template: 'order'
        },
        {
          label: '操作',
          // 表示将当前列定义为模板列
          type: 'template',
          // 表示当前这一列使用模板名称
          template: 'opt'
        }
      ]

https://element.eleme.cn/2.5/#/ji-chu-yong-fa

6.渲染分页页码条

使用element ui中完整的分页页码条代码

  1. 触发了size-change事件,即pagesize发生了变化
  2. 定义监听pagesize的页码事件handleSizeChange
  3. 当前页码值发生了改变,就会触发handleCurrentChange事件
   <!-- 分页区域 -->
      <el-pagination
        @size-change="handleSizeChange"
        @current-change="handleCurrentChange"
        :current-page="querInfo.pagenum"
        :page-sizes="[3, 5, 10, 15]"
        :page-size="querInfo.pagesize"
        layout="total, sizes, prev, pager, next, jumper"
        :total="total">
      </el-pagination>

  // 监听pagesize改变
    handleSizeChange (newSize) {
      // 为其赋新值
      this.querInfo.pagesize = newSize
      // 刷新数据
      this.getCateList()
    },
    // 监听pagenum改变
    handleCurrentChange (newPage) {
      // 拿到最新的页码值,给其赋值
      this.querInfo.pagenum = newPage
      // 拿到值后,立即刷新数值列表
      this.getCateList()
    }

https://element.eleme.cn/2.5/#/fu-jia-gong-neng

7.添加分类的操作

<!-- 卡片视图区域 -->
<el-card>
 <el-row>
    <el-button type="primary" @click="showAddCateDialog">添加分类</el-button>
 </el-row>
<!-- 添加分类的对话框 -->
 <el-dialog
        title="添加分类"
        :visible.sync="addCateDialogVisible"
        width="50%">
   <!-- 添加分类的表单 -->
   <el-form
          :model="addCateForm"
          :rules="addCateFormRules"
          ref="addCateFormRef"
          label-width="100px" >
      <el-form-item label="分类名称:" prop="cat_name">
         <el-input v-model="addCateForm.cat_name"></el-input>
      </el-form-item>
          <el-form-item label="父级分类:"> </el-form-item>
  </el-form>
  <span slot="footer" class="dialog-footer">
    <el-button @click="addCateDialogVisible = false">取 消</el-button>
    <el-button type="primary" @click="addCateDialogVisible = false">确 定</el-button>
  </span>
</el-dialog>

// 控制添加分类对话框的显示和隐藏
      addCateDialogVisible: false

// 点击按钮,展示添加分类的对话框
    showAddCateDialog () {
      this.addCateDialogVisible = true
    }

https://element.eleme.cn/2.5/#/ji-ben-yong-fa

https://element.eleme.cn/2.5/#/biao-dan-yan-zheng

 添加分类API接口

  • 请求路径:categories

  • 请求方法:post

  • 请求参数

参数名参数说明备注
cat_pid分类父 ID不能为空,如果要添加1级分类,则父分类Id应该设置为 0
cat_name分类名称不能为空
cat_level分类层级不能为空,0表示一级分类;1表示二级分类;2表示三级分类
  • 响应数据

{
    "data": {
        "cat_id": 62,
        "cat_name": "相框",
        "cat_pid": "1",
        "cat_level": "1"
    },
    "meta": {
        "msg": "创建成功",
        "status": 201
    }
}

8.点击添加分类后,加载父级分类

API见4。

 // 父级分类的列表
      parentCateList: []

 // 点击按钮,展示添加分类的对话框
    showAddCateDialog () {
      // 先获取父级分类的数据列表
      this.getParentCatelist()
      // 再展示出对话框
      this.addCateDialogVisible = true
    },
    // 获取父级分类的数据列表
    async getParentCatelist () {
      const { data: res } = await this.$http.get('categories', { params: { type: 2 } })
      if (res.meta.status !== 200) {
        return this.$message.error('获取父级分类数据失败!')
      }
      console.log(res.data)
      this.parentCateList = res.data
    }

 9.渲染父级分类的级联选择器

按需导入组件,并作全局注册

import { Cascader} from 'element-ui'

Vue.use(Cascader)
<el-form-item label="父级分类:">
<!-- options用来指定数据源 -->
<!-- props 用来指定配置对象 -->
   <el-cascader 
      expand-trigger="hover" 
      :options="parentCateList" 
      :props="cascaderProps"
      v-model="selectedKeys"
      @change="parentCateChange"
      clearable
      change-on-select>
   </el-cascader>
</el-form-item>

// 父级分类的列表
parentCateList: [],
// 指定级联选择器的配置对象
cascaderProps: {
   //value指定具体选中值的属性
    value: 'cat_id',
   //label指定看到的属性
    label: 'cat_name',
    children: 'children'
},
// 选中的父级分类的Id数组
selectedKeys: []

 // 选择项发生变化触发这个函数
parentCateChange () {
      console.log(this.selectedKeys)
}

.el-cascader {
  width: 100%;
}
clearable是否支持清空选项booleanfalse
change-on-select是否允许选择任意一级的选项booleanfalse
props配置选项,具体见下表object

props

参数说明类型可选值默认值
value指定选项的值为选项对象的某个属性值string
label指定选项标签为选项对象的某个属性值string
children指定选项的子选项为选项对象的某个属性值string
disabled指定选项的禁用为选项对象的某个属性值string
//全局样式限制一下父级分类的高度
.el-cascader-menu {
  height: 400px;
}

https://element.eleme.cn/2.5/#/ji-chu-yong-fa

​ 

element ui有改动,如果不使用新方法会出现警告,但是不会报错,只是警告

 expand-trigger is removed, use `props.expandTrigger` instead.

[Element Migrating][ElCascader][Attribute]: change-on-select is removed, use `props.checkStrictly` instead.

<el-cascader
              :options="parentCateList"
              :props="{
                expandTrigger: 'hover',
                checkStrictly: 'true',
                ...cascaderProps,
              }"
              v-model="selectedKeys" @change="parentCateChange" clearable>

10.添加分类的表单数据

如果分类名字为a,未选择父级分类,则父级id和等级level都为0;如果选择了二级分类,则应该修改父级id和level的值。

 只要选择项发生了变化,selectedKeys也应该发生变化;如果数组里,id长度大于0了,则表示有选中父级分类;否则就是没有选中父级分类(以最后一项为父级的id     console.log(this.selectedKeys)打印出来的值

<el-button type="primary" @click="addCate">确 定</el-button>

// 选中的父级分类的Id数组
      selectedKeys: []
 
// 选择项发生变化触发这个函数
    parentCateChange () {
      console.log(this.selectedKeys)
      // 如果selectKeys数组中的length大于0,证明选中了父级分类
      // 反之说明码云选中如何父级分类
      if (this.selectedKeys.length > 0) {
        // 父级分类的id
        this.addCateForm.cat_pid = this.selectedKeys[this.selectedKeys.length - 1]
        // 为当前分类的等级赋值
        this.addCateForm.cat_level = this.selectedKeys.length
      } else {
        this.addCateForm.cat_pid = 0
        this.addCateForm.cat_level = 0
      }
    },

// 点击按钮,添加新的分类
 addCate () {
      console.log(this.addCateForm)
}

 监听级联选择器的change事件,再change事件中选择项的length大于0,则表示选中了父级分类,为父级分类的id值和level值赋值;小于等于0,则表示没有选中父级分类,将其id和level都赋值为0。

11.监听添加分类对话框的关闭事件

添加分类的对话框关闭后,立即将其输入过的分类名称,父级分类清空。

 <!-- 添加分类的对话框 -->
<el-dialog title="添加分类" :visible.sync="addCateDialogVisible" width="50%"
        @close="addCateDialogClosed">
 // 监听对话框的关闭事件,重置表单数据
    addCateDialogClosed () {
      this.$refs.addCateFormRef.resetFields()
      // 将数组清空
      this.selectedKeys = []
      // 表单的level和pid重置为0
      this.addCateForm.cat_level = 0
      this.addCateForm.cat_pid = 0
    }

12.具体的添加操作

<el-button type="primary" @click="addCate">确 定</el-button>

// 点击按钮,添加新的分类
addCate () {
   console.log(this.addCateForm)
   this.$refs.addCateFormRef.validate(async valid => {
     if (!valid) return
     const { data: res } = await this.$http.post('categories', this.addCateForm)
     if (res.meta.status !== 201) {
        return this.$message.error('添加分类失败!')
     }
     this.$message.success('添加分类成功!')
        // 刷新数据列表
     this.getCateList()
        // 隐藏添加的对话框
     this.addCateDialogVisible = false
      })
}

13.商品分类提交到git仓库

  1. git branch 查看当前所处分支
  2. git status 查看当前文件状态  红色
  3. git add .  将已经修改的文件添加到暂存区  
  4. git status 绿色
  5. git commit -m "完成了分类功能的开发" 将修改保存到仓库中
  6. git status 显示干净
  7. git push  将本地提交到云端
  8. 将本地的goods_cate分支合并到master分支中去
  9. git checkout master  先切换到主分支
  10. git merge goods_cate  ​​​​​​​再合并分支
  11. git push 云端仓库也要更新master分支

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值