emis-frontend/src/components/XdTable/index_bak20250705.vue

1500 lines
53 KiB
Vue
Raw Normal View History

2025-07-07 02:09:48 +00:00
<template>
<div class="xd-table full-block flex-layout" :id="tableId" >
<div class="table-operate-btn-content" v-show="showOperateButton">
<slot name="operateBtnContent">
<div class="operate-btn-content">
<slot name="toolbar">
<div />
</slot>
<div class="top-right-btn" v-show="showRightButton">
<el-row>
<el-tooltip class="item" effect="dark" :content="showSearch ? '隐藏搜索' : '显示搜索'" placement="top">
<el-button size="mini" circle icon="el-icon-search" @click="toggleSearch()" />
</el-tooltip>
<el-tooltip class="item" effect="dark" content="刷新" placement="top">
<el-button size="mini" circle icon="el-icon-refresh" @click="refresh()" />
</el-tooltip>
<el-tooltip class="item" effect="dark" content="间距" placement="top">
<el-dropdown size="mini" @command="(command) => handleAdjustTableSize(command)">
<el-button size="mini" circle style="margin-left: 10px;" class="icon iconfont icon-hangjianju" />
<el-dropdown-menu slot="dropdown">
<el-dropdown-item command="small" >中等</el-dropdown-item>
<el-dropdown-item command="mini" >紧凑</el-dropdown-item>
<el-dropdown-item command="medium" >宽松</el-dropdown-item>
</el-dropdown-menu>
</el-dropdown>
</el-tooltip>
<el-tooltip class="item" effect="dark" content="显隐列" placement="top" v-if="canHideColumns">
<el-popover
placement="bottom-end"
popper-class="table-cloumn-setting-popper"
trigger="click"
:show-arrow="false"
>
<div class="setting-row-content">
<div style="text-align:right;display: inline-flex;width:240px;border-bottom: 1px solid #d5d4d438;padding: 0px 0px 10px 0px;">
<div style="text-align: left;width: 55%;">
<el-select
v-model="curentTbShowTpl"
size="mini"
clearable
filterable
allow-create
default-first-option
placeholder="模版名称"
@blur="onTplSelectInputBlur($event)"
:style="{width: '100%'}"
@change="changeTbShowTpl"
:disabled="!isNeedDbSaveTpl"
>
<el-option
v-for="(item, index) in storeTplList"
:key="index"
:label="item.tplName"
:value="item.tplCode"
/>
</el-select>
</div>
<div style="text-align: right;width: 45%;line-height: 30px;display:inline-flex">
<el-button type="text" size="mini" style="padding: 7px 5px;" @click="savaTbShowTpl" :disabled="!isNeedDbSaveTpl">保存</el-button>
<!-- <el-button type="text" size="mini" style="padding: 7px 5px;" icon="el-icon-refresh" @click="delStorage" ></el-button> -->
<el-button type="text" size="mini" style="padding: 7px 5px;" icon="el-icon-setting" @click="setTbShowTpl" :disabled="!isNeedDbSaveTpl"></el-button>
</div>
</div>
<div style="">
<div style="width:50%">
<el-checkbox :indeterminate="isIndeterminate" v-model="checkAll" @change="handleCheckAllChange">全选</el-checkbox>
</div>
<el-scrollbar style="height: calc(100vh - 200px);box-sizing: border-box;" >
<draggable v-model="storageList"
ghostClass="drag-ghost"
chosenClass="drag-chosen"
:animation="500"
handle=".el-icon-s-operation"
@end="updateTable"
>
<div v-for="col in storageList" :key="col.label" class="setting-row">
<i class="el-icon-s-operation icon iconfont icon-ui_drag_horizontally" />
<el-checkbox v-model="col.show" class="label" @change="showOrHidden($event,col)">{{ col.label }}</el-checkbox>
</div>
</draggable>
</el-scrollbar>
</div>
</div>
<el-button style="margin-left: 10px;" slot="reference" size="mini" circle icon="el-icon-menu" />
</el-popover>
</el-tooltip>
</el-row>
</div>
</div>
</slot>
</div>
<!-- @mouseenter="initKeyDownEvent" @mouseleave="removeKeyDownEvent" -->
<div >
<!-- <div class="flex-auto"> -->
<orig-table ref="table" :key="refreshKeyId" tabindex="0" :config="config" v-dragSelect class="xd-tb-wrapper" />
<!-- </div> -->
<!-- 统计数据 v-dragColumn v-dragSelect-->
<!-- <div class="flex-none"> -->
<div v-if="showStatInfo" style="display: inline-flex; width: 100%;">
<div style="width:40%" >
<div class="pagination-container"><slot name="statInfo" /></div>
</div>
<div v-if="showPagination" style="width:60%;overflow: hidden;" >
<pagination
v-show="total>0 "
:total="total"
:page-sizes="[10,20,50,100,300,500,1000,2000,5000]"
:page.sync="queryParams.pageNum"
:limit.sync="queryParams.pageSize"
:page-size="queryParams.pageSize"
@pagination="queryTable"
/>
</div>
</div>
<div v-else >
<div v-if="showPagination">
<pagination
v-show="total>0 "
:total="total"
:page-sizes="[5,10,20,50,100,300,500,1000,2000,5000]"
:page.sync="queryParams.pageNum"
:limit.sync="queryParams.pageSize"
:page-size="queryParams.pageSize"
@pagination="queryTable"
/>
</div>
</div>
<!-- </div> -->
</div>
<!-- 数据框选复制 -->
<div id="contextMenu" class="menuDiv" v-show="contextVisible">
<ul class="el-dropdown-menu el-popper el-dropdown-menu--medium"
style="transform-origin: center top; z-index: 2009;width: 180px;"
x-placement="bottom-end">
<li class="el-dropdown-menu__item" @click.stop="handleCopySelect($event)" > <span >复制</span></li>
<li class="el-dropdown-menu__item" @click.stop="handleSelectCurrentColumn($event)" > <span >选中当前列</span></li>
<li class="el-dropdown-menu__item" > <span @click="handleSelectCurrentRow(null,$event)">选中当前行</span></li>
</ul>
</div>
<el-dialog title="设置模板" :visible.sync="openTbShowTplDlg" width="50%">
<el-form ref="form" :model="form" size="small" :rules="rules" label-width="100px" :disabled="!isNeedDbSaveTpl">
<el-row :gutter="0" style="display: flex;flex-wrap: wrap;">
<el-col :span="12">
<el-form-item label="模板名称" prop="tplCode">
<el-select
ref="refNewTplCode"
v-model="form.tplCode"
size="mini"
clearable
filterable
allow-create
placeholder="选择模版"
:style="{width: '100%'}"
@change="changeSaveTbShowTpl"
>
<el-option
v-for="(item, index) in storeTplList"
:key="index"
:label="item.tplName"
:value="item.tplCode"
/>
</el-select>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="默认此模板" prop="blDefault">
<el-radio-group v-model="form.blDefault">
<el-radio label="1" value="1">是</el-radio>
<el-radio label="0" value="0">否</el-radio>
</el-radio-group>
</el-form-item>
</el-col>
<el-col :span="24">
<el-form-item label="备注" prop="remark">
<el-input v-model="form.remark" type="textarea" placeholder="" />
</el-form-item>
</el-col>
</el-row>
</el-form>
<div slot="footer" class="dialog-footer" style="text-align: center;margin-bottom:20px">
<el-button size="mini" @click="delStorage">重置</el-button>
<el-button size="mini" @click="delTbShowTpl">删除该模版</el-button>
<el-button type="primary" size="mini" @click="savaTbShowTpl">保 存</el-button>
<el-button size="mini" @click="openTbShowTplDlg = false">关 闭</el-button>
</div>
</el-dialog>
</div>
</template>
<script>
import { listSysCustomizeTpl, delSysCustomizeTpl, addSysCustomizeTpl, updateSysCustomizeTpl } from "@/api/system/sysCustomizeTpl";
import { genJsSeqNo } from "@/utils/custom";
import clip from '@/utils/clipboard'
import Sortable from 'sortablejs'
import draggable from 'vuedraggable'
import origTable from './table.jsx'
import VirtualScroll from "el-table-virtual-scroll";
import { VirtualColumn } from "el-table-virtual-scroll";
const components = { origTable, draggable,VirtualScroll }
export default {
name: 'XdTable',
components,
props: {
id: {
type: String,
},
showSearch: {
type: Boolean,
default: true,
},
showStatInfo: {
type: Boolean,
default: false,
},
canHideColumns: {
type: Boolean,
default: true,
},
storageName: {
type: String,
required: false
},
queryParams:{
type: Object,
default: null,
},
total:{
type: Number,
default: 0,
},
showRightButton:{
type: Boolean,
default: true,
},
showPagination:{
type: Boolean,
default: true,
},
showOperateButton:{
type: Boolean,
default: true,
},
showCustomizeTpl:{
type: Boolean,
default: true,
},
},
// 框选的指令
directives: {
dragSelect: {
// 指令的定义
inserted: function (el, binding, vnode) {
var oDiv = el;
var tbBodyDiv=oDiv.getElementsByClassName("el-table__body-wrapper")[0];
// 鼠标按下事件
tbBodyDiv.onmousedown = function (ev) {
var evt = window.event || arguments[0];
var flag = true;
// 鼠标右键菜单,并且记录当前位置
if(evt.button == 2){
flag=false;
if(
vnode.context.multipleSelection
&&vnode.context.multipleSelection.length>0
&& vnode.context.mouseInScope
)
{
// 记住当前单元格位置
vnode.context.currentOdiv=oDiv;
vnode.context.currentCell=evt.target;
const currentCellInfo=getCellPosition(evt.target);
vnode.context.currentCellInfo=currentCellInfo;
// 绑定右键菜单
bindRightContextMenu(evt);
}
return;
}
// 清除已有选择
let selNodes=document.querySelectorAll(".seled");
if(selNodes!=null&&selNodes.length>0){
for (var i = 0; i < selNodes.length; i++) {
selNodes[i].classList.remove("seled")
}
}
vnode.context.contextVisible=false;
// 增加图层
var xdTableObj = document.getElementById(vnode.context.tableId);
var tbBody1=xdTableObj.getElementsByClassName("el-table__body-wrapper")[0];
var selDiv = document.createElement("div");
selDiv.style.cssText = "position:absolute;width:0px;height:0px;font-size:0px;margin:0px;padding:0px;border:2px solid #409eff;background-color:#d9ecff;z-index:1000;filter:alpha(opacity:60);opacity:0.6;display:none;";
selDiv.id = "selectDiv-"+vnode.context.tableId;
tbBody1.appendChild(selDiv);
// 表格对象
const refTableObj=vnode.context.getInstance();
const tableDom=vnode.context.$refs.table.$refs.elTable.$el;
//用来存储列表 单元格和行
var selList = [];
var selRowList = [];
//获得指令下的dom对应的表格
var fileNodes = oDiv.getElementsByTagName("td");
var fileRowNodes = oDiv.getElementsByTagName("tr");
// 获得鼠标 X,Y
var startX = (evt.x || evt.clientX);
var startY = (evt.y || evt.clientY);
// 优先选中当前单元格
setMouseCellSelect(evt.target);
var _x = null;
var _y = null;
vnode.context.clearEventBubble(evt);
// //打开开关
vnode.context.mouseflag = true;
const tbBodyDivRect = tbBodyDiv.getBoundingClientRect();
// //鼠标拖动时画框
document.onmousemove = function (ev) {
evt = window.event || arguments[0];
_x = (evt.x || evt.clientX);
_y = (evt.y || evt.clientY);
//过滤在范围外的事件
if(_x<tbBodyDivRect.x || _x>(tbBodyDivRect.x+tbBodyDivRect.width)
|| _y<tbBodyDivRect.y || _y>(tbBodyDivRect.y+tbBodyDivRect.height)
){
vnode.context.isTableFocused=false;
vnode.context.mouseInScope=false;
// cancelRightContextMenu();
return;
}
// if(!tbBodyDiv.contains(document.activeElement)){
// vnode.context.isTableFocused=false;
// vnode.context.mouseInScope=false;
// return;
// }
vnode.context.isTableFocused=true;
vnode.context.mouseInScope=true;
if(Math.abs(_x - startX)<5 && Math.abs(_y - startY)<5){
// setMouseCellSelect(evt.target);
// setMouseRowSelect(evt.target);
return;
}
//
if(flag&&vnode.context.mouseflag){
vnode.context.multipleSelection=[];
console.log("===fileNodes.length==>",fileNodes.length);
// 只选取范围内的数据
for (var i = 0; i < fileNodes.length; i++) {
// console.log("===fileNodes==>",i);
if (fileNodes[i].className.indexOf("el-table__cell") != -1) {
fileNodes[i].classList.remove("seled");
console.log("===selList.length==>",selList.length);
selList.push(fileNodes[i]);
}
}
for (var i = 0; i < fileRowNodes.length; i++) {
if (fileRowNodes[i].className.indexOf("el-table__row") != -1) {
fileRowNodes[i].classList.remove("rowSeled");
selRowList.push(fileRowNodes[i]);
}
}
flag = false;
}
if (vnode.context.mouseflag) {
if (selDiv.style.display == "none") {
selDiv.style.display = "";
}
// 获取表格的位置
let tbPosRect2=getTablePosition(tableDom);
var tbBody2=oDiv.getElementsByClassName("el-table__body-wrapper")[0];
var tbHeader2=oDiv.getElementsByClassName("el-table__header-wrapper")[0];
selDiv.style.left = Math.min(_x, startX)-tbPosRect2.left+tbBody2.scrollLeft + "px";
//表头的高度
selDiv.style.top = Math.min(_y, startY)-tbPosRect2.top - tbHeader2.offsetHeight+tbBody2.scrollTop+ "px";
selDiv.style.width = Math.abs(_x - startX) + "px";
selDiv.style.height = Math.abs(_y - startY) + "px";
// 核心,判断选择的区域
var _l = selDiv.offsetLeft, _t = selDiv.offsetTop;
var _w = selDiv.offsetWidth, _h = selDiv.offsetHeight;
if(_y>(tbPosRect2.y+tbPosRect2.height)){
tbBody2.scrollBy(0, 60);
}
// else if(_y<(tbPosRect2.y-tbHeader2.offsetHeight)){
// tbBody2.scrollBy(0, 0-60);
// }
// 单元格
for (var i = 0; i < selList.length; i++) {
var sl = selList[i].offsetWidth + selList[i].offsetLeft;
var st = selList[i].offsetHeight + selList[i].offsetTop;
if(sl > _l && st > _t && selList[i].offsetLeft < _l + _w && selList[i].offsetTop < _t + _h) {
// 选择列不允许选择
if(selList[i].className.indexOf("--selection") != -1 ){
continue;
}
if (selList[i].className.indexOf("seled") == -1) {
selList[i].className = selList[i].className + " seled";
const cellInfo=getCellPosition(selList[i]);
vnode.context.multipleSelection.push(cellInfo);
}
}
}
// 行
for (var i = 0; i < selRowList.length; i++) {
var sl = selRowList[i].offsetWidth + selRowList[i].offsetLeft;
var st = selRowList[i].offsetHeight + selRowList[i].offsetTop;
if (sl > _l && st > _t && selRowList[i].offsetLeft < _l + _w && selRowList[i].offsetTop < _t + _h) {
if (selRowList[i].className.indexOf("rowSeled") == -1) {
selRowList[i].className = selRowList[i].className + " rowSeled";
refTableObj.toggleRowSelection(vnode.context.tableData[i],true)
//把选中的都存入到table标签中的已选中
// if(vnode.context.tableData[i]){
// vnode.context.multipleRowSelection.push(vnode.context.tableData[i]);
// }
}
} else {
if (selRowList[i].className.indexOf("rowSeled") != -1 ) {
// selRowList[i].className = "el-table__row";
refTableObj.toggleRowSelection(vnode.context.tableData[i],false);
selRowList[i].classList.remove("rowSeled");
}
}
}
}
vnode.context.clearEventBubble(evt);
};
function bindRightContextMenu(evt){
var xdTableObj = document.getElementById(vnode.context.tableId);
xdTableObj.addEventListener("contextmenu", vnode.context.handleOnContextMenu);
}
function cancelRightContextMenu() {
var xdTableObj = document.getElementById(vnode.context.tableId);
xdTableObj.removeEventListener('contextmenu',vnode.context.handleOnContextMenu)
// document.oncontextmenu = new Function("event.returnValue=true");
}
// 获取el-table元素的位置信息
function getTablePosition(tbDom) {
const tableRect = tbDom.getBoundingClientRect();
return tableRect;
}
function getCellXY(cell) {
try{
while(cell.tagName !== 'TD'){
cell = cell.parentElement;
}
// // console.log("xdtable==>",cell);
const cellRect = cell.getBoundingClientRect();
return { x:cellRect.x,y:cellRect.y,width:cellRect.width,height:cellRect.height};
}catch(e){
return { left:-1,top:-1,width:-1,height:-1};
}
}
function setMouseCellSelect(cell,selRowList) {
try{
while(cell.tagName !== 'TD'){
cell = cell.parentElement;
}
if(cell.className.indexOf("--selection") != -1 ){
return;
}
// 选中和取消选中
if(cell.className.indexOf("seled") != -1 ){
// cell.classList.remove("seled");
// vnode.context.multipleSelection=[];
}
else{
cell.className = cell.className + " seled";
vnode.context.mouseInScope=true;
}
const cellInfo=getCellPosition(cell);
vnode.context.multipleSelection=[];
vnode.context.multipleSelection.push(cellInfo);
// 行样式设置
// const refTableObj=vnode.context.getInstance();
// let rowIndex = cell.rowIndex;
// // selRowList[i].className = selRowList[i].className + " rowSeled";
// refTableObj.toggleRowSelection(vnode.context.tableData[rowIndex],true)
}catch(e){
}
}
// 获取鼠标位置的单元格
function getCellPosition(cell) {
try{
while(cell.tagName !== 'TD'){
cell = cell.parentElement;
}
const rowIndex = cell.parentElement.rowIndex;
const cellIndex = cell.cellIndex;
const text = cell.innerText;
return { row:rowIndex,col: cellIndex ,text:text};
}catch(e){
return { rowIndex:-1,cellIndex:-1};
}
}
//在鼠标抬起后做的重置
document.onmouseup = function () {
//把鼠标移动事初始化
// document.onmousemove=null;
var xdTableObj = document.getElementById(vnode.context.tableId);
var selDiv=document.getElementById("selectDiv-"+vnode.context.tableId);
if (selDiv) {
xdTableObj.getElementsByClassName("el-table__body-wrapper")[0].removeChild(selDiv);
}
selList = null, _x = null, _y = null, selDiv = null, startX = null, startY = null, evt = null;
vnode.context.mouseflag = false;
vnode.context.handleBatchSelect();
// cancelContextMenu();
};
};
}
},
dragColumn: {
update: function (el, binding, vnode) {
var oDiv = el;
vnode.context.$nextTick(() => {
vnode.context.setHeaderSortable();
})
}
},
},
data() {
return {
refreshKeyId:Math.random().toString(36).substring(3,10),
tableId:this.id?this.id:"XdTable"+Math.random().toString(36).substring(3,10),
// 弹出层标题
title: "显示/隐藏",
// 是否显示弹出层
open: false,
showTable: false,
popVisible:false,
isMouseDown: true, // 是否需要(允许)处理鼠标的移动事件
tbSize:"",
name: '',
config: {
children: [],
attrs: {size:"small"},
listeners: {
},
key: ''
},
tableData:[],
dropCol:[],
sortable:null,
isDragging: false,
startRowIndex: -1,
endRowIndex: -1,
//指令中确定的时候是鼠标按下事件
mouseflag: false,
// 鼠标位置在表格区域内
mouseInScope: false,
//选中的数组
multipleSelection: [],
multipleRowSelection:[],
//控制右键菜单弹出显示
contextVisible:false,
//分页当前的页数
currentPage:1 ,
//当前右键点击的列
currentRow:[],
//当前滚动的距离,
targetScroll:0,
//鼠标滑动选中
isSelecting: false, // 是否正在进行选择操作
selectionStart:{rowIndex:-1,cellIndex:-1}, // 选择操作起始单元格位置
selectionEnd:{rowIndex:-1,cellIndex:-1}, // 选择操作结束单元格位置
currentCellInfo:null,
currentSelectStr:null,
currentOdiv:null,
currentCell:null,
checkAll: false, //招标阶段 是否全选
isIndeterminate: false, //全选复选框标识
isTableFocused: false,
copyHanderEvent:null,
// 表格个性化记忆配置
isNeedDbSaveTpl:false,
fullUrl:null,
pageId:null,
saveStorageName:this.storageName,
storeTplList:[],
storageList: [],
openTbShowTplDlg:false,
curentTbShowTpl:null,
form:{
id: null,
tplCode: null,
tplName: null,
tplType: null,
tagId: null,
blDefault: null,
tplData: null,
},
rules: {
tplName: [
{ required: true, message: "模版名称必填", trigger: "blur" }
],
}
}
},
watch: {
'$attrs': {
handler(newV) {
this.$set(this.config, 'attrs', newV)
this.tableData=this.config.attrs.data;
},
deep: true,
immediate: true
},
},
mounted() {
if(this.saveStorageName&&this.saveStorageName!=undefined&&this.saveStorageName!=''){
this.isNeedDbSaveTpl=true;
}else{
this.fullUrl=window.location.origin + window.location.pathname + window.location.search + window.location.hash;
this.pageId=this.MD5(this.fullUrl);
this.saveStorageName=this.pageId;
this.isNeedDbSaveTpl=false;
}
// 监听全局焦点变化事件
// document.addEventListener('focusin', this.handleGlobalFocusIn);
// document.addEventListener('focusout', this.handleGlobalFocusOut);
this.initKeyDownEvent();
// 初始化默认模版到本地
this.initDefaultTplList();
this.initStorage()
this.updateTable()
this.tableDom=this.getTableDom();
},
beforeDestroy () {
document.removeEventListener('keydown', this.handleGlobalKeydown)
},
methods: {
getInstance() {
return this.$refs.table.$refs?.elTable
},
getUUID() {
return Math.random().toString(36).substring(3,10);
},
// 处理全局焦点进入事件
handleGlobalFocusIn(event) {
// var tableEl = document.getElementById(this.tableId);
// const hasFocus = tableEl.contains(event.target);
// console.log("===>hasFocus===>",hasFocus,tableEl,event.target);
// 表格获得焦点
// if (hasFocus && !this.isTableFocused) {
// this.tableHasFocus = true;
// this.$message({
// message: '表格已获得焦点',
// type: 'success',
// duration: 1500
// });
// }
},
// 全局键盘事件处理
handleGlobalKeydown(event) {
// 检查是否按下了Ctrl+C组合键
event = event||window.event;
if ((event.ctrlKey || event.metaKey) && event.key === 'c') {
// 如果焦点在表格内,处理复制操作
if (this.isTableFocused) {
event.preventDefault();
this.handleCopySelect();
}
}
},
handleOnContextMenu(event){
// vnode.context.clearEventBubble(event)
var xdTableObj = document.getElementById(this.tableId);
this.clearEventBubble(event)
var menu = xdTableObj.querySelector("#contextMenu");
let tbPosRect=this.getTablePosition(xdTableObj);
menu.style.left = (event.clientX-tbPosRect.left+5) + "px";
menu.style.top = (event.clientY-tbPosRect.top-35) + "px";
menu.style.display = "block";
menu.style.zIndex = 3000;
this.contextVisible=true;
event.preventDefault();
},
clearSelection(){
this.$nextTick(()=>{
this.$refs.table.$refs.elTable.clearSelection();
});
},
initKeyDownEvent(){
document.addEventListener('keydown', this.handleGlobalKeydown );
},
removeKeyDownEvent(){
document.removeEventListener('keydown', this.handleGlobalKeydown );
},
onTplSelectInputBlur(e) {
if (e.target.value.trim()!== '') {
//e.target.value就是录入的内容
this.curentTbShowTpl = e.target.value;
this.form.tplName = e.target.value;
// 如果是对象,要使用this.$set方法
// this.$set('typeObj', 'name', e.target.value)
}
},
setTbShowTpl(){
this.openTbShowTplDlg=true;
},
changeSaveTbShowTpl(val){
if(val){
const tplItem = this.storeTplList.find(d => d.tplCode === val)
if(tplItem){
this.form=Object.assign({},tplItem);
}else{
this.form.id=null;
this.form.tplName=val;
}
}else{
this.form = {
id: null,
tplCode: null,
tplName: null,
tplType: null,
tagId: null,
blDefault: null,
tplData: null,
}
this.resetForm("form");
this.form.blDefault='1';
}
},
changeTbShowTpl(val){
if(val){
if(this.storeTplList&&this.storeTplList.length>0){
const tplItem = this.storeTplList.find(d => d.tplCode === val)
// // console.log("===>changeTbShowTpl==111->",tplItem);
this.form=Object.assign({},tplItem);
if(this.form.tplData){
let tplColList=JSON.parse(this.form.tplData);
// 保存模版数据到本地
this.storeTplToLocal(tplColList);
this.initStorage();
this.updateTable();
}
}
}else{
this.form = {
id: null,
tplCode: null,
tplName: null,
tplType: null,
tagId: null,
blDefault: null,
tplData: null,
}
window.localStorage.removeItem('tableStorage');
this.reInitList();
}
},
async initDefaultTplList() {
if(!this.isNeedDbSaveTpl){
return;
}
let queryParams = {
tagId:this.saveStorageName
};
this.storeTplList=[];
// 获取模版列表
let res=await listSysCustomizeTpl(queryParams)
if(res.rows&&res.rows.length>0){
this.storeTplList=res.rows;
// 设置默认模版
const selTplItem=this.storeTplList.find(item=>item.blDefault == '1' );
if(selTplItem){
this.form=selTplItem;
this.curentTbShowTpl=selTplItem.tplCode;
const tplColList=JSON.parse(this.form.tplData);
// console.log("===>initDefaultTplList=2222=>",tplColList);
// 存储到本地tpl
this.storeTplToLocal(tplColList);
}
}
},
// 矫正模版数据
savaTbShowTpl(){
if(!this.form.tplName){
// this.form.tplName='默认'
this.$modal.msgError("模版名称必填");
return;
}
// 判断模版是否存在,若存在则覆盖
const tmpTplItem=this.storeTplList.find(item=>item.tplName == this.form.tplName );
if(tmpTplItem){
this.form=tmpTplItem;
}
if (this.form.id != null) {
this.curentTbShowTpl=this.form.tplCode;
this.form.tagId=this.saveStorageName;
this.form.tplData=JSON.stringify(this.storageList);
updateSysCustomizeTpl(this.form).then(response => {
this.$modal.msgSuccess("修改成功");
this.openTbShowTplDlg=false;
this.initDefaultTplList();
this.curentTbShowTpl=this.form.tplCode;
});
} else {
this.form.tplCode=genJsSeqNo();
this.form.tagId=this.saveStorageName;
this.form.tplData=JSON.stringify(this.storageList);
addSysCustomizeTpl(this.form).then(response => {
this.$modal.msgSuccess("新增成功");
this.openTbShowTplDlg=false;
this.initDefaultTplList();
this.curentTbShowTpl=this.form.tplCode;
});
}
},
delTbShowTpl(){
const ids = this.form.id;
if(!ids || ids==undefined){
this.$modal.msgSuccess("未选择模版");
return;
}
this.$modal.confirm('是否确认删除').then(function() {
return delSysCustomizeTpl(ids);
}).then(() => {
this.curentTbShowTpl=null;
this.initDefaultTplList();
this.openTbShowTplDlg=false;
this.changeTbShowTpl(null);
this.$modal.msgSuccess("删除成功");
}).catch(() => {});
},
// 获取导出参数
getExportParam(){
// header:[],filter:[]
var header = [];
var filter = [];
this.storageList.forEach(item => {
if (item.show) {
header.push(item.label);
filter.push(item.prop)
}
})
let params={
header: header,
filter: filter
}
return params;
},
// 鼠标框选----------
//当批量选中结束调用
handleBatchSelect(){
let vList = [];
// 按行列排序
if(this.multipleSelection&&this.multipleSelection.length>0){
this.multipleSelection.sort(function(a,b){
if(a.row === b.row){//如果row相同,按照col的升序
return a.col-b.col
}else{
return a.row-b.row
}
})
let selStr="";
let currentRow=-1;
this.multipleSelection.forEach(item=>{
if(currentRow!=-1 && currentRow!=item.row){
// 去除末尾的\t
selStr=this.trimTabChar(selStr,'\t','');
selStr=selStr+"\n";
}
let str=item.text;
if(!str || str==''){
str=' ';
}
selStr = selStr+str+"\t";
currentRow=item.row;
});
selStr=this.trimTabChar(selStr,'\t','');
// 去除两端空格
this.currentSelectStr=selStr;
}
// this.$emit('handleSelect',this.multipleSelection)
},
getCellInfo(cell) {
try{
while(cell.tagName !== 'TD'){
cell = cell.parentElement;
}
const rowIndex = cell.parentElement.rowIndex;
const cellIndex = cell.cellIndex;
const text = cell.innerText;
return { row:rowIndex,col: cellIndex ,text:text};
}catch(e){
return { rowIndex:-1,cellIndex:-1};
}
},
// 复制选中数据
handleCopySelect(event) {
this.contextVisible=false;
if(this.currentSelectStr){
if (navigator.clipboard && window.isSecureContext) {
// navigator clipboard 向剪贴板写文本
this.$modal.msgSuccess('复制成功')
return navigator.clipboard.writeText(this.currentSelectStr)
} else {
// 创建text area
const textArea = document.createElement('textarea')
textArea.value = this.currentSelectStr
// 使text area不在viewport,同时设置不可见
document.body.appendChild(textArea)
textArea.focus()
textArea.select()
this.$modal.msgSuccess('复制成功')
return new Promise((res, rej) => {
// 执行复制命令并移除文本框
document.execCommand('copy') ? res() : rej()
textArea.remove()
})
}
}
},
// 选择整行
handleSelectCurrentRow(evt){
this.contextVisible=false;
var fileNodes = this.currentOdiv.getElementsByTagName("td");
if(this.currentCellInfo){
this.multipleSelection=[];
for (var i = 0; i < fileNodes.length; i++) {
const selItem=fileNodes[i];
if (selItem.className.indexOf("el-table__cell") != -1 && selItem.parentElement.rowIndex == this.currentCellInfo.row ) {
selItem.className = selItem.className + " seled";
const cellInfo=this.getCellInfo(selItem);
this.multipleSelection.push(cellInfo);
}else{
selItem.classList.remove("seled");
}
}
}
},
// 选择整列
handleSelectCurrentColumn(evt){
this.contextVisible=false;
var fileNodes = this.currentOdiv.getElementsByTagName("td");
if(this.currentCellInfo){
this.multipleSelection=[];
for (var i = 0; i < fileNodes.length; i++) {
const selItem=fileNodes[i];
if (selItem.className.indexOf("el-table__cell") != -1 && selItem.cellIndex == this.currentCellInfo.col ) {
selItem.className = selItem.className + " seled";
const cellInfo=this.getCellInfo(selItem);
this.multipleSelection.push(cellInfo);
}else{
selItem.classList.remove("seled");
}
}
}
},
trimTabChar(str,char, type) {
if (char) {
if (type == 'left') {
return str.replace(new RegExp('^\\'+char+'+', 'g'), '');
} else if (type == 'right') {
return str.replace(new RegExp('\\'+char+'+$', 'g'), '');
}
return str.replace(new RegExp('^\\'+char+'+|\\'+char+'+$', 'g'), '');
}
return str.replace(/^\s+|\s+$/g, '');
},
// ---------------
//清除默认事件
clearEventBubble(evt) {
if(evt!=null){
if (evt.stopPropagation)
evt.stopPropagation();
else
evt.cancelBubble = true;
if (evt.preventDefault)
evt.preventDefault();
else
evt.returnValue = false;
}
},
getTableDom() {
return this.$refs.table.$refs.elTable.$el;
},
getTablePosition() {
return this.tableDom.getBoundingClientRect();
},
handleCopy(text, event) {
clip(text, event)
},
setHeaderSortable(){
let that=this;
this.$nextTick(function () {
const wrapperTr = document.querySelector('#'+that.tableId+' .el-table__header-wrapper > table > thead > tr');
// // console.log("===>wrapperTr==>",wrapperTr);
if(wrapperTr){
Sortable.create(wrapperTr, {
animation: 100,
delay: 50,
dragClass: "dragClass",
ghostClass: "ghostClass",
chosenClass: "chosenClass",
onStart: () => {
},
// 结束拖动事件
onEnd: ({ newIndex, oldIndex }) => {
let arr = that.storageList;
const currCol = arr.splice(oldIndex-1, 1)[0];
arr.splice(newIndex-1, 0, currCol);
that.storageList = arr;
console.log("====>setHeaderSortable===>",that.storageList)
this.storeTplToLocal(that.storageList)
this.initStorage()
this.updateTable()
// that.updateTable();
// this.refreshKeyId=Math.random().toString(36).substring(3,10);
// const currCol = vnode.context.storageList.splice(oldIndex-1, 1)[0];
// vnode.context.storageList.splice(newIndex-1, 0, currCol);
// vnode.context.updateTable();
},
});
}
})
},
// 定义方法 isEqual 来比较两个选中数据对象是否相同
isEqual(data1, data2) {
return (
data1.rowId === data2.rowId &&
data1.column === data2.column &&
data1.sampleTime === data2.sampleTime &&
data1.factor === data2.factor
);
},
// 重新初始化
reInitList() {
let list=[];
this.$vnode.componentOptions.children.forEach(node => {
// 以prop为准,因为可能会改文本
if (!(!node.componentOptions || node.componentOptions.propsData.type) && list.findIndex(i => i.prop === node.componentOptions.propsData.prop) < 0) {
// 非插槽且 不是特殊类型的 找不到就加上
const propsData = JSON.parse(JSON.stringify(node.componentOptions.propsData))
if (propsData.fixed === undefined || propsData.fixed === false) {
propsData.fixed = false
} else {
propsData.fixed = propsData.fixed ? propsData.fixed : 'left'
}
list.push({
fixed: false, // 默认新增的都是不固定
show: true, // 默认新增的都是显示的
...propsData
})
}
})
this.storeTplToLocal(list)
this.initStorage()
this.updateTable()
},
download(){
this.$emit("download");
},
// 查询
queryTable(){
this.$emit("queryTable");
},
// 显示搜索
toggleSearch() {
this.$emit("update:showSearch", !this.showSearch);
},
// 刷新
refresh() {
this.$emit("queryTable");
},
// 打开显隐列
showColumn() {
this.open = true;
},
delStorage() {
this.$confirm('是否恢复默认设置?', '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
}).then(() => {
const storage = window.localStorage.getItem('tableStorage') ? JSON.parse(window.localStorage.getItem('tableStorage')) : {}
storage[this.saveStorageName] = []
window.localStorage.setItem('tableStorage', JSON.stringify(storage))
this.changeSaveTbShowTpl(null);
this.reInitList();
})
},
handleCheckAllChange(isCheckAll){
if(isCheckAll){
this.storageList.forEach(col=>{
col.show = true
});
}else{
this.storageList.forEach((col,index)=>{
if(index!=0){
col.show = false;
}
});
}
this.updateTable();
},
showOrHidden(val, clo) {
if (!val && this.storageList.filter(i => i.show).length === 0) {
this.$message.warning('列表最少显示一列')
this.$nextTick(() => {
clo.show = true
})
return
}
this.updateTable()
},
setFixed(value, clo) {
if (clo.fixed === value) {
clo.fixed = false
} else {
clo.fixed = value
}
this.updateTable()
},
// 更多操作触发
handleAdjustTableSize(command) {
//size:mini/small/medium;
// // console.log(this.config);
switch (command) {
case "small":
this.config.attrs.size='small';
break;
case "mini":
this.config.attrs.size='mini';
break;
case "medium":
this.config.attrs.size='medium';
break;
default:
break;
}
this.updateTable();
},
// 初始化缓存配置
initStorage() {
this.storageList = []
let list = [];
const storage = window.localStorage.getItem('tableStorage') ? JSON.parse(window.localStorage.getItem('tableStorage')) : {}
if(this.showCustomizeTpl && this.saveStorageName!=undefined && this.saveStorageName!=''){
list = storage[this.saveStorageName] ? storage[this.saveStorageName] : []
}
// || node.componentOptions.propsData.type
// 不管是否初次还是要做一下处理,万一页面有修改,做一下更新,以最新的node节点数组为准
this.$vnode.componentOptions.children.forEach(node => {
// 以prop为准,因为可能会改文本
if (!(!node.componentOptions ) && list.findIndex(i => i.prop === node.componentOptions.propsData.prop) < 0) {
// 非插槽且 不是特殊类型的 找不到就加上
const propsData = JSON.parse(JSON.stringify(node.componentOptions.propsData))
if (propsData.fixed === undefined || propsData.fixed === false) {
propsData.fixed = false
} else {
propsData.fixed = propsData.fixed ? propsData.fixed : 'left'
}
list.push({
fixed: false, // 默认新增的都是不固定
show: true, // 默认新增的都是显示的
...propsData
})
}
})
// 必须在节点数组存在的才有意义
list = list.filter(item => this.$vnode.componentOptions.children.find(n => {
return n.componentOptions && n.componentOptions.propsData.label && item.prop === n.componentOptions.propsData.prop
}))
// 去除重复数据
let map = new Map();
let list2 = []; // 数组用于返回结果
for (let i = 0; i < list.length; i++) {
if(map.has(list[i].prop)) { // 如果有该key值
map.set(list[i].prop, true);
} else {
map.set(list[i].prop, false); // 如果没有该key值
// 必须要存在 列名称才处理
if(list[i].label){
list2.push(list[i]);
}
}
}
list=list2;
this.storageList = list
},
// 根据缓存的数组进行渲染表格
updateTable() {
// 特殊类型
const childrenNodes = this.$vnode.componentOptions.children.filter(node => node.componentOptions && node.componentOptions.propsData.type)
this.storageList.forEach(item => {
if (item.show) {
const node = this.$vnode.componentOptions.children.find(n => n.componentOptions && n.componentOptions.propsData.prop === item.prop)
if (node) {
let nodeItem=node.componentOptions.propsData;
if(item.label != nodeItem.label){
item.label=nodeItem.label;
}
node.componentOptions.propsData.fixed = item.fixed
childrenNodes.push(node)
}
}
})
this.config.children = childrenNodes
this.config.attrs = this.$attrs
this.config.listeners = this.$listeners;
// 通过key值触发表格刷新,避免拖拽由于数组长度一致导致diff算法无法识别
// this.config.key = Math.random() + ''
// 控制下表格重新刷新
this.getInstance()?.doLayout()
if(this.showCustomizeTpl){
this.storeTplToLocal(this.storageList);
}else{
// 清除本地缓存
// window.localStorage.removeItem('tableStorage')
}
// const storage = window.localStorage.getItem('tableStorage') ? JSON.parse(window.localStorage.getItem('tableStorage')) : {}
// storage[this.saveStorageName] = this.storageList
// window.localStorage.setItem('tableStorage', JSON.stringify(storage))
},
storeTplToLocal(tplColList){
const storage = window.localStorage.getItem('tableStorage') ? JSON.parse(window.localStorage.getItem('tableStorage')) : {}
storage[this.saveStorageName] = tplColList
window.localStorage.setItem('tableStorage', JSON.stringify(storage))
},
/** 导出excel文件操作 */
exportData(fileName,dataList,formatJson,loadingInstance){
const curList =dataList
import('@/vendor/Export2Excel').then(excel => {
const exportParam=this.getExportParam();
const tHeader = exportParam.header;
const filterVal = exportParam.filter;
const data = formatJson(filterVal, curList, selData)
excel.export_json_to_excel({
header: tHeader,
data,
filename: fileName,
autoWidth: true
})
loadingInstance.close()
})
},
}
}
</script>
<style lang="scss" scoped>
.table-cloumn-setting-popper{
.setting-row-content{
max-height: 600px;
overflow-y: auto;
//overflow-y: hidden;
.setting-row{
height: 30px;
line-height: 30px;
.el-icon-s-operation{
cursor: move;
font-size: 16px;
margin-right: 8px;
}
.label{
margin-right: 8px;
}
.btn{
padding: 4px!important;
}
}
}
}
.xd-table{
width:100%;
height:100%;
position: relative;
.el-icon-setting{
position: absolute;
right: 7px;
top: 5px;
cursor: pointer;
}
.table-operate-btn-content{
// width: calc(100% - 40px);
width: 100%;
// min-height: 28px; // 给一个最低的高度,防止没有插槽,右侧icon被吞
min-height: 40px; // 给一个最低的高度,防止没有插槽,右侧icon被吞
.operate-btn-content {
display: flex;
justify-content: space-between;
align-items: center;
min-height: 28px;
padding-bottom: 6px;
}
}
.parent:has(.child){
background-color: #eee;
}
}
.pagination-container{
padding: 0px 20px !important;
}
.menuDiv {
position: absolute;
background-color: #fff;
width: 100px;
/*height: 106px;*/
}
:deep .seled{
background-color: #51dd397d !important;
color: black;
font-weight: 600;
}
:deep .rowSeled{
background-color: #ffa5a55e !important;
color: black;
font-weight: 600;
}
.xd-tb-wrapper :deep .el-table__body tr:hover > td {
background-color: #ffa5a55e;
}
.xd-tb-wrapper{
-webkit-user-select: none; /* Safari */
-moz-user-select: none; /* Firefox */
-ms-user-select: none; /* Internet Explorer/Edge */
user-select: none;
}
.drag-ghost { background-color: #e7e7e77d; }
.drag-chosen { background-color: #e7e7e77d; }
// 拖拽
.dragClass {
background: rgba($color: #41c21a, $alpha: 0.5) !important;
}
// 停靠
.ghostClass {
background: rgba($color: #6cacf5, $alpha: 0.5) !important;
}
// 选择
.chosenClass:hover > td {
background: rgba($color: #f56c6c, $alpha: 0.5) !important;
}
.el-table__body tr.current-row > td {
background-color: #78f709 !important;
}
.el-table--enable-row-hover .el-table__body tr:hover > td {
background-color: #f6d604 !important;
cursor:pointer;
}
.full-block{
height:100%;
width:100%;
overflow:hidden;
}
.flex-layout{
display:flex;
flex-direction:column;
}
.flex-auto{
flex:1 1 auto
}
.flex-none{
flex:none
}
.el-table {
width: 100%;
display: flex;
flex-direction: column;
.el-table__body-wrapper {
flex: 1;
}
}
</style>