import type { PropType , VNode , CSSProperties } from 'vue' ; import { computed , defineComponent , ref } from 'vue' ; import type { Size , TextAlign } from '../_utils/constant' ; import { getPrefixCls } from '../_utils/global-config' ; import { isArray , isFunction , isObject } from '../_utils/is' ; export type DescData = { key : string ; label : string | ( ( ) => VNode ) ; value : string | ( ( ) => VNode ) ; span : number ; } ; const DESC_LAYOUTS = [ 'horizontal' , 'vertical' , 'inline-horizontal' , 'inline-vertical' , ] as const ; type DescLayout = typeof DESC_LAYOUTS [ number ] ; const getItemSpan = ( item , column ) => { if ( ! item . span ) { return 1 ; } if ( item . span > column ) { return column ; } return item . span ; } ; const getTotalSpan = ( arr ? ) => { return isArray ( arr ) ? arr . reduce ( ( total , data ) => total + ( data . span || 1 ) , 0 ) : 0 ; } ; export default defineComponent ( { name : 'Descriptions' , props : { zh en data : { type : Array as PropType < DescData [ ] > , default : ( ) => [ ] } , zh en column : { type : Number , default : 3 } , zh en title : String , zh en values layout : { type : String as PropType < DescLayout > , default : 'horizontal' } , zh en align : { type : [ String , Object ] as PropType < TextAlign | { label ? : TextAlign ; value ? : TextAlign ; } > , default : 'left' } , zh en values size : { type : String as PropType < Size > , default : 'medium' } , zh en bordered : { type : Boolean , default : false } , zh en labelStyle : { type : Object as PropType < CSSProperties > } , zh en valueStyle : { type : Object as PropType < CSSProperties > } } , zh en slot zh en slot binding binding binding zh en slot binding binding binding setup ( props , { slots } ) { const prefixCls = getPrefixCls ( 'descriptions' ) ; const screen = ref ( ) ; const column = computed ( ( ) => isObject ( props . column ) ? props . column [ screen . value ] : props . column ) ; const labelAlign = computed ( ( ) => ( isObject ( props . align ) ? props . align . label : props . align ) ?? 'left' ) ; const valueAlign = computed ( ( ) => ( isObject ( props . align ) ? props . align . value : props . align ) ?? 'left' ) ; const labelStyle = computed < CSSProperties > ( ( ) => ( { textAlign : labelAlign . value , ... props . labelStyle } ) ) ; const valueStyle = computed < CSSProperties > ( ( ) => ( { textAlign : valueAlign . value , ... props . valueStyle } ) ) ; const data = computed ( ( ) => { const data = [ ] ; if ( isArray ( props . data ) && props . data . length > 0 && column . value > 0 ) { for ( const item of props . data ) { const itemSpan = getItemSpan ( item , column . value ) ; const lastData = data [ data . length - 1 ] ; const lastDataTotalSpan = getTotalSpan ( lastData ) ; if ( lastDataTotalSpan === 0 || lastDataTotalSpan >= column . value ) { data . push ( [ { ... item , span : itemSpan } , ] ) ; } else { const span = item . span ? item . span + lastDataTotalSpan > column . value ? column . value - lastDataTotalSpan : item . span : 1 ; lastData . push ( { ... item , span } ) ; } } const lastData = data [ data . length - 1 ] ; const lastDataTotalSpan = getTotalSpan ( lastData ) ; if ( lastDataTotalSpan < column . value ) { lastData [ lastData . length - 1 ] . span = lastData [ lastData . length - 1 ] . span + column . value - lastDataTotalSpan ; } } return data ; } ) ; const renderVerticalItems = ( data ) => ( < > < tr class = { `${ prefixCls }-row` } > { data . map ( ( item , index ) => ( < td key = { `${ item . key ?? index }_label` } class = { `${ prefixCls }-item-label` } style = { labelStyle . value } colspan = { item . span } > { slots . label ?. ( { label : item . label , index , data : item } ) ?? ( isFunction ( item . label ) ? item . label ( ) : item . label ) } < /td>))} < /tr> < tr class = { `${ prefixCls }-row` } > { data . map ( ( item , index ) => ( < td key = { `${ item . key ?? index }_value` } class = { `${ prefixCls }-item-value` } style = { valueStyle . value } colspan = { item . span } > { slots . value ?. ( { value : item . value , index , data : item } ) ?? ( isFunction ( item . value ) ? item . value ( ) : item . value ) } < /td>))} < /tr> < />); const renderHorizontalItems = ( data , index ) => ( < tr class = { `${ prefixCls }-row` } key = { `tr-${ index }` } > { data . map ( ( item ) => ( < > < td class = { `${ prefixCls }-item-label` } style = { labelStyle . value } > { slots . label ?. ( { label : item . label , index , data : item } ) ?? ( isFunction ( item . label ) ? item . label ( ) : item . label ) } < /td> < td class = { `${ prefixCls }-item-value` } style = { valueStyle . value } colspan = { item . span * 2 - 1 } > { slots . value ?. ( { value : item . value , index , data : item } ) ?? ( isFunction ( item . value ) ? item . value ( ) : item . value ) } < /td> < />))} < /tr>); const renderInlineItems = ( data , index ) => ( < tr class = { `${ prefixCls }-row` } key = { `inline-${ index }` } > { data . map ( ( item , index ) => ( < td key = { item . key ?? index } class = { `${ prefixCls }-item` } colspan = { item . span } > < div class = { `${ prefixCls }-item-label-inline` } style = { labelStyle . value } > { slots . label ?. ( { label : item . label , index , data : item } ) ?? ( isFunction ( item . label ) ? item . label ( ) : item . label ) } < /div> < div class = { `${ prefixCls }-item-value-inline` } style = { valueStyle . value } > { slots . value ?. ( { value : item . value , index , data : item } ) ?? ( isFunction ( item . value ) ? item . value ( ) : item . value ) } < /div> < /td>))} < /tr>); const renderItems = ( data , index ) => { if ( [ 'inline-horizontal' , 'inline-vertical' ] . includes ( props . layout ) ) { return renderInlineItems ( data , index ) ; } if ( props . layout === 'vertical' ) { return renderVerticalItems ( data ) ; } return renderHorizontalItems ( data , index ) ; } ; const cls = computed ( ( ) => [ prefixCls , `${ prefixCls }-layout-${ props . layout }` , `${ prefixCls }-size-${ props . size }` , { [ `${ prefixCls }-border` ] : props . bordered } , ] ) ; const renderTitle = ( ) => { const title = slots . title ?. ( ) ?? props . title ; if ( title ) { return < div class = { `${ prefixCls }-title` } > { title } < /div>; } return null ; } ; return ( ) => ( < div class = { cls . value } > { renderTitle ( ) } < div class = { `${ prefixCls }-body` } > < table class = { `${ prefixCls }-table` } > < tbody > { data . value . map ( ( data , index ) => renderItems ( data , index ) ) } < /tbody> < /table> < /div> < /div>); } } ) ;