目录
10.添加分类的表单数据
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>
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('确认了删除!')
}
}
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 | 是否默认展开所有节点 | boolean | — | false |
<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
- 确定按钮绑定单击事件处理函数allotRights( )
- 定义分配权限的函数allotRights( )
- 分配权限期间要拿到所有的keys,获取全选半选的id,
- 给tree加引用,获取它的引用ref
- 打印新数组keys,拿到id
- 拿到id数组后,将它变成以逗号拼接的字符串idStr
- 调用API接口
- showSetRightDialog把id保存到data中
- data中定义默认的id值roleId
- 可以把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.分配角色功能
- 确定按钮绑定点击事件saveRoleInfo
- 触发整个事件是要先判断有没有选中新的角色
- 发起put请求
- 对话框关闭后并没有重置选择项,监听对话框的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 | 手机号 | |
邮箱 |
-
响应数据
{ "data": {
"id": 508,
"rid": "30",
"username": "asdf1",
"mobile": "123123",
"email": "adfsa@qq.com"
},
"meta": {
"msg": "设置角色成功",
"status": 200
}}
21.提交权限管理代码
- git branch 查看当前所处分支,处于rights分支
- git add . 所有修改后的文件添加到暂存区
- git commit -m "完成了权限功能的开发" 把当前所有代码提交到rights分支
- git push 把本地rights分支提交到远程的rights分支(不需要-u,因为远程已经有了rights分支)
- git checkout master 切换到master主分支
- git merge rights 合并rights所有的代码到master中
- git branch 查看当前所处分支,处于master分支
- git push 将本地的master分支推送到云端
2.分类管理开发
商品分类用于在购物时,快速找到所要购买的商品,可以通过电商平台主页直观的看到。
1.创建分类管理子分支
- git branch 当前处于master分支
- git checkout -b goods_cate 从主分支上分出一个子分支,创建一个子分支
- git branch 此时处于goods_cate子分支
- 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;
}
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中完整的分页页码条代码
- 触发了size-change事件,即pagesize发生了变化
- 定义监听pagesize的页码事件handleSizeChange
- 当前页码值发生了改变,就会触发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 | 是否支持清空选项 | boolean | — | false |
change-on-select | 是否允许选择任意一级的选项 | boolean | — | false |
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仓库
- git branch 查看当前所处分支
- git status 查看当前文件状态 红色
- git add . 将已经修改的文件添加到暂存区
- git status 绿色
- git commit -m "完成了分类功能的开发" 将修改保存到仓库中
- git status 显示干净
- git push 将本地提交到云端
- 将本地的goods_cate分支合并到master分支中去
- git checkout master 先切换到主分支
- git merge goods_cate 再合并分支
- git push 云端仓库也要更新master分支