NormalTable.vue 3.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152
  1. <template>
  2. <n-data-table class="normal-table"
  3. :columns="columns"
  4. :data="tableData"
  5. :single-line="true"
  6. />
  7. </template>
  8. <script setup lang="ts">
  9. import { NDataTable, DataTableColumn } from 'naive-ui'
  10. interface ColumnConfig {
  11. title: string;
  12. children?: ColumnConfig[];
  13. align?: 'left' | 'right' | 'center'; // 列文本对齐方式,默认left
  14. titleAlign?: 'left' | 'right' | 'center'; // 列标题对齐方式,默认同文本
  15. minWidth?: number | string;
  16. maxWidth?: number | string;
  17. width?: number | string;
  18. }
  19. type TableConfig = (string | ColumnConfig)[]
  20. interface CellDataExt {
  21. text: string;
  22. colspan?: number | undefined; // 向右合并 N 个单元格
  23. rowspan?: number | undefined; // 向下合并 N 个单元格
  24. }
  25. interface CellDataType {
  26. [title: string]: string | CellDataExt
  27. }
  28. interface Props {
  29. config?: TableConfig;
  30. data?: CellDataType[];
  31. }
  32. const props = withDefaults(defineProps<Props>(), {
  33. config: () => ({}),
  34. data: () => []
  35. })
  36. const handleRowSpan = (rowData: DataTableColumn, rowIndex: number, key: string): number => {
  37. const data = props.data[rowIndex]
  38. if (!data) return 1
  39. const keyValue = data[key]
  40. if (!keyValue) return 1
  41. if (typeof keyValue === "string") return 1
  42. return keyValue.rowspan ?? 1
  43. }
  44. const handleColSpan = (rowData: DataTableColumn, rowIndex: number, key: string): number => {
  45. const data = props.data[rowIndex]
  46. if (!data) return 1
  47. const keyValue = data[key]
  48. if (!keyValue) return 1
  49. if (typeof keyValue === "string") return 1
  50. return keyValue.colspan ?? 1
  51. }
  52. function traversalChildren(child: ColumnConfig[]) {
  53. return child.map(item => {
  54. let obj: DataTableColumn = {}
  55. obj.title = item.title
  56. obj.key = item.title
  57. obj.align = item.align
  58. obj.titleAlign = item.titleAlign
  59. obj.minWidth = item.minWidth
  60. obj.maxWidth = item.maxWidth
  61. obj.width = item.width
  62. if (item.children) {
  63. obj.children = traversalChildren(item.children)
  64. } else {
  65. obj.rowSpan = (rowData, rowIndex) => {
  66. return handleRowSpan(rowData, rowIndex, item.title)
  67. }
  68. obj.colSpan = (rowData, rowIndex) => {
  69. return handleColSpan(rowData, rowIndex, item.title)
  70. }
  71. }
  72. return obj
  73. })
  74. }
  75. function createColumns(config: TableConfig) {
  76. return config.map(column => {
  77. let obj: DataTableColumn = {}
  78. if (typeof column === 'string') {
  79. obj.title = column
  80. obj.key = column
  81. obj.rowSpan = (rowData, rowIndex) => {
  82. return handleRowSpan(rowData, rowIndex, column)
  83. }
  84. obj.colSpan = (rowData, rowIndex) => {
  85. return handleColSpan(rowData, rowIndex, column)
  86. }
  87. } else {
  88. obj.title = column.title
  89. obj.key = column.title
  90. obj.align = column.align
  91. obj.titleAlign = column.titleAlign
  92. obj.minWidth = column.minWidth
  93. obj.maxWidth = column.maxWidth
  94. obj.width = column.width
  95. if (column.children) {
  96. obj.children = traversalChildren(column.children)
  97. } else {
  98. obj.rowSpan = (rowData, rowIndex) => {
  99. return handleRowSpan(rowData, rowIndex, column.title)
  100. }
  101. obj.colSpan = (rowData, rowIndex) => {
  102. return handleColSpan(rowData, rowIndex, column.title)
  103. }
  104. }
  105. }
  106. return obj
  107. })
  108. }
  109. function createData(data: CellDataType[]) {
  110. return data.map((row, index) => {
  111. let obj = {
  112. key: index
  113. }
  114. for (const key in row) {
  115. const value = row[key as keyof typeof row];
  116. if (typeof value === "string") {
  117. obj[key] = value
  118. } else {
  119. obj[key] = value.text
  120. }
  121. }
  122. return obj
  123. })
  124. }
  125. const columns = createColumns(props.config)
  126. const tableData = createData(props.data)
  127. </script>
  128. <style scoped>
  129. /* 覆盖.vp-doc table */
  130. .normal-table :deep(table) {
  131. margin: 0 0 !important;
  132. }
  133. .normal-table :deep(td) {
  134. white-space: pre-wrap; /* 保留换行和空格 */
  135. }
  136. </style>