formDetail.vue 3.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128
  1. <template>
  2. <div class="app-container p-2">
  3. <el-row :gutter="20">
  4. <el-col :lg="30" :xs="24" style="">
  5. <el-row :span="24" :gutter="10">
  6. <el-col :span="18" label="任务名称">
  7. <h2 v-if="detailData.title" key="business" style="font-weight: bolder">{{ detailData.title }}</h2>
  8. <p class="report-period">【填报周期】:{{ detailData.start }} 至 {{ detailData.end }}</p>
  9. </el-col>
  10. <el-col :span="1.5">
  11. <el-button type="primary" @click="exportToExcel()"> 导出表格 </el-button>
  12. </el-col>
  13. <el-col :span="1.5">
  14. <el-button type="danger" @click="handleReturn()"> 返回 </el-button>
  15. </el-col>
  16. </el-row>
  17. </el-col>
  18. <el-col :lg="30" :xs="24">
  19. <div :style="{ height: tableHeight + 'px' }">
  20. <hot-table v-if="tableData.length > 0" ref="wrapper" :data="tableData" :settings="hotSettings" />
  21. </div>
  22. </el-col>
  23. </el-row>
  24. </div>
  25. </template>
  26. <script setup lang="ts">
  27. import * as XLSX from 'xlsx';
  28. import { fillDetail } from '@/api/dataFilling/datafilling';
  29. import { HotTable } from '@handsontable/vue3';
  30. import 'handsontable/languages';
  31. import 'handsontable/dist/handsontable.full.css';
  32. import { registerAllModules } from 'handsontable/registry';
  33. import { deepClone } from '@/utils';
  34. registerAllModules();
  35. const emits = defineEmits(['close']);
  36. const props = defineProps<{
  37. eventId: string | number;
  38. }>();
  39. // 更新表头以匹配新的数据结构
  40. const editableHeaders = ref([]);
  41. const tableData = ref([]);
  42. const hotData = ref([]);
  43. const detailData = ref({
  44. title: '表单数据',
  45. start: '',
  46. end: ''
  47. });
  48. let tableHeight = window.innerHeight - 230;
  49. const exportToExcel = () => {
  50. const data = deepClone(tableData.value);
  51. data.unshift(editableHeaders.value);
  52. const worksheet = XLSX.utils.aoa_to_sheet(data, {});
  53. const workbook = { Sheets: { data: worksheet }, SheetNames: ['data'] };
  54. XLSX.utils.book_append_sheet(workbook, worksheet, 'Sheet1');
  55. XLSX.writeFile(workbook, '导出数据.xlsx');
  56. };
  57. const fetchFillDetail = async () => {
  58. fillDetail({ report_id: props.eventId }).then((res: any) => {
  59. detailData.value.start = res.start_time;
  60. detailData.value.end = res.end_time;
  61. const headers = [];
  62. const data = [];
  63. res.data.forEach((item, index) => {
  64. let arr = [];
  65. for (let key in item) {
  66. if (item.hasOwnProperty(key)) {
  67. const value = item[key];
  68. if (index === 0) {
  69. headers.push(value);
  70. } else {
  71. arr.push(value);
  72. }
  73. }
  74. }
  75. if (arr.length > 0) {
  76. data.push(arr);
  77. }
  78. });
  79. editableHeaders.value = headers;
  80. tableData.value = data;
  81. });
  82. };
  83. const handleReturn = () => {
  84. emits('close');
  85. };
  86. const hotSettings = reactive({
  87. language: 'zh-CN',
  88. colHeaders: editableHeaders,
  89. readOnly: true,
  90. rowHeaders: true,
  91. autoColumnSize: true,
  92. width: '100%', // auto or 100%
  93. height: '100%', // auto or 100%
  94. licenseKey: 'non-commercial-and-evaluation', // 隐藏版权文字
  95. colWidths: 129, // 默认单元格宽度
  96. rowHeights: 28, // 默认单元格高度
  97. wordWrap: true // 单元格文字是否换行展示
  98. });
  99. onMounted(() => {
  100. fetchFillDetail();
  101. });
  102. </script>
  103. <style scoped>
  104. .app-container {
  105. font-family: Avenir, Helvetica, Arial, sans-serif;
  106. -webkit-font-smoothing: antialiased;
  107. -moz-osx-font-smoothing: grayscale;
  108. color: #2c3e50;
  109. }
  110. .report-period {
  111. margin-top: 10px;
  112. font-size: 14px;
  113. color: #606266;
  114. }
  115. .editable-span {
  116. cursor: default;
  117. }
  118. .editable-header {
  119. cursor: default;
  120. }
  121. </style>