@ -2,7 +2,15 @@
< div class = "list-table-v2" >
< div class = "list-table-v2" >
<!-- Debug info -- >
<!-- Debug info -- >
< div v-if ="debug" class="debug-info" >
< div v-if ="debug" class="debug-info" >
< json -view :data ="debugInfo" :deep ="3" :virtual ="true" :show-icon ="true" :show-double-quotes ="false" / >
< json -view
: data = "debugInfo"
: deep = "1"
: virtual = "true"
: show - icon = "true"
: show - double - quotes = "false"
inline
collapse - fully - inline - node
/ >
< / div >
< / div >
<!-- Main table container with ResizeObserver for width tracking -- >
<!-- Main table container with ResizeObserver for width tracking -- >
@ -22,25 +30,25 @@
< div class = "table-spacer" : style = "{ height: `${virtualTotalHeight}px` }" >
< div class = "table-spacer" : style = "{ height: `${virtualTotalHeight}px` }" >
<!-- Visible rows -- >
<!-- Visible rows -- >
< div
< div
v - for = "row in visibleRows"
v - for = "virt in visibleRows"
: key = "row.index"
: key = "lodash.get(getRow(virt.index), rowKey) ?? virt .index"
class = "table-row"
class = "table-row"
: style = " {
: style = " {
transform : ` translateY( ${ row . offsetY } px) ` ,
transform : ` translateY( ${ virt . offsetY } px) ` ,
height : ` ${ row . height } px ` ,
height : ` ${ virt . height } px ` ,
} "
} "
@ click = "handleRowClick(row .index)"
@ click = "handleRowClick(virt .index)"
>
>
< div
< div
v - for = "col in visibleColumns"
v - for = "col in visibleColumns"
: key = "col.key"
: key = "col.key"
class = "table-cell"
class = "table-cell"
: style = "getColumnStyle(col)"
: style = "getColumnStyle(col)"
@ click = "handleCellClick(row .index, col)"
@ click = "handleCellClick(virt .index, col)"
>
>
< slot :name ="col.key" :row ="getRow(row .index)" >
< slot :name ="col.key" :row ="getRow(virt .index)" >
< span class = "cell-text" :style ="getTextStyle(col)" > { {
< span class = "cell-text" :style ="getTextStyle(col)" > { {
getRow ( row . index ) ? formatCellValue ( getRow ( row . index ) ! , col ) : "--"
getRow ( virt . index ) ? formatCellValue ( getRow ( virt . index ) ! , col ) : "--"
} } < / span >
} } < / span >
< / slot >
< / slot >
< / div >
< / div >
@ -66,7 +74,7 @@
< / template >
< / template >
< script lang = "tsx" setup generic = "T" >
< script lang = "tsx" setup generic = "T" >
import { ref , computed , onMounted , onUnmounted , toRef , StyleValue , CSSProperties } from "vue" ;
import { ref , computed , onMounted , onUnmounted , toRef , CSSProperties , watch } from "vue" ;
import { useStore } from "vuex" ;
import { useStore } from "vuex" ;
import { useI18n } from "vue3-i18n" ;
import { useI18n } from "vue3-i18n" ;
import * as lodash from "lodash-es" ;
import * as lodash from "lodash-es" ;
@ -78,8 +86,12 @@ import { formatTimestampFromValue } from "../../../../plugs/composables";
import { match } from "ts-pattern" ;
import { match } from "ts-pattern" ;
import { JsonView } from "noob-mengyxu" ;
import { JsonView } from "noob-mengyxu" ;
const DEFAULT _FONT = "14px sans-serif" ;
const DEFAULT _FONT = "14px Microsoft YaHei, sans-serif" ;
const DEFAULT _HEADER _FONT = "bold 16px Microsoft YaHei, sans-serif" ;
const DEFAULT _TEXT _MAX _WIDTH = 400 ;
const DEFAULT _TEXT _MAX _WIDTH = 400 ;
const DEFAULT _LINE _HEIGHT = 20 ;
const DEFAULT _TOP _BOTTOM _PADDING = 8 ;
const DEFAULT _LEFT _RIGHT _PADDING = 4 ;
const { t } = useI18n ( ) ;
const { t } = useI18n ( ) ;
const { state } = useStore ( ) ;
const { state } = useStore ( ) ;
@ -113,6 +125,7 @@ interface Props {
estimatedRowHeight ? : number ;
estimatedRowHeight ? : number ;
headerHeight ? : number ;
headerHeight ? : number ;
font ? : string ;
font ? : string ;
headerFont ? : string ;
debug ? : boolean ;
debug ? : boolean ;
}
}
@ -170,6 +183,8 @@ const pageDataRef = toRef(pageData);
/ / = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
/ / = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
/ / C e l l f o r m a t t i n g
/ / C e l l f o r m a t t i n g
/ / = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
/ / = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
const isNullish = ( value : any ) => value === undefined || value === null || value === "" ;
const getHeaderText = ( col : ListTableColumn < T > ) : string => {
const getHeaderText = ( col : ListTableColumn < T > ) : string => {
if ( col . name ) return col . name ;
if ( col . name ) return col . name ;
if ( col . i18n ) return t ( col . i18n ) ;
if ( col . i18n ) return t ( col . i18n ) ;
@ -180,7 +195,7 @@ const formatCellValue = (row: T, col: ListTableColumn<T>): string => {
const value = ( row as any ) [ col . dataKey || col . key ] ;
const value = ( row as any ) [ col . dataKey || col . key ] ;
if ( col . dict ) {
if ( col . dict ) {
return formatterByDis t ( col . dict , value ) ;
return formatByDic t ( col . dict , value ) ;
}
}
if ( col . timestamp ) {
if ( col . timestamp ) {
if ( ( typeof value !== "string" && typeof value !== "number" ) || value === "" ) {
if ( ( typeof value !== "string" && typeof value !== "number" ) || value === "" ) {
@ -198,12 +213,7 @@ const formatCellValue = (row: T, col: ListTableColumn<T>): string => {
return String ( value ) ;
return String ( value ) ;
} ;
} ;
const getValue = ( value : any ) : string => {
const display = ( value : any ) : string => ( isNullish ( value ) ? "--" : String ( value ) ) ;
if ( ( typeof value === "undefined" || value === null || value === "" ) && value !== 0 ) {
return "--" ;
}
return value ;
} ;
const formatFileSize = ( value : any ) : string => {
const formatFileSize = ( value : any ) : string => {
const k = value / 1024 ;
const k = value / 1024 ;
@ -215,11 +225,12 @@ const formatFileSize = (value: any): string => {
return g . toFixed ( 2 ) + "G" ;
return g . toFixed ( 2 ) + "G" ;
} ;
} ;
const formatterByDist = ( dictKey : string , cellData : any ) : string => {
const formatByDict = ( dictKey : string , cellData : any ) : string => {
if ( ! dictKey ) return getValue ( cellData ) ;
if ( ! dictKey ) return ` UNKNOWN_DICT: ${ dictKey } ` ;
const mapping = ( state as any ) . dict [ dictKey ] ;
const mapping = ( state as any ) . dict [ dictKey ] ;
if ( mapping == null ) return getValue ( cellData ) ;
if ( mapping == null ) return ` UNKNOWN_DICT: ${ dictKey } ` ;
return mapping [ cellData ] == null ? cellData : mapping [ cellData ] ;
return display ( mapping [ cellData ] ) ;
} ;
} ;
/ / = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
/ / = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
@ -231,11 +242,8 @@ const { computedConfigs, totalFlexBasis, columnWidths } = usePretextColumnWidths
pageDataRef ,
pageDataRef ,
columnsRef ,
columnsRef ,
containerWidth ,
containerWidth ,
{
formatCellValue ,
font : "14px Inter, sans-serif" ,
{ font : props . font , headerFont : DEFAULT _HEADER _FONT /* TODO: add props.headerFont */ }
headerFont : "bold 14px Inter, sans-serif" ,
formatCellValue ,
}
) ;
) ;
/ / R o w h e i g h t s v i a p r e t e x t - u s e a c t u a l c o l u m n w i d t h s f r o m f l e x b o x a l g o r i t h m
/ / R o w h e i g h t s v i a p r e t e x t - u s e a c t u a l c o l u m n w i d t h s f r o m f l e x b o x a l g o r i t h m
@ -247,7 +255,15 @@ const { rowHeights, cellHeights } = resolveRowHeights(
formatCellValue ,
formatCellValue ,
{
{
font : props . font ,
font : props . font ,
lineHeight : 20 ,
lineHeight : DEFAULT _LINE _HEIGHT ,
padding : {
top : DEFAULT _TOP _BOTTOM _PADDING ,
bottom : DEFAULT _TOP _BOTTOM _PADDING ,
left : DEFAULT _LEFT _RIGHT _PADDING + 1 ,
right : DEFAULT _LEFT _RIGHT _PADDING ,
} ,
} ,
{
debug : props . debug ,
debug : props . debug ,
fixedRowHeight : props . rowHeight ,
fixedRowHeight : props . rowHeight ,
}
}
@ -278,12 +294,13 @@ const tableContainerStyle = computed(() => {
} ;
} ;
if ( props . height !== undefined ) {
if ( props . height !== undefined ) {
const h = String ( props . height ) ;
const h = String ( props . height ) ;
style . maxHeight = h . endsWith ( "px" ) ? h : ` ${ h } px ` ;
style . flex = "unset" ;
style . height = h . endsWith ( "px" ) ? h : ` ${ h } px ` ;
}
if ( props . maxHeight !== undefined ) {
const mh = String ( props . maxHeight ) ;
style . maxHeight = mh . endsWith ( "px" ) ? mh : ` ${ mh } px ` ;
}
}
/ / i f ( p r o p s . m a x H e i g h t ! = = u n d e f i n e d ) {
/ / c o n s t m h = S t r i n g ( p r o p s . m a x H e i g h t ) ;
/ / s t y l e . m a x H e i g h t = m h . e n d s W i t h ( " p x " ) ? m h : ` $ { m h } p x ` ;
/ / }
return style ;
return style ;
} ) ;
} ) ;
@ -394,12 +411,12 @@ const handleCurrentChange = (val: number) => {
const debugInfo = computed ( ( ) => ( {
const debugInfo = computed ( ( ) => ( {
containerWidth ,
containerWidth ,
virtualTotalHeight ,
virtualTotalHeight ,
visibleRows : visibleRows . value . map ( ( entry ) => entry . height ) . join ( "," ) ,
visibleRows : visibleRows . value . map ( ( entry ) => entry . height ) ,
cellHeights : cellHeights . value ? . map ( ( rowCellHeights ) =>
cellHeights : cellHeights . value ? . map ( ( rowCellHeights ) =>
rowCellHeights . map ( ( entry ) => ( entry ? ` ${ entry . isCustomRenderer ? "*" : "" } ${ entry . height } ` : "null" ) ) . join ( "," )
rowCellHeights . map ( ( entry ) => ( entry ? ` ${ entry . isCustomRenderer ? "*" : "" } ${ entry . height } ` : "null" ) )
) ,
) ,
totalRows : pageData . value . length ,
totalRows : pageData . value . length ,
columnWidths : columnWidths . value . map ( ( w ) => Math . round ( w ) ) . join ( "," ) ,
columnWidths : columnWidths . value . map ( ( w ) => Math . round ( w ) ) ,
columnConfigs : computedConfigs ,
columnConfigs : computedConfigs ,
} ) ) ;
} ) ) ;
@ -477,7 +494,7 @@ onUnmounted(() => {
flex : 1 1 120 px ;
flex : 1 1 120 px ;
align - items : center ;
align - items : center ;
justify - content : center ;
justify - content : center ;
padding : 8 px 4 px ;
padding : v - bind ( "`${DEFAULT_TOP_BOTTOM_PADDING}px ${DEFAULT_LEFT_RIGHT_PADDING}px`" ) ;
box - sizing : border - box ;
box - sizing : border - box ;
border - right : 1 px solid v - bind ( "state.style.tableBorderColor" ) ;
border - right : 1 px solid v - bind ( "state.style.tableBorderColor" ) ;
overflow : hidden ;
overflow : hidden ;
@ -496,8 +513,8 @@ onUnmounted(() => {
text - overflow : ellipsis ;
text - overflow : ellipsis ;
white - space : nowrap ;
white - space : nowrap ;
color : v - bind ( "state.style.tableColor" ) ;
color : v - bind ( "state.style.tableColor" ) ;
font - weight : bold ;
font : v - bind ( "props.headerFont ?? props.font ?? DEFAULT_HEADER_FONT" ) ;
font - size : var ( -- el - font - size - base ) ;
font - weight : v - bind ( "!props.headerFont && props.font ? 'bold' : 'unset'" ) ;
}
}
. table - body {
. table - body {
@ -556,6 +573,7 @@ onUnmounted(() => {
word - break : break - word ;
word - break : break - word ;
color : v - bind ( "state.style.tableColor" ) ;
color : v - bind ( "state.style.tableColor" ) ;
font : v - bind ( "props.font" ) ;
font : v - bind ( "props.font" ) ;
line - height : v - bind ( "`${DEFAULT_LINE_HEIGHT}px`" ) ;
}
}
. my - pagination {
. my - pagination {