| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133 |
- <script setup lang="ts">
- import symbolKeys from "@@@/table/symbol"
- import VbTr from "@@@/table/partials/header/HeaderTr.vue"
- import type { Sort, Header, HeaderEx } from "@@@/table/models"
- const propOpts = inject(symbolKeys.header, {
- columns: ref([]),
- hasCheckbox: true,
- isMultipleCheck: true,
- sortField: "",
- sortOrder: "asc",
- headerClass: "fixed",
- thTrClass: "text-center text-gray-800 fw-bold fs-7"
- })
- const { columns } = propOpts
- const sort = ref<Sort>({
- label: propOpts.sortField,
- order: propOpts.sortOrder as "asc" | "desc"
- })
- const columnList = ref<HeaderEx[][]>([])
- const headerColumns = ref<HeaderEx[][]>([])
- const rowspan = computed(() => {
- return columnList.value.length
- })
- const convert = (headers: Header[], deep: number): HeaderEx[][] => {
- const allLists: HeaderEx[][] = []
- const recursion = (h: Header[], d: number): HeaderEx[] => {
- if (!allLists[d]) {
- allLists[d] = []
- }
- const currentLevelList = allLists[d]
- const currentChildren: HeaderEx[] = []
- h.forEach((v) => {
- if (
- v.visible === false ||
- (v.children && v.children.every((child) => child.visible === false))
- ) {
- return
- }
- const item: HeaderEx = Object.assign({}, v, {
- rowspan: (rs: number) => rs - d,
- colspan: v.children?.length ?? 1,
- children: [] as HeaderEx[]
- })
- // 处理有子级的列:行合并为1,递归处理子级
- if (v.children && v.children.length > 0) {
- delete item.isSort
- item.rowspan = 1 // 有子级的列,自身行合并为1
- const childItems = recursion(v.children, d + 1)
- item.children = childItems
- }
- currentChildren.push(item)
- currentLevelList.push(item)
- })
- const calcColspan = (children?: HeaderEx[]): number => {
- let totalColspan = 0
- if (!children || children.length === 0) return totalColspan
- children.forEach((child) => {
- totalColspan +=
- child.children && child.children.length > 0 ? calcColspan(child.children) : child.colspan
- })
- return totalColspan
- }
- currentLevelList.forEach((item) => {
- if (item.children && item.children.length > 0) {
- item.colspan = calcColspan(item.children) // 子级列数求和作为当前列colspan
- } else {
- item.colspan = 1 // 无子级的列,列合并为1
- }
- })
- return currentChildren
- }
- recursion(headers, deep)
- return allLists
- }
- watch(
- () => columns.value,
- async () => {
- await nextTick() // 等待DOM更新,确保计算准确
- columnList.value = []
- headerColumns.value = []
- if (columns.value.some((v) => v.children && v.children.length > 0)) {
- const convertedLists = convert(columns.value, 0)
- columnList.value = convertedLists
- headerColumns.value = convertedLists
- } else {
- const flatColumns = columns.value.filter((v) => v.visible !== false) as HeaderEx[]
- flatColumns.forEach((item) => {
- item.rowspan = rowspan.value
- item.colspan = 1
- })
- columnList.value = [flatColumns]
- headerColumns.value = [flatColumns]
- }
- },
- {
- immediate: true, // 初始化执行一次
- deep: true // 深度监听columns(包括children变化)
- }
- )
- </script>
- <template>
- <thead :class="propOpts.headerClass">
- <template v-for="(v, i) in headerColumns" :key="i">
- <vb-tr
- :rowspan="rowspan"
- :columns="v"
- :sort="sort"
- :has-checkbox="i === 0 && propOpts.hasCheckbox"
- :is-multiple-check="propOpts.isMultipleCheck"
- :th-tr-class="propOpts.thTrClass">
- <template v-for="(_, name) in $slots" #[name]="{ row }">
- <slot :name="name" :row="row" />
- </template>
- </vb-tr>
- </template>
- </thead>
- </template>
|