vue3 表格嵌套表格

<template>
  <el-scrollbar style="height: 100%">
    <div
      v-loading="loading"
      :element-loading-svg="svg"
      element-loading-svg-view-box="-10, -10, 50, 50"
      element-loading-text="加载中"
      class="right-card"
      :style="{ height: heights, width: '100%' }"
      element-loading-background="rgba(255, 255, 255, 0.6)"
    >
      <!-- 普通表格 + 树形表格 -->
      <!-- lu 把stripe删了,row-class-name="row-style"改为“tableRowClolor” -->
      <!--      style="border: none !important;"-->
      <!-- row-key=ID ,这个ID必须跟表格数据中的ID匹配上 -->
      <div
        v-if="isOrdinary"
        class="table-style"
      >
        <el-table
          @expand-change="handleExpandChange"
          :row-class-name="tableRowColor"
          class="mainHeight"
          :key="itemKey"
          :height="heights"
          row-key="ID"
          :data="tableData"
          header-row-class-name="row-style"
          @row-click="rowToggleSelection"
          @select="select"
          @select-all="selectAll"
          @selection-change="handleSelectionChange"
          ref="TableRef"
          :tree-props="{ children: 'Children', hasChildren: 'hasChildren' }"
          :table-layout="auto"
          :default-expand-all="defaultall"
          @row-dblclick="dblclick"
          :header-cell-style="{background:'#a6c5f8'}"
          highlight-current-row
        >
          <!-- 多选 -->
          <el-table-column
            v-if="isMultiple == 1"
            type="selection"
            width="55"
          ></el-table-column>
          <!-- <el-table-column type="index" label="序号" width="55" /> 单选 -->
          <!-- show-over...,min-with lu  下拉-->
          <template v-for="(item, index) in tableHeader">
            <el-table-column
              v-if="item.ispass"
              :key="index"
              :label="item.label"
              :prop="item.fieldName"
              :align="item.iscenter"
              :sortable="item.sortable"
              show-overflow-tooltip
              min-width="110px"
              header-align="center"
            >
              <!-- 此处通过插槽的形式动态将值赋予新的表单 逻辑稍微有些恶心  FormOption[index].option-->
              <template
                v-if="item.isTransition"
                v-slot="scope"
              >
                <!-- 递归组件 -->
                <Recursion
                  :list="FormOption[index].oldOption !== undefined
                  ? FormOption[index].oldOption
                  : FormOption[index].option
                  "
                  :rows="scope"
                />
              </template>
              <!-- 图片 -->
              <template
                v-if="item.isImages"
                v-slot="scope"
              >
                <!-- <el-button @click="Test(scope.row.Files)"></el-button> -->
                <!-- this.$FWurl + i -->
                <!-- <el-image
                  :initial-index="4"
                  :preview-teleported="true"
                  hide-on-click-modal
                  v-for="(item, indexFiles) in scope.row.Files"
                  :key="indexFiles"
                  style="width: 30px; height: 30px"
                  :src="item"
                  :preview-src-ProcessInfo="[item]"
                ></el-image> -->
                <template v-if="scope.row.Files != null">
                  <el-image
                    fit="cover"
                    :initial-index="0"
                    :preview-teleported="true"
                    style="width: 40px; height: 40px"
                    :src="scope.row.Files[0]"
                    :preview-src-list="scope.row.Files"
                  ></el-image>
                </template>
              </template>
            </el-table-column>
          </template>
          <!-- Table中的控制 -->
          <!-- <el-table-column align="center" width="60px" label="操作">
          <template #default="scope">
            <div class="btn-option" @click="submitData(scope)">
              <el-button class="el-icon-tickets"></el-button>
            </div>
          </template>
        </el-table-column> -->
        </el-table>
        <!-- 分页 -->
        <div
          class="pagination"
          v-if="showFenYe"
          style="margin-top: 10px"
        >
          <el-pagination
            :key="itemKeyFy"
            @size-change="handleSizeChange"
            @current-change="handleCurrentChange"
            :current-page="pageNum"
            :page-sizes="[1, 3, 5, 10, 20, 30, 40]"
            :page-size="pageSize"
            layout="total, sizes, prev, pager, next"
            :total="total"
            popper-class="select_bottom"
          >
          </el-pagination>
        </div>
      </div>
      <!-- 表格嵌套表格 -->
      <!-- 如果isOrdinary=false,执行这个 -->
      <!-- 我把这个删了 row-class-name="row-style" -->
      <div v-if="!isOrdinary">
        <el-table
          :table-layout="auto"
          :row-class-name="tableRowColor"
          class="tableIntable"
          :key="itemKey"
          :height="heights"
          border
          row-key="id"
          :data="tableData"
          @row-click="rowToggleSelection"
          @select="select"
          @select-all="selectAll"
          @selection-change="handleSelectionChange"
          ref="TableRef"
          :tree-props="{ children: 'Children', hasChildren: 'hasChildren' }"
          :default-expand-all="false"
          :align="textCenter"
        >
          <!-- 多选 -->
          <el-table-column
            v-if="isMultiple == 1"
            type="selection"
            width="55"
          ></el-table-column>
          <!-- 子表格 -->
          <!-- 我把这个删了 row-class-name="row-style" -->
          <el-table-column type="expand">
            <template #default="props">
              <el-table
                :table-layout="auto"
                class="bqqqb"
                :data="props.row.sonData"
                style="width: 90%; margin-left: 20px;margin-right;: 20px"
                :key="itemKey"
                border
                row-key="id"
                :show-summary="isOpenSums"
                :summary-method="getSummaries"
              >
                <!-- :align="item.label == '备注' ? 'left':'center'" -->
                <template v-for="(item, index) in sonColumns">
                  <el-table-column
                    class="ccc"
                    v-if="item.ispass"
                    :key="index"
                    :label="item.label"
                    :prop="item.fieldName"
                    :sortable="item.sortable"
                    header-align="center"
                    :align="Test(item)"
                    min-width="110px"
                  >
                    <template
                      class="aaaaaaaaaa"
                      v-if="item.isTransition"
                      v-slot="scope"
                    >
                      <!-- <el-button @click="Test(item, FormOption)">用于测试</el-button> -->
                      <!-- 递归组件 -->
                      <Recursion
                        :list="SonFormOption[index].oldOption !== undefined
                        ? SonFormOption[index].oldOption
                        : SonFormOption[index].option
                        "
                        :rows="scope"
                      />
                    </template>
                    <!-- 图片 -->
                    <template
                      v-if="item.isImages"
                      v-slot="scope"
                    >
                      <template v-if="scope.row.Files != null">
                        <el-image
                          fit="cover"
                          :initial-index="0"
                          :preview-teleported="true"
                          style="width: 40px; height: 40px"
                          :src="scope.row.Files[0]"
                          :preview-src-list="scope.row.Files"
                        ></el-image>
                      </template>
                    </template>
                  </el-table-column>
                </template>
                <el-table-column
                  min-width="110px"
                  label="操作"
                  header-align="center"
                  v-if="isOpenOperation"
                >
                  <template v-slot="scope">
                    <el-button
                      type="success"
                      plain
                      size="mini"
                      @click="SonhandleEdit(scope.$index, scope.row)"
                    >编辑</el-button>
                  </template>
                </el-table-column>
              </el-table>
            </template>
          </el-table-column>
          <!-- 外层表头,父表头  -->
          <template
            v-for="(item, index) in tableHeader"
            class="aaa"
          >
            <el-table-column
              v-if="item.ispass"
              :key="index"
              :label="item.label"
              :prop="item.fieldName"
              :sortable="item.sortable"
              header-align="center"
              :align="Test(item)"
              min-width="160px"
            >
              <!-- 此处通过插槽的形式动态将值赋予新的表单 逻辑稍微有些恶心 -->

              <template
                class="aaaaaaaaaa"
                v-if="item.isTransition"
                v-slot="scope"
              >
                <!-- 递归组件   FormOption[index].option-->
                <Recursion
                  :list="FormOption[index].oldOption !== undefined
                  ? FormOption[index].oldOption
                  : FormOption[index].option
                  "
                  :rows="scope"
                />
              </template>
              <!-- 图片 -->
              <template
                v-if="item.isImages"
                v-slot="scope"
              >
                <template v-if="scope.row.Files != null">
                  <el-image
                    fit="cover"
                    :initial-index="0"
                    :preview-teleported="true"
                    style="width: 40px; height: 40px"
                    :src="scope.row.Files[0]"
                    :preview-src-list="scope.row.Files"
                  ></el-image>
                </template>
              </template>
            </el-table-column>
          </template>
        </el-table>
        <!-- 分页 -->
        <div
          class="pagination"
          v-if="showFenYe"
          style="margin-top: 10px"
        >
          <el-pagination
            :key="itemKeyFy"
            @size-change="handleSizeChange"
            @current-change="handleCurrentChange"
            :current-page="pageNum"
            :page-sizes="[10, 20, 30, 40]"
            :page-size="pageSize"
            layout="total, sizes, prev, pager, next"
            :total="total"
            popper-class="select_bottom"
          >
          </el-pagination>
        </div>
      </div>
    </div>
  </el-scrollbar>
</template>

<script>
import { inject, reactive, ref, toRefs, defineExpose } from "@vue/runtime-core";
import { watchEffect, getCurrentInstance, nextTick } from "vue";
import SvgIcon from "../../components/SvgIcon.vue";
import Recursion from "../components/TableDialogTreeCol.vue";
import tableStyle from "../../assets/css/tableStyle.css";
//选中的数据
let listData = [];

export default {
  components: { SvgIcon, Recursion, tableStyle },
  name: "TableDialog",
  emits: ["tableMessage"],
  props: {
    showFenYe: {
      default: true,
      type: Boolean,
    },
    // 接收的是:树结构是否展开,默认不展开
    defaultall: {
      default: false,
      type: Boolean,
    },
  },

  setup(props, context) {
    //是否为普通表格
    let isOrdinary = true;
    //默认不开启子表格操作
    let isOpenOperation = false;
    //默认不开启合计行
    let isOpenSums = false;
    const loading = ref(true);
    const svg = `
        <path class="path" d="
          M 30 15
          L 28 17
          M 25.61 25.61
          A 15 15, 0, 0, 1, 15 30
          A 15 15, 0, 1, 1, 27.99 7.5
          L 15 15
        " style="stroke-width: 4px; fill: rgba(0, 0, 0, 0)"/>
      `;
    //表头设置,是否为多选,默认为多选
    let isMultiple = 0;
    // 表头配置
    let tableHeader = ref([]);

    // 数据及配置
    // let tableData = reactive([]);
    let tableData = ref([]);

    const multipleSelection = ref([]);
    const TableRef = ref(null);

    const instance = getCurrentInstance();

    const tableHeaderConfig = inject("tableHeaderConfig");
    const tableDataConfig = inject("tableDataConfig");

    // 监听表单配置数据
    watchEffect(() => {
      tableHeader = tableHeaderConfig;
      tableData = tableDataConfig ? tableDataConfig.tableData : [];

      //默认普通表格,true
      isOrdinary =
        tableDataConfig.isOrdinary != undefined
          ? tableDataConfig.isOrdinary
          : true;
      //默认不开启子表格操作
      isOpenOperation =
        tableDataConfig.isOpenOperation != undefined
          ? tableDataConfig.isOpenOperation
          : false;
      //默认不开启合计操作
      isOpenSums =
        tableDataConfig.isOpenSums != undefined
          ? tableDataConfig.isOpenSums
          : false;
    });

    //#region 表单监听事件

    //表格内部操作按钮,目前不用
    function submitData(scope) {
      context.emit("tableMessage", { page: page, type: scope });
    }

    //lu table背景色
    function tableRowColor({ row, rowIndex }) {
      if (
        (row.sonData && row.sonData.length > 0) ||
        (row.children && row.children.length > 0)
      ) {
        return "success-row";
      }
    }

    //复选框监听事件,值变化    定义方法可以这么写:const handleSelectionChange = (val) =>  也可以  function
    const handleSelectionChange = (val) => {
      multipleSelection.value = val;
      listData = val;
      debugger;
      context.emit("tableMessage", { listData: listData, type: "列表选择" });
    };
    //#endregion

    //公共方法,用于子集选择

    // nextTick(() => {
    //   otherParam.showA = true;
    // });
    //选择事件   需要注意,此处位置在部署服务器上后,失效,体现在 toRefs(instance.refs.TableRef);
    // ultipleTabInstance.toggleRowSelection.value(row, select);  最终为空,需要找寻其他方法实现!,另外还有一个在form表单的动态生成,估计是响应参数出了问题!周一记得解决

    //注册
    return {
      listData,
      tableHeader,
      tableData,
      isMultiple, //默认为1,多选
      loading,
      svg,
      submitData,
      tableRowColor,
      handleSelectionChange, //行事件
      TableRef, //ref参数,用于选中取消
      isOrdinary, //是否为普通表格
      isOpenOperation, // 是否开启子表格操作
      isOpenSums, // 是否开启合计
    };
  },
  data() {
    return {
      // defaultall: false, //是否默认展开所有行(用于有树状结构的表格)
      heights: 1,
      itemKey: "",
      itemKeyFy: "",
      pageNum: 1, //当前页
      pageSize: 10, //页大小
      total: 0, //总数
      FormOption: null, //父表表单Option
      SonFormOption: null, //子表表单Option
      sonColumns: [], //内层table的表头
      textCenter: "", //文字居中
      flag: 1, //判断表格高度的时候使用
      expandRows: [],
      expandRowKeys: [],
    };
  },

  created() {
    // this.heights = window.innerHeight - 200;
    this.TimeoutOpen();
    // 监听事件
    // window.addEventListener('resize', this.onresize)
  },
  beforeDestroy() {
    // 取消监听事件
    // window.removeEventListener('resize', this.onresize)
  },
  mounted() {
    this.$nextTick(() => {
      this.$refs.TableRef.$el.getBoundingClientRect().top; //表格距离浏览器的高度
      let height;
      switch (this.flag) {
        case 1:
          height = 0;
          break;
        case 2:
          height = 80;
          break;
        case 3:
          height = 110;
          break;
        case 4:
          height = -30;
          break;
        case 5:
          height = -65;
          break;
        case 6:
          height = 125;
          break;
        case 7:
          height = 90;
          break;
        case 8:
          height = 30;
          break;
        case 9:
          height = 135;
          break;
        default:
          break;
      }
      // 根据浏览器高度设置初始高度
      this.heights =
        window.innerHeight - this.$refs.TableRef.$el.offsetTop - 280 - height;
      // 监听浏览器高度变化,修改表格高度
      window.onresize = () => {
        this.heights =
          window.innerHeight - this.$refs.TableRef.$el.offsetTop - 280 - height;
      };
    });
  },
  methods: {
    //展开行只能展开一行
    handleExpandChange(row, expanded) {
      if (expanded) {
        this.expandRows.forEach((item) => {
          this.$refs.TableRef.toggleRowExpansion(item, false);
        });
        this.expandRows.push(row);
      } else {
        this.expandRows = this.expandRowKeys.filter(
          (item) => item.ID !== row.ID
        );
      }
    },
    Test(item) {
      var test = item.iscenter ? "center" : "left";
      if (item.label.indexOf("费") > 0 || item.label.indexOf("金额") > 0) {
        test = "right";
      }
      if (item.label.indexOf("备注") > 0) {
        test = "left";
      }
      return test;
    },
    //自定义合计方法
    getSummaries(param) {
      const { columns, data } = param;
      const sums = {};
      const HJJE = {}; // 合计金额 = 数量 * 单价金额
      columns.forEach((column, index) => {
        if (index === 0) {
          sums[index] = "合计";
          return;
        }

        // // if (index === 3) {
        // //     sums[index] = '';
        // //     return;
        // // }
        const values = data.map((item) => Number(item[column.property]));
        if (column.label == "数量" || column.label == "单价金额") {
          if (!values.every((value) => isNaN(value))) {
            sums[index] = values.reduce((prev, curr) => {
              const value = Number(curr);
              if (!isNaN(value)) {
                return prev + curr;
              } else {
                return prev;
              }
            }, 0);
            if (column.label == "数量") {
              HJJE.sl = values;
            }
            if (column.label == "单价金额") {
              HJJE.dj = values;
            }
            // sums[index] += ' kg';
          } else {
            // sums[index] = 'N/A';
          }
        }
      });
      let rowsHJ = 0;
      //合计总价 = 数量 * 单价金额
      if (HJJE.sl !== undefined && HJJE.dj !== undefined) {
        for (let index = 0; index < HJJE.sl.length; index++) {
          rowsHJ += HJJE.sl[index] * HJJE.dj[index];
        }
      }
      sums[0] = "合计总金额\n SUM(数量 * 单价金额) = " + rowsHJ;
      return sums;
    },
    //子表格中按钮事件
    SonhandleEdit(index, row) {
      //按钮事件,暂时维护编辑按钮,后续有需要添加
      this.$emit("SonButtonChange", row);
    },
    //嵌套表格下的样式 —— 貌似不生效
    tableRowClassName({ row, rowIndex }) {
      if (row.sonData.length > 0) {
        return "success-row";
      }
      return "";
    },
    //#region 数据表格事件
    //清空表格全部选择
    ClearSelect() {
      this.$nextTick(() => {
        this.$refs.TableRef.clearSelection();
      });
    },

    setChildren(children, type) {
      // 编辑多个子层级
      children.map((j) => {
        this.toggleSelection(j, type);
        if (j.children) {
          this.setChildren(j.children, type);
        }
      });
    },

    toggleSelection(row, select) {
      this.$nextTick(() => {
        this.$refs.TableRef.toggleRowSelection(row, select);
      });
    },

    //行点击事件
    rowToggleSelection(rows) {
      this.$emit("rowClick", rows); //传给父组件行点击数据
      const selected = listData.some((item) => item.id === rows.id);
      if (!selected) {
        if (rows.children) {
          // 解决子组件没有被勾选到
          this.setChildren(rows.children, true);
        }
        this.toggleSelection(rows, true);
      } else {
        if (rows.children) {
          // 解决子组件没有被勾选到
          this.setChildren(rows.children, false);
        }
        this.toggleSelection(rows, false);
      }
    },
    //#endregion
    handleSizeChange(val) {
      this.pageSize = val;

      // 调用自定义事件,传入参数
      this.$emit("getPage", { pageSize: this.pageSize, pageNum: this.pageNum });
      this.TimeoutOpen();
    },
    /**
     * 切换页码
     * @param {*} val
     */
    handleCurrentChange(val) {
      this.pageNum = val;

      this.$emit("getPage", { pageSize: this.pageSize, pageNum: this.pageNum });
      this.TimeoutOpen();
    },

    /**
     * 获取父组件传递过来的新的数据表头
     * @param {} GetDataLists
     */
    SetDataTableHeader(GetDataLists, flag) {
      //重新渲染,itemKey用于处理Table不渲染的问题
      this.itemKey = Math.random();
      this.flag = flag ? flag : this.flag;
      //重新渲染数据表

      this.tableHeader = GetDataLists.lstSubset[0].Headers;
      this.FormOption = GetDataLists.lstSubset[0].Froms;

      this.FormOption.forEach((item) => {
        if (item.oldOption === undefined) {
          //存储旧集合
          item.oldOption = item.option;
        }
      });
      //清空选择
      this.ClearSelect();
    },
    /**
     * 获取父组件传递过来的新的数据表头,仅对于子表格使用
     * @param {} GetDataLists
     */
    SetDataTableHeaderByZiTable(GetDataLists) {
      //重新渲染,itemKey用于处理Table不渲染的问题
      this.itemKey = Math.random();
      //重新渲染数据表
      this.sonColumns = GetDataLists.lstSubset[0].Headers;
      this.SonFormOption = GetDataLists.lstSubset[0].Froms;
      this.SonFormOption.forEach((item) => {
        if (item.oldOption === undefined) {
          //存储旧集合
          item.oldOption = item.option;
        }
      });

      //清空选择
      this.ClearSelect();
    },

    /**
     * 用于父组件获取子组件当前Table数据信息,最终用于勾选选择使用
     */
    GetDataTable() {
      return this.tableData;
    },
    /**
     * 获取父组件传递过来的新的数据Data进行重新赋值
     * @param {*} GetDataLists 新增、修改、删除后,重新查询的数据
     */
    SetDataTable(GetDataLists) {
      //重新渲染,itemKey用于处理Table不渲染的问题
      this.itemKey = Math.random();
      this.itemKeyFy = Math.random();
      let dataList =
        typeof GetDataLists.rows == "string"
          ? JSON.parse(GetDataLists.rows)
          : GetDataLists.rows;

      this.SetTreeDataTableIds(dataList, 1);
      //重新渲染数据表
      this.tableData = dataList;
      this.total = GetDataLists.total;
      //清空选择
      this.ClearSelect();
      this.$forceUpdate();
      this.TimeoutOpen();
    },

    //递归算法动态赋值
    SetTreeDataTableIds(GetDataLists, AllIndex) {
      //此处添加Id是为了保证每一条的唯一性,因为很多表中的ID命名规则不统一,所以在此自行规定,实质上此id无其他作用
      GetDataLists.forEach((element, index) => {
        element.id = AllIndex * 1000 + (index + 1);
        if (element.children) {
          if (element.children.length > 0) {
            this.SetTreeDataTableIds(element.children, element.id);
          }
        }
      });
    },

    //切换表格
    SetTableType(val) {
      //普通表格为True,嵌套表格为false
      this.isOrdinary = val;
    },

    //#region 关于树形列表复选框事件组

    /**
     * 选中父节点时,子节点一起选中取消
     * @param {*} selection
     * @param {*} row
     */
    select(selection, row) {
      const hasSelect = selection.some((el) => {
        return row.id === el.id;
      });
      if (hasSelect) {
        if (row.children) {
          // 解决子组件没有被勾选到
          this.setChildren(row.children, true);
        }
      } else {
        if (row.children) {
          this.setChildren(row.children, false);
        }
      }
    },
    //双击
    dblclick(row, column, cell, event) {
      this.$emit("doubleClick", row);
    },
    /**
     * 选择全部
     * @param {*} selection
     */
    selectAll(selection) {
      // tabledata第一层只要有在selection里面就是全选
      const isSelect = selection.some((el) => {
        const tableDataIds = this.tableData.map((j) => j.id);
        return tableDataIds.includes(el.id);
      });
      // tableDate第一层只要有不在selection里面就是全不选
      const isCancel = !this.tableData.every((el) => {
        const selectIds = selection.map((j) => j.id);
        return selectIds.includes(el.id);
      });
      if (isSelect) {
        selection.map((el) => {
          if (el.children) {
            // 解决子组件没有被勾选到
            this.setChildren(el.children, true);
          }
        });
      }
      if (isCancel) {
        this.tableData.map((el) => {
          if (el.children) {
            // 解决子组件没有被勾选到
            this.setChildren(el.children, false);
          }
        });
      }
    },
    //#endregion
    TimeoutOpen() {
      this.loading = true;
      setTimeout(() => {
        //需要定时执行的代码
        this.loading = false;
      }, 800);
    },
    setCurrent() {
      this.$refs.TableRef.setCurrentRow();
    },
  },
};
</script>
<style scoped>
.el-table .warning-row {
  --el-table-tr-bg-color: var(--el-color-warning-light-9);
}
/*最外层透明*/
.el-table,
.el-table__expanded-cell {
  /*border: none !important;*/
  background-color: transparent;
}
/* 表格内背景颜色 */
::v-deep .el-table th,
::v-deep .el-table tr,
::v-deep .el-table td {
  background-color: transparent;
}

.el-table .success-row {
  --el-table-tr-bg-color: var(--el-color-success-light-9);
}

.el-table {
  --el-table-row-hover-bg-color: #409effab;
  /* 去除表格线 */
}
::v-deep .cell {
  color: black;
  /* text-align: center; */
}
::v-deep .el-table td.el-table__cell,
.el-table th.el-table__cell.is-leaf {
  border: 1px solid #a5c4f7;
  /* line-height: 3rem; */
  font-size: 16px;
}
::v-deep .el-table__inner-wrapper::before {
  background-color: transparent !important;
}
</style>

猜你喜欢

转载自blog.csdn.net/CMDN123456/article/details/134143654
今日推荐