消毒机设备
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

145 lines
3.0 KiB

2 months ago
  1. <script setup lang="ts">
  2. import type { VNode } from 'vue'
  3. import { onMounted, reactive } from 'vue'
  4. import Expand from './expand'
  5. defineOptions({
  6. name: 'FtTable',
  7. })
  8. const props = withDefaults(defineProps<TableProp>(), {
  9. columns: () => [],
  10. mustInit: true,
  11. hasHeader: true,
  12. getDataFn: () => Promise.resolve([]),
  13. })
  14. const emits = defineEmits([])
  15. enum ColumnType {
  16. index = 'index',
  17. selection = 'selection',
  18. expand = 'expand',
  19. }
  20. interface TableColumn {
  21. title: string
  22. key: string
  23. type?: ColumnType
  24. width?: number // 列宽
  25. fixed?: 'left' | 'right' | undefined // 是否固定列
  26. render?: (row: any) => VNode // 内容自定义
  27. }
  28. interface Btn {
  29. name: string
  30. icon?: string
  31. type?: string
  32. serverUrl: string
  33. }
  34. interface TableProp {
  35. columns: TableColumn[]
  36. getDataFn: (params: any) => Promise<any> // 表格数据的接口
  37. mustInit?: boolean // 是否在mounted里执行getDataFn
  38. hasHeader?: boolean
  39. btnList?: Btn[]
  40. }
  41. // const attrs = useAttrs()
  42. async function methodParent(fn: any) {
  43. const newFn = fn[0] === '/' ? fn.slice(1) : fn
  44. emits(newFn as never)
  45. }
  46. onMounted(() => {
  47. if (props.mustInit) {
  48. initData()
  49. }
  50. })
  51. const state = reactive({
  52. loading: false,
  53. dataTotal: 0,
  54. tableData: [],
  55. })
  56. function initData() {
  57. state.loading = true
  58. props
  59. .getDataFn({})
  60. .then((data) => {
  61. console.log(data)
  62. state.tableData = data
  63. state.loading = false
  64. })
  65. .finally(() => {
  66. state.loading = false
  67. })
  68. }
  69. defineExpose({
  70. initData,
  71. })
  72. </script>
  73. <template>
  74. <div v-if="hasHeader" class="header">
  75. <div v-for="btn in btnList" :key="btn.serverUrl">
  76. <el-button :icon="btn.icon" :type="btn.type" @click="methodParent(btn.serverUrl)">
  77. {{ btn.name }}
  78. </el-button>
  79. </div>
  80. <div class="search">
  81. <el-input v-prevent-keyboard>
  82. <template #suffix>
  83. <el-icon class="el-input__icon">
  84. <search />
  85. </el-icon>
  86. </template>
  87. </el-input>
  88. </div>
  89. </div>
  90. <el-table
  91. v-loading="state.loading"
  92. :="$attrs"
  93. :data="state.tableData"
  94. style="width: 100%"
  95. height="100%"
  96. :highlight-current-row="true"
  97. class="container-table"
  98. header-row-class-name="header-row-class"
  99. >
  100. <template v-for="(column, index) in columns" :key="column.key">
  101. <el-table-column
  102. show-overflow-tooltip
  103. :prop="column.key"
  104. :label="column.title"
  105. :width="column.width"
  106. :type="column.type"
  107. :fixed="column.fixed"
  108. >
  109. <template v-if="column.render" #default="scope">
  110. <Expand :column="column" :row="scope.row" :render="column.render" :index="index" />
  111. </template>
  112. </el-table-column>
  113. </template>
  114. </el-table>
  115. </template>
  116. <style lang="scss" scoped>
  117. .header {
  118. display: flex;
  119. justify-content: space-between;
  120. align-items: center;
  121. height: 40px;
  122. .search {
  123. width: 200px;
  124. }
  125. }
  126. :deep(.header-row-class) {
  127. th {
  128. background-color: rgba(0,0,0,0.02 ) !important;
  129. //font-weight: 500;
  130. //border-bottom: none;
  131. color: rgba(0, 0, 0, 0.85)
  132. }
  133. }
  134. </style>