vue el-table封装。。。

56 阅读4分钟

一.组件调用

1.引入组件

import cuTable from "@/components/cu-table/cu-table";

2.引入配置文件

import { paramData } from "./config/common.js";

3.template、script写法

<script> export default { components: { cuTable }, 
data() { 
return { 
paramData: paramData, 
} 
}, 
 methods: { 
search(params) {
      this.$refs.cuTable.curPage = 1;
      this.$refs.cuTable.getTableData({ ...params });
    },
} 
} 
</script>
<template>
<cu-table ref="cuTable" :param="paramData">
        <template #action="{ data }"></template>
      </cu-table>
</template>

4.在js文件中进行配置json

// 绩效考核
export const paramData1 = {
  border: true,
  getDataUrl: "hr/performanceEvaluationScore/assessmentList",
  methodFun: "post",
  noGetData: true,
  tableHeader: [
    {
      title: `标题中文`,
      align: "center",
      field: "英文字段",
      width: 100,
    },
    {
      title: `操作`,
      align: "center",
      width: 120,
      slotName: "action", // 插槽
    },
  ],
};

二.封装组件

<template>
  <div class="table_wrap">
    <slot name="header"></slot>
    <el-table
      ref="table"
      v-loading="loading"
      :data.sync="tableData"
      highlight-current-row
      :border="param.border"
      @row-click="rowClick"
      :span-method="spanmethod"
      :row-class-name="tableRowClassName"
      :empty-text="emptyText"
      :tree-props="{ children: 'children' }"
      @selection-change="selectChange"
      @select="selectFun"
      @select-all="selectAll"
      @sort-change="sortChange"
      :default-sort="defaultSort"
    >
      <el-table-column
        v-if="param.selection"
        type="selection"
        width="55"
        align="center"
        :selectable="selecTableChoice"
      ></el-table-column>
      <!-- <el-table-column type="selection" width="55" :selectable="selecTableFun"  v-if="param.selection" align="center"></el-table-column> -->
      <el-table-column
        v-if="param.radio && !param.selection"
        width="55"
        align="center"
      >
        <template slot-scope="scope">
          <el-radio
            v-model="activeRowIndex"
            class="radio_column"
            :label="scope.$index"
            @change.native="
              () => {
                activeRowIndex = scope.$index;
                selecTableFun(scope.row);
              }
            "
          ></el-radio>
        </template>
      </el-table-column>
      <el-table-column
        v-if="!param.indexNum"
        type="index"
        label="序号"
        width="60"
        align="center"
      >
        <template slot-scope="scope">
          {{ orderNumber(scope.$index) }}
        </template>
      </el-table-column>
      <!--&lt;!&ndash; prop: 字段名name, label: 展示的名称, fixed: 是否需要固定(left, right), minWidth: 设置列的最小宽度(不传默认值), oper:&ndash;&gt;
          &lt;!&ndash;是否有操作列&ndash;&gt;
          &lt;!&ndash;oper.name: 操作列字段名称, oper.clickFun: 操作列点击事件, formatData: 格式化内容 &ndash;&gt;-->
      <el-table-column
        v-for="(th, key) in param.tableHeader"
        :key="key"
        :prop="th.field"
        :label="th.title"
        :fixed="th.fixed"
        :show-overflow-tooltip="!th.tooltip"
        :min-width="th.width"
        :sortable="th.sortable"
        :align="th.align ? th.align : 'center'"
      >
        <!--加入template主要是对列的操作,dic表示字典,link表示详情,button表示按钮操作,swich表示开关-->
        <template slot-scope="scope">
          <div class="rowClass_1">
            <slot
              v-if="th.slotName"
              :name="th.slotName"
              :data="{ row: scope.row, index: scope.$index, th: th }"
            ></slot>
            <span v-else-if="th.oper && th.oper.name == 'dicArray'">
              <template v-for="item in th.oper.options">
                <span
                  v-if="
                    item[th.oper.valueKey || 'value'] == scope.row[th.field]
                  "
                  >{{ item[th.oper.labelKey] || item.label }}</span
                >
              </template>
            </span>
            <span v-else-if="th.oper && th.oper.name == 'dic'">{{
              scope.row[th.field]
            }}</span>
            <!-- <span v-else-if="th.oper && th.oper.name == 'dic'" :style="{color:th.oper.styleColor && th.oper.styleColor[scope.row[th.field]]}">{{ scope.row[th.field] | filterDic(th.oper) }}</span> -->
            <span v-else-if="th.oper && th.oper.name == 'area'">{{
              scope.row[th.field] | filterDic(th.oper.fun)
            }}</span>
            <span v-else-if="th.oper && th.oper.name == 'timeStamp'">{{
              scope.row[th.field]
                | filterTimeFormat(
                  th.oper.timeFormat
                    ? th.oper.timeFormat
                    : "YYYY-MM-DD HH:mm:ss"
                )
            }}</span>
            <span v-else-if="th.oper && th.oper.name == 'link'">
              <!-- <span @click="th.oper.clickFun(scope.row)"   :class='["link",th.oper.color=="1" ? "active" : ""]'>{{ scope.row[th.field] }}</span> -->
              <span
                :class="handleEvalStatuslist(th.oper.color)"
                @click="th.oper.clickFun(scope.row)"
                >{{ scope.row[th.field] }}</span
              >
            </span>
            <!-- 表格中按钮添加了flag和icon ,flag用于自定义class名修改样式,icon用于按钮图标。-->
            <!-- 公共按钮 编辑flag:update,icon:bianji  删除 flag:delete,icon:shanchu -->
            <span
              v-else-if="th.oper && th.oper.name == 'button'"
              style="display: inline"
              class="table_oper_btn"
            >
              <span
                v-for="(o, key) in th.oper.btnObj"
                :key="key"
                v-show="!o.condition || o.condition(scope.row, scope.$index)"
              >
                <el-button
                  v-hasPermi="o.hasPermi"
                  size="mini"
                  :class="buttonText(scope.row, o).flag"
                  @click="o.clickFun(scope.row, scope.$index)"
                >
                  <span
                    style="display: inline"
                    v-text="buttonText(scope.row, o).name"
                  ></span>
                </el-button>
                <slot
                  v-if="o.slotName"
                  :name="o.slotName"
                  :data="{ row: scope.row, th: th }"
                ></slot>
              </span>
            </span>
            <span
              v-else-if="th.oper && th.oper.name == 'switch'"
              style="min-width: 60px; display: inline-block"
            >
              <el-switch
                v-model="scope.row[th.field]"
                :active-value="th.oper.flag.on ? th.oper.flag.on : flag.on"
                :inactive-value="th.oper.flag.off ? th.oper.flag.off : flag.off"
                :active-text="th.oper.activeText ? th.oper.activeText : '启用'"
                :inactive-text="
                  th.oper.inactiveText ? th.oper.inactiveText : '停用'
                "
                :disabled="th.oper.disabled"
                :width="60"
                @change="th.oper.clickFun(scope.row)"
              >
              </el-switch>
            </span>
            <span v-else>{{
              scope.row[th.field] ? scope.row[th.field] : "-"
            }}</span>
          </div>
        </template>
      </el-table-column>
    </el-table>
    <div class="pagination">
      <el-pagination
        :pager-count="5"
        @current-change="currentChange"
        @size-change="sizeChange"
        :current-page="curPage"
        :page-size="maxSize"
        :page-sizes="[10, 20, 30, 40, 50]"
        :total="recordCnt"
        v-if="!param.pagination"
        layout="total, sizes, prev, pager, next, jumper"
        background
      >
      </el-pagination>
    </div>
  </div>
</template>
<script>
import request from "@/utils/request";
import moment from "moment";
import { tableData } from "../../views/pm/ledgerInfo/info/config";
export default {
  props: {
    spanmethod: {
      type: Function,
      default: function () {
        return {
          rowspan: 1,
          colspan: 1,
        };
      },
    },
    param: {
      noParamsMap: {
        type: Boolean,
        default: function () {
          return false;
        },
      },
      getDataUrl: {
        type: String,
        default: function () {
          return "";
        },
      },
      methodFun: {
        type: String,
        default: function () {
          return "get";
        },
      },
      getDataParam: {
        type: Object,
        default: function () {
          return {};
        },
      },
      tableHeader: {
        type: Array,
        default: function () {
          return [];
        },
      },
      noGetData: {
        type: Boolean,
      },
      where: {
        type: Object,
        default: function () {
          return {};
        },
      },
      tableRowClassNameFun: {
        type: Function,
        default: function () {
          return false;
        },
      },
    },
    pagination: {
      type: Boolean,
    },
    summaryMethod: {
      type: Function,
      default: function () {
        return function () {};
      },
    },
    selecTableFun: {
      type: Function,
    },
    mouseEnter: {
      type: Function,
    },
    mouseLeave: {
      type: Function,
    },
    dataConversion: {
      type: Function,
    },
    otherType: {
      type: String,
    },
    defaultSort: {
      type: Object,
    },
    emptyText:{
      type: String,
      default:"",
    }
  },
  data() {
    return {
      searchFormData: {},
      activeRowIndex: "",
      loading: false,
      curPage: 1,
      maxSize: 10,
      disabled: false,
      nextPage: "",
      prePage: "",
      recordCnt: 0,
      tableData: [],
      tableHeader: this.param.tableHeader,
      flag: {
        on: 0,
        off: 1,
      },
      selectRow: [],
      linkcolor: true,
      selecTableChoice1: true,
    };
  },
  filters: {
    filterTimeFormat: function (val, timeFormat) {
      return moment(val).format(timeFormat);
    },
  },
  computed: {
    interval: function () {
      let total = this.curPage * this.maxSize;
      if (this.curPage == 1) {
        return this.curPage + "-" + total;
      } else {
        let start = total - this.maxSize + 1;
        if (this.recordCnt < total) {
          total = this.recordCnt;
        }
        return start + "-" + total;
      }

      // return this.curPage
    },
    buttonText: function () {
      return function (row, o) {
        if (o && o.funText && o.funText(row)) {
          return o.funText(row);
        }
        return o;
      };
    },
  },
  watch: {
    tableData(val) {
      this.$nextTick(() => {
        // 多选框根据字段checked默认勾选选中
        this.setDefaultChecked(val);
      });
    },
  },
  created() {
    this.searchFormData = {};
    let that = this;
    this.param.tableHeader.filter(function (item) {
      // let type, url, index;
      let url;
      if (item.oper && item.oper.name == "dic") {
        if (item.oper.realTimeUrl) {
          // 表格列数据需实时请求
          url = item.oper.realTimeUrl;
          that.common.realTimeRequest(
            url,
            item.oper.type,
            item.oper.dicDataConversion
          );
        } else {
          // 表格列数据从字典获取
          url = that.$urlList.common.dic;
          that.common.getDic(url, item.oper.type);
        }
      }
    });
    let self = this;
    setTimeout(() => {
      if (!self.param.noGetData) {
        self.getTableData();
      }
    }, 500);
  },
  mounted() {
    this.EventBus.$off("searchTableData");
    this.EventBus.$on("searchTableData", (parmas) => {
      // if (parmas.type === 0) {
      this.curPage = 1;
      // }
      this.getTableData(parmas);
    });
  },
  destroyed() {
    /**
     * Bus这个事件需要解绑,要不然路由切换回缓存之前的调用
     */
    // this.EventBus.$off('searchTableData');
  },
  methods: {
    selecTableChoice(row) {
      if (this.$parent.selecTableChoice) {
        // this.$emit('selecTableChoice',row)
        if (row.status == 1 || row.status == 2 ) {
          return true;
        } else {
          return false;
        }
      } else {
        return true;
      }
    },
    sortChange(e) {
      this.$emit("sortChange", e);
    },
    rowClick(e) {
      this.$emit("row-click", e);
    },
    tableRowClassName({ row }) {
      if (this.param.tableRowClassNameFun) {
        return this.param.tableRowClassNameFun(row);
      }
    },
    // 设置默认选中多选框
    setDefaultChecked(rows) {
      if (rows.length > 0) {
        rows.forEach((row) => {
          if (row.checked) {
            this.$refs.table.toggleRowSelection(row, true);
            this.selectRow.push(row);
          }
        });
      }
    },
    orderNumber(index) {
      if (this.curPage > 1) {
        return this.maxSize * (this.curPage - 1) + index + 1;
      } else {
        if (index < 9) {
          return index + 1;
        } else {
          return index + 1;
        }
      }
    },
    firstPage() {
      this.curPage = 1;
      this.getTableData();
    },
    lastPage() {
      let val = this.recordCnt / this.maxSize;
      if (val < 1) {
        val = 1;
      } else {
        val = Math.ceil(val);
      }
      this.curPage = val;
      this.getTableData();
    },
    currentChange(val) {
      this.curPage = val;
      this.getTableData();
      console.log("currentChange", val);
      this.$emit("handleCurrentPage", val);
    },
    sizeChange(val) {
      this.maxSize = val;
      this.curPage = 1;
      this.getTableData();
      this.$emit("handlePageSize", val);
    },
    resetPageSize() {
      this.maxSize = 10;
      this.curPage = 1;
      this.getTableData();
    },
    getTableData(form) {
      let paramData = {
        pageNum: this.curPage,
        pageSize: this.maxSize,
      };
      // 没有分页不需要 初始分页参数
      if (this.param.pagination) {
        paramData = {};
      }
      // 遍历检索条件form对象,每一项添加在请求报文params中
      if (form) {
        this.searchFormData = form;
        paramData = { ...paramData, ...this.searchFormData };
      }
      // console.log("where", this.param.where);
      if (this.param.where) {
        paramData = { ...paramData, ...this.param.where };
      }
      // 根据id判断在哪个菜单中,获取对应的json路径对象
      let url = this.param.getDataUrl;
      // 判断页面是否有配置表格的请求接口路径,若没配默认用getpage。
      // 配置接口路径适用于详情等弹框页面的表格
      // if (!this.param.getDataUrl) {
      //   url = this.$urlList.business[this.param.bussName].getPage;
      // } else {
      //   url = this.param.getDataUrl;
      // }
      this.loading = true;
      paramData = { ...this.searchFormData, ...this.param.where, ...paramData };
      this.curPage = paramData.pageNum;
      let config = {};
      if (this.param.paramsHaveArray) {
        config.haveArray = true;
      }
      this.param.methodFun = this.param.methodFun
        ? this.param.methodFun
        : "get";
      let fun =
        this.param.methodFun == "get"
          ? request({ url: url, method: "get", params: paramData })
          : request({ url: url, method: "post", data: paramData });
      fun
        .then((res) => {
          // 需要数据处理时传入此方法
          if (res.code == 200) {
            if (this.dataConversion) {
              res = this.dataConversion(res);
            }
            this.tableData = res.data.rows;
            this.recordCnt = res.data.total;
            if (res.other && this.param.otherType) {
              this.totalLine(res.other);
            }
            if (res.data.rows.length == 0 && this.curPage != 1) {
              this.curPage = this.curPage - 1;
              this.getTableData(this.searchFormData);
              return;
            }
            this.$emit("getTableData", res);
          }
        })
        .finally(() => {
          this.loading = false;
        });
    },
    //合计增加字段
    totalLine(total) {
      //是否增加"合计"行
      let tatalObj = {
        //收款合计
        contract: {
          contractName: "合计",
          totalGetPrice: total != null ? total.total.totalGetPrice : "",
          amount: total.total != null ? total.amount : "",
          totalOpenPrice: total != null ? total.total.totalOpenPrice : "",
        },
        attendance: {
          userName: "合计",
          amount: total != null ? total.amount : "",
          totalOpenPrice: total != null ? total.totalOpenPrice : "",
          totalGetPrice: total != null ? total.totalGetPrice : "",
        },
        ticketList: {
          code: "合计",
          totalGetPrice: total != null ? total.total.totalGetPrice : "",
          invoicingPrice: total != null ? total.total.invoicingPrice : "",
        },
        payeeList: {
          inCode: "合计",
          getPrice: total != null ? total.total : "",
        },
      };
      this.$nextTick(() => {
        this.tableData.push(tatalObj[this.param.otherType]);
      });
    },

    selectChange(selection) {
      this.$emit('selecTableChoice',selection);
    },
    selectFun(selection) {
      // selectFun(selection, row) {
      this.selectRow = selection;
    },
    selectAll(selection) {
      this.selectRow = selection;
    },
    //传值设置单独td的字体颜色
    handleEvalStatuslist(val) {
      if (val == 1) {
        return "linkcolor";
      } else {
        return " ";
      }
    },
    // ,selectionChange(selection) {}
  },
};
</script>
<style lang="scss" scoped>
.table_oper_btn :not(:last-child) {
  position: relative;
  &::after {
    content: " ";
    // clear:both;
    // display: inline-block;
    position: absolute;
    right: 0;
    top: 5px;
    height: 8px;
    width: 1px;
    background: #e4e4e4;
  }
}
.table_wrap {
  font-size: 14px;
  // height: calc(100vh - 229px);
  color: #303133;
  // padding: 0 30px;
  display: flex;
  flex-direction: column;
  justify-content: space-between;
  .el-table {
    // min-height: 480px;
    border-radius: 4px 4px 0 0;
    // overflow: auto;
    margin-bottom: 10px;
    .cell {
      font-weight: bold;
    }
    .el-table__row {
      height: 40px;
      td {
        .el-radio.radio_column ::v-deep.el-radio__label {
          display: none;
        }
        div {
          overflow: hidden;
          text-overflow: ellipsis;
        }
        span {
          font-size: 12px;
          font-weight: 400;
        }
        .el-button {
          border: none;
          background: transparent;
          // color: $main-color;
        }
        .delete_btn {
          // color: $error-color;
          color: #d9001b;
        }
        .edit_btn {
          color: #0e73ee;
        }
        .edits_btn {
          color: #0e73ee;
        }
        .drawer_btn {
          color: #0e73ee;
        }
        .cancel_btn {
          color: #0e73ee;
        }
      }
    }
  }
  .pagination {
    display: flex;
    justify-content: flex-end;
  }
  .page.el-pagination {
    font-weight: normal;
    text-align: right;
    // color: $content-text-color;
    margin-bottom: 10px;
    .records {
      margin-right: 22px;
      .high_light {
        // color: $main-color;
        min-width: 0;
        padding: 0 3px;
      }
    }
    .first_page,
    .last_page {
      display: inline-block;
      cursor: pointer;
      height: 30px;
      padding: 0;
      border: 1px solid #e4e7ee;
      border-radius: 4px;
      padding: 0 10px;
    }
    .last_page {
      margin-left: 10px;
    }
    ::v-deep.el-pagination__jump {
      margin-left: 20px;
    }
    .first_page:hover,
    .last_page:hover {
      // color: $main-color;
    }
    ::v-deep button,
    ::v-deep .el-pager li {
      min-width: 30px;
      height: 30px;
      padding: 0;
      border: 1px solid #e4e7ee;
      border-radius: 4px;
      margin: 0 4.5px;
    }

    ::v-deep li.active {
      color: #fff;
      // background-color: $main-color;
      cursor: default;
    }
  }
}
//1
.active {
  color: #3366ee;
}

.linkcolor {
  color: #3366ee;
  cursor: pointer;
}
</style>