vxe-table + ant design 实现 树形表格增删改、行上移、下移。

一、功能说明

1. 效果图

在这里插入图片描述

2. 说明

  1. 新增:新增表格父行
  2. 新增:新增表格子行
  3. 删除:删除父行
  4. 更多下拉菜单(上移):上移父行 / 子行
  5. 更多下拉菜单(下移):下移父行 / 子行
  6. 编辑:父行只有名称列可编辑,子行没有限制。触发方式为点击单元格。

二、实现

<template>
  <div class="box">
    <span @click="addParent" style="margin-bottom:5px">
      <a-icon type="plus-circle" style="margin-right:5px" />新增
    </span>

    <a-spin :spinning="spinning">
      <vxe-table
        border
        resizable
        auto-resize
        show-overflow
        highlight-hover-row
        highlight-current-row
        ref="xTable"
        row-id="id"
        max-height="500px"
        :data="tableData"
        :edit-config="{
    
    
        trigger: 'click',
        mode: 'cell',
        activeMethod: activeMethod
        }"
        :tree-config="{ children: 'children' }"
      >
        <vxe-column field="name" title="名称" :edit-render="{}" tree-node>
          <template #edit="{ row }">
            <vxe-input v-model="row.name" type="text"></vxe-input>
          </template>
        </vxe-column>
        <vxe-column field="code" title="代号" :edit-render="{}">
          <template #edit="{ row }">
            <vxe-input v-model="row.code" type="text"></vxe-input>
          </template>
        </vxe-column>
        <vxe-column field="condition" title="条件" :edit-render="{}">
          <template #edit="{ row }">
            <vxe-input v-model="row.condition" type="text"></vxe-input>
          </template>
        </vxe-column>
        <vxe-column title="操作" fixed="right">
          <template #default="{ row,rowIndex }">
            <!-- 父行操作按钮 -->
            <span v-if="'children' in row">
              <span @click="addChild(row, rowIndex)" class="op-btn">新增</span>
              <span @click="deleteParent(row, rowIndex)" class="op-btn">删除</span>
              <a-dropdown :trigger="['click']">
                <a @click.prevent>
                  <a-icon type="dash" style="color:black;transform: rotate(90deg);" />
                </a>
                <template #overlay>
                  <a-menu>
                    <a-menu-item :key="0" @click="upRow(row, rowIndex)">上移</a-menu-item>
                    <a-menu-item :key="1" @click="downRow(row, rowIndex)">下移</a-menu-item>
                  </a-menu>
                </template>
              </a-dropdown>
            </span>
            <!-- 子行操作按钮 -->
            <span v-else>
              <span @click="deleteChild(row, rowIndex)" class="op-btn">删除</span>
              <span @click="upRow(row, rowIndex)" class="op-btn">上移</span>
              <span @click="downRow(row, rowIndex)" class="op-btn">下移</span>
            </span>
          </template>
        </vxe-column>
      </vxe-table>
    </a-spin>
  </div>
</template>

<script>

export default {
    
    
  data() {
    
    
    return {
    
    
      spinning: false, // 表格加载状态
      tableData: [], // 表格数据
      moveArray: [] // 移动数组
    }
  },
  async created() {
    
    
    await this.getTableData()
  },
  methods: {
    
    
    // 获取表格数据
    async getTableData() {
    
    
      // 1.开启表格加载状态
      this.spinning = true
      // 2.获取表格数据
      this.tableData = [
        {
    
    
          creator: '小红',
          code: 'xh',
          name: '工艺1',
          description: '',
          condition: '',
          id: 1,
          children: [
            {
    
    
              creator: '红红',
              code: 'hh',
              name: '工艺11',
              condition: '',
              description: '',
              id: 11
            },
            {
    
    
              creator: '花花',
              code: 'hh',
              name: '工艺12',
              condition: '',
              description: '',
              id: 12
            },
            {
    
    
              creator: 'aa',
              code: 'hh',
              name: '工艺13',
              condition: '',
              description: '',
              id: 13
            }
          ]
        },
        {
    
    
          creator: '小蓝',
          code: 'xl',
          name: '工艺2',
          description: '',
          condition: '',
          id: 2,
          children: [
            {
    
    
              creator: '蓝蓝',
              code: 'll',
              name: '工艺22',
              condition: '',
              description: '',
              id: 21
            }
          ]
        },
        {
    
    
          creator: '小白',
          code: 'xb',
          name: '工艺3',
          condition: '',
          description: '',
          id: 3,
          children: []
        }
      ]
      // 3.关闭表格加载状态
      this.spinning = false
    },
    // 新增表格父行
    addParent() {
    
    
      const record = {
    
    
        name: '',
        code: '',
        condition: '',
        id: this.getGUID(),
        children:[]
      }
      this.tableData.push(record)
      this.$message.success('新增成功!')
    },
    // 删除父行
    deleteParent(row, rowIndex) {
    
    
      this.tableData.splice(rowIndex, 1)
      this.$message.success('删除成功!')
    },
    // 删除子
    deleteChild(row) {
    
    
      let info = this.findChildIndex(this.tableData, row.id)
      this.tableData[info[1]].children.splice(info[0], 1)
      this.$message.success('删除成功!')
    },
    // 下移行
    downRow(row, rowIndex) {
    
    
      // 1.默认是父行的数据
      let index = rowIndex
      this.moveArray = this.tableData
      // 2.如果上移子行,需要找到子行索引和父行索引
      if ('children' in row === false) {
    
    
        // 找子行、父行索引
        let info = this.findChildIndex(this.tableData, row.id)
        // 更新数据
        index = info[0]
        this.moveArray = this.tableData[info[1]].children
      }
      // 3.是最后一行
      if (index === this.moveArray.length - 1) {
    
    
        this.$message.warning('此行不能下移!')
      } else {
    
    
        // 4.不是最后一行
        this.moveArray = this.swapItem(this.moveArray, index, index + 1)
        this.$message.success('下移成功!')
      }
    },
    // 上移行
    upRow(row, rowIndex) {
    
    
      // 1.默认是父行的数据
      let index = rowIndex
      this.moveArray = this.tableData
      // 2.如果上移子行,需要找到子行索引和父行索引
      if ('children' in row === false) {
    
    
        // 找子行、父行索引
        let info = this.findChildIndex(this.tableData, row.id)
        // 更新数据
        index = info[0]
        this.moveArray = this.tableData[info[1]].children
      }
      // 3.是第一行
      if (index === 0) {
    
    
        this.$message.warning('此行不能上移!')
      } else {
    
    
        // 4.不是第一行
        this.moveArray = this.swapItem(this.moveArray, index, index - 1)
        this.$message.success('上移成功!')
      }
    },
    swapItem(arr, index1, index2) {
    
    
      arr[index1] = arr.splice(index2, 1, arr[index1])[0]
      return arr
    },
    // 判断单元格是否可编辑
    activeMethod({
     
      row, column }) {
    
    
      // 父行只有名称可编辑
      let tag =
        'children' in row &&
        ['code', 'condition'].includes(column.property)
      return !tag
    },
    // 新增子
    addChild(row, rowIndex) {
    
    
      const record = {
    
    
        name: '',
        code: '',
        condition: '',
        description: '',
        id: this.getGUID()
      }
      this.tableData[rowIndex].children.push(record)
      this.$message.success('新增成功!')
    },
    // 找到子行的索引、父行索引
    findChildIndex(data, id) {
    
    
      let result = []
      function find(data, id, parentId) {
    
    
        for (let i = 0; i < data.length; i++) {
    
    
          if (result.length > 0) {
    
    
            return
          }
          if (data[i].id === id) {
    
    
            result.push(i)
            result.push(parentId)
          }
          if (data[i].children && data[i].children.length > 0) {
    
    
            find(data[i].children, id, i)
          }
        }
      }
      find(data, id, 0)
      return result
    },
    // 随机生成id
    getGUID() {
    
    
      var d = new Date().getTime()
      var uuid = 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(
        /[xy]/g,
        function (c) {
    
    
          var r = (d + Math.random() * 16) % 16 | 0
          d = Math.floor(d / 16)
          return (c == 'x' ? r : (r & 0x3) | 0x8).toString(16)
        }
      )
      return uuid
    }
  }
}
</script>

<style>
.box {
    
    
  width: 1000px;
  margin: 100px;
}

.op-btn {
    
    
  margin: 0 2px;
  cursor: pointer;
}
</style>

三、导入

猜你喜欢

转载自blog.csdn.net/qq_45325810/article/details/129752898