ie-table.vue 2.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114
  1. <template>
  2. <view class="">
  3. <view class="table-header">
  4. <view class="table-header-cell" v-for="item in tableColumns" :key="item.prop" :style="getHeaderStyle(item)">
  5. {{ item.label }}
  6. </view>
  7. </view>
  8. <view class="table-body">
  9. <block v-if="data.length">
  10. <view class="table-row" :class="{ 'sibling-border-top': getTableConfig.border }" v-for="(row, index) in data"
  11. :key="getRowKey(row, index)" @click="handleRowClick(row)">
  12. <view class="table-row-cell" v-for="item in tableColumns" :key="item.prop" :style="getCellStyle(item)">
  13. <view v-if="item.type === 'index'">
  14. {{ index + 1 }}
  15. </view>
  16. <slot v-else :name="item.slot" :item="row" :index="index">
  17. <text>{{ getCellValue(row, item.prop) }}</text>
  18. </slot>
  19. </view>
  20. </view>
  21. </block>
  22. <view v-else class="no-data">{{ getTableConfig.emptyText }}</view>
  23. </view>
  24. </view>
  25. </template>
  26. <script lang="ts" setup generic="T extends Record<string, any>">
  27. import { TableColumnConfig, TableConfig } from '@/types';
  28. import { CSSProperties } from 'vue';
  29. // 使用泛型定义props
  30. interface Props<T> {
  31. tableConfig: TableConfig;
  32. tableColumns: TableColumnConfig[];
  33. data: T[];
  34. cellStyle: CSSProperties;
  35. }
  36. const props = defineProps<Props<any>>();
  37. // 使用泛型定义emits
  38. const emit = defineEmits<{
  39. rowClick: [row: T]
  40. }>();
  41. const getTableConfig = computed(() => {
  42. return {
  43. ...{
  44. border: true,
  45. stripe: false,
  46. emptyText: '暂无数据',
  47. loading: false,
  48. rowKey: 'id'
  49. },
  50. ...props.tableConfig
  51. };
  52. });
  53. const getHeaderStyle = (item: TableColumnConfig) => {
  54. return {
  55. flex: item.flex ? item.flex : 1,
  56. minWidth: '1px',
  57. textAlign: item.headerAlign ? item.headerAlign : 'center'
  58. };
  59. };
  60. const getCellStyle = (item: TableColumnConfig) => {
  61. return {
  62. flex: item.flex ? item.flex : 1,
  63. minWidth: '1px',
  64. flexShrink: 0,
  65. width: '100%',
  66. textAlign: item.align ? item.align : 'center',
  67. ...props.cellStyle
  68. };
  69. };
  70. const handleRowClick = (row: any) => {
  71. emit('rowClick', row);
  72. };
  73. // 安全地获取行key
  74. const getRowKey = (row: any, index: number) => {
  75. const rowKey = getTableConfig.value.rowKey;
  76. return row[rowKey] || index;
  77. };
  78. // 安全地获取单元格值
  79. const getCellValue = (row: any, prop: string) => {
  80. return row[prop] || '';
  81. };
  82. </script>
  83. <style lang="scss" scoped>
  84. .table-header {
  85. @apply flex items-center bg-[#EBF9FF] rounded-5;
  86. }
  87. .table-header-cell {
  88. @apply flex-1 px-20 py-20 text-30 text-fore-light;
  89. }
  90. .table-row {
  91. @apply flex items-center;
  92. }
  93. .table-row-cell {
  94. @apply px-20 py-20 text-28 text-fore-title;
  95. }
  96. .no-data {
  97. @apply mt-16 bg-[#F6F8FA] text-center py-50 text-26 text-fore-light rounded-5;
  98. }
  99. </style>