| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230 |
- <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>
|