✔ 掌握员工头像上传的业务逻辑。
✔ 掌握给用户分配角色,给角色分配权限的操作(RBAC)。
员工详情-封装员工头像组件
- 创建 image-upload 组件,
src/views/employee/components/image-upload.vue
。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65
| <template> <el-upload class="avatar-uploader" action="" :show-file-list="false" :before-upload="beforeAvatarUpload"> <img v-if="value" :src="value" class="avatar"> <i v-else class="el-icon-plus avatar-uploader-icon" /> </el-upload> </template>
<script> export default { props: { value: { type: String, default: '' } }, methods: { beforeAvatarUpload(file) {
const isJPG = ['image/jpeg', 'image/png', 'image/gif', 'image/bmp'].includes(file.type) const isLt5M = file.size / 1024 / 1024 < 5
if (!isJPG) { this.$message.error('上传头像图片只能是 JPG PNG GIF BMP 格式!') } if (!isLt5M) { this.$message.error('上传头像图片大小不能超过 5MB!') } return isJPG && isLt5M } } } </script>
<style> .avatar-uploader .el-upload { border: 1px dashed #d9d9d9; border-radius: 6px; cursor: pointer; position: relative; overflow: hidden; }
.avatar-uploader .el-upload:hover { border-color: #409EFF; }
.avatar-uploader-icon { font-size: 28px; color: #8c939d; width: 178px; height: 178px; line-height: 178px; text-align: center; }
.avatar { width: 178px; height: 178px; display: block; } </style>
|
- 在父组件中应用,
src/views/employee/detail.vue
。
1
| <image-upload v-model="userInfo.staffPhoto" />
|
员工详情-上传图片-创建腾讯云存储桶
注册腾讯云账号(课前完成 https://cloud.tencent.com/login)。
创建腾讯云存储桶。
得到应用密钥和应用标识。
先点击头像左边的【控制台】。
获取存储桶相关信息
将存储桶和所属地域拷贝下来,备用。获取应用标识 https://console.cloud.tencent.com/cam/capi。
将 SecretId 和 SecretKey 拷贝下来,备用。
员工详情-使用cos-sdk完成上传
- 安装腾讯云 js-sdk。
- 使用 el-upload 自定义上传,
src/views/employee/components/image-upload.vue
。
1 2 3 4 5 6 7 8
| <template> <el-upload class="avatar-uploader" action="" :show-file-list="false" :before-upload="beforeAvatarUpload" :http-request="uploadImage"> <img v-if="value" :src="value" class="avatar"> <i v-else class="el-icon-plus avatar-uploader-icon" /> </el-upload> </template>
|
- 实现上传方法。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
| import COS from 'cos-js-sdk-v5'
uploadImage(params) { console.log(params.file) const cos = new COS({ SecretId: 'AKIDQmu0HrSQcZeU3cqA4iCcmgYidIhrQr4jy7', SecretKey: 'jDRPmTx8rrdBTWXINPltwjKvJRmqfEYl' }) cos.putObject({ Bucket: 'ifer-1253924894', Region: 'ap-nanjing', Key: params.file.name, StorageClass: 'STANDARD', Body: params.file }, (err, data) => { if (data.statusCode === 200 && data.Location) { this.$emit('input', 'http://' + data.Location) } else { this.$message.error(err.Message) } }) }
|
权限管理-搭建权限页面
实现权限管理的页面结构, src/views/permission/index.vue
。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29
| <template> <div class="container"> <div class="app-container"> <el-card> <el-button class="btn-add" size="mini" type="primary">添加权限</el-button> <el-table> <el-table-column label="名称" /> <el-table-column label="标识" /> <el-table-column label="描述" /> <el-table-column label="操作"> <el-button size="mini" type="text">添加</el-button> <el-button size="mini" type="text">编辑</el-button> <el-button size="mini" type="text">删除</el-button> </el-table-column> </el-table> </el-card> </div> </div> </template> <script> export default { name: 'Permission' } </script> <style> .btn-add { margin: 10px; } </style>
|
权限管理-获取数据转化树形
- 封装获取权限 API,
src/api/permission.js
。
1 2 3 4 5 6 7
| import request from '@/utils/request'
export function getPermissionList() { return request({ url: '/sys/permission' }) }
|
- 获取数据-转化树形-控制二级权限不显示添加按钮,
src/views/permission/index.vue
。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50
| <template> <div class="container"> <div class="app-container"> <el-card> <el-button class="btn-add" size="mini" type="primary">添加权限</el-button> <el-table default-expand-all :data="list" row-key="id"> <el-table-column prop="name" label="名称" /> <el-table-column prop="code" label="标识" /> <el-table-column prop="description" label="描述" /> <el-table-column label="操作"> <template v-slot="{ row }"> <el-button v-if="row.type === 1" size="mini" type="text">添加</el-button> <el-button size="mini" type="text">编辑</el-button> <el-button size="mini" type="text">删除</el-button> </template> </el-table-column> </el-table> </el-card> </div> </div> </template> <script> import { getPermissionList } from '@/api/permission' import { transListToTreeData } from '@/utils' export default { name: 'Permission', data() { return { list: [] } }, created() { this.getPermissionList() }, methods: { async getPermissionList() { this.list = transListToTreeData(await getPermissionList(), 0) } } } </script> <style> .btn-add { margin: 10px; } </style>
|
权限管理-作业
基于权限接口和线上效果,完成权限点的新增、删除、编辑功能。
作业要求如下。
- 封装权限管理的 API 接口,
src/api/permission.js
。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
| export function addPermission(data) { return request({ url: '/sys/permission', method: 'post', data }) }
export function updatePermission(data) { return request({ url: `/sys/permission/${data.id}`, method: 'put', data }) }
export function delPermission(id) { return request({ url: `/sys/permission/${id}`, method: 'delete' }) }
export function getPermissionDetail(id) { return request({ url: `/sys/permission/${id}` }) }
|
- 新增编辑权限的弹层,
src/views/permission/index.vue
。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
| <el-dialog :title="`${showText}权限点`" :visible="showDialog" @close="btnCancel"> <el-form ref="perForm" :model="formData" :rules="rules" label-width="120px"> <el-form-item label="权限名称" prop="name"> <el-input v-model="formData.name" style="width:90%" /> </el-form-item> <el-form-item label="权限标识" prop="code"> <el-input v-model="formData.code" style="width:90%" /> </el-form-item> <el-form-item label="权限描述"> <el-input v-model="formData.description" style="width:90%" /> </el-form-item> <el-form-item label="开启"> <el-switch v-model="formData.enVisible" active-value="1" inactive-value="0" /> </el-form-item> </el-form> <el-row slot="footer" type="flex" justify="center"> <el-col :span="6"> <el-button size="small" type="primary" @click="btnOK">确定</el-button> <el-button size="small" @click="btnCancel">取消</el-button> </el-col> </el-row> </el-dialog>
|
- 声明控制弹层需要的变量、表单数据和校验规则,
src/views/permission/index.vue
。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53
| import { getPermissionList, updatePermission, addPermission, getPermissionDetail, delPermission } from '@/api/permission' import { transListToTreeData } from '@/utils' export default { data() { return { list: [], formData: { name: '', code: '', description: '', type: '', pid: '', enVisible: "0" }, rules: { name: [{ required: true, message: '权限名称不能为空', trigger: 'blur' }], code: [{ required: true, message: '权限标识不能为空', trigger: 'blur' }] }, showDialog: false } }, computed: { showText() { return this.formData.id ? '编辑' : '新增' } }, created() { this.getPermissionList() }, methods: { async getPermissionList() { this.list = transListToTreeData(await getPermissionList(), 0) }, btnOK() {}, btnCancel() {} } }
|
- 实现一级权限新增-二级权限新增,
src/views/permission/index.vue
。
注意:一级添加的 type 为 1, 二级添加的 type 为 2。
1
| <el-button class="btn-add" size="mini" type="primary" @click="addPermission(0, 1)">添加权限</el-button>
|
1 2 3 4 5
| <el-table-column label="操作"> <template v-slot="{ row }"> <el-button v-if="row.type === 1" size="mini" type="text" @click="addPermission(row.id, 2)">添加</el-button> </template> </el-table-column>
|
- 点击添加按钮显示弹框,并记录 pid 和 type。
1 2 3 4 5
| addPermission(pid, type) { this.formData.pid = pid this.formData.type = type this.showDialog = true },
|
- 点击确定按钮调用添加接口、取消按钮操作。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32
| export default { name: 'Permission', methods: { btnOK() { this.$refs.perForm.validate().then(() => { if (this.formData.id) { return updatePermission(this.formData) } return addPermission(this.formData) }).then(() => { this.$message.success('新增成功') this.getPermissionList() this.showDialog = false }) }, btnCancel() { this.formData = { name: '', code: '', description: '', type: '', pid: '', enVisible: '0' } this.$refs.perForm.resetFields() this.showDialog = false } } }
|
- 实现编辑功能。
1
| <el-button type="text" size="mini" @click="editPermission(row.id)">编辑</el-button>
|
1 2 3 4 5 6 7 8 9 10 11 12
| export default { name: 'Permission', methods: { async editPermission(id) { this.formData = await getPermissionDetail(id) this.showDialog = true } } }
|
- 实现删除功能。
1
| <el-button type="text" size="mini" @click="delPermission(row.id)"> 删除</el-button>
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| export default { name: 'Permission', methods: { async delPermission(id) { try { await this.$confirm('确定要删除该数据吗') await delPermission(id) this.getPermissionList() this.$message.success('删除成功') } catch (error) { console.log(error) } }, } }
|
权限应用-权限概念
权限是通过角色这个中间人实现,首先员工拥有角色,角色拥有权限,那么员工也就自动拥有了角色所对应的权限。
所以接下来,我们需要实现给员工分配角色,给角色分配权限。
给员工分角色,views/employee/index.vue
。
给角色分权限,views/role/index.vue
。
权限应用-员工分配角色-弹出层
- 封装获取所有角色的 API,
src/api/employee.js
。
1 2 3 4 5 6 7 8 9
|
export function getEnableRoleList() { return request({ url: '/sys/role/list/enabled' }) }
|
- 声明相关变量,
src/views/employee/index.vue
。
1 2 3 4 5 6 7
| data() { return { showRoleDialog: false, roleList: [], roleIds: [] } }
|
- 点击角色按钮,获取角色列表,
src/views/employee/index.vue
。
1 2 3 4 5 6
| import { getEnableRoleList } from '@/api/employee'
async btnRole() { this.showRoleDialog = true this.roleList = await getEnableRoleList() }
|
- 放置弹层,绑定变量和渲染 checkbox,
src/views/employee/index.vue
。
1 2 3 4 5 6 7 8
| <el-dialog :visible.sync="showRoleDialog" title="分配角色"> <el-checkbox-group v-model="roleIds"> <el-checkbox v-for="item in roleList" :key="item.id" :label="item.id">{{ item.name }}</el-checkbox> </el-checkbox-group> </el-dialog>
|
权限应用-员工分配角色-回显数据并提交
- 封装给员工分配角色的接口,
src/api/employee.js
。
1 2 3 4 5 6 7 8 9 10 11
|
export function assignRole(data) { return request({ url: '/sys/user/assignRoles', method: 'put', data }) }
|
- 点击角色按钮时,录当前点击的用户 id,并获取员工已经拥有的角色,
src/views/employee/index.vue
。
1 2 3 4 5
| data() { return { currentUserId: null } }
|
1 2 3 4 5 6 7 8 9 10
| async btnRole(id) { this.roleList = await getEnableRoleList() this.currentUserId = id const { roleIds } = await getEmployeeDetail(id) this.roleIds = roleIds this.showRoleDialog = true },
|
- 点击确定实现给用户分配角色,
src/views/employee/index.vue
1 2 3 4 5 6
| <el-row slot="footer" type="flex" justify="center"> <el-col :span="6"> <el-button type="primary" size="mini" @click="btnRoleOK">确定</el-button> <el-button size="mini" @click="showRoleDialog = false">取消</el-button> </el-col> </el-row>
|
1 2 3 4 5 6 7 8 9
| async btnRoleOK() { await assignRole({ id: this.currentUserId, roleIds: this.roleIds }) this.$message.success('分配用户角色成功') this.showRoleDialog = false }
|
权限应用-给角色分配权限-弹出层
- 声明控制弹层显示和接收权限数据的变量,
src/views/role/index.vue
。
1 2 3 4 5 6
| data() { return { showPermissionDialog: false, permissionData: [] } }
|
- 点击分配权限-弹出层-获取数据并转化树形,
src/views/role/index.vue
。
1
| <el-button size="mini" type="text" @click="btnPermission">分配权限</el-button>
|
1 2 3 4 5 6
| import { transListToTreeData } from '@/utils' import { getPermissionList } from '@/api/permission' async btnPermission() { this.showPermissionDialog = true this.permissionData = transListToTreeData(await getPermissionList(), 0) }
|
- 放置弹层和树组件,
src/views/role/index.vue
。
1 2 3 4 5
| <el-dialog :visible.sync="showPermissionDialog" title="分配权限"> <el-tree :data="permissionData" :props="{ label: 'name' }" show-checkbox default-expand-all /> </el-dialog>
|
权限应用-角色分配权限-显示已有权限数据
- 获取当前角色的权限,
src/api/role.js
。
1 2 3 4 5
| export function getRoleDetail(id) { return request({ url: `/sys/role/${id}` }) }
|
- 声明变量,记录当前点击的角色 id 和角色所拥有的权限数据,
src/views/role/index.vue
。
1 2 3 4 5 6
| data() { return { currentRoleId: null, permIds: [] } }
|
- 点击分配权限按钮时传递角色 id,并根据 id 获取该角色所拥有的权限,
src/views/role/index.vue
。
1
| <el-button size="mini" type="text" @click="btnPermission(row.id)">分配权限</el-button>
|
1 2 3 4 5 6 7 8 9
| async btnPermission(id) { this.currentRoleId = id const { permIds } = await getRoleDetail(id) this.permIds = permIds this.permissionData = transListToTreeData(await getPermissionList(), 0) this.showPermissionDialog = true }
|
- 设置 el-tree 组件的属性 node-key 和当前选中数据,
src/views/role/index.vue
。
1
| <el-tree check-strictly node-key="id" :data="permissionData" :props="{ label: 'name' }" show-checkbox default-expand-all :default-checked-keys="permIds" />
|
default-checked-keys
的属性是设置当前选中的节点,但是必须配合 node-key
属性,因为 permIds 变量中存储的都是 id,必须让 el-tree 组件知道 key 是哪个字段,所以设置 node-key="id"
。
check-strictly
表示父子不关联。
权限应用-角色分配权限-确定提交
- 封装分配权限的接口 API,
src/api/role.js
。
1 2 3 4 5 6 7 8 9 10 11 12
|
export function assignPerm(data) { return request({ url: '/sys/role/assignPrem', method: 'put', data }) }
|
- 确定和取消事件,
src/views/role/index.vue
。
1 2 3 4 5 6
| <el-row slot="footer" type="flex" justify="center"> <el-col :span="6"> <el-button type="primary" size="mini" @click="btnPermissionOK">确定</el-button> <el-button size="mini" @click="cancelPermDialog">取消</el-button> </el-col> </el-row>
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| async btnPermissionOK() { await assignPerm({ id: this.currentRoleId, permIds: this.$refs.permTree.getCheckedKeys() }) this.$message.success('角色分配权限成功') this.showPermissionDialog = false }, cancelPermDialog() { this.showPermissionDialog = false this.permIds = [] }
|
1 2
| <el-dialog :visible="showPermissionDialog" title="分配权限" @close="cancelPermDialog"></el-dialog>
|