You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 

688 lines
21 KiB

<template>
<div class="heavy-container">
<!-- 列筛选 -->
<el-popover
placement="right"
title="列筛选"
trigger="click"
class="right-toolbar"
>
<el-checkbox-group v-model="checkedColumns">
<el-checkbox
class="checkoutItem"
v-for="(item, index) in config"
:key="index"
:label="item.label"
:value="item.istrue"
></el-checkbox>
</el-checkbox-group>
<el-button
slot="reference"
plain
:disabled="ColumnFilteringFlag"
><i class="el-icon-arrow-down el-icon-menu" /></el-button>
</el-popover>
<!-- <div class="w-table" :class="{ 'w-table_moving': dragState.dragging }"> -->
<el-table
:row-key="changeId"
border
show-overflow-tooltip="true"
ref="heavyTable"
:class="tableClass"
v-bind="tableProps"
:data="data"
height="500px"
v-loading="loading"
@selection-change="handleSelectionChange"
@sort-change="sortChange"
@row-click="rowClick"
@cell-dblclick="cellDblclick"
:row-class-name="tableRowClassName"
:row-style="{height:'0px'}"
:cell-style="{padding:'2px'}"
style="font-size: 12px"
>
<!-- :row-style="selectedHighlight" -->
<!-- v-table-drag -->
<template v-for="(item, index) in config">
<el-table-column
v-if="item.istrue && ['selection', 'index'].includes(item.type)"
:key="index"
v-bind="item"
:index="
paging && ((i) => paging.page * paging.size + i + 1 - paging.size)
"
:width="item.width || '55'"
:align="item.align || 'center'"
:column-key="index.toString()"
>
<!-- :render-header="renderHeader" -->
</el-table-column>
<el-table-column
v-else-if="item.istrue && item.type === 'radio'"
:key="index + 'radio'"
v-bind="item"
:width="item.width || '55'"
:align="item.align || 'center'"
:column-key="index.toString()"
>
<template slot-scope="scope">
<el-radio
v-model="radioSlot"
:label="scope.row"
@change="
(status) =>
item.event && item.event(status, scope.row, item.prop)
"
>{{ "" }}</el-radio>
</template>
</el-table-column>
<el-table-column
v-else-if="item.istrue && item.type === 'slot'"
:key="index + 'slot'"
v-bind="item"
:show-overflow-tooltip="item.tooltip === false ? false : true"
:column-key="index.toString()"
>
<!-- :render-header="renderHeader" -->
<template slot-scope="scope">
<slot
:name="item.slotName || item.name"
v-bind="{ row: scope.row }"
></slot>
</template>
</el-table-column>
<el-table-column
v-else-if="item.istrue"
:key="index + 'content'"
v-bind="item"
:show-overflow-tooltip="item.tooltip === false ? false : true"
:column-key="index.toString()"
>
<!-- :render-header="renderHeader" -->
<template v-if="item.children">
<el-table-column
v-for="(item, key) in item.children"
:key="'s' + key"
v-bind="item"
:show-overflow-tooltip="item.tooltip === false ? false : true"
>
<template slot-scope="scope">
<slot
v-if="item.type === 'slot'"
:name="item.slotName || item.name"
v-bind="{ row: scope.row }"
></slot>
<table-cell
v-else
:item="item"
:scope="scope"
@handlerEvent="handlerEvent"
/>
</template>
</el-table-column>
</template>
<template
v-if="!item.children"
slot-scope="scope"
>
<table-cell
:item="item"
:scope="scope"
@handlerEvent="handlerEvent"
/>
</template>
</el-table-column>
</template>
</el-table>
<!-- </div> -->
<!-- <div v-if="paging && paging.total / paging.size > 1" class="shim"></div> -->
<div
v-if="paging"
class="pagination"
>
<!-- v-if="paging.total / paging.size > 1" -->
<!-- v-show="paging.total>0" -->
<el-pagination
background
v-show="paging.total>0"
:current-page.sync="paging.page"
:page-size="paging.size"
:total="paging.total"
:pager-count="paging.pagerCount || 7"
:page-sizes="[10, 50, 100]"
layout="total, sizes, prev, pager, next,jumper"
@current-change="(value) => $emit('current-change', value)"
@size-change="(value) => $emit('current-change', { size: value })"
>
</el-pagination>
</div>
</div>
</template>
<script>
import TableCell from './item.vue'
import elementOffsetTop from './elementOffsetTop'
import debounce from './debounce'
import Vue from 'vue'
// v-table-drag 自定义指令拖动的方式 存在bug
Vue.directive('tableDrag', {
update: function (el, binding, vnode) {
var container = el.parentNode
var tbody = el.getElementsByClassName('el-table__body-wrapper')[0]
var thead = el.getElementsByClassName('el-table__header-wrapper')[0]
// 更新数据时,先还原数据本来的顺序,不然新加载的数据和表头对不上
var trCollection = container.getElementsByTagName('tr')
for (var i = 0; i < trCollection.length; i++) {
var tr = trCollection[i]
if (i == 0) {
var collection = tr.getElementsByTagName('th')
} else {
var collection = tr.getElementsByTagName('td')
}
if (collection.length > 1) {
let cellArr = []
for (let j = 0; j < collection.length; j++) {
let cell = collection[j]
let classNames = cell.className
let className = classNames.split(' ')[0]
let arr = className.split('_')
if (arr.length) {
let index = arr[arr.length - 1]
cellArr[index - 1] = cell
}
}
for (let k = 0; k < cellArr.length; k++) {
tr.insertBefore(cellArr[k], collection[k])
}
}
}
// 列拖拽开始...
if (!container.className.includes('drag-table')) container.className = ' drag-table'
thead.onmousedown = function (e) {
const clickX = event.clientX
const rect = event.target.getBoundingClientRect()
const divLeft = rect.left
const divRight = rect.right
//拖动列
if (event.target.tagName == 'DIV' && clickX > divLeft + 5 && clickX < divRight - 5) {
//被拖动的th
var ev_th = event.target.parentNode
var scrollLeft = tbody.scrollLeft
//算出鼠标相对元素的位置
let disX = e.clientX + scrollLeft - ev_th.offsetLeft
let disY = e.clientY - ev_th.offsetTop
let thWidthArr = [] // 记录所有的th的宽度,依次累加
let thWidthObj = {} // 记录所有的th的宽度,依次累加
let finallIndex = 0 //最终的th index
let directionIndex = 0 // 单击的是第几个th
let move = 0 // 移动的方向 1-右 2-左
const ths = ev_th.parentNode.children
var len = ths.length - 1 // 删除elementUI最后的class="gutter"的元素
for (let thi = 0; thi < len; thi++) {
const itemth = ths[thi]
itemth.index = thi
thWidthArr.push(itemth.offsetLeft)
}
directionIndex = ev_th.index
// 以鼠标按下的这个th处,创建一个和th内容一样的div,
const createDiv = document.createElement('div')
createDiv.id = 'created-div'
container.appendChild(createDiv)
document.onmousemove = (e) => {
// 用鼠标的位置减去鼠标相对元素的位置,得到元素的位置
let left = e.clientX - disX
let top = e.clientY - disY
if (Math.abs(e.clientX - disX - ev_th.offsetLeft) < 10) {
return
}
//绑定元素位置到positionX和positionY上面
//移动当前元素
const thText = ev_th.innerHTML
createDiv.innerHTML = thText
createDiv.style.position = 'absolute'
createDiv.style.width = ev_th.offsetWidth + 'px'
createDiv.style.height = ev_th.offsetHeight + 'px'
createDiv.style.background = 'rgb(242, 242, 242)'
createDiv.style.lineHeight = ev_th.offsetHeight + 'px'
createDiv.style.textAlign = 'center'
createDiv.style.left = left + 'px'
createDiv.style.top = top + 'px'
createDiv.style.whiteSpace = 'nowrap'
createDiv.style.textOverflow = 'ellipsis'
createDiv.style.overflow = 'hidden'
finallIndex = 0 //鼠标拖动过程中所停留在的th的index
var distance = createDiv.offsetLeft + scrollLeft
var i = thWidthArr.length - 1
while (i >= 0) {
if (distance >= thWidthArr[i]) {
finallIndex = i
break
}
i--
}
}
document.onmouseup = (e) => {
if (directionIndex < finallIndex) {
move = 1
} //右移
else if (directionIndex > finallIndex) {
move = 2
} //左移
const th_trs = thead.getElementsByTagName('tr')
const td_trs = tbody.getElementsByTagName('tr')
container.removeChild(createDiv)
// 取消鼠标拖动和鼠标抬起事件
document.onmousemove = null
document.onmouseup = null
// 如果没有进行拖动操作(鼠标点下就抬起)
if (Math.abs(e.clientX - disX - ev_th.offsetLeft) < 10) {
thWidthArr = []
disX = 0
return
}
// 遍历tr,将th和td放到最终的位置上
var itemtr = th_trs[0]
if (itemtr.getElementsByTagName('th').length) {
const ths = itemtr.getElementsByTagName('th')
if (move === 1) {
itemtr.insertBefore(ths[directionIndex], ths[finallIndex + 1])
} else if (move === 2) {
itemtr.insertBefore(ths[directionIndex], ths[finallIndex])
}
}
for (let i = 0; i < td_trs.length; i++) {
const itemtr = td_trs[i]
if (itemtr.getElementsByTagName('td').length) {
const tds = itemtr.getElementsByTagName('td')
if (move === 1) {
itemtr.insertBefore(tds[directionIndex], tds[finallIndex + 1])
} else if (move === 2) {
itemtr.insertBefore(tds[directionIndex], tds[finallIndex])
}
}
}
// 重置thWidthArr和disX
thWidthArr = []
disX = 0
}
}
}
}
})
export default {
name: 'RfHeavyTable',
components: {
TableCell
},
props: {
ColumnFilteringFlag: {
type: Boolean,
default: false,
require: false
},
config: {
type: Array,
default: () => []
},
data: {
type: Array,
default: () => []
},
paging: {
type: Object,
default: () => ({
page: 1,
size: 10,
total: 0,
autoSize: false,
lineHeight: null,
offsetBottom: null
})
},
loading: Boolean,
tableClass: {
type: String,
default: 'heavyTable'
},
tableProps: Object,
/** 表格根据状态显示对应背景色
* @param fieldName 状态对应的字段名
* @param colorList [{ status: "字典状态", color: "背景颜色" }]
*/
colorStatus: {
type: Object,
default: () => ({})
},
// 是否显示点击样式
isSelectedHighlight: {
type: Boolean,
default: true
}
},
data() {
return {
radioSlot: '',
selecteddata: [], //选中数据
sortdata: {}, //排序
getIndex: '', //行点击
checkedColumns: [], //列筛选
checkBoxGroup: [], //列筛选
// dragState: {
// // 拖动
// start: -8, // 起始元素的 index
// end: -8, // 移动鼠标时所覆盖的元素 index
// dragging: false, // 是否正在拖动
// direction: undefined, // 拖动方向
// },
tableHeader: this.config //表头
}
},
computed: {
changeId() {
return this.tableProps && this.tableProps['row-key'] ? this.tableProps['row-key'] : 'id'
}
},
beforeUpdate() {
// 重新布局表格
this.$nextTick(() => {
this.$refs.heavyTable.doLayout()
})
},
// 监控列隐藏
watch: {
checkedColumns: {
handler(val) {
this.$emit('configChangeShow', val)
let arr = this.checkBoxGroup.filter((i) => !val.includes(i)) // 未选中
/**
* 是否记录本地缓存
* localStorage.setItem(this.colTable, JSON.stringify(arr));
*/
this.config.filter((i) => {
if (arr.indexOf(i.label) != -1) {
this.$nextTick(function () {
i.istrue = false
this.$refs.heavyTable.doLayout()
})
} else {
this.$nextTick(function () {
i.istrue = true
this.$refs.heavyTable.doLayout()
})
}
})
},
immediate: false
}
},
created() {
// 列筛选
this.config.forEach((item, index) => {
this.checkBoxGroup.push(item.label)
if (item.istrue || item.istrue === undefined) {
// 初始化并不是所有都为true,且会存在不写istrue属性的(这时为undefined)
this.checkedColumns.push(item.label)
}
})
/**
* 是否记录本地缓存
*
// this.checkedColumns = this.checkedColumns;
// let UnData = localStorage.getItem(this.colTable);
// UnData = JSON.parse(UnData);
// if (UnData != null) {
// this.checkedColumns = this.checkedColumns.filter((item) => {
// return !UnData.includes(item);
// });
// }
*/
},
mounted() {
if (this.paging.autoSize) {
this.autoTableContentHeight()
window.addEventListener('resize', debounce(this.autoTableContentHeight, 1000))
}
},
methods: {
// 处理点击表格当前项目按钮事件
handlerEvent(event, row, currItemKey) {
this.$emit(event, row, currItemKey)
},
// 翻页
handlePageChange(val) {
this.operatBtnClick('handlePageChange', val, this.propdata)
},
// 选择框改变事件
handleSelectionChange(val) {
this.selecteddata = val
this.$emit('handleselection', val)
this.$emit('selectionChange', val)
},
// 过滤改变事件
sortChange(val) {
// console.log(val)
this.sortdata = val
this.$emit('sortChange', val)
},
// 行点击事件
rowClick(row) {
this.getIndex = row.index
this.$emit('rowClick', row)
},
// 双击某个单元格
cellDblclick(row, column) {
this.$emit('cell-dblclick', row, column)
},
// 清除或者设置点击样式
setIndex(index = '') {
this.getIndex = index
},
// 行点击事件
tableRowClassName({ row, rowIndex }) {
//把每一行的索引放进row
row.index = rowIndex
},
// 行点击事件
selectedHighlight({ row, rowIndex }) {
if (this.getIndex === rowIndex && this.isSelectedHighlight) {
return {
'background-color': '#e6f1fe'
}
}
const { fieldName, colorList } = this.colorStatus
if (!fieldName || !colorList) return
const status = row[fieldName]
const item = colorList.find((it) => it.status === status)
if (item && item.color) {
return {
'background-color': `${item.color}`
}
}
},
// // //拖拽列
// renderHeader(createElement, { column }) {
// console.log(createElement);
// return createElement(
// "span",
// {
// class: ["thead-cell"],
// on: {
// mousedown: ($event) => {
// this.handleMouseDown($event, column);
// },
// mousemove: ($event) => {
// this.handleMouseMove($event, column);
// },
// },
// },
// [
// // 添加 <a> 用于显示表头 label
// createElement("a", column.label),
// // 添加一个空标签用于显示拖动动画
// createElement("span", {
// class: ["virtual"],
// }),
// ]
// );
// },
//拖拽列
// 表头
// renderHeader(h, data) {
// console.log(h, h);
// console.log(222, data);
// return h("span", [
// h(
// "el-tooltip",
// {
// attrs: {
// class: "item",
// effect: "dark",
// content: data.column.label,
// placement: "top",
// },
// },
// [h("span", data.column.label)]
// ),
// ]);
// },
// // // 按下鼠标开始拖动
// handleMouseDown(e, column) {
// this.dragState.dragging = true;
// this.dragState.start = parseInt(column.columnKey);
// // 给拖动时的虚拟容器添加宽高
// let table = document.getElementsByClassName("w-table")[0];
// let virtual = document.getElementsByClassName("virtual");
// for (let item of virtual) {
// item.style.height = table.clientHeight - 1 + "px";
// item.style.width = item.parentElement.parentElement.clientWidth + "px";
// }
// document.addEventListener("mouseup", this.handleMouseUp);
// },
// // 鼠标放开结束拖动
// handleMouseUp() {
// this.dragColumn(this.dragState);
// // 初始化拖动状态
// this.dragState = {
// start: -8,
// end: -8,
// dragging: false,
// direction: undefined,
// };
// document.removeEventListener("mouseup", this.handleMouseUp);
// },
// // 拖动中
// handleMouseMove(e, column) {
// if (this.dragState.dragging) {
// let index = parseInt(column.columnKey); // 记录起始列
// if (index - this.dragState.start !== 0) {
// this.dragState.direction =
// index - this.dragState.start < 0 ? "left" : "right"; // 判断拖动方向
// this.dragState.end = parseInt(column.columnKey);
// } else {
// this.dragState.direction = undefined;
// }
// } else {
// return false;
// }
// },
// // 拖动易位
// dragColumn({ start, end, direction }) {
// let tempData = [];
// let left = direction === "left";
// let min = left ? end : start - 1;
// let max = left ? start + 1 : end;
// for (let i = 0; i < this.tableHeader.length; i++) {
// if (i === end) {
// tempData.push(this.tableHeader[start]);
// } else if (i > min && i < max) {
// tempData.push(this.tableHeader[left ? i - 1 : i + 1]);
// } else {
// tempData.push(this.tableHeader[i]);
// }
// }
// //this.config = tempData;// 不能直接改变子组件的值
// this.$emit("configChangeMove", tempData);
// },
// // 拖拽列
// headerCellClassName({ column, columnIndex }) {
// let active =
// columnIndex - 1 === this.dragState.end
// ? `darg_active_${this.dragState.direction}`
// : "";
// let start = columnIndex - 1 === this.dragState.start ? `darg_start` : "";
// return `${active} ${start}`;
// },
// //拖拽列
// cellClassName({ column, columnIndex }) {
// return columnIndex - 1 === this.dragState.start ? `darg_start` : "";
// },
// 设置表格一页最大行数
autoTableContentHeight() {
if (!this.$refs['heavyTable']) return
const el = this.$refs['heavyTable'].bodyWrapper
// const ele = this.$refs["heavyTable"].bodyWrapper.firstChild.children[1].children[0]//el-table__cell
// console.log(ele.offsetHeight)
const fullHeight = document.body.clientHeight
const offsetTop = elementOffsetTop(el)
const offsetBottom = this.paging.offsetBottom || 92
const tableLineHeight = this.paging.lineHeight || 57
const visibleHeight = fullHeight - offsetTop - offsetBottom
const rows = Math.floor(visibleHeight / tableLineHeight)
const oldPages = Math.ceil(this.paging.total / this.paging.size)
const nowPages = Math.ceil(this.paging.total / rows)
if (oldPages > nowPages && this.paging.page > nowPages) {
this.paging.page = nowPages
}
this.paging.size = rows < 1 ? 1 : rows
this.$emit('current-change', this.paging.page)
}
}
}
</script>
<style lang="css" scoped>
.heavy-container {
height: 100%;
position: relative;
box-sizing: border-box;
}
.pagination {
/* position: absolute;
bottom: 0;
right: 0; */
display: flex;
justify-content: flex-end;
margin-top: 10px;
}
.shim {
height: 52px;
}
/* 隐藏列样式 */
::v-deep.checkoutItem {
display: block !important;
}
</style>