Răsfoiți Sursa

Update 优化table组件,增加数据列合并

Yue 1 lună în urmă
părinte
comite
ddcafcb97a

+ 38 - 27
UI/VB.VUE/src/components/table/VbDataTable.vue

@@ -86,6 +86,7 @@ const props = withDefaults(
 		scroll?: Scroll
 		/* rowspan */
 		rowSpanSuffix?: string // rowspan 的字段后缀 后台应该组成 `${字段}${后缀}`
+		colSpanSuffix?: string // colspan 的字段后缀 后台应该组成 `${字段}${后缀}`
 		/* tree */
 		isTree?: boolean
 		expandDepth?: number
@@ -146,6 +147,7 @@ const props = withDefaults(
 		fixedNumber: 0,
 		fixedRightNumber: 0,
 		rowSpanSuffix: "_rowSpan",
+		colSpanSuffix: "_colSpan",
 		isTree: false,
 		parentField: "parent_id",
 		childrenField: "children",
@@ -778,6 +780,7 @@ provide(symbolKeys.bodyTr, {
 provide(symbolKeys.bodyTds, {
 	columns: rowColumns,
 	rowSpanSuffix: props.rowSpanSuffix,
+	colSpanSuffix: props.colSpanSuffix,
 	expandDepth: props.expandDepth,
 	intervalLeft: props.intervalLeft,
 	iconField: props.iconField,
@@ -982,36 +985,44 @@ function BindInterEvent() {
 
 function initFixedColumns() {
 	if (fixedColumn.value) {
-		const tr = tableRef.value?.querySelector("tbody tr")
-		if (tr && tr.children) {
-			let width = 0
-			if (leftFixedRef.value) {
-				let num = props.fixedNumber
-				if (props.hasCheckbox || props.checkMultiple || props.checkPageMultiple) {
-					num += 1
-				}
-				for (let i = 0; i < num; i++) {
-					width += tr.children[i]?.clientWidth ?? 0
-				}
-				leftFixedRef.value.style.width = width + "px"
-				leftFixedRef.value.firstElementChild.style.width = tableRef.value.clientWidth + "px"
-			}
-			if (rightFixedRef.value) {
-				width = 0
-				const trLength = tr.children.length
-				for (let i = trLength - 1; i >= trLength - props.fixedRightNumber; i--) {
-					width += tr.children[i]?.clientWidth ?? 0
+		setTimeout(() => {
+			const tr = tableRef.value?.querySelector("thead tr")
+			if (tr && tr.children) {
+				let width = 0,
+					_temp = 0
+				if (leftFixedRef.value) {
+					let num = props.fixedNumber
+					if (props.hasCheckbox || props.checkMultiple || props.checkPageMultiple) {
+						num += 1
+					}
+					for (let i = 0; _temp < num; i++) {
+						const item = tr.children[i]
+						_temp += Number(item.getAttribute("colspan"))
+						width += tr.children[i]?.clientWidth ?? 0
+					}
+					leftFixedRef.value.style.width = width + "px"
+					leftFixedRef.value.firstElementChild.style.width = tableRef.value.clientWidth + "px"
 				}
-				rightFixedRef.value.style.width = width + "px"
-				rightFixedRef.value.firstElementChild.style.width = tableRef.value.clientWidth + "px"
-				rightFixedRef.value.firstElementChild.style.transform = `translateX(-${
-					tableRef.value.clientWidth - width
-				}px)`
-				if (tableRef.value.clientWidth <= tableResponsiveRef.value.clientWidth) {
-					rightFixedRef.value.className += " no-shadow"
+				if (rightFixedRef.value) {
+					width = 0
+					_temp = 0
+					const trLength = tr.children.length
+					for (let i = trLength - 1; _temp < props.fixedRightNumber; i--) {
+						const item = tr.children[i]
+						_temp += Number(item.getAttribute("colspan"))
+						width += tr.children[i]?.clientWidth ?? 0
+					}
+					rightFixedRef.value.style.width = width + "px"
+					rightFixedRef.value.firstElementChild.style.width = tableRef.value.clientWidth + "px"
+					rightFixedRef.value.firstElementChild.style.transform = `translateX(-${
+						tableRef.value.clientWidth - width
+					}px)`
+					if (tableRef.value.clientWidth <= tableResponsiveRef.value.clientWidth) {
+						rightFixedRef.value.className += " no-shadow"
+					}
 				}
 			}
-		}
+		}, 10)
 	}
 }
 function init() {

+ 72 - 22
UI/VB.VUE/src/components/table/partials/body/BodyTds.vue

@@ -13,6 +13,7 @@ const props = defineProps<{
 const propOpts = inject(symbolKeys.bodyTds, {
 	columns: ref([]),
 	rowSpanSuffix: "_rowSpan",
+	colSpanSuffix: "_colSpan",
 	parentField: "parent_id",
 	childrenField: "children",
 	iconField: "name",
@@ -30,32 +31,81 @@ provide(
 	symbolKeys.bodyTd,
 	Object.assign({}, propOpts, { isExpand: props.isExpand, hasChildren: props.hasChildren })
 )
+let curColCount = 0
+
+function hasRowSpan(row, field) {
+	if (Number(row[field + propOpts.rowSpanSuffix]) > 0) {
+		return true
+	} else if (
+		Number(row[field + propOpts.rowSpanSuffix]) == 0 &&
+		Number(row[field + propOpts.colSpanSuffix]) == 0
+	) {
+		return false
+	}
+	return true
+}
+function hasColumnSpan(row, field) {
+	if (Number(row[field + propOpts.colSpanSuffix]) > 0) {
+		curColCount = Number(row[field + propOpts.colSpanSuffix]) - 1
+		if (Number(row[field + propOpts.rowSpanSuffix]) == 0) {
+			return false
+		}
+		return true
+	} else if (curColCount > 0) {
+		if (Number(row[field + propOpts.rowSpanSuffix]) == 0) {
+			return false
+		}
+		curColCount--
+		return curColCount < 0
+	} else {
+		return true
+	}
+}
 </script>
 <template>
 	<template v-for="(column, i) in visibleColumns" :key="i">
-		<template v-if="row[column.field + propOpts.rowSpanSuffix]">
-			<BodyTd
-				:row="row"
-				:column="column"
-				:index="index"
-				:is-tree="isTree"
-				:depth="depth"
-				:rowspan="`${
-					row[column.field + propOpts.rowSpanSuffix]
-						? row[column.field + propOpts.rowSpanSuffix]
-						: ''
-				}`">
-				<template v-for="(_, name) in $slots" #[name]="{ row }">
-					<slot :name="name" :row="row"></slot>
-				</template>
-			</BodyTd>
+		<template v-if="hasRowSpan(row, column.field)">
+			<template v-if="hasColumnSpan(row, column.field)">
+				<BodyTd
+					:row="row"
+					:column="column"
+					:index="index"
+					:is-tree="isTree"
+					:depth="depth"
+					:rowspan="`${
+						row[column.field + propOpts.rowSpanSuffix]
+							? row[column.field + propOpts.rowSpanSuffix]
+							: '1'
+					}`"
+					:colspan="`${
+						row[column.field + propOpts.colSpanSuffix]
+							? row[column.field + propOpts.colSpanSuffix]
+							: '1'
+					}`">
+					<template v-for="(_, name) in $slots" #[name]="{ row }">
+						<slot :name="name" :row="row"></slot>
+					</template>
+				</BodyTd>
+			</template>
 		</template>
-		<template v-else-if="row[column.field + propOpts.rowSpanSuffix] != 0">
-			<BodyTd :row="row" :column="column" :index="index" :is-tree="isTree" :depth="depth">
-				<template v-for="(_, name) in $slots" #[name]="{ row }">
-					<slot :name="name" :row="row"></slot>
-				</template>
-			</BodyTd>
+		<template v-else-if="hasRowSpan(row, column.field)">
+			<template v-if="hasColumnSpan(row, column.field)">
+				<BodyTd
+					:row="row"
+					:column="column"
+					:index="index"
+					:is-tree="isTree"
+					:depth="depth"
+					:colspan="`${
+						row[column.field + propOpts.colSpanSuffix]
+							? row[column.field + propOpts.colSpanSuffix]
+							: '1'
+					}`">
+					<template v-for="(_, name) in $slots" #[name]="{ row }">
+						<slot :name="name" :row="row"></slot>
+					</template>
+				</BodyTd>
+			</template>
 		</template>
 	</template>
 </template>

+ 1 - 0
UI/VB.VUE/src/components/table/symbol.ts

@@ -59,6 +59,7 @@ export default {
 	bodyTds: Symbol("bodyTds") as InjectionKey<{
 		columns: Ref<Header[]>
 		rowSpanSuffix: string
+		colSpanSuffix: string
 		expandDepth: number
 		intervalLeft: number
 		iconField: string