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