|
<template> |
|
<div |
|
class="static-table" |
|
:style="{ width: totalWidth + 'px' }" |
|
> |
|
<table |
|
:class="{ |
|
'theme': theme, |
|
'row-header': theme?.rowHeader, |
|
'row-footer': theme?.rowFooter, |
|
'col-header': theme?.colHeader, |
|
'col-footer': theme?.colFooter, |
|
}" |
|
:style="`--themeColor: ${theme?.color}; --subThemeColor1: ${subThemeColor[0]}; --subThemeColor2: ${subThemeColor[1]}`" |
|
> |
|
<colgroup> |
|
<col span="1" v-for="(width, index) in colSizeList" :key="index" :width="width"> |
|
</colgroup> |
|
<tbody> |
|
<tr v-for="(rowCells, rowIndex) in data" :key="rowIndex" :style="{ height: cellMinHeight + 'px' }"> |
|
<td |
|
class="cell" |
|
:style="{ |
|
borderStyle: outline.style, |
|
borderColor: outline.color, |
|
borderWidth: outline.width + 'px', |
|
...getTextStyle(cell.style), |
|
}" |
|
v-for="(cell, colIndex) in rowCells" |
|
:key="cell.id" |
|
:rowspan="cell.rowspan" |
|
:colspan="cell.colspan" |
|
v-show="!hideCells.includes(`${rowIndex}_${colIndex}`)" |
|
> |
|
<div class="cell-text" :style="{ minHeight: (cellMinHeight - 4) + 'px' }" v-html="formatText(cell.text)" /> |
|
</td> |
|
</tr> |
|
</tbody> |
|
</table> |
|
</div> |
|
</template> |
|
|
|
<script lang="ts" setup> |
|
import { computed, ref, watch } from 'vue' |
|
import type { PPTElementOutline, TableCell, TableTheme } from '@/types/slides' |
|
import { getTextStyle, formatText } from './utils' |
|
import useHideCells from './useHideCells' |
|
import useSubThemeColor from './useSubThemeColor' |
|
|
|
const props = withDefaults(defineProps<{ |
|
data: TableCell[][] |
|
width: number |
|
cellMinHeight: number |
|
colWidths: number[] |
|
outline: PPTElementOutline |
|
theme?: TableTheme |
|
editable?: boolean |
|
}>(), { |
|
editable: true, |
|
}) |
|
|
|
const colSizeList = ref<number[]>([]) |
|
const totalWidth = computed(() => colSizeList.value.reduce((a, b) => a + b)) |
|
|
|
watch([ |
|
() => props.colWidths, |
|
() => props.width, |
|
], () => { |
|
colSizeList.value = props.colWidths.map(item => item * props.width) |
|
}, { immediate: true }) |
|
|
|
const cells = computed(() => props.data) |
|
const { hideCells } = useHideCells(cells) |
|
|
|
const theme = computed(() => props.theme) |
|
const { subThemeColor } = useSubThemeColor(theme) |
|
</script> |
|
|
|
<style lang="scss" scoped> |
|
.static-table { |
|
position: relative; |
|
user-select: none; |
|
} |
|
table { |
|
width: 100%; |
|
position: relative; |
|
table-layout: fixed; |
|
border-collapse: collapse; |
|
border-spacing: 0; |
|
border: 0; |
|
word-wrap: break-word; |
|
user-select: none; |
|
|
|
--themeColor: $themeColor; |
|
--subThemeColor1: $themeColor; |
|
--subThemeColor2: $themeColor; |
|
|
|
&.theme { |
|
background-color: #fff; |
|
|
|
tr:nth-child(2n) .cell { |
|
background-color: var(--subThemeColor1); |
|
} |
|
tr:nth-child(2n + 1) .cell { |
|
background-color: var(--subThemeColor2); |
|
} |
|
|
|
&.row-header { |
|
tr:first-child .cell { |
|
background-color: var(--themeColor); |
|
} |
|
} |
|
&.row-footer { |
|
tr:last-child .cell { |
|
background-color: var(--themeColor); |
|
} |
|
} |
|
&.col-header { |
|
tr .cell:first-child { |
|
background-color: var(--themeColor); |
|
} |
|
} |
|
&.col-footer { |
|
tr .cell:last-child { |
|
background-color: var(--themeColor); |
|
} |
|
} |
|
} |
|
|
|
.cell { |
|
position: relative; |
|
white-space: normal; |
|
word-wrap: break-word; |
|
vertical-align: middle; |
|
background-clip: padding-box; |
|
} |
|
|
|
.cell-text { |
|
padding: 5px; |
|
line-height: 1.5; |
|
} |
|
} |
|
</style> |