StaticTable.vue 5.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230
  1. <template>
  2. <div
  3. class="static-table"
  4. :style="{ width: totalWidth + 'px' }"
  5. >
  6. <table
  7. :class="{
  8. 'theme': theme,
  9. 'row-header': theme?.rowHeader,
  10. 'row-footer': theme?.rowFooter,
  11. 'col-header': theme?.colHeader,
  12. 'col-footer': theme?.colFooter,
  13. }"
  14. :style="`--themeColor: ${theme?.color}; --subThemeColor1: ${subThemeColor[0]}; --subThemeColor2: ${subThemeColor[1]}`"
  15. >
  16. <colgroup>
  17. <col span="1" v-for="(width, index) in colSizeList" :key="index" :width="width">
  18. </colgroup>
  19. <tbody>
  20. <tr
  21. v-for="(rowCells, rowIndex) in data"
  22. :key="rowIndex"
  23. >
  24. <td
  25. class="cell"
  26. :style="{
  27. borderStyle: outline.style,
  28. borderColor: outline.color,
  29. borderWidth: outline.width + 'px',
  30. ...getTextStyle(cell.style),
  31. }"
  32. v-for="(cell, colIndex) in rowCells"
  33. :key="cell.id"
  34. :rowspan="cell.rowspan"
  35. :colspan="cell.colspan"
  36. v-show="!hideCells.includes(`${rowIndex}_${colIndex}`)"
  37. >
  38. <div class="cell-text" v-html="cell.text" />
  39. </td>
  40. </tr>
  41. </tbody>
  42. </table>
  43. </div>
  44. </template>
  45. <script lang="ts">
  46. import { computed, defineComponent, PropType, ref, watch } from 'vue'
  47. import tinycolor from 'tinycolor2'
  48. import { PPTElementOutline, TableCell, TableCellStyle, TableTheme } from '@/types/slides'
  49. export default defineComponent({
  50. name: 'static-table',
  51. props: {
  52. data: {
  53. type: Array as PropType<TableCell[][]>,
  54. required: true,
  55. },
  56. width: {
  57. type: Number,
  58. required: true,
  59. },
  60. colWidths: {
  61. type: Array as PropType<number[]>,
  62. required: true,
  63. },
  64. outline: {
  65. type: Object as PropType<PPTElementOutline>,
  66. required: true,
  67. },
  68. theme: {
  69. type: Object as PropType<TableTheme>,
  70. },
  71. editable: {
  72. type: Boolean,
  73. default: true,
  74. },
  75. },
  76. setup(props) {
  77. const colSizeList = ref<number[]>([])
  78. const totalWidth = computed(() => colSizeList.value.reduce((a, b) => a + b))
  79. watch([
  80. () => props.colWidths,
  81. () => props.width,
  82. ], () => {
  83. colSizeList.value = props.colWidths.map(item => item * props.width)
  84. }, { immediate: true })
  85. const hideCells = computed(() => {
  86. const hideCells = []
  87. for(let i = 0; i < props.data.length; i++) {
  88. const rowCells = props.data[i]
  89. for(let j = 0; j < rowCells.length; j++) {
  90. const cell = rowCells[j]
  91. if(cell.colspan > 1 || cell.rowspan > 1) {
  92. for(let row = i; row < i + cell.rowspan; row++) {
  93. for(let col = row === i ? j + 1 : j; col < j + cell.colspan; col++) {
  94. hideCells.push(`${row}_${col}`)
  95. }
  96. }
  97. }
  98. }
  99. }
  100. return hideCells
  101. })
  102. const subThemeColor = ref(['', ''])
  103. watch(() => props.theme, () => {
  104. if(props.theme) {
  105. const rgba = tinycolor(props.theme.color).toRgb()
  106. const subRgba1 = { r: rgba.r, g: rgba.g, b: rgba.b, a: rgba.a * 0.3 }
  107. const subRgba2 = { r: rgba.r, g: rgba.g, b: rgba.b, a: rgba.a * 0.1 }
  108. subThemeColor.value = [
  109. `rgba(${[subRgba1.r, subRgba1.g, subRgba1.b, subRgba1.a].join(',')})`,
  110. `rgba(${[subRgba2.r, subRgba2.g, subRgba2.b, subRgba2.a].join(',')})`,
  111. ]
  112. }
  113. }, { immediate: true })
  114. const getTextStyle = (style?: TableCellStyle) => {
  115. if(!style) return {}
  116. const {
  117. bold,
  118. em,
  119. underline,
  120. strikethrough,
  121. color,
  122. backcolor,
  123. fontsize,
  124. fontname,
  125. align,
  126. } = style
  127. return {
  128. fontWeight: bold ? 'bold' : 'normal',
  129. fontStyle: em ? 'italic' : 'normal',
  130. textDecoration: `${underline ? 'underline' : ''} ${strikethrough ? 'line-through' : ''}`,
  131. color: color || '#000',
  132. backgroundColor: backcolor || '',
  133. fontSize: fontsize || '14px',
  134. fontFamily: fontname || '微软雅黑',
  135. textAlign: align || 'left',
  136. }
  137. }
  138. return {
  139. colSizeList,
  140. totalWidth,
  141. hideCells,
  142. getTextStyle,
  143. subThemeColor,
  144. }
  145. },
  146. })
  147. </script>
  148. <style lang="scss" scoped>
  149. .static-table {
  150. position: relative;
  151. user-select: none;
  152. }
  153. table {
  154. width: 100%;
  155. position: relative;
  156. table-layout: fixed;
  157. border-collapse: collapse;
  158. border-spacing: 0;
  159. border: 0;
  160. word-wrap: break-word;
  161. user-select: none;
  162. --themeColor: $themeColor;
  163. --subThemeColor1: $themeColor;
  164. --subThemeColor2: $themeColor;
  165. &.theme {
  166. tr:nth-child(2n) .cell {
  167. background-color: var(--subThemeColor1);
  168. }
  169. tr:nth-child(2n + 1) .cell {
  170. background-color: var(--subThemeColor2);
  171. }
  172. &.row-header {
  173. tr:first-child .cell {
  174. background-color: var(--themeColor);
  175. }
  176. }
  177. &.row-footer {
  178. tr:last-child .cell {
  179. background-color: var(--themeColor);
  180. }
  181. }
  182. &.col-header {
  183. tr .cell:first-child {
  184. background-color: var(--themeColor);
  185. }
  186. }
  187. &.col-footer {
  188. tr .cell:last-child {
  189. background-color: var(--themeColor);
  190. }
  191. }
  192. }
  193. tr {
  194. height: 36px;
  195. }
  196. .cell {
  197. position: relative;
  198. white-space: normal;
  199. word-wrap: break-word;
  200. vertical-align: middle;
  201. }
  202. .cell-text {
  203. min-height: 32px;
  204. padding: 5px;
  205. border: 0;
  206. outline: 0;
  207. line-height: 1.5;
  208. font-size: 14px;
  209. user-select: none;
  210. }
  211. }
  212. </style>