mirror of
https://github.com/pipipi-pikachu/PPTist.git
synced 2025-04-15 02:20:00 +08:00
230 lines
5.5 KiB
Vue
230 lines
5.5 KiB
Vue
<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"
|
|
>
|
|
<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" v-html="cell.text" />
|
|
</td>
|
|
</tr>
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
</template>
|
|
|
|
<script lang="ts">
|
|
import { computed, defineComponent, PropType, ref, watch } from 'vue'
|
|
import tinycolor from 'tinycolor2'
|
|
import { PPTElementOutline, TableCell, TableCellStyle, TableTheme } from '@/types/slides'
|
|
|
|
export default defineComponent({
|
|
name: 'static-table',
|
|
props: {
|
|
data: {
|
|
type: Array as PropType<TableCell[][]>,
|
|
required: true,
|
|
},
|
|
width: {
|
|
type: Number,
|
|
required: true,
|
|
},
|
|
colWidths: {
|
|
type: Array as PropType<number[]>,
|
|
required: true,
|
|
},
|
|
outline: {
|
|
type: Object as PropType<PPTElementOutline>,
|
|
required: true,
|
|
},
|
|
theme: {
|
|
type: Object as PropType<TableTheme>,
|
|
},
|
|
editable: {
|
|
type: Boolean,
|
|
default: true,
|
|
},
|
|
},
|
|
setup(props) {
|
|
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 hideCells = computed(() => {
|
|
const hideCells = []
|
|
|
|
for(let i = 0; i < props.data.length; i++) {
|
|
const rowCells = props.data[i]
|
|
|
|
for(let j = 0; j < rowCells.length; j++) {
|
|
const cell = rowCells[j]
|
|
|
|
if(cell.colspan > 1 || cell.rowspan > 1) {
|
|
for(let row = i; row < i + cell.rowspan; row++) {
|
|
for(let col = row === i ? j + 1 : j; col < j + cell.colspan; col++) {
|
|
hideCells.push(`${row}_${col}`)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return hideCells
|
|
})
|
|
|
|
const subThemeColor = ref(['', ''])
|
|
watch(() => props.theme, () => {
|
|
if(props.theme) {
|
|
const rgba = tinycolor(props.theme.color).toRgb()
|
|
const subRgba1 = { r: rgba.r, g: rgba.g, b: rgba.b, a: rgba.a * 0.3 }
|
|
const subRgba2 = { r: rgba.r, g: rgba.g, b: rgba.b, a: rgba.a * 0.1 }
|
|
subThemeColor.value = [
|
|
`rgba(${[subRgba1.r, subRgba1.g, subRgba1.b, subRgba1.a].join(',')})`,
|
|
`rgba(${[subRgba2.r, subRgba2.g, subRgba2.b, subRgba2.a].join(',')})`,
|
|
]
|
|
}
|
|
}, { immediate: true })
|
|
|
|
const getTextStyle = (style?: TableCellStyle) => {
|
|
if(!style) return {}
|
|
const {
|
|
bold,
|
|
em,
|
|
underline,
|
|
strikethrough,
|
|
color,
|
|
backcolor,
|
|
fontsize,
|
|
fontname,
|
|
align,
|
|
} = style
|
|
|
|
return {
|
|
fontWeight: bold ? 'bold' : 'normal',
|
|
fontStyle: em ? 'italic' : 'normal',
|
|
textDecoration: `${underline ? 'underline' : ''} ${strikethrough ? 'line-through' : ''}`,
|
|
color: color || '#000',
|
|
backgroundColor: backcolor || '',
|
|
fontSize: fontsize || '14px',
|
|
fontFamily: fontname || '微软雅黑',
|
|
textAlign: align || 'left',
|
|
}
|
|
}
|
|
|
|
return {
|
|
colSizeList,
|
|
totalWidth,
|
|
hideCells,
|
|
getTextStyle,
|
|
subThemeColor,
|
|
}
|
|
},
|
|
})
|
|
</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 {
|
|
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);
|
|
}
|
|
}
|
|
}
|
|
|
|
tr {
|
|
height: 36px;
|
|
}
|
|
|
|
.cell {
|
|
position: relative;
|
|
white-space: normal;
|
|
word-wrap: break-word;
|
|
vertical-align: middle;
|
|
}
|
|
|
|
.cell-text {
|
|
min-height: 32px;
|
|
padding: 5px;
|
|
border: 0;
|
|
outline: 0;
|
|
line-height: 1.5;
|
|
font-size: 14px;
|
|
user-select: none;
|
|
}
|
|
}
|
|
</style> |