el-table合并行,控制全选框的可选状态

给相同的类合并行

 <el-table
            border
            class="customer-no-border-table"
            element-loading-text="数据正在加载中..."
            :row-class-name="tableRowClassName"
            :header-cell-style="{ background: '#E7F2FD', color: '#252525' }"
            style="width: 100%; border-top: 1px solid #409eff"
            :cell-style="{ borderColor: '#1890ff' }"
            v-loading="leftLoading"
            ref="leftTable"
            :data="leftTable"
            @row-click="getItem"
            highlight-current-row
            height="400"
            :span-method="objectSpanMethod"
          >
            <el-table-column
              prop="detailTypeGroupStr"
              align="center"
              width="100"
            >
            </el-table-column>
            <el-table-column
              label="升级对象"
              prop="detailTypeStr"
              align="center"
            >
              <template slot-scope="{ row, $index }">
                <div
                  style="
                    display: flex;
                    justify-content: space-around;
                    align-items: center;
                  "
                >
                  <div>{{ row.detailTypeStr }}</div>
                  <div>
                    <el-button
                      type="primary"
                      size="small"
                      style="margin-left: 20px"
                      v-if="
                        (row.flagIndex !== 0 && row.detailTypeGroup === 11) ||
                        (row.flagIndex !== 0 && row.detailTypeGroup === 12)
                      "
                      @click="oneClickSet(row)"
                      >一键同步</el-button
                    >
                  </div>
                </div>
              </template>
            </el-table-column>
</el-table>
  this.leftTable = res.data;
          this.getSpanArr(res.data);
          // 给要显示一键设置按钮的行,添加flagIndex标识
          const newArray = this.leftTable.map((i, index) => {
            const j = this.spanArr[index];
            return {
              ...i,
              flagIndex: j,
            };
          });
          this.leftTable = newArray;

 // 合并行
    objectSpanMethod({ rowIndex, columnIndex }) {
      if (columnIndex === 0) {
        const _row = this.spanArr[rowIndex];
        const _col = _row > 0 ? 1 : 0;
        return {
          // [0,0] 表示这一行不显示, [2,1]表示行的合并数
          rowspan: _row,
          colspan: _col,
        };
      }
    },
    getSpanArr(data) {
      // data就是我们从后台拿到的数据
      for (let i = 0; i < data.length; i++) {
        //如果是第一条记录(索引为0),向数组中加入1,并设置索引位置
        if (i === 0) {
          this.spanArr.push(1);
          this.pos = 0; //spanArr的索引
        } else {
          //如果不是第一条记录,则判断它与前一条记录是否相等
          //根据相同 扣分类别名称 进行合并,根据需要可进行修改
          if (data[i].detailTypeGroup === data[i - 1].detailTypeGroup) {
            //如果相等,则向spanArr中添入元素0,并将前一位元素+1,表示合并行数+1
            this.spanArr[this.pos] += 1;
            this.spanArr.push(0);
          } else {
            this.spanArr.push(1);
            this.pos = i;
          }
        }
      }
    },

禁止选中

  <el-table
            border
            class="customer-no-border-table"
            element-loading-text="数据正在加载中..."
            :row-class-name="tableRowClassName"
            :header-cell-style="{ background: '#E7F2FD', color: '#252525' }"
            style="width: 100%; border-top: 1px solid #409eff"
            v-loading="centerLoading"
            ref="centerTable"
            :data="centerTable"
            highlight-current-row
            height="400"
            :row-key="rowKey"
            @row-click="getItemCenter"
            :header-cell-class-name="cellClass"
          >
            <el-table-column
              align="center"
              :resizable="false"
              :render-header="renderHeader"
              width="55"
            >
              <template #default="scope">
                <el-checkbox
                  v-model="scope.row.checked"
                  @change="select(scope.row)"
                  :disabled="disabled()"
                />
              </template>
            </el-table-column>
            <el-table-column
              label="硬件类型"
              prop="deviceDictCodeStr"
              align="center"
            ></el-table-column>
            <div slot="empty">
              <img
                alt="暂无数据"
                src="@/assets/noReport.png"
                style="margin-top: 80px"
              />
            </div>
          </el-table>
computed: {
    cellClass() {
      if (
        (this.leftItem.detailTypeGroup == 11 && this.leftItem.flagIndex == 0) ||
        (this.leftItem.detailTypeGroup == 12 && this.leftItem.flagIndex == 0)
      ) {
        return "DisableSelection";
      }
    },
  },
methods:{
 // 控制选择硬件的多选框能否被点击
    disabled() {
      // 有一键设置的时候, 不能编辑下面的厂商;
      if (
        (this.leftItem.detailTypeGroup == 11 && this.leftItem.flagIndex == 0) ||
        (this.leftItem.detailTypeGroup == 12 && this.leftItem.flagIndex == 0)
      ) {
        return true;
      } else {
        return false;
      }
    }
}

完整代码:

<template>
  <div>
    <div class="bigBox">
      <div class="leftBox">
        <div class="title">
          <div class="img">
            <img src="@/assets/upgradeObject.png" alt="升级对象" />
          </div>
          <div class="text">升级对象</div>
        </div>
        <el-form :inline="true" class="searchBox">
          <el-form-item>
            <el-input
              v-model.trim="upgradeObject"
              placeholder="请输入升级对象"
              clearable
            ></el-input>
          </el-form-item>

          <el-form-item>
            <el-button type="primary" class="searchBut" @click="searchLeftTable"
              >搜 索</el-button
            >
          </el-form-item>
        </el-form>
        <div class="leftTable">
          <el-table
            border
            class="customer-no-border-table"
            element-loading-text="数据正在加载中..."
            :row-class-name="tableRowClassName"
            :header-cell-style="{ background: '#E7F2FD', color: '#252525' }"
            style="width: 100%; border-top: 1px solid #409eff"
            :cell-style="{ borderColor: '#1890ff' }"
            v-loading="leftLoading"
            ref="leftTable"
            :data="leftTable"
            @row-click="getItem"
            highlight-current-row
            height="400"
            :span-method="objectSpanMethod"
          >
            <el-table-column
              prop="detailTypeGroupStr"
              align="center"
              width="100"
            >
            </el-table-column>
            <el-table-column
              label="升级对象"
              prop="detailTypeStr"
              align="center"
            >
              <template slot-scope="{ row, $index }">
                <div
                  style="
                    display: flex;
                    justify-content: space-around;
                    align-items: center;
                  "
                >
                  <div>{{ row.detailTypeStr }}</div>
                  <div>
                    <el-button
                      type="primary"
                      size="small"
                      style="margin-left: 20px"
                      v-if="
                        (row.flagIndex !== 0 && row.detailTypeGroup === 11) ||
                        (row.flagIndex !== 0 && row.detailTypeGroup === 12)
                      "
                      @click="oneClickSet(row)"
                      >一键同步</el-button
                    >
                  </div>
                </div>
              </template>
            </el-table-column>
            <div slot="empty">
              <img
                alt="暂无数据"
                src="@/assets/noReport.png"
                style="margin-top: 80px"
              />
            </div>
          </el-table>
        </div>
      </div>
      <div v-if="isShow" class="rightBox">
        <div class="centerTable">
          <div class="title">
            <div class="img">
              <img src="@/assets/hardwareType.png" alt="硬件类型" />
            </div>
            <div class="text">硬件类型</div>
          </div>
          <el-form :inline="true" class="searchBox">
            <el-form-item>
              <el-input
                v-model.trim="hardwareType"
                placeholder="请输入硬件类型"
                clearable
              ></el-input>
            </el-form-item>

            <el-form-item>
              <el-button
                type="primary"
                class="searchBut"
                @click="searchCenterTable"
                >搜 索</el-button
              >
            </el-form-item>
          </el-form>
          <el-table
            border
            class="customer-no-border-table"
            element-loading-text="数据正在加载中..."
            :row-class-name="tableRowClassName"
            :header-cell-style="{ background: '#E7F2FD', color: '#252525' }"
            style="width: 100%; border-top: 1px solid #409eff"
            v-loading="centerLoading"
            ref="centerTable"
            :data="centerTable"
            highlight-current-row
            height="400"
            :row-key="rowKey"
            @row-click="getItemCenter"
            :header-cell-class-name="cellClass"
          >
            <el-table-column
              align="center"
              :resizable="false"
              :render-header="renderHeader"
              width="55"
            >
              <template #default="scope">
                <el-checkbox
                  v-model="scope.row.checked"
                  @change="select(scope.row)"
                  :disabled="disabled()"
                />
              </template>
            </el-table-column>
            <el-table-column
              label="硬件类型"
              prop="deviceDictCodeStr"
              align="center"
            ></el-table-column>
            <div slot="empty">
              <img
                alt="暂无数据"
                src="@/assets/noReport.png"
                style="margin-top: 80px"
              />
            </div>
          </el-table>
        </div>
        <div class="rightTable" v-if="isShowRight">
          <div class="title">
            <div class="img">
              <img src="@/assets/factoryName.png" alt="厂商名称" />
            </div>
            <div class="text">厂商名称</div>
          </div>
          <el-table
            border
            class="customer-no-border-table"
            element-loading-text="数据正在加载中..."
            :row-class-name="tableRowClassName"
            :header-cell-style="{ background: '#E7F2FD', color: '#252525' }"
            style="width: 100%; border-top: 1px solid #409eff"
            v-loading="rightLoading"
            ref="rightTable"
            :data="rightTable"
            height="400"
          >
            <el-table-column
              label="厂商名称"
              prop="factoryDictCodeStr"
              align="center"
            ></el-table-column>
            <div slot="empty">
              <img
                alt="暂无数据"
                src="@/assets/noReport.png"
                style="margin-top: 80px"
              />
            </div>
          </el-table>
        </div>
        <div v-else style="margin: auto">
          <img
            src="@/assets/selectUpgrdeObject.png"
            alt="请选择硬件类型进行配置"
          />
          <div style="text-align: center">请选择硬件类型进行配置</div>
        </div>
      </div>
      <div v-else style="margin: auto">
        <img
          src="@/assets/selectUpgrdeObject.png"
          alt="请选择升级对象进行配置"
        />
        <div style="text-align: center">请选择升级对象进行配置</div>
      </div>
    </div>

    <div style="position: fixed; right: 40px">
      <el-button
        type="primary"
        @click="save"
        style="height: 30px; width: 78px; padding: 0; line-height: 30px"
        >保存</el-button
      >
    </div>
  </div>
</template>

<script>
import {
  getBasicDataDictList,
  getDetailTypeList,
  getModuleList,
  getFactoryList,
  saveDetailTypeModuleLink,
} from "_config/url.js";
export default {
  props: ["power"],
  data() {
    return {
      upgradeObject: "", //升级对象
      hardwareType: "", //硬件类型

      leftTable: [],
      centerTable: [],
      rightTable: [],

      leftLoading: false,
      centerLoading: false,
      rightLoading: false,

      isShow: false,
      isShowRight: false,
      leftItem: "", //左边表格的选中行
      centerItem: "", //中间表格的选中行
      powerType: "", //功率code
      spanArr: [], //每行合并数
      pos: 0, //角标索引
      isCheckAll: false,
      isIndeterminate: false,
      centerTableNoCondition: [],
    };
  },
  computed: {
    cellClass() {
      if (
        (this.leftItem.detailTypeGroup == 11 && this.leftItem.flagIndex == 0) ||
        (this.leftItem.detailTypeGroup == 12 && this.leftItem.flagIndex == 0)
      ) {
        return "DisableSelection";
      }
    },
  },
  mounted() {
    this.getOptions();
  },
  methods: {
    // 控制选择硬件的多选框能否被点击
    disabled() {
      // 有一键设置的时候, 不能编辑下面的厂商;
      if (
        (this.leftItem.detailTypeGroup == 11 && this.leftItem.flagIndex == 0) ||
        (this.leftItem.detailTypeGroup == 12 && this.leftItem.flagIndex == 0)
      ) {
        return true;
      } else {
        return false;
      }
    },
    // 一键同步
    oneClickSet(row) {
      let group = row.detailTypeGroup;
      this.leftTable = this.leftTable.map((item, i) => {
        if (item.detailTypeGroup === group) {
          return {
            ...item,
            deviceCodeList: row.deviceCodeList,
          };
        } else {
          return item;
        }
      });
    },
    // 合并行
    objectSpanMethod({ rowIndex, columnIndex }) {
      if (columnIndex === 0) {
        const _row = this.spanArr[rowIndex];
        const _col = _row > 0 ? 1 : 0;
        return {
          // [0,0] 表示这一行不显示, [2,1]表示行的合并数
          rowspan: _row,
          colspan: _col,
        };
      }
    },
    getSpanArr(data) {
      // data就是我们从后台拿到的数据
      for (let i = 0; i < data.length; i++) {
        //如果是第一条记录(索引为0),向数组中加入1,并设置索引位置
        if (i === 0) {
          this.spanArr.push(1);
          this.pos = 0; //spanArr的索引
        } else {
          //如果不是第一条记录,则判断它与前一条记录是否相等
          //根据相同 扣分类别名称 进行合并,根据需要可进行修改
          if (data[i].detailTypeGroup === data[i - 1].detailTypeGroup) {
            //如果相等,则向spanArr中添入元素0,并将前一位元素+1,表示合并行数+1
            this.spanArr[this.pos] += 1;
            this.spanArr.push(0);
          } else {
            this.spanArr.push(1);
            this.pos = i;
          }
        }
      }
    },
    //获取字典项
    getOptions() {
      this.$fetch(getBasicDataDictList)
        .then((res) => {
          if (res.code == 200) {
            this.optionsPowerType = res.data.powerTypeDict; //功率类型

            const foundItem = this.optionsPowerType.find(
              (i) => i.name == this.power
            );
            this.powerType = foundItem ? foundItem.code : "";
            this.searchLeftTable();
          } else {
            this.$message.error(res.message);
          }
        })
        .catch((err) => {
          this.errorMessage(err);
        });
    },
    // 左边表格选中
    getItem(val) {
      // console.log("🚀 ~ getItem ~ val:", val);

      this.leftItem = val;
      this.searchCenterTable();
      this.isShow = true;
      this.isShowRight = false;
    },
    //中间表格选中
    getItemCenter(val) {
      console.log("🚀 ~ getItemCenter ~ val:", val);
      this.centerItem = val;
      this.searchRightTable();
      this.isShowRight = true;
    },
    // 升级对象列表接口场景传参:
    // 设备厂商管理:powerType,detailTypeName

    // 获取左侧数据列表
    async searchLeftTable() {
      this.leftLoading = true;
      this.isShow = false;
      this.isShowRight = false;
      this.spanArr = []; //每行合并数
      this.pos = 0; //角标索引
      if (!this.powerType) {
        return this.$message.warning("此功率类型已被禁用");
      }
      try {
        const res = await this.$postjson(getDetailTypeList, {
          powerType: this.powerType, //功率类型编码
          detailTypeName: this.upgradeObject, //升级对象
        });

        if (res.code == 200) {
          this.leftTable = res.data;
          this.getSpanArr(res.data);
          // 给要显示一键设置按钮的行,添加flagIndex标识
          const newArray = this.leftTable.map((i, index) => {
            const j = this.spanArr[index];
            return {
              ...i,
              flagIndex: j,
            };
          });
          this.leftTable = newArray;
        } else {
          this.$message.error(res.message);
        }
        this.leftLoading = false;
      } catch (error) {
        this.leftLoading = false;
        // console.log("🚀 ~ searchLeftTable ~ error:", error);
        this.$message.error("网络异常,稍后请重试");
      }
    },

    renderHeader(h) {
      return h("span", [
        h("el-checkbox", {
          on: {
            change: this.selectBox,
          },
          props: {
            value: this.isCheckAll,
            indeterminate: this.isIndeterminate,
          },
        }),
      ]);
    },
    // 全选框事件
    selectBox(val) {
      // 控制多选状态
      this.isCheckAll = val;
      this.isIndeterminate = false;
      this.centerTable.forEach((k) => {
        k.checked = val;
      });
      // 控制数据存储
      if (val) {
        this.multipleSelection = this.centerTable;
      } else {
        this.multipleSelection = [];
      }
      this.handleSelectionChange(this.multipleSelection);
    },
    // 勾选行
    select(row) {
      // 控制行多选状态
      const checked = row.checked;
      console.log("🚀 ~ select ~  checked :", checked);
      this.centerTable.forEach((t) => {
        if (row.deviceDictCode === t.deviceDictCode) {
          t.checked = checked;
        }
      });
      // 控制全选框状态
      this.changeAllChecked();
      // 控制数据存储
      this.pushIfNotExists(this.multipleSelection, row);
      this.handleSelectionChange(this.multipleSelection);
      console.log(this.leftItem.deviceCodeList, "this.leftItem.deviceCodeList");
    },

    pushIfNotExists(arr, newItem) {
      // console.log("🚀 ~ pushIfNotExists ~ arr, newItem:", arr, newItem);
      // 检查数组中是否存在与 newItem 相同 deviceDictCode 的项
      const existingItem = arr.find(
        (item) => item.deviceDictCode === newItem.deviceDictCode
      );
      // 如果数组中有相同的项,进行删除
      if (existingItem) {
        const index = arr.indexOf(existingItem);
        if (index !== -1) {
          arr.splice(index, 1);
        }
      } else {
        // 如果数组中不存在相同的项,则直接添加新项
        arr.push(newItem);
      }

      return arr;
    },
    // 控制全选框状态
    changeAllChecked() {
      let array = this.centerTable.reduce((acc, i) => {
        acc.push(i.checked);
        return acc;
      }, []);
      this.isCheckAll = array.length > 0 && array.every((element) => element);
      this.isIndeterminate =
        !this.isCheckAll && array.some((element) => element);
    },
    async getCenterTableNoCondition() {
      const res = await this.$postjson(getModuleList, {
        detailType: this.leftItem.detailType, //升级对象编码
        powerType: this.powerType, //功率类型编码
        deviceName: "", //	设备名称
        source: 1,
      });
      if (res.code == 200) {
        this.centerTableNoCondition = res.data;
      }
    },
    // 获取中间数据列表
    async searchCenterTable() {
      if (this.$refs.centerTable) {
        this.$refs.centerTable.setCurrentRow();
      }
      this.isShowRight = false;
      this.centerLoading = true;
      try {
        const res = await this.$postjson(getModuleList, {
          detailType: this.leftItem.detailType, //升级对象编码
          powerType: this.powerType, //功率类型编码
          deviceName: this.hardwareType, //	设备名称
          source: 1,
        });
        if (res.code == 200) {
          this.centerTable = res.data.map((i) => {
            return {
              ...i,
              checked: false,
            };
          });
          this.multipleSelection = [];
          if (this.leftItem.deviceCodeList) {
            //前端操作过,回显this.leftItem.deviceCodeList中存储的
            if (this.hardwareType) {
              // 有硬件类型搜索条件;
              await this.getCenterTableNoCondition();
              this.multipleSelection = this.centerTableNoCondition.filter((i) =>
                this.leftItem.deviceCodeList.some((j) => i.deviceDictCode === j)
              );
            } else {
              // 无硬件类型搜索条件
              this.multipleSelection = this.centerTable.filter((i) =>
                this.leftItem.deviceCodeList.some((j) => i.deviceDictCode === j)
              );
            }
          } else {
            if (this.hardwareType) {
              // 有硬件类型搜索条件;
              await this.getCenterTableNoCondition();
              this.multipleSelection = this.centerTableNoCondition.filter(
                (i) => i.isSelected === 1
              );
            } else {
              // 无硬件类型搜索条件
              this.multipleSelection = this.centerTable.filter(
                (i) => i.isSelected === 1
              );
            }
          }
          console.log(
            "🚀 ~ searchCenterTable ~ this.multipleSelection :",
            this.multipleSelection
          );
          // 多选框状态回显
          this.centerTable.forEach((i) => {
            this.multipleSelection.forEach((j) => {
              if (i.deviceDictCode == j.deviceDictCode) {
                i.checked = true;
              }
            });
          });
          console.log(
            "🚀 ~ this.centerTable.forEach ~  this.centerTable:",
            this.centerTable
          );
          // 全选框状态回显
          this.changeAllChecked();
        } else {
          this.$message.error(res.message);
        }
        this.centerLoading = false;
      } catch (error) {
        console.log("🚀 ~ searchCenterTable ~ error:", error);
        this.centerLoading = false;
        this.$message.error("网络异常,稍后请重试");
      }
    },
    // 获取右侧数据列表
    async searchRightTable() {
      this.rightLoading = true;
      try {
        const res = await this.$postjson(getFactoryList, {
          detailType: this.leftItem.detailType, //升级对象编码
          powerType: this.powerType, //功率类型编码
          deviceCode: this.centerItem.deviceDictCode, //	硬件类型编码
        });
        if (res.code == 200) {
          this.rightTable = res.data;
        } else {
          this.$message.error(res.message);
        }
        this.rightLoading = false;
      } catch (error) {
        // console.log("🚀 ~ searchRightTable ~ error:", error);
        this.rightLoading = false;
        this.$message.error("网络异常,稍后请重试");
      }
    },
    rowKey(row) {
      return row.deviceDictCode;
    },
    // 中间表格多选
    handleSelectionChange(val) {
      // console.log("🚀 ~ handleSelectionChange ~ val:", val);
      this.multipleSelection = val;

      // 1.勾选了就存,在leftItem中存硬件类型的list,
      let array = this.multipleSelection.map((i) => {
        return i.deviceDictCode;
      });
      // console.log("🚀 ~ array ~ array:", array);
      this.leftTable.forEach((i) => {
        if (this.leftItem.detailTypeStr == i.detailTypeStr) {
          i.deviceCodeList = array;
        }
      });
      console.log(this.leftItem.deviceCodeList, "this.leftItem.deviceCodeList");
    },
    async save() {
      let paramsArray = this.leftTable.map((i) => {
        return {
          detailType: i.detailType, //升级对象编码
          powerType: this.powerType, //功率类型编码
          deviceCodeList: i.deviceCodeList, //	硬件类型编码
          operator: JSON.parse(localStorage.getItem("user")).staffAccount, //	操作人,
        };
      });
      paramsArray = paramsArray.filter((i) => i.deviceCodeList);

      console.log("🚀 ~ save ~ paramsArray :", paramsArray);

      try {
        const res = await this.$postjson(saveDetailTypeModuleLink, paramsArray);
        if (res.code == 200) {
          this.$message.success(res.message);
        } else {
          this.$message.error(res.message);
        }
      } catch (error) {
        // console.log("🚀 ~ save ~ error:", error);
        this.$message.error("网络异常,稍后请重试");
      }
    },
    tableRowClassName({ rowIndex }) {
      if (rowIndex % 2 === 1) {
        return "success-row";
      }
      return "";
    },
  },
};
</script>

<style lang="less" scoped>
.leftTable /deep/ .el-table__body tr.current-row td {
  border-top: 3px solid #4091f7;
  border-bottom: 3px solid #4091f7;
}
.leftTable /deep/.el-table__body tr.current-row td:first-child {
  border-left: 3px solid #4091f7;
}

.leftTable /deep/.el-table__body tr.current-row td:last-child {
  border-right: 3px solid #4091f7;
}

.leftTable
  /deep/.el-table--striped
  .el-table__body
  tr.el-table__row--striped.current-row
  td:last-child {
  border-right: 3px solid #4091f7;
}

/deep/ .el-table .DisableSelection .cell .el-checkbox__inner {
  visibility: hidden;
}

/deep/.el-table__empty-text {
  width: 100%;
}
/deep/ .el-form-item {
  margin-bottom: 0px !important;
}
.title {
  display: flex;
  align-items: center;
  margin-bottom: 10px;

  .img {
    height: 21px;
    width: 21px;
    margin-right: 10px;
  }
  .text {
    font-size: 18px;
    color: #1890ff;
  }
}
.bigBox {
  display: flex;
  overflow-y: scroll;
  .leftBox {
    width: 30%;
    padding-right: 20px;
    border-right: 1px solid #d9d9d9;
  }
  .rightBox {
    display: flex;
    width: 70%;
    .centerTable {
      width: 50%;
      padding: 0 20px;
      border-right: 1px solid #d9d9d9;
    }
    .rightTable {
      width: 50%;
      margin-left: 20px;
    }
  }
}
</style>
posted @   崛起崛起  阅读(105)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】
点击右上角即可分享
微信分享提示