u
This commit is contained in:
1 parent
9c76e2769a
commit
f285ff776f
16 files changed
+884
-89
No files matched your search
+241
-25
@@ -1,11 +1,13 @@
|
||||
import type { PropType, VNode } from 'vue'
|
||||
import { computed, defineComponent } from 'vue'
|
||||
import { defineComponent } from 'vue'
|
||||
import { getPrefixCls } from '../_utils/getPrefixCls'
|
||||
import { getComponentInnerData } from '../_utils/vnode'
|
||||
import Descriptions from './descriptions'
|
||||
|
||||
interface DescriptionsData {
|
||||
label: string | VNode | (() => VNode)
|
||||
content: string | VNode | (() => VNode)
|
||||
span: number
|
||||
label: string | VNode | (() => string | VNode)
|
||||
content: string | VNode | (() => string | VNode)
|
||||
span?: number
|
||||
}
|
||||
|
||||
export default defineComponent({
|
||||
@@ -15,13 +17,17 @@ export default defineComponent({
|
||||
type: Array as PropType<DescriptionsData[]>,
|
||||
default: () => [],
|
||||
},
|
||||
title: {
|
||||
header: {
|
||||
type: [String, Object, Function] as PropType<string | VNode | (() => VNode)>,
|
||||
},
|
||||
size: {
|
||||
type: String as PropType<'small' | 'medium' | 'large'>,
|
||||
default: 'medium',
|
||||
},
|
||||
tableLayout: {
|
||||
type: String as PropType<'fixed' | 'auto'>,
|
||||
default: 'fixed',
|
||||
},
|
||||
layout: {
|
||||
type: String as PropType<'row' | 'row-vertical' | 'column' | 'column-vertical'>,
|
||||
default: 'row',
|
||||
@@ -30,6 +36,28 @@ export default defineComponent({
|
||||
type: Number,
|
||||
default: 3,
|
||||
},
|
||||
border: {
|
||||
type: Boolean,
|
||||
default: true,
|
||||
},
|
||||
colon: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
labelClass: {
|
||||
type: [String, Array, Object],
|
||||
},
|
||||
labelStyle: {
|
||||
type: Object,
|
||||
default: () => ({}),
|
||||
},
|
||||
contentClass: {
|
||||
type: [String, Array, Object],
|
||||
},
|
||||
contentStyle: {
|
||||
type: Object,
|
||||
default: () => ({}),
|
||||
},
|
||||
class: {
|
||||
type: [String, Array, Object],
|
||||
default: '',
|
||||
@@ -40,36 +68,224 @@ export default defineComponent({
|
||||
},
|
||||
},
|
||||
emits: [],
|
||||
setup(props, { slots, emit }) {
|
||||
const prefixCls = getPrefixCls('descriptions-group')
|
||||
const renderHeader = () => {
|
||||
const title = slots.title
|
||||
? slots.title()
|
||||
: typeof props.title === 'function'
|
||||
? props.title()
|
||||
: props.title
|
||||
setup(props, { slots }) {
|
||||
const prefixCls = getPrefixCls('descriptions')
|
||||
|
||||
return <div class={`${prefixCls}-header`}>{title}</div>
|
||||
const renderLabel = (item: DescriptionsData) => {
|
||||
if (typeof item.label === 'function')
|
||||
return item.label()
|
||||
return item.label
|
||||
}
|
||||
|
||||
const childrenVNodes = computed(() => {
|
||||
const nodes = slots.default?.() ?? []
|
||||
return nodes.filter(node =>
|
||||
node.type && (typeof node.type === 'string' || typeof node.type === 'object' || typeof node.type === 'function'),
|
||||
)
|
||||
})
|
||||
const renderContent = (item: DescriptionsData) => {
|
||||
if (typeof item.content === 'function')
|
||||
return item.content()
|
||||
return item.content
|
||||
}
|
||||
|
||||
const groupedData = computed(() => {
|
||||
c
|
||||
})
|
||||
const getRows = () => {
|
||||
const dataList: DescriptionsData[] = []
|
||||
|
||||
// 1️⃣ 构建基础数据列表
|
||||
if (props.data && props.data.length) {
|
||||
props.data.forEach((item) => {
|
||||
dataList.push({
|
||||
label: item.label,
|
||||
content: item.content,
|
||||
span: item.span ?? 1, // 默认 span = 1
|
||||
})
|
||||
})
|
||||
}
|
||||
else if (slots.default) {
|
||||
const childrenData = getComponentInnerData(slots.default(), Descriptions)
|
||||
childrenData.forEach(({ item, slots }) => {
|
||||
dataList.push({
|
||||
label: slots.label ? slots.label() : item.label,
|
||||
content: slots.content
|
||||
? slots.content()
|
||||
: slots.default
|
||||
? slots.default()
|
||||
: item.content,
|
||||
span: item.span ?? 1,
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
// 2️⃣ 如果是列布局,直接一行返回
|
||||
if (props.layout === 'column' || props.layout === 'column-vertical') {
|
||||
return [dataList]
|
||||
}
|
||||
|
||||
// 3️⃣ Row 布局按列分行
|
||||
const res: DescriptionsData[][] = []
|
||||
let temp: DescriptionsData[] = []
|
||||
let currentSpan = 0
|
||||
|
||||
const addRow = () => {
|
||||
if (temp.length) {
|
||||
// 填充剩余列到最后一个 item
|
||||
const restSpan = props.columns - currentSpan
|
||||
if (restSpan > 0) {
|
||||
const lastItem = temp[temp.length - 1]
|
||||
lastItem.span = (lastItem.span ?? 1) + restSpan
|
||||
}
|
||||
res.push(temp)
|
||||
}
|
||||
}
|
||||
|
||||
dataList.forEach((item) => {
|
||||
const span = Math.min(item.span ?? 1, props.columns)
|
||||
|
||||
if (currentSpan + span > props.columns) {
|
||||
addRow()
|
||||
temp = []
|
||||
currentSpan = 0
|
||||
}
|
||||
|
||||
temp.push({ ...item, span })
|
||||
currentSpan += span
|
||||
})
|
||||
|
||||
// 最后一行
|
||||
addRow()
|
||||
|
||||
return res
|
||||
}
|
||||
|
||||
const label = (node: DescriptionsData) => {
|
||||
const labelClass = [`${prefixCls}-label`]
|
||||
|
||||
let colspan = 1
|
||||
|
||||
// 水平布局下
|
||||
if (props.layout === 'row') {
|
||||
colspan = 1
|
||||
}
|
||||
else if (props.layout === 'row-vertical') {
|
||||
colspan = node.span ?? 1
|
||||
}
|
||||
|
||||
return (
|
||||
<td
|
||||
colspan={colspan}
|
||||
class={[labelClass, props.labelClass]}
|
||||
style={props.labelStyle}
|
||||
>
|
||||
{renderLabel(node)}
|
||||
{props.colon ? ':' : null}
|
||||
</td>
|
||||
)
|
||||
}
|
||||
|
||||
const content = (node: DescriptionsData) => {
|
||||
const contentClass = [`${prefixCls}-content`]
|
||||
|
||||
let colspan = 1
|
||||
if (props.layout === 'row') {
|
||||
const span = node.span ?? 1
|
||||
colspan = span * 2 - 1
|
||||
}
|
||||
else if (props.layout === 'row-vertical') {
|
||||
colspan = node.span ?? 1
|
||||
}
|
||||
|
||||
return (
|
||||
<td
|
||||
colspan={colspan}
|
||||
class={[contentClass, props.contentClass]}
|
||||
style={props.contentStyle}
|
||||
>
|
||||
{renderContent(node)}
|
||||
</td>
|
||||
)
|
||||
}
|
||||
|
||||
const row = (data: DescriptionsData[]) => {
|
||||
return (
|
||||
<tr>
|
||||
{
|
||||
data.map(node => (
|
||||
<>
|
||||
{label(node)}
|
||||
{content(node)}
|
||||
</>
|
||||
))
|
||||
}
|
||||
</tr>
|
||||
)
|
||||
}
|
||||
|
||||
const rowVertical = (data: DescriptionsData[]) => {
|
||||
return (
|
||||
<>
|
||||
<tr>{data.map(node => label(node))}</tr>
|
||||
<tr>{data.map(node => content(node))}</tr>
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
const column = (data: DescriptionsData[]) => {
|
||||
return (
|
||||
<>
|
||||
{data.map(node => (
|
||||
<tr>
|
||||
{label(node)}
|
||||
{content(node)}
|
||||
</tr>
|
||||
))}
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
const columnVertical = (data: DescriptionsData[]) => {
|
||||
return (
|
||||
<>
|
||||
{data.map(node => (
|
||||
<>
|
||||
<tr>{label(node)}</tr>
|
||||
<tr>{content(node)}</tr>
|
||||
</>
|
||||
))}
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
const renderHeader = () => {
|
||||
const header = slots.header
|
||||
? slots.header()
|
||||
: typeof props.header === 'function'
|
||||
? props.header()
|
||||
: props.header
|
||||
|
||||
return <div class={`${prefixCls}-header`}>{header}</div>
|
||||
}
|
||||
|
||||
const renderBody = () => {
|
||||
return (
|
||||
<table class={[
|
||||
`${prefixCls}-body`,
|
||||
`${prefixCls}-body-${props.tableLayout}`,
|
||||
`${prefixCls}-size-${props.size}`,
|
||||
{ [`${prefixCls}-body-border`]: props.border },
|
||||
]}
|
||||
>
|
||||
<tbody>
|
||||
{getRows().map((item) => {
|
||||
if (props.layout === 'row') {
|
||||
return row(item)
|
||||
}
|
||||
else if (props.layout === 'row-vertical') {
|
||||
return rowVertical(item)
|
||||
}
|
||||
else if (props.layout === 'column') {
|
||||
return column(item)
|
||||
}
|
||||
else if (props.layout === 'column-vertical') {
|
||||
return columnVertical(item)
|
||||
}
|
||||
// 默认 fallback
|
||||
return row(item)
|
||||
})}
|
||||
</tbody>
|
||||
</table>
|
||||
)
|
||||
@@ -77,8 +293,8 @@ export default defineComponent({
|
||||
|
||||
return () => (
|
||||
<div class={[prefixCls, props.class]} style={{ ...props.style }}>
|
||||
{renderHeader}
|
||||
{renderBody}
|
||||
{renderHeader()}
|
||||
{renderBody()}
|
||||
</div>
|
||||
)
|
||||
},
|
||||
|
||||
Reference in new issue
Block a user