ExportToCSV.vue 4.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184
  1. <template>
  2. <div>
  3. <div class="table-container" :style="props.tableStyle">
  4. <div class="btn-toggle-table" :class="{ 'hide-table': hideTable }" @click="hideTable = !hideTable">
  5. {{ hideTable ? '展开' : '收起' }}明细数据<svg width="14" height="14" viewBox="0 0 14 14" fill="none"
  6. xmlns="http://www.w3.org/2000/svg">
  7. <path d="M10.5 8.75L7 5.25L3.5 8.75" stroke="#167AF0" stroke-width="1.5" stroke-linecap="round"
  8. stroke-linejoin="round" />
  9. </svg>
  10. </div>
  11. <div v-if="fileName" class="export-button" @click="handleExportData(dataList, columns, fileName)">导出
  12. <span style="vertical-align: middle; margin: 0 0 0 8px;">
  13. <Svg name="export2"></Svg>
  14. </span>
  15. </div>
  16. <el-table class="table" :data="paginatedData" row-key="name" style="width: 100%"
  17. :cell-style="cellStyle" :header-cell-style="headerCellStyle" v-if="!hideTable">
  18. <el-table-column v-for="(column, index) in columns" :key="column.prop" :label="column.label"
  19. :prop="column.prop" show-overflow-tooltip :formatter="statusFormatter">
  20. <template #default="scope">
  21. {{ scope.row[column.prop] }}
  22. </template>
  23. </el-table-column>
  24. </el-table>
  25. <pagination v-if="!hideTable && !hidePage" @current-change="handleCurrentChange" @size-change="handleSizeChange"
  26. v-bind="state.pagination">
  27. </pagination>
  28. </div>
  29. </div>
  30. </template>
  31. <script setup lang="ts">
  32. import { BasicTableProps, useTable } from '/@/hooks/table';
  33. import { ref, reactive, PropType, watch, computed } from 'vue'
  34. import { exportToExcel, formatTableDataForExport } from '/@/utils/exportExcel';
  35. import { useMessage } from '/@/hooks/message';
  36. import Svg from '/@/components/Svg.vue';
  37. const cellStyle = ref({
  38. textAlign: 'center',
  39. fontSize: '14px',
  40. height: '50px',
  41. background: 'transparent !important'
  42. })
  43. const headerCellStyle = ref({
  44. textAlign: 'center',
  45. border: 'none',
  46. background: 'rgba(244, 245, 250, 1)',
  47. height: '32px',
  48. color: 'rgba(100, 100, 100, 1)',
  49. fontSize: '14px',
  50. })
  51. const props = defineProps({
  52. data: {
  53. type: Array,
  54. default: () => []
  55. },
  56. columns: {
  57. type: Array as PropType<{ prop: string; label: string }[]>,
  58. default: () => []
  59. },
  60. fileName: {
  61. type: String,
  62. default: ''
  63. },
  64. hideTable: {
  65. type: Boolean,
  66. default: true
  67. },
  68. tableStyle: {
  69. type: Object,
  70. default: () => ({})
  71. },
  72. hidePage: {
  73. type: Boolean,
  74. default: false
  75. }
  76. })
  77. // 表格数据
  78. const dataList = ref(props.data);
  79. const hideTable = ref(props.hideTable);
  80. const state: BasicTableProps = reactive<BasicTableProps>({
  81. queryForm: {
  82. ip: '',
  83. },
  84. pageList: () => Promise.resolve([]),
  85. pagination: {
  86. current: 1,
  87. size: 5,
  88. total: 0,
  89. pageSizes: [5, 10, 20, 50, 100]
  90. },
  91. // dataList: []
  92. });
  93. // 计算分页后的数据
  94. const paginatedData = computed(() => {
  95. if (!state.pagination || typeof state.pagination.current === 'undefined' || typeof state.pagination.size === 'undefined') {
  96. return dataList.value;
  97. }
  98. const start = (state.pagination.current - 1) * state.pagination.size;
  99. const end = start + state.pagination.size;
  100. return dataList.value.slice(start, end);
  101. });
  102. watch(() => props.data, (newVal) => {
  103. dataList.value = newVal;
  104. console.log(`dataList: `);
  105. console.log(dataList.value);
  106. state.pagination!.total = dataList.value.length;
  107. }, { immediate: true, deep: true })
  108. const { getDataList, currentChangeHandle, sizeChangeHandle, tableStyle } = useTable(state);
  109. // 重写分页处理函数,实现本地分页
  110. const handleCurrentChange = (val: number) => {
  111. state.pagination!.current = val;
  112. };
  113. const handleSizeChange = (val: number) => {
  114. state.pagination!.size = val;
  115. state.pagination!.current = 1; // 切换每页条数时重置到第一页
  116. };
  117. const statusFormatter = (row: any, column: any, cellValue: any, index: any) => {
  118. return cellValue || '--';
  119. }
  120. const handleExportData = (data: any, columns: any, fileName: string) => {
  121. try {
  122. // 检查是否有数据
  123. if (!data || data.length === 0) {
  124. useMessage().warning('没有数据可导出');
  125. return;
  126. }
  127. const exportData = formatTableDataForExport(data, columns);
  128. exportToExcel(exportData, fileName);
  129. } catch (error) {
  130. console.error('导出失败:', error);
  131. useMessage().error('导出失败,请检查数据格式');
  132. }
  133. }
  134. </script>
  135. <style scoped lang="scss">
  136. @import '/@/views/count/styles/common.scss';
  137. svg {
  138. vertical-align: middle;
  139. margin: 0 0 0 12px;
  140. }
  141. .table-container {
  142. margin: 0 auto;
  143. width: 100%;
  144. max-width: 1360px;
  145. }
  146. .export-button {
  147. font-size: 14px;
  148. font-family: Source Han Sans SC;
  149. font-weight: 500;
  150. font-size: 14px;
  151. color: rgba(22, 122, 240, 1);
  152. svg {
  153. margin-left: 8px;
  154. margin-right: 0;
  155. }
  156. }
  157. :deep(.el-input__inner),
  158. :deep(.el-date-editor--dates .el-input__wrapper) {
  159. cursor: pointer;
  160. }
  161. </style>