14 changed files with 538 additions and 427 deletions
@ -0,0 +1,345 @@ |
|||
import { computed, Ref, ref, toRaw } from 'vue'; |
|||
import { Tools } from '@/platform'; |
|||
import { Base } from '../Base'; |
|||
import { Constant, PropsType, TableType } from '../index'; |
|||
|
|||
/** |
|||
* w-grid 列标题(表头)处理相关 |
|||
*/ |
|||
export class ColumnTitle extends Base { |
|||
/** |
|||
* 表头总行数,多表头时 > 1 |
|||
*/ |
|||
rowNum: Ref = ref(1); |
|||
/** |
|||
* 多表头集合,每一个数组为一行,每一行中包括列。 |
|||
* 示例:[ |
|||
* [{name: 'industry', label: '行业分类', colspan: 2}, {name: 'company', label: '公司名称', rowspan: 2}], |
|||
* [{name: 'industry2', label: '二级行业'}, {name: 'industry3', label: '三级行业'}], |
|||
* ] |
|||
*/ |
|||
multiTitles: Ref = ref([]); |
|||
/** |
|||
* 多表头以列名称为key的Map对象 |
|||
*/ |
|||
multiTitleMap: Map<string, MultiTitleType> = new Map<string, MultiTitleType>(); |
|||
/** |
|||
* 用户配置的原始列以列名称为key的Map对象 |
|||
*/ |
|||
originalColumnMap: Map<string, any> = new Map(); |
|||
/** |
|||
* 被锁定的列集合 |
|||
*/ |
|||
stickyColumn: Ref = ref([]); |
|||
/** |
|||
* 被锁定的最顶层的列集合 |
|||
*/ |
|||
stickyTopColumn: Ref = ref([]); |
|||
|
|||
/** |
|||
* 子列最大层级 |
|||
*/ |
|||
private childrenMaxLevel: number = 0; |
|||
/** |
|||
* 跨列数 |
|||
*/ |
|||
private colspan: number = 0; |
|||
|
|||
constructor(props: PropsType, table: TableType) { |
|||
super(props, table); |
|||
this.handleColumnTitle = this.handleColumnTitle.bind(this); |
|||
this.multiTitleThPropsHandle = this.multiTitleThPropsHandle.bind(this); |
|||
|
|||
this.showIfIsFalse = this.showIfIsFalse.bind(this); |
|||
this.processColumns = this.processColumns.bind(this); |
|||
this.processMap = this.processMap.bind(this); |
|||
} |
|||
|
|||
/** |
|||
* 处理表头 |
|||
*/ |
|||
handleColumnTitle() { |
|||
this.multiTitleMap = new Map<string, MultiTitleType>(); |
|||
this.originalColumnMap = new Map(); |
|||
|
|||
// 深度克隆列,避免被内部操作列覆盖原有数据。
|
|||
const clonedArray = JSON.parse(JSON.stringify(this.table.originalColumns)); |
|||
clonedArray.forEach((column: any) => { |
|||
this.columnToMap(toRaw(column)); |
|||
}); |
|||
|
|||
this.childrenMaxLevel = 0; |
|||
this.colspan = 0; |
|||
const deepArr = []; |
|||
|
|||
// 剔除被隐藏的列
|
|||
this.originalColumnMap = this.processMap(this.originalColumnMap); |
|||
this.multiTitleMap = this.removeMultiTitleMap(); |
|||
|
|||
for (const key of this.originalColumnMap.keys()) { |
|||
// 处理列的 childrenLevel
|
|||
let tmpChildrenLevel = 0; |
|||
this.getChildrenLevel(this.originalColumnMap.get(key), 0, deepArr); |
|||
tmpChildrenLevel = Math.max(...deepArr); |
|||
if (tmpChildrenLevel > this.childrenMaxLevel) { |
|||
this.childrenMaxLevel = tmpChildrenLevel; |
|||
} |
|||
deepArr.splice(0, deepArr.length); |
|||
this.multiTitleMap.get(key)!.childrenLevel = tmpChildrenLevel; |
|||
|
|||
// 处理列的 colspan
|
|||
this.multiTitleMap.get(key)!.colspan = this.colspan; |
|||
this.colspan = 0; |
|||
|
|||
// 处理列的 parent
|
|||
const parent = this.findParents(this.table.originalColumns, key); |
|||
this.multiTitleMap.get(key)!.parents = parent; |
|||
|
|||
// 处理列的 parentLevel
|
|||
this.multiTitleMap.get(key)!.parentLevel = parent.length; |
|||
|
|||
// 处理列的 rowIndex
|
|||
this.multiTitleMap.get(key)!.rowIndex = parent.length; |
|||
} |
|||
if (this.childrenMaxLevel > 0) { |
|||
// 更改列头总行数 = 最大子层级数 + 1
|
|||
this.rowNum.value = this.childrenMaxLevel + 1; |
|||
} |
|||
|
|||
const map = new Map<number, [any]>(); |
|||
for (const key of this.multiTitleMap.keys()) { |
|||
const value: any = this.multiTitleMap.get(key); |
|||
// 得到列头总行数后处理列的 rowspan
|
|||
if (value.parentLevel === 0 && value.childrenLevel === 0) { |
|||
value.rowspan = this.rowNum.value; |
|||
} else if (value.parentLevel === 0) { |
|||
value.rowspan = 1; |
|||
} else { |
|||
// 总行数 - 父层级数 - 子层级数
|
|||
value.rowspan = this.rowNum.value - value.parentLevel - value.childrenLevel; |
|||
} |
|||
if (map.has(value.rowIndex)) { |
|||
(map.get(value.rowIndex) as any).push(value); |
|||
} else { |
|||
map.set(value.rowIndex, [value]); |
|||
} |
|||
} |
|||
const arr = Array.from(map); |
|||
|
|||
this.multiTitles.value = []; |
|||
arr.sort((a, b) => a[0] - b[0]); |
|||
arr.forEach((item) => { |
|||
this.multiTitles.value.push(item[1]); |
|||
}); |
|||
|
|||
this.setStickyColumn(); |
|||
} |
|||
|
|||
/** |
|||
* 多表头 th 所需的 props 处理 |
|||
* @param column |
|||
* @param scope |
|||
* @returns |
|||
*/ |
|||
multiTitleThPropsHandle(column: any, scope: any) { |
|||
if (this.table.columns?.length > 0) { |
|||
const i = this.table.columns.findIndex((item: any) => item['name'] === column.name); |
|||
if (i > -1) { |
|||
return scope; |
|||
} |
|||
} |
|||
return undefined; |
|||
} |
|||
|
|||
/** |
|||
* 根据传入的名称,获得其在多表头集合中下标 |
|||
* @param name |
|||
* @returns |
|||
*/ |
|||
getMultiTitleIndex(name: any) { |
|||
let trIndex = -1; |
|||
let tdIndex = -1; |
|||
for (let tr = 0; tr < this.multiTitles.value.length; tr++) { |
|||
const tdArr = this.multiTitles.value[tr]; |
|||
let flag = false; |
|||
for (let td = 0; td < tdArr.length; td++) { |
|||
if (name === tdArr[td].name) { |
|||
trIndex = tr + 1; |
|||
tdIndex = td + 1; |
|||
flag = true; |
|||
break; |
|||
} |
|||
} |
|||
if (flag) { |
|||
break; |
|||
} |
|||
} |
|||
return { trIndex: trIndex, tdIndex: tdIndex }; |
|||
} |
|||
|
|||
/** |
|||
* 获得被固定的列 |
|||
* @returns |
|||
*/ |
|||
getStickyColumn() { |
|||
const columns = <any>[]; |
|||
for (let i = 0; i < this.table.originalColumns.length; i++) { |
|||
const column = this.table.originalColumns[i]; |
|||
if (columns.length < this.table.configStore.stickyNum && this.originalColumnMap.get(column['name'])) { |
|||
columns.push(column); |
|||
} |
|||
} |
|||
this.stickyTopColumn.value = columns; |
|||
const arr = []; |
|||
columns.forEach((item) => { |
|||
this.handleStickyChildrenColumn(item, arr); |
|||
}); |
|||
return arr; |
|||
} |
|||
|
|||
private setStickyColumn() { |
|||
this.stickyColumn.value = this.getStickyColumn(); |
|||
} |
|||
|
|||
/** |
|||
* 处理被固定的孩子列 |
|||
* @param item |
|||
* @param columns |
|||
*/ |
|||
private handleStickyChildrenColumn(item, columns) { |
|||
columns.push(item); |
|||
if (item.columns && item.columns.length > 0) { |
|||
item.columns.forEach((children) => { |
|||
this.handleStickyChildrenColumn(children, columns); |
|||
}); |
|||
} |
|||
} |
|||
|
|||
private findParents(arrData: any, name: any) { |
|||
if (arrData.length == 0) return; |
|||
for (let i = 0; i < arrData.length; i++) { |
|||
if (arrData[i].name == name) { |
|||
return []; |
|||
} else { |
|||
if (arrData[i].columns) { |
|||
const res = this.findParents(arrData[i].columns, name); |
|||
if (res !== undefined) { |
|||
return res.concat(arrData[i].name).reverse(); |
|||
} |
|||
} |
|||
} |
|||
} |
|||
} |
|||
|
|||
private getChildrenLevel(column, deep, deepArr) { |
|||
if (column && column.columns && column.columns.length > 0) { |
|||
deep++; |
|||
column.columns.forEach((item) => { |
|||
this.getChildrenLevel(item, deep, deepArr); |
|||
}); |
|||
} else if (column) { |
|||
deepArr.push(deep); |
|||
this.colspan += 1; |
|||
} |
|||
} |
|||
|
|||
private showIfIsFalse(name: string) { |
|||
const column_ = this.table.columns.find((item) => item.name === name); |
|||
if (!Tools.isEmpty(column_) && Tools.hasOwnProperty(column_, 'showIf') && column_.showIf === false) { |
|||
return true; |
|||
} |
|||
return false; |
|||
} |
|||
|
|||
private processColumns(columns) { |
|||
return columns.reduce((acc, column) => { |
|||
if (column.columns) { |
|||
column.columns = this.processColumns(column.columns); |
|||
if (column.columns.length > 0) { |
|||
acc.push(column); |
|||
} |
|||
} else if (!this.showIfIsFalse(column.name)) { |
|||
acc.push(column); |
|||
} |
|||
return acc; |
|||
}, []); |
|||
} |
|||
|
|||
private processMap(map: Map<string, any>) { |
|||
const newMap = new Map(); |
|||
for (const key of map.keys()) { |
|||
const item = map.get(key); |
|||
if (item.columns) { |
|||
item.columns = this.processColumns(item.columns); |
|||
if (item.columns.length > 0) { |
|||
newMap.set(key, item); |
|||
} |
|||
} else if (!this.showIfIsFalse(item.name)) { |
|||
newMap.set(key, item); |
|||
} |
|||
} |
|||
return newMap; |
|||
} |
|||
|
|||
private removeMultiTitleMap() { |
|||
const newMap = new Map(); |
|||
for (const key of this.multiTitleMap.keys()) { |
|||
const value: any = this.multiTitleMap.get(key); |
|||
if (this.originalColumnMap.get(key)) { |
|||
newMap.set(key, value); |
|||
} |
|||
} |
|||
return newMap; |
|||
} |
|||
|
|||
private setMap(column: any) { |
|||
this.originalColumnMap.set(column.name, column); |
|||
this.multiTitleMap.set(column.name, { |
|||
name: column.name, |
|||
label: column.label, |
|||
title: column.title, |
|||
parentLevel: 0, |
|||
childrenLevel: 0, |
|||
rowspan: 0, |
|||
colspan: 0, |
|||
rowIndex: 0, |
|||
style: column.style, |
|||
classes: column.classes, |
|||
parents: [], |
|||
}); |
|||
} |
|||
|
|||
private columnToMap(column: any) { |
|||
if (Tools.isEmpty(column.name)) { |
|||
column.name = Tools.uuid(); |
|||
} |
|||
if (Tools.isEmpty(column.label)) { |
|||
column.label = column.name; |
|||
} |
|||
if (column && column.columns && column.columns.length > 0) { |
|||
this.setMap(column); |
|||
column.columns.forEach((item) => { |
|||
this.columnToMap(item); |
|||
}); |
|||
} else { |
|||
this.setMap(column); |
|||
} |
|||
} |
|||
} |
|||
|
|||
/** |
|||
* 多表头类型 |
|||
*/ |
|||
type MultiTitleType = { |
|||
name: string; // 列模型的name
|
|||
title: string; // 列模型的title(鼠标移动上去显示内容)
|
|||
label: string; // 列模型的label
|
|||
parentLevel: number; // 父层级数
|
|||
childrenLevel: number; // 子层级数
|
|||
rowspan: number; // 跨行数
|
|||
colspan: number; // 跨列数
|
|||
rowIndex: number; // 列模型所处的行下标
|
|||
style: any; // 列模型配置的内嵌样式
|
|||
classes: any; // 列模型配置的 classes
|
|||
parents: any; // 列模型的父name集合
|
|||
}; |
Loading…
Reference in new issue