利用el-table的 @selection-change="handleSelectionChange"实现左右动态显示且表格变化数据仍在

需求:左侧可控制右侧,右侧也可控制左侧。点搜索显示相应数据,右侧不会被清空,点击右侧X左侧对应勾选的数据会被取消
在这里插入图片描述

                  <el-table
                    class="table-class"
                    :data="tableData"
                    stripe
                    v-loading="tableLoading"
                    ref="multipleTable"
                    @selection-change="handleSelectionChange"
                  >
                    <el-table-column
                      type="selection"
                      align="center"
                      :width="$store.state.htmlSize * 5"
                    ></el-table-column>
                  </el-table>

由于列表的改变会触发handleSelectionChange事件,所以为了解决这个问题,需要用一个变量去控制这个状态,上述需求里面除了初始触发,还会有搜索触发的问题只要做到搜索触发时拦截即可。话不多说,代码如下:

<template>
  <div class="root">
    <el-dialog
      :visible="true"
      class="dialog-root"
      :show-close="false"
      :close-on-press-escape="false"
    >
      <div slot="title" class="dialog-title">
        <div class="dialong-text">
          <div class="title-icon"></div>
          <div class="title-text">关联设备</div>
        </div>
        <span class="el-icon-close i-close" @click="cancel" title="关闭"></span>
      </div>

      <div class="dialog-body">
        <div class="content">
          <div class="item content-left">
            <div class="tableRoot">
              <!-- 内容区域 -->
              <div class="tableContent">
                <div class="search-content" ref="searchContent">
                  <div class="search_main">
                    <div class="search-item">
                      <el-select
                        class="search-inp"
                        v-model="searchParam.param.devType"
                        clearable
                        placeholder="选择类型"
                      >
                        <el-option
                          v-for="item in optionsType"
                          :key="item.typeCode"
                          :label="item.typeName"
                          :value="item.typeCode"
                        ></el-option>
                      </el-select>
                    </div>
                    <div class="search-item">
                      <el-input
                        class="search-inp"
                        v-model="searchParam.param.devName"
                        clearable
                        placeholder="输入名称"
                      ></el-input>
                    </div>
                    <div class="search-item">
                      <el-button
                        class="query-btn"
                        icon="el-icon-search"
                        @click="searchTable"
                        >查 询</el-button
                      >
                    </div>
                  </div>
                </div>
                <!-- table 区域 -->
                <div class="table">
                  <el-table
                    class="table-class"
                    :data="tableData"
                    stripe
                    v-loading="tableLoading"
                    ref="multipleTable"
                    @selection-change="handleSelectionChange"
                  >
                    <el-table-column
                      type="selection"
                      align="center"
                      :width="$store.state.htmlSize * 5"
                    ></el-table-column>
                    <el-table-column
                      type="index"
                      :width="$store.state.htmlSize * 5"
                      align="center"
                      show-overflow-tooltip
                      label="序号"
                    ></el-table-column>
                    <el-table-column
                      prop="devTypeName"
                      align="center"
                      :formatter="formatterType"
                      show-overflow-tooltip
                      label="设备类型"
                    ></el-table-column>
                    <el-table-column
                      prop="devName"
                      align="center"
                      show-overflow-tooltip
                      label="设备名称"
                    ></el-table-column>
                  </el-table>
                </div>
              </div>
            </div>
          </div>
          <div class="item content-right">
            <div class="tableRoot">
              <!-- 内容区域 -->
              <div class="tableContent">
                <div class="search-content" ref="searchContent">
                  <div class="search_main">
                    <div class="search-item">
                      已选择{{ tableDataRight.length }}个设备
                    </div>
                  </div>
                </div>
                <div class="table">
                  <el-table
                    class="table-class"
                    :data="tableDataRight"
                    stripe
                    v-loading="tableLoading"
                  >
                    <el-table-column
                      :width="$store.state.htmlSize * 5"
                      align="center"
                      :render-header="renderHeader"
                    >
                      <template slot-scope="scope">
                        <div class="delTableItem">
                          <div
                            class="delItemIcon"
                            @click="delItemTable(scope.row)"
                          >
                            x
                          </div>
                        </div>
                      </template>
                    </el-table-column>
                    <el-table-column
                      type="index"
                      :width="$store.state.htmlSize * 5"
                      align="center"
                      show-overflow-tooltip
                      label="序号"
                    ></el-table-column>
                    <el-table-column
                      prop="devTypeName"
                      align="center"
                      :formatter="formatterType"
                      show-overflow-tooltip
                      label="设备类型"
                    ></el-table-column>
                    <el-table-column
                      prop="devName"
                      align="center"
                      show-overflow-tooltip
                      label="设备名称"
                    ></el-table-column>
                  </el-table>
                </div>
              </div>
            </div>
          </div>
        </div>
        <div slot="footer" class="dialog-footer">
          <div class="confirm-btn btn" @click="confirm">确 定</div>
          <div class="cancel-btn btn" @click="cancel">取 消</div>
        </div>
      </div>
    </el-dialog>
  </div>
</template>

<script>
import Api from "@/api/Api.js";
export default {
  props: {
    mainDevId: {
      type: [String, Number],
      default: () => "",
      required: true
    },
    optionsTypeEquip: {
      type: Array,
      default: () => [],
      required: true
    }
  },
  data() {
    return {
      searchParam: {
        current: 1,
        size: 9999999,
        param: {
          devCode: null,
          devName: null,
          devStatus: null,
          devType: null
        }
      },
      tableLoading: false,
      tableData: [],
      tableDataRight: [],
      hasRelatedTableList: [
        // {
        //   devCode: "999999999",
        //   devTypeName: "模拟已关联设备",
        //   devName: "测试数据"
        // }
      ],
      search: 0, // 1.搜索开始  0搜索结束
      value: "",
      optionsType: this.optionsTypeEquip,
      checkedList: [],
      mapListParam: [
        {
          mainDevId: this.mainDevId, //主设备id
          subDevId: "" //关联设备id
        }
      ],
      tableDataRightCodes: [], //右侧code集合
      leftCodes: [] //左侧列表code集合
    };
  },
  async mounted() {
    // 查询已经关联的设备信息 ==> 右侧列表需要显示已经关联的设置的信息
    let res = await this.getMapDevices();
    // 右侧列表需要显示已经关联的设置的信息
    if (res == 0) this.tableDataRight.unshift(...this.hasRelatedTableList);

    // 左边表格的原始信息
    this.getPages();
  },
  methods: {
    // 已选择的设备需要默认勾选
    defaultChoose(arr, tableArr, choose = true) {
      /*
      注意:这里不能直接遍历arr,element和item 他们在内存中的地址不同,所以他们是两份不同的数据,所以这么写 toggleRowSelection(element, true) 是不会回显选中的
       */
      for (let index = 0; index < tableArr.length; index++) {
        const item = tableArr[index];
        arr.forEach(element => {
          if (element.devCode == item.devCode) {
            this.$nextTick(() => {
              this.$refs.multipleTable.toggleRowSelection(item, choose);
            });
          }
        });
      }
    },
    // 查询已经关联的设备信息
    async getMapDevices() {
      let res = await Api.device.device.getMapDevices(this.mainDevId);
      if (res.code == 0) {
        this.hasRelatedTableList = res.data;
      }
      return res.code;
    },
    // 表格选中的数组
    handleSelectionChange(array) {
      if (this.search) return; //解决搜索右侧排序变化的问题
      // =================新增的情况====勾选复选框=========
      this.tableDataRightCodes = this.tableDataRight.map(dev => dev.devCode);
      array.forEach(dev => {
        if (this.tableDataRightCodes.indexOf(dev.devCode) < 0) {
          this.tableDataRight.push(dev);
        }
      });
      // =================取消选中左侧复选框的情况=============
      let changeCodes = array.map(dev => dev.devCode); //拿到当前被选中的全部code
      this.tableDataRight = this.tableDataRight.filter(
        dev =>
          !(
            this.leftCodes.indexOf(dev.devCode) >= 0 &&
            changeCodes.indexOf(dev.devCode) < 0
          )
      );
    },
    // 判断参数里面有没有空值有空值将值改为none
    initParamEmpty(obj) {
      let arrKeys = Object.keys(obj);
      arrKeys.map(v => {
        if (!obj[v]) {
          obj[v] = null;
        }
        return v;
      });
    },
    // 查询
    searchTable() {
      this.initParamEmpty(this.searchParam.param);
      this.search = 1;
      this.getPages();
    },
    // 将自己 this.mainDevId 主设备id 的这条数据 删除 因为设备不能关联本身 避免全选出bug 删除最为稳妥
    delSelfTable(array) {
      for (let index = 0; index < array.length; index++) {
        const item = array[index];
        if (item.devCode == this.mainDevId) {
          array.splice(index, 1);
        }
      }
      return array;
    },
    getPages() {
      Api.device.device.getPages(this.searchParam).then(res => {
        if (res.code == 0) {
          this.tableData = this.delSelfTable(res.data.data);
          this.leftCodes = this.tableData.map(dev => dev.devCode);
          this.defaultChoose(this.tableDataRight, this.tableData);
          this.$nextTick(() => {
            this.search = 0;
          });
        }
      });
    },
    // 类别格式化
    formatterType(row) {
      if (row.devTypeName != "unknown") {
        return row.devTypeName;
      } else {
        return "--";
      }
    },
    // 右边表格头部渲染函数
    renderHeader(h) {
      return h(
        "div", //  标签的名称
        {
          domProps: {
            innerHTML:
              '<div class="delTableItem"><span class="headerDelTable">x</span></div>'
          },
          on: {
            click: () => {
              this.delAllTable();
            }
          }
        },
        [h("span")]
      );
    },
    delAllTable() {
      this.tableDataRight = [];
      this.$refs.multipleTable.clearSelection();
      // this.defaultChoose([], this.tableData, false);
    },
    delItemTable(row) {
      // tableDataRight 对应删除这条数据
      // 左侧列表也要对应删除这条数据
      this.tableDataRight.forEach((item, index) => {
        if (item.devCode == row.devCode) {
          this.tableDataRight.splice(index, 1);
          this.defaultChoose([item], this.tableData, false);
        }
      });
    },
    cancel() {
      this.$emit("close");
    },
    confirm() {
      // 主设备id和关联设备id不能相同  前期已经做了删除,这里不用判断了
      this.mapListParam = [];
      this.tableDataRight.forEach(v => {
        let obj = {
          mainDevId: this.mainDevId, //主设备id
          subDevId: v.devCode //关联设备id
        };
        this.mapListParam.push(obj);
      });
      this.mapDevices(this.mapListParam);
    },
    // 关联设备
    mapDevices(param) {
      Api.device.device.mapDevices(param).then(res => {
        if (res.code == 0) {
          this.$message.success(res.data);
          this.$emit("submit");
        }
      });
    }
  }
};
</script>

<style lang="stylus" scoped>
>>>.headerDelTable {
  display: flex;
  justify-content: center;
  align-items: center;
  width: 100%;
  height: 80px;
  background: rgba(52, 89, 157, 0.6);
  border-radius: 4px;
  cursor: pointer;
  padding-bottom: 20px;
}

.dialog-root {
  /deep/.el-dialog {
    width: 4708px;
    height: 2292px;
  }

  .dialog-body {
    width: 4587px;
    height: 2050px;
  }

  .content {
    width: 100%;
    height: calc(100% - 200px);
    padding: 80px;
    display: flex;
    align-items: center;
    justify-content: center;
    font-size: 52px;
    font-family: Microsoft YaHei;
    font-weight: 400;
    color: #D3DCFF;

    .item {
      width: 50%;
      height: 100%;
    }

    .content-left {
      border-right: 2px solid rgba(68, 107, 255, 0.4);
    }

    .content-right {
      padding: 30px 0px 0px 60px;

      >>>.cell {
        > div {
          height: 100% !important;
        }
      }

      >>>.delTableItem {
        display: flex;
        justify-content: center;
        align-items: center;
        width: 100px;
        height: 100%;
        border-radius: 4px;

        // border:5px solid red;
        .delItemIcon {
          display: flex;
          justify-content: center;
          align-items: center;
          width: 100%;
          height: 80px;
          background: rgba(52, 89, 157, 0.6);
          border-radius: 4px;
          cursor: pointer;
          padding-bottom: 20px;
        }
      }
    }
  }

  .tableRoot {
    width: 100%;
    height: 100%;
    color: #fff;
    padding: 0px 60px 40px 0;

    .search-inp {
      width: 720px;

      /deep/.el-input__inner {
        width: 100%;
        font-size: 52px;
        background: rgba(26, 39, 100, 0.6);
        border: 2px solid #2D449D;
        border-radius: 12px;
      }
    }

    .search-content {
      margin-top: 0;
    }

    .search-content .search_main {
      padding: 0;
      background: none;
      border: 0;

      .search-item {
        margin-right: 80px;
      }

      .search-item:last-child {
        margin-right: 0;
      }
    }

    .query-btn {
      width: 500px;
      height: 130px;
    }

    .table {
      background: none;
      border: 0;
      padding: 0;

      // border:5px solid yellow;
      .table-class {
        width: 100%;
        height: 1460px;
        overflow-y: scroll;
      }

      >>>.el-checkbox__inner {
        width: 68px;
        height: 68px;
        transition: none;
        border-color: #89c9ff;
        border-radius: 8px;
      }

      >>>.el-checkbox__input.is-checked .el-checkbox__inner::after {
        height: 40px;
        width: 20px;
        left: 18px;
        /* top: px; */
        border-width: 10px;
        border-radius: 10px;
      }

      >>>.el-checkbox__input.is-indeterminate .el-checkbox__inner::before {
        top: 25px;
        height: 10px;
      }

      >>>.el-checkbox {
        padding-left: 2px;
      }
    }
  }
}
</style>


Logo

为开发者提供学习成长、分享交流、生态实践、资源工具等服务,帮助开发者快速成长。

更多推荐