06-HR-角色管理模块

776 阅读3分钟

角色管理模块

角色管理介绍

目标:不同的用户登录系统后,能够操作不同的菜单。

image.png

总结:角色的增删改查

image.png

  • 用户(员工)账号:用来登录系统
  • 角色:员工的身份,不同的身份拥有不同的菜单,角色可以分配给用户
  • 权限:功能按钮,可以分配给角色

总结:不同的用户登录系统后可以操作不同的菜单

角色管理组件布局

根据以上的结构,我们采用element-ui的组件实现**src/views/setting/index.vue**

<template>
  <div class="setting-container">
    <div class="app-container">
      <el-card>
        <el-tabs>
          <!-- 左侧 -->
          <el-tab-pane label="角色管理">
            <!-- 按钮 -->
            <el-button
              icon="el-icon-plus"
              size="small"
              type="primary"
            >新增角色</el-button>
            <!-- 表格 -->
            <el-table>
              <el-table-column label="序号" width="100" />
              <el-table-column label="角色名称" width="240" />
              <el-table-column label="描述" />
              <el-table-column label="操作">
                <el-button size="small" type="success">分配权限</el-button>
                <el-button size="small" type="primary">编辑</el-button>
                <el-button size="small" type="danger">删除</el-button>
              </el-table-column>
            </el-table>
          </el-tab-pane>

          <el-tab-pane label="公司信息">
            <!-- 公司信息 -->
          </el-tab-pane>
        </el-tabs>
      </el-card>
    </div>
  </div>
</template>

总结:

  1. 卡片组件 el-card
  2. 选项卡组件用法 el-tabs
  3. 表格组件的用法 el-table

获取角色列表数据

  • 首先,封装读取角色的信息的请求 src/api/setting.js
import request from '@/utils/request'
/**
 * 获取角色列表
 * ***/
export function reqGetRoleList(options) {
  return request({
    method: 'get',
    url: '/sys/role',
    data: options
  })
}
  • 然后,在页面中调用接口获取数据 src/views/setting/index.vue
import { reqGetRoleList } from '@/api/setting.js'

export default {
  name: 'Setting',
  data () {
    return {
      // 查询参数
      fillterParams: {
        page: 1,
        pagesize: 10
      },
      // 角色列表
      list: [],
      // 角色列表的总数
      total: 0
    }
  },
  created () {
    this.loadRoleList()
  },
  methods: {
    // 加载角色列表的数据
    async loadRoleList () {
      try {
        const ret = await reqGetRoleList(this.fillterParams)
        this.list = ret.data.rows
        this.total = ret.data.total
      } catch {
        this.$message.error('获取角色列表失败')
      }
    }
  }
}
  • 绑定表格数据
<el-table :data="list">
  <el-table-column type="index" label="序号" width="120" />
  <el-table-column prop="name" label="角色名称" width="240" />
  <el-table-column prop="description" label="描述" />
  <el-table-column label="操作">
    <el-button size="small" type="success">分配权限</el-button>
    <el-button size="small" type="primary">编辑</el-button>
    <el-button size="small" type="danger">删除</el-button>
  </el-table-column>
</el-table>

总结:调用接口;获取数据;渲染表格

注意:表格列的索引 type='index' 是ElementUI提供的规则

注意:分页方式基于页码和每页条数

处理表格分页

需求:基于ElementUI提供的分页组件实现分页

<el-pagination
  layout="prev, pager, next"
  :total="total"
  :current-page="page"
  :page-size="pagesize"
  @current-change="changePage"
/>
// 控制页码的变化
changePage (page) {
  // page表示当前页码
  this.queryData.page = page
  this.loadRoleList()
},

总结:分页的本质,根据当前的页码的变化,重新加载当前页的数据,并且把之前的数据覆盖了

  • 控制每页条数的切换 sizes @size-change
  • 控制跳转到第几页 jumper
  • 显示总条数 total
  • --> 用于控制布局(左右布局)
  • slot 用于自定义模板

处理序号问题

  • 自定义序号
<el-table-column type="index" :index="handleIndex" label="序号" width="120" />
  • 配置自定义函数
methods: {
   handleIndex (index) {
      // 形参index表示列表数据的索引,从0开始
      // 动态计算累加的索引
      // (当前页码 - 1) * 每页的条数
      const { page, pagesize } = this.filterParams
      return (page - 1) * pagesize + 1 + index
   },
}

总结:动态计算索引的累加值

  1. 表格列组件提供的index属性绑定一个函数,用于动态计算索引
  2. 基于分页参数计算连续的索引值

添加表格loading效果

  • 绑定加载状态位
<el-table v-loading="loading" :data="list">
data () {
	return {
		loading: false
	}
}
  • 动态设置 loading 的状态
// 获取角色列表数据
async loadRoleList () {
  try {
    this.loading = true
    const ret = await reqGetRoleList(this.queryData)
    if (ret.code === 10000) {
      this.list = ret.data.rows
      this.total = ret.data.total
    }
  } catch {
    this.$message.error('获取角色列表失败')
  } finally {
    this.loading = false
  }
}

总结:通过v-loading绑定表格的加载状态,接口调用之前显示加载状态,接口数据返回后隐藏状态。

删除角色功能

目标 实现删除角色的功能

  1. 绑定事件
  2. 提示删除
  3. 调用接口实现删除
  4. 刷新列表
  • 封装删除角色的api
export function reqDeleteRole(id) {
  return request({
    url: `/sys/role/${id}`,
    method: 'delete'
  })
}
  • 删除按钮注册事件
<el-table-column label="操作">
  <template #default="{ row }">
    <el-button size="small" type="success">分配权限</el-button>
    <el-button size="small" type="primary">编辑</el-button>
    <el-button size="small" type="danger" @click="delRole(row.id)">删除</el-button>
  </template>
</el-table-column>
  • 删除功能实现
// 删除角色
handleDelete (id) {
  // 删除前进行提示
  this.$confirm('确认要删除角色吗?, 是否继续?', '提示', {
    confirmButtonText: '确定',
    cancelButtonText: '取消',
    type: 'warning'
  }).then(async () => {
    // 点击确定
    const ret = await reqDeleteRole(id)
    // 删除角色成功,刷新列表
    if (ret.code === 10000) {
      this.loadRoleList()
    } else {
      this.$message.error(ret.message)
    }
  }).catch((err) => {
    if (err !== 'cancel') {
      // 点击取消
      this.$message.error('删除角色失败')
    }
  })
}
// ----------------------------------------
// 删除操作
async handleDel (id) {
  const ret = await this.$confirm('确认要删除吗', '提示', {
    type: 'warning'
  }).catch(err => err)
  // 点击取消
  if (ret === 'cancel') return
  // 点击确定
  try {
    const delRet = await reqDeleteRole(id)
    if (delRet.code === 10000) {
        // 删除成功,刷新列表
        // 如果当前页面数据被删除完成了,刷新上一页数据
        if (this.queryData.page > 1 && this.list.length === 1) {
            // 页码需要大于1且当前页就剩一条数据
            this.queryData.page -= 1
            this.loadSettingList()
        }
    } else {
      // 删除失败
      this.$message.error('删除失败')
    }
  } catch {
    this.$message.error('删除失败')
  }
},

总结:绑定事件;调用接口;刷新列表

  1. 作用域插槽
  2. 提示方法的使用

注意:如果当前页面删除完了数据,那么就刷新上一页。

添加角色弹窗控制

添加角色流程

  1. 点击添加按钮绑定事件
  2. 显示弹窗
  3. 实现表单,添加表单验证
  4. 提交表单
  5. 刷新列表
  • 准备弹框
<el-dialog title="弹层标题" :visible.sync="isShowAddBox">
  我是弹层
</el-dialog>
// data中添加一个状态位
isShowAddBox: false
  • 给按钮注册点击事件
<el-button
  icon="el-icon-plus"
  size="small"
  type="primary"
  @click="isShowAddBox=true"
>新增角色</el-button>
  • 准备弹框表单结构
<el-dialog title="弹层标题" :visible="showDialog" @close="btnCancel">
  <el-form ref="roleForm" :model="form" :rules="rules" label-width="100px">
    <el-form-item label="角色名称" prop="name">
      <el-input v-model="form.name" placeholder="请输入角色名称" />
    </el-form-item>
    <el-form-item label="角色描述">
      <el-input v-model="form.description" placeholder="请输入角色描述" />
    </el-form-item>
  </el-form>

  <template #footer>
    <el-button @click="btnCancel">取消</el-button>
    <el-button type="primary">确认</el-button>
  </template>
</el-dialog>
  • 准备数据 - 注意: 这边接口文档字段有误,namedescription
data() {
  return {
    ...
    form: {
      name: '',
      description: ''
    },
    rules: {
      name: [
        { required: true, message: '请输入角色名称', trigger: ['blur', 'change'] }
      ]
    }
  }
},

总结

  1. 表单的角色描述的名称和接口文档不一致(接口文档有误)
  2. 表单验证

添加角色提交表单

步骤:

  1. 准备接口
  2. 表单验证
  3. 触发接口调用
  4. 刷新列表
  • 封装新增角色功能api setting.js
export function reqAddRole(data) {
  return request({
    url: '/sys/role',
    data,
    method: 'post'
  })
}
  • 校验完成添加功能
<el-button type="primary" @click="handleSubmit">确认</el-button>
// 添加角色提交表单
async handleSubmit () {
  // 添加角色,提交表单
  try {
    const ret = await reqAddRole(this.form)
    if (ret.code === 10000) {
      // 添加成功,关闭弹窗,属性列表
      this.isShowAddBox = false
      this.loadRoleList()
    } else {
      this.$message.error('添加角色失败')
    }
  } catch {
    this.$message.error('添加角色失败')
  }
},

总结:封装接口;绑定事件;验证表单;调用接口

  • 重置表单的用法
    • 重置表单的方法resetFields需要表单项有prop才可以
    • 也可以通过this.$options.data()的方式获取表单的原始数据
// 取消操作
handleCancel () {
  // 隐藏弹窗
  this.showDialog = false
  // this.$refs.roleForm.resetFields()
  // this.$options.data()表示data中的原始数据
  // 重置表单
  this.form = this.$options.data().form
},

总结:重置表单

  1. 直接调用表单组件的resetFields方法,可以重置验证提示信息
  2. 也可以借助this.$options.data()方式重置表单,不可以重置验证提示信息

编辑角色封装接口

编辑角色:

  1. 点击按钮加载角色的数据并且回填表单
  2. 修改信息后提交表单
  • 封装接口
// 修改角色
export function reqUpdateRole(data) {
  return request({
    method: 'put',
    url: `/sys/role/${data.id}`,
    data
  })
}

// 获取角色详情
export function reqGetRoleDetail(id) {
  return request({
    method: 'get',
    url: `/sys/role/${id}`
  })
}

编辑角色显示数据

  • 点击编辑按钮
<el-button size="small" type="primary" @click="handleEdit(row.id)">编辑</el-button>
  • 显示弹层, 获取数据回显
import { reqAddRole, reqDeleteRole, reqGetRoleDetail, reqGetRoleList } from '@/api/setting'

// 编辑显示弹窗
async handleEdit (id) {
  try {
    // 根据id获取该角色的信息,填充表单
    const ret = await reqGetRoleDetail(id)
    if (ret.code === 10000) {
      this.form = ret.data
      // 显示弹窗
      this.isShowAddBox = true
    }
  } catch {
    this.$message.error('获取角色信息失败')
  }
},
  • 计算属性 - 控制标题
computed: {
  title() {
    return this.form.id ? '编辑角色' : '添加角色'
  }
},
  • 编辑完成
// 添加角色提交表单
async handleSubmit () {
  // 添加橘色和编辑角色提交表单
  if (this.form.id) {
    // 编辑角色
    try {
      const ret = await reqUpdateRole(this.form)
      if (ret.code === 10000) {
        // 编辑成功,关闭弹窗,刷新列表
        this.isShowAddBox = false
        this.loadRoleList()
      }
    } catch {
      this.$message.error('编辑角色失败')
    }
  } else {
    // 添加角色
    try {
      const ret = await reqAddRole(this.form)
      if (ret.code === 10000) {
        // 添加成功,关闭弹窗,刷新列表
        this.isShowAddBox = false
        this.loadRoleList()
      }
    } catch {
      this.$message.error('添加角色失败')
    }
  }
},

总结:添加和编辑角色重用提交逻辑(通过表单数据的id存在与否区分两种操作)