人力资源管理后台 === 左树右表

1.角色管理-编辑角色-进入行内编辑

  • 获取数据之后针对每个数据定义标识-使用$set-代码位置(src/views/role/index.vue)

    // 针对每一行数据添加一个编辑标记
    this.list.forEach(item => {
    // item.isEdit = false // 添加一个属性 初始值为false
    // 数据响应式的问题 数据变化 视图更新
    // 添加的动态属性 不具备响应式特点
    // this.set(目标对象, 属性名称, 初始值) 可以针对目标对象 添加的属性 添加响应式 this.set(item, 'isEdit', false)
    })

为什么不使用item.isEdit = false , 因为动态添加的属性不具备响应式的特点,如果想要具备响应式,可以使用$set

  • 点击编辑时,将当前行的标记isEdit设置为true-代码位置(src/views/role/index.vue)

    <el-table-column align="center" label="操作"> <template> <el-button size="mini" type="text">分配权限</el-button> <el-button size="mini" type="text" @click="btnEditRow(row)">编辑</el-button> <el-button size="mini" type="text">删除</el-button> </template> </el-table-column>
  • 点击编辑的方法-代码位置(src/views/role/index.vue)

    复制代码
      // 点击编辑行
      btnEditRow(row) {
        row.isEdit = true // 改变行的编辑状态
      }
  • 表格列中根据当前的isEdit标记-渲染结构-代码位置(src/views/role/index.vue)

    <el-table-column prop="name" align="center" width="200" label="角色"> <template v-slot="{ row }"> <el-input v-if="row.isEdit" size="mini" /> {{ row.name }} </template> </el-table-column> <el-table-column prop="state" align="center" width="200" label="启用"> <template v-slot="{ row }"> <el-switch v-if="row.isEdit" /> {{ row.state === 1 ? "已启用" : row.state === 0 ? "未启用" : "无" }} </template> </el-table-column> <el-table-column prop="description" align="center" label="描述"> <template v-slot="{ row }"> <el-input v-if="row.isEdit" type="textarea" /> {{ row.description }} </template> </el-table-column> <el-table-column align="center" label="操作"> <template v-slot="{ row }"> <template v-if="row.isEdit"> <el-button type="primary" size="mini">确定</el-button> <el-button size="mini">取消</el-button> </template> <template v-else> <el-button size="mini" type="text">分配权限</el-button> <el-button size="mini" type="text" @click="btnEditRow(row)">编辑</el-button> <el-button size="mini" type="text">删除</el-button> </template> </template> </el-table-column>

$set的应用

  • this.$set(目标对象, 属性名称, 初始值 )
  • 等价于 Vue.set(目标对象, 属性名称, 初始值)
  • 向响应式对象中添加一个属性,并确保这个新属性同样是响应式的,且触发视图更新。

2.角色管理-行内编辑-数据缓存

为什么要做数据缓存?

答: 因为编辑时,可以取消会滚到之前的状态,所以编辑时的数据是临时的数据。

如图,editRow的数据是针对当前行的数据做了一份拷贝,针对这个拷贝,我们可以随意修改。

  • 初始化时缓存数据-代码位置(src/views/role/index.vue)

    复制代码
      this.list.forEach(item => {
          // item.isEdit = false // 添加一个属性 初始值为false
          // 数据响应式的问题  数据变化 视图更新
          // 添加的动态属性 不具备响应式特点
          // this.$set(目标对象, 属性名称, 初始值) 可以针对目标对象 添加的属性 添加响应式
          this.$set(item, 'isEdit', false)
          this.$set(item, 'editRow', {
            name: item.name,
            state: item.state,
            description: item.description
          })
    })
  • 点击编辑时更新缓存数据-代码位置(src/views/role/index.vue)

    btnEditRow(row) {
    row.isEdit = true // 改变行的编辑状态
    // 更新缓存数据
    row.editRow.name = row.name
    row.editRow.state = row.state
    row.editRow.description = row.description
    }

  • 将编辑时的表单双向绑定缓存数据-代码位置(src/views/role/index.vue)

    复制代码
          <el-table-column prop="name" align="center" width="200" label="角色">
            <template v-slot="{ row }">
              <!-- 条件判断 -->
              <el-input v-if="row.isEdit" v-model="row.editRow.name" size="mini" />
              <span v-else>{{ row.name }}</span>
            </template>
          </el-table-column>
          <el-table-column prop="state" align="center" width="200" label="启用">
            <!-- 自定义列结构 -->
            <template v-slot="{ row }">
              <!-- 开 1 关 0 -->
              <el-switch v-if="row.isEdit" v-model="row.editRow.state" :active-value="1" :inactive-value="0" />
              <span v-else>  {{ row.state === 1 ? "已启用" : row.state === 0 ? "未启用" : "无" }} </span>
            </template>
          </el-table-column>
          <el-table-column prop="description" align="center" label="描述">
            <template v-slot="{ row }">
              <el-input v-if="row.isEdit" v-model="row.editRow.description" size="mini" type="textarea" />
              <span v-else>{{ row.description }}</span>
            </template>
          </el-table-column>

3.角色管理-编辑角色-确定取消

  • 封装更新角色信息的API-代码位置(src/api/role.js)

    /**

    • 更新角色
    • ***/

    export function updateRole(data) {
    return request({
    url: /sys/role/${data.id},
    method: 'put',
    data
    })
    }

  • 确定方法-代码位置(src/views/role/index.vue)

    <el-button type="primary" size="mini" @click="btnEditOK(row)">确定</el-button>

    // 点击确定时触发
    async btnEditOK(row) {
    if (row.editRow.name && row.editRow.description) {
    // 下一步操作
    await updateRole({ ...row.editRow, id: row.id })
    // 更新成功
    this.message.success('更新角色成功') // 更新显示数据 退出编辑状态 // row.name = row.editRow.name // eslint的一校验 误判 // Object.assign(target, source) Object.assign(row, { ...row.editRow, isEdit: false // 退出编辑模式 }) // 规避eslint的误判 } else { this.message.warning('角色和描述不能为空')
    }
    }

注意: 这里既然更新成功了,要把缓存数据回显到页面上,并且关闭编辑模式

  • 取消方法-代码位置(src/views/role/index.vue)

    <el-button size="mini" @click="row.isEdit = false">取消</el-button>

4.角色管理-删除角色

  • 封装删除角色的API-代码位置(src/api/role.js)

    /** *

    • 删除角色
    • **/

    export function delRole(id) {
    return request({
    url: /sys/role/${id},
    method: 'delete'
    })
    }

  • 在删除位置加入气泡框-代码位置(src/views/role/index.vue)

    <el-popconfirm title="这是一段内容确定删除吗?" @onConfirm="confirmDel(row.id)" >
    <el-button slot="reference" style="margin-left:10px" size="mini" type="text">删除</el-button>
    </el-popconfirm>

注意:这里element-ui文档有点问题,el-popconfirm的确认事件是onConfirm,但是文档上写的是confirm事件,这里需要注意

  • 删除方法-代码位置(src/views/role/index.vue)

    async confirmDel(id) {
    await delRole(id) // 后端删除
    this.$message.success('删除角色成功')
    // 删除的如果是最后一个
    if (this.list.length === 1) this.pageParams.page--
    this.getRoleList()
    }

5.员工管理-页面结构

  • 基本的页面结构-代码位置(src/views/employee/index.vue)

    <template>
    <el-input style="margin-bottom:10px" type="text" prefix-icon="el-icon-search" size="small" placeholder="输入员工姓名全员搜索" />
    <el-row class="opeate-tools" type="flex" justify="end"> <el-button size="mini" type="primary">添加员工</el-button> <el-button size="mini">excel导入</el-button> <el-button size="mini">excel导出</el-button> </el-row>
    </template> <script> export default { name: 'Employee' } </script> <style lang="scss" scoped> .app-container { background: #fff; display: flex; .left { width: 280px; padding: 20px; border-right: 1px solid #eaeef4; } .right { flex: 1; padding: 20px; .opeate-tools { margin:10px ; } .username { height: 30px; width: 30px; line-height: 30px; text-align: center; border-radius: 50%; color: #fff; background: #04C9BE; font-size: 12px; display:inline-block; } } } </style>

6.员工管理-左侧树的加载

  • 定义树组件需要的数据-代码位置(src/views/employee/index.vue)

    data() {
    return {
    depts: [], // 组织数据
    defaultProps: {
    label: 'name',
    children: 'children'
    }
    }
    }

  • 放置树形组件-代码位置(src/views/employee/index.vue)

    <el-tree :data="depts" :props="defaultProps" default-expand-all :expand-on-click-node="false" highlight-current />

  • 初始化时加载数据转化树形-代码位置(src/views/employee/index.vue)

    复制代码
    created() {
      this.getDepartment()
    },
    methods: {
      async getDepartment() {
        // 递归方法 将列表转化成树形
        // let result = await getDepartment()
        this.depts = transListToTreeData(await getDepartment(), 0)
      }
    }

7.员工管理-选中首个节点

  • 在data中声明一个记录id的参数-代码位置(src/views/employee/index.vue)

    data () {
    return {
    // 存储查询参数
    queryParams: {
    departmentId: null
    }
    }
    }

为什么要放在queryParams中,因为后面的查询会有很多查询条件,到时候查询条件都会聚合到一起,所以使用一个公共的对象来管理更方便和合适

  • 初始化时首个id节点,并且选中-代码位置(src/views/employee/index.vue)

    methods: {
    async getDepartment() {
    // 递归方法 将列表转化成树形
    // let result = await getDepartment()
    this.depts = transListToTreeData(await getDepartment(), 0)
    this.queryParams.departmentId = this.depts[0].id
    // 设置选中节点
    // 树组件渲染是异步的 等到更新完毕
    this.nextTick(() => { // 此时意味着树渲染完毕 this.refs.deptTree.setCurrentKey(this.queryParams.departmentId)
    })
    }
    }

为什么使用��������,因为我们设置完树形之后立刻选中首个节点,此时更新还没有完成,必须等待更新完成后,再去选中首个节点,所以需要使用nextTick,因为我们设置完树形之后立刻选中首个节点,此时更新还没有完成,必须等待更新完成后,再去选中首个节点,所以需要使用nextTick

  • 监听树组件的节点切换事件-代码位置(src/views/employee/index.vue)

    <el-tree
    ref="deptTree"
    node-key="id"
    :data="depts"
    :props="defaultProps"
    default-expand-all
    :expand-on-click-node="false"
    highlight-current
    @current-change="selectNode"
    />

这里需要明白,需要给定node-key属性,否则setCurrentKey方法不知道设置的是哪个字段的值

  • 切换节点时再次记录id-代码位置(src/views/employee/index.vue)

    selectNode(node) {
    this.queryParams.departmentId = node.id
    }

8.员工管理-员工列表结构

  • 右侧列表页面结构-代码位置(src/views/employee/index.vue)

    <el-table> <el-table-column align="center" label="头像" /> <el-table-column label="姓名" /> <el-table-column label="手机号" sortable /> <el-table-column label="工号" sortable /> <el-table-column label="聘用形式" /> <el-table-column label="部门" /> <el-table-column label="入职时间" sortable /> <el-table-column label="操作" width="280px"> <template> <el-button 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-row style="height: 60px" align="middle" type="flex" justify="end"> <el-pagination layout="total,prev, pager, next" :total="1000" /> </el-row>

9.员工管理-获取员工数据

第一次加载之后 或者是切换节点之后,都要去根据点击的节点去查询员工的数据

  • 封装获取员工数据的API-代码位置(src/api/employee.js)

    export function getEmployeeList(params) {
    return request({
    url: '/sys/user',
    params // 地址参数 查询参数
    })
    }

  • 声明一个list数据进行接受list-代码位置(src/views/employee/index.vue)

    data () {
    return {
    list: []
    }
    }

  • 初始化后获取右侧表格数据-代码位置(src/views/employee/index.vue)

    methods: {
    async getDepartment() {
    // 递归方法 将列表转化成树形
    // let result = await getDepartment()
    this.depts = transListToTreeData(await getDepartment(), 0)
    this.queryParams.departmentId = this.depts[0].id
    // 设置选中节点
    // 树组件渲染是异步的 等到更新完毕
    this.nextTick(() => { // 此时意味着树渲染完毕 this.refs.deptTree.setCurrentKey(this.queryParams.departmentId)
    })
    // 这个时候参数 记录了id
    this.getEmployeeList()
    },
    // 获取员工列表的方法
    async getEmployeeList() {
    const { rows } = await getEmployeeList(this.queryParams)
    this.list = rows
    }
    }

  • 切换节点时,获取右侧表格数据-代码位置(src/views/employee/index.vue)

    selectNode(node) {
    this.queryParams.departmentId = node.id // 重新记录了参数
    this.getEmployeeList()
    },

  • 绑定表格-代码位置(src/views/employee/index.vue)

    <el-table :data="list"> <el-table-column prop="staffPhoto" align="center" label="头像" /> <el-table-column prop="username" label="姓名" /> <el-table-column prop="mobile" label="手机号" sortable /> <el-table-column prop="workNumber" label="工号" sortable /> <el-table-column prop="formOfEmployment" label="聘用形式" /> <el-table-column prop="departmentName" label="部门" /> <el-table-column prop="timeOfEntry" label="入职时间" sortable /> ... </el-table>

10.员工管理-头像和聘用形式的处理

  • 头像的设置-代码位置(src/views/employee/index.vue)

    <el-table-column prop="staffPhoto" align="center" label="头像"> <template v-slot="{ row }"> <el-avatar v-if="row.staffPhoto" :src="row.staffPhoto" :size="30" /> {{ row.username?.charAt(0) }} </template> </el-table-column>
  • 聘用形式的处理-代码位置(src/views/employee/index.vue)

    <el-table-column prop="formOfEmployment" label="聘用形式"> <template v-slot="{ row }"> 正式 非正式 </template> </el-table-column>

11.员工管理-员工分页处理

  • 定义分页参数-代码位置(src/views/employee/index.vue)

    data () {
    return {
    queryParams: {
    departmentId: null,
    page: 1, // 当前页码
    pagesize: 10
    },
    total: 0, // 记录员工的总数
    }
    }

  • 绑定分页参数-代码位置(src/views/employee/index.vue)

    <el-pagination
    layout="total,prev, pager, next"
    :total="total"
    :current-page="queryParams.page"
    :page-size="queryParams.pagesize"
    @current-change="changePage"
    />

  • 切换页码事件-代码位置(src/views/employee/index.vue)

    // 切换页码
    changePage(newPage) {
    this.queryParams.page = newPage // 赋值新页码
    this.getEmployeeList() // 查询数据
    }

  • 切换部门时,查询第一页数据-代码位置(src/views/employee/index.vue)

    selectNode(node) {
    this.queryParams.departmentId = node.id // 重新记录了参数
    this.queryParams.page = 1 // 设置第一页
    this.getEmployeeList()
    },

  • 设置ElementUI的语言为中文-代码位置(src/main.js)

    Vue.use(ElementUI)

12.员工管理-员工模糊搜索

  • 设置模糊搜索的参数字段-代码位置(src/views/employee/index.vue)

    data () {
    return {
    queryParams: {
    departmentId: null,
    page: 1, // 当前页码
    pagesize: 10,
    keyword: '' // 模糊搜索字段
    },
    }
    }

  • 双向绑定input输入框,监听值改变事件-代码位置(src/views/employee/index.vue)

    <el-input
    v-model="queryParams.keyword"
    style="margin-bottom:10px"
    type="text"
    prefix-icon="el-icon-search"
    size="small"
    placeholder="输入员工姓名全员搜索"
    @input="changeValue"
    />

这里监听的事件是input,有同学可能会问,为什么不用change事件,注意change事件是离开焦点触发,input是只要内容发生变化就会触发,所以这里使用input更符合使用场景

  • 值改变查询数据-支持防抖查询-代码位置(src/views/employee/index.vue)

    changeValue() {
    // 单位时间内只执行最后一次
    // this的实例上赋值了一个timer的属性
    clearTimeout(this.timer) // 清理上一次的定时器
    this.timer = setTimeout(() => {
    this.queryParams.page = 1
    this.getEmployeeList()
    }, 300)
    }

相关推荐
技术钱几秒前
vue3基于 Vxe Table 实现可拖拽分组 + 动态求和的高级表格
javascript·vue.js
还是大剑师兰特1 分钟前
Vue3 + Element Plus 日期选择器:开始 / 结束时间,结束时间不超过今天
前端·javascript·vue.js
不会写DN2 分钟前
Js常用数组处理
开发语言·javascript·ecmascript
还是大剑师兰特3 分钟前
数组中有两个数据,将其变成字符串
开发语言·javascript·vue.js
Saga Two4 分钟前
Vue实现核心原理
前端·javascript·vue.js
技术钱4 分钟前
vue3实现时间根据系统时区转换对应的时间
javascript·vue.js
殷忆枫11 分钟前
基于STM32的ML307R连接Onenet平台
服务器·前端·javascript
Java 码农12 分钟前
vue cli 环境搭建
前端·javascript·vue.js
酉鬼女又兒17 分钟前
零基础入门前端JavaScript Object 对象完全指南:从基础到进阶(可用于备赛蓝桥杯Web应用开发赛道)
开发语言·前端·javascript·职场和发展·蓝桥杯
RPGMZ20 分钟前
RPGMakerMZ游戏引擎 地图角色顶部显示称号
javascript·游戏引擎·rpgmz·rpgmakermz