<!-- * @description 表格组件 * @fileName TableList.vue * @authorQ * @date 2021/05/15 15:13:45 --> <template> <div class="table-container"> <el-table v-if="showTable" ref="filterTable" :span-method="spanName?objectSpanMethod:null" :data="data" :show-summary="showSummary.show ? showSummary.show : null" :summary-method="showSummary.show ? summaryMethod : null" :sum-text="showSummary.sumText ? showSummary.sumText : null" @filter-change="handleFilterChange" :border="border" :stripe="stripe" empty-text="暂无数据" style="width: 100%" :show-header="showHeader" :tooltip-effect="tooltipTheme" @selection-change="handleSelectionChange" > <!-- 选择框列 --> <el-table-column v-if="selection" type="selection" :align="'center'" ></el-table-column> <!-- 排序列 --> <el-table-column v-if="indexShow" width="100" label="序号" :align="'center'" > <template slot-scope="scope"> <div> <span>{{ scope.$index + 1 }}</span> </div> </template> </el-table-column> <template v-for="(item, index) in columns"> <!-- 特殊列处理 --> <template v-if="item.render"> <!-- visible 是否显示该列 --> <el-table-column v-if="item.visible" :filters="item.filters ? item.filters : null" :column-key="item.prop" :key="index" :prop="item.prop ? item.prop : null" :align="item.align ? item.align : null" :fixed="item.fixed ? item.fixed : null" :label="item.label ? item.label : null" :show-overflow-tooltip="item.tooltip" :class-name="className" :sortable="item.sortable ? item.sortable : false" :width="item.width ? item.width : null" > <!-- 多级表头 --> <template v-if="item.children && item.children.length > 0"> <div v-for="(item1, index1) in item.children" :key="index1"> <el-table-column :key="index1" :filters="item.filters ? item.filters : null" :column-key="item.prop" :prop="item1.prop ? item1.prop : null" :align="item1.align ? item1.align : null" :fixed="item1.fixed ? item1.fixed : null" :label="item1.label ? item1.label : null" :show-overflow-tooltip="item1.tooltip" :class-name="className" :sortable="item1.sortable ? item1.sortable : false" :width="item1.width ? item1.width : null" > <exSlot :render="item1.render" :row="scope.row" :index1="scope.$index" :column="item1" /> </el-table-column> </div> </template> <!-- 不是多级表头 --> <template slot-scope="scope"> <exSlot :render="item.render" :row="scope.row" :index="scope.$index" :column="item" /> </template> </el-table-column> </template> <!-- 正常列 --> <template v-else> <!-- visible 是否显示该列 --> <el-table-column v-if="item.visible" :key="index" :column-key="item.prop" :filters="item.filters ? item.filters : null" :prop="item.prop ? item.prop : null" :align="item.align ? item.align : null" :fixed="item.fixed ? item.fixed : null" :label="item.label ? item.label : null" :class-name="className" :show-overflow-tooltip="item.tooltip" :sortable="item.sortable ? item.sortable : false" :width="item.width ? item.width : null" > <!-- 多级表头 --> <template v-if="item.children && item.children.length > 0"> <template v-for="(item1, index1) in item.children"> <el-table-column :prop="item1.prop ? item1.prop : null" :column-key="item.prop" :filters="item.filters ? item.filters : null" :align="item1.align ? item1.align : null" :fixed="item1.fixed ? item1.fixed : null" :label="item1.label ? item1.label : null" :show-overflow-tooltip="item1.tooltip" :class-name="className" :sortable="item1.sortable ? item1.sortable : false" :width="item1.width ? item1.width : null" > <template slot-scope="scope"> <span v-html="formatter(scope.row[item1.prop])"></span> </template> </el-table-column> </template> </template> <template slot-scope="scope"> <!-- 字典处理 --> <template v-if="item.dict"> <!-- 判断原始数据是否有效,有效转为字典数据,无效则转为--占位符 --> <span v-if="!scope.row[item.prop]" v-html="formatter(scope.row[item.prop])" ></span> <dict-tag v-else :options="dict.type[item.prop]" :value="scope.row[item.prop]" /> </template> <!-- 时间格式化 --> <span v-else-if="item.time">{{ parseTime(scope.row[item.prop], "{y}-{m}-{d}") }}</span> <!-- 不做处理 --> <span v-else v-html="formatter(scope.row[item.prop])"></span> </template> </el-table-column> </template> </template> <!-- 操作列 --> <el-table-column v-if="isEdit === true" label="操作" :align="'center'" width="200" :fixed="fixed" > <template slot-scope="scope"> <slot name="editSlot"> <template> <el-button type="primary" @click="editClick(scope.row)" >编辑</el-button > <el-button type="danger" @click="deleteClick(scope.row)" >删除</el-button > </template> </slot> </template> </el-table-column> </el-table> <el-pagination :style="{ float: `${paginationPosition}` }" v-if="pagination" :background="background" :current-page.sync="currentPage" :page-size.sync="currentSize" :layout="layout" :page-sizes="pageSizes" :total="total" @size-change="handleSizeChange" @current-change="handleCurrentChange" /> </div> </template> <script> // 自定义内容的组件 var exSlot = { functional: true, props: { row: Object, render: Function, index: Number, column: { type: Object, default: null, }, }, // render 函数 render: (h, context) => { const params = { row: context.props.row, index: context.props.index, }; if (context.props.columns) params.columns = context.props.columns; return context.props.render(h, params); }, }; export default { name: "TableList", components: { exSlot }, props: { data: { type: Array, default: () => [], }, update: { type: Number, default: () => null, }, // 是否显示合计列 showSummary: { type: Object, default: () => { return { show: false, sumText: "总计", }; }, }, // 需要通过那个字段属性进行比较合并 spanName: { type: String, default: () => { return null; }, }, // 需要合并数组 spanColumnArr:{ type:Array, default:()=>{ return [0] } }, tooltipTheme: { type: String, default: "dark", }, // 是否显示表头 showHeader: { type: Boolean, default: true, }, // 是否添加排序列 indexShow: { type: Boolean, default: true, }, showTable: { type: Boolean, default: true, }, // 是否显示选择框列 selection: { type: Boolean, default: false, }, // 字段名 columns: { type: Array, default: () => [], }, // 是否含有边框 border: { type: Boolean, default: false, }, // 是否显示斑马条纹 stripe: { type: Boolean, default: false, }, // 是否是可以编辑的表格 isEdit: { type: Boolean, default: false, }, // 是否固定右侧一列,只对右侧操作栏起作用 fixed: { type: String, default: "right", }, // 是否显示分页 pagination: { type: Boolean, default: false, }, // 分页的位置 paginationPosition: { type: String, default: "center", }, total: { required: false, type: Number, }, page: { type: Number, default: 1, // 默认第一页 }, limit: { type: Number, default: 10, // 默认每页20条 }, pageSizes: { type: Array, // default: [10, 20, 30, 50] default: function () { return [1, 2, 3, 5]; // 默认显示可选的每页多少条数据 }, }, layout: { type: String, default: "total, sizes, prev, pager, next, jumper", }, background: { type: Boolean, default: true, }, autoScroll: { type: Boolean, default: true, }, hidden: { type: Boolean, default: false, }, className: { type: String, default: "", }, render: { type: Function, default: function () {}, }, }, data() { return { cloneColumns: [], spanArr: [], // 跨行数组 pos: null, // 跨行数组 }; }, computed: { // 当前页多少条数据并且赋值给父组件 currentPage: { get() { return this.page; }, set(val) { this.$emit("update:page", val); }, }, // 改变当前页几条数据得值赋值给父组件 currentSize: { get() { return this.limit; }, set(val) { this.$emit("update:limit", val); }, }, }, created() { this.cloneColumns = JSON.parse(JSON.stringify(this.columns)); }, watch: { columns(value) {}, }, mounted() { if (this.spanName) { this.getSpanArr(this.data); } }, methods: { // 合同单元格直接传入:spanName="id或者其他字段属性名" getSpanArr(data) { for (let i = 0; i < data.length; i++) { if (i === 0) { this.spanArr.push(1); this.pos = 0; } else { // 判断当前的元素和上一个元素是否相同 // name 需要通过哪个字段来进行比较合并 if (data[i][this.spanName] === data[i - 1][this.spanName]) { this.spanArr[this.pos] += 1; this.spanArr.push(0); } else { this.spanArr.push(1); this.pos = i; } } } }, // 合并 objectSpanMethod({ row, column, rowIndex, columnIndex }) { if (this.spanColumnArr.includes(columnIndex)) { const _row = this.spanArr[rowIndex]; const _col = _row > 0 ? 1 : 0; return { rowspan: _row, colspan: _col, }; } }, // 自定义合计行 summaryMethod(params) { const { columns, data } = params; const sums = []; columns.forEach((column, index) => { if (index === 0) { sums[index] = "总计"; return; } const values = data.map((item) => item[column.property]); let num = 0; for (let i = 0; i < values.length; i++) { if (values[i]) { num += Number(values[i]); sums[index] = num; } else { if (isNaN(values[i])) { } else { num += Number(values[i]); sums[index] = num; } } } if (column.property === "lv1Time" || column.property === "lv2Time") { if (values.filter(Boolean).length === 0) { sums[index] = ""; } else { let num = 0; for (let i = 0; i < values.length; i++) { if (values[i]) { num += Number(values[i]); sums[index] = num; } else { if (isNaN(values[i])) { } else { num += Number(values[i]); sums[index] = num; } } } } } }); let arr = []; sums.map((i, index) => { if (index === 0) { arr.push(i); } else { if (!isNaN(i)) { arr.push(i); } else { arr.push(""); } } }); return arr; }, handleFilterChange(filters) { if (filters.length > 0) { this.$refs.filterTable.clearSelection(); this.$refs.filterTable.toggleRowSelection(filters.pop()); } else { this.columns.map((item) => { // 判断当前是那一列进行了筛选 if (item.prop === Object.keys(filters)[0]) { item.filterValues = filters; } }); this.$emit("filtersParams", this.columns); } }, // 当前行当前列数据是否有效,无效的话,返回--占位符 formatter(row) { if (row) { return isNaN(parseFloat(row)) && isFinite(row) ? '<span class="isNaN">--</span>' : row; } else { return '<span class="isNaN">--</span>'; } }, /** * @param {*} * @return {*} * @author: Q * @Date: 2021-09-01 11:56:37 * @description: 已选的数据项 */ handleSelectionChange(val) { this.$emit("selectVal", val); }, handleSizeChange(val) { this.pageSize = val; this.$emit("pagination", { pageIndex: this.page, pageSize: val }); }, handleCurrentChange(val) { this.$emit("pagination", { pageIndex: val, pageSize: this.limit }); }, // 修改按钮的点击事件 editClick(val) { this.$emit("edit", val); }, // 删除按钮点击事件 deleteClick(val) { this.$confirm("此操作将永久删除该文件, 是否继续?", "提示", { confirmButtonText: "确定", cancelButtonText: "取消", type: "warning", }) .then(() => { this.$emit("del", val); }) .catch(() => { this.$message({ type: "info", message: "已取消删除", }); }); }, }, }; </script> <style lang="scss"> .table-container { text-align: center; .el-pagination { margin-left: 0 !important; margin-top: 0 !important; background: #fff !important; height: 112px; line-height: 112px; display: flex; justify-content: center; align-items: center; ul { display: flex; justify-content: space-around; align-items: center; li { border-radius: 6px !important; color: #666666 !important; } .active { color: #fff !important; background: #1677ffff !important; } } button { border-radius: 6px !important; color: #666666 !important; } } } .table-container.el-table { margin-top: 20px; } .table-container .el-pagination { margin-top: 20px; margin-left: 20px; } .isNaN { color: red; } </style>