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.
189 lines
4.7 KiB
189 lines
4.7 KiB
<template> |
|
<div class="el_TablePage"> |
|
<span>表格导出名称</span> |
|
<el-input |
|
v-model="exportFileName" |
|
placeholder="请输入导出的表格名称" |
|
style="margin-bottom: 10px" |
|
/> |
|
<el-transfer |
|
v-model="checkedColumns" |
|
:data="transferData" |
|
:titles="['可选字段', '已选字段']" |
|
:filterable="true" |
|
:props="transferProps" |
|
/> |
|
<div class="el_TablePage_btn"> |
|
<el-button type="primary" @click="exportToExcel"> |
|
<el-icon><Download /></el-icon>导出表格 |
|
</el-button> |
|
</div> |
|
</div> |
|
</template> |
|
|
|
<script setup> |
|
import { ref, computed } from 'vue'; |
|
import { ElMessage } from 'element-plus'; |
|
import * as XLSX from 'xlsx'; |
|
import { Download } from '@element-plus/icons-vue'; |
|
|
|
// 传入的参数 |
|
const props = defineProps({ |
|
data: { |
|
type: Array, |
|
required: true, |
|
}, |
|
menuData: { |
|
type: Array, |
|
required: true, |
|
}, |
|
}); |
|
|
|
// 将 menuData 复制到一个局部变量中,以便在 setup 中操作 |
|
const menuData = ref([...props.menuData]); |
|
// 移除指定列的函数 |
|
const removeColumn = (columnLabel) => { |
|
const index = menuData.value.findIndex(item => item.label === columnLabel); |
|
if (index !== -1) { |
|
menuData.value.splice(index, 1); |
|
} |
|
}; |
|
// 移除 '序号' 列 |
|
removeColumn('序号'); |
|
removeColumn('操作'); |
|
removeColumn('复选框'); |
|
|
|
const exportFileName = ref(''); |
|
// 已选择的列 |
|
const checkedColumns = ref([]); |
|
const initializeCheckedColumns = () => { |
|
checkedColumns.value = transferData.value.map(item => item.key); |
|
}; |
|
|
|
// 构建 el-transfer 所需的数据格式,并添加类型检查 |
|
const transferData = computed(() => { |
|
if (Array.isArray(menuData.value)) { |
|
return menuData.value.map(item => ({ |
|
...item, |
|
key: item.prop, |
|
})); |
|
} else { |
|
console.error('menuData 不是一个数组:', menuData.value); |
|
return []; |
|
} |
|
}); |
|
initializeCheckedColumns(); |
|
// 设置 el-transfer 的 props |
|
const transferProps = { |
|
key: 'key', |
|
label: 'label', |
|
}; |
|
|
|
// 导出到 Excel 的函数 |
|
const exportToExcel = () => { |
|
if (checkedColumns.value.length === 0) { |
|
ElMessage.warning('请选择要导出的字段'); |
|
return; |
|
} |
|
if (!exportFileName.value) { |
|
ElMessage({ |
|
message: '请输入导出名称', |
|
type: 'warning', |
|
}); |
|
return; |
|
} |
|
|
|
const selectedColumns = transferData.value.filter(item => |
|
checkedColumns.value.includes(item.key) |
|
); |
|
const headers = selectedColumns.map(col => col.label); |
|
const fields = selectedColumns.map(col => col.prop); |
|
|
|
// 准备导出数据 |
|
let exportData = props.data.map(item => { |
|
return fields.map(field => { |
|
const value = item[field]; |
|
return value !== undefined && value !== null ? value : ''; |
|
}); |
|
}); |
|
|
|
// 填充空白单元格 |
|
exportData = fillEmptyCells(exportData); |
|
|
|
// 添加表头 |
|
exportData.unshift(headers); |
|
|
|
// 创建工作表 |
|
const worksheet = XLSX.utils.aoa_to_sheet(exportData); |
|
|
|
// 设置列宽和样式 |
|
applyStyles(worksheet, exportData); |
|
|
|
const workbook = XLSX.utils.book_new(); |
|
XLSX.utils.book_append_sheet(workbook, worksheet, exportFileName.value); |
|
|
|
// 生成文件并下载 |
|
XLSX.writeFile(workbook, `${exportFileName.value}.xlsx`); |
|
}; |
|
|
|
// 填充空白单元格的函数 |
|
const fillEmptyCells = (data) => { |
|
return data; |
|
}; |
|
|
|
// 设置样式的函数 |
|
const applyStyles = (worksheet, data) => { |
|
const rowCount = data.length; |
|
const colCount = data[0].length; |
|
|
|
// 计算每列的最大宽度 |
|
const colWidths = new Array(colCount).fill(0); |
|
data.forEach(row => { |
|
row.forEach((cell, index) => { |
|
const cellWidth = cell ? cell.toString().length : 0; |
|
if (cellWidth > colWidths[index]) { |
|
colWidths[index] = cellWidth; |
|
} |
|
}); |
|
}); |
|
|
|
// 设置列宽 |
|
const wscols = colWidths.map(width => ({ wch: Math.min(width + 2, 50) })); // 加2为了留些边距,最大宽度限制为50 |
|
worksheet['!cols'] = wscols; |
|
|
|
// 设置所有单元格的默认样式 |
|
const range = XLSX.utils.decode_range(worksheet['!ref']); |
|
for (let col = range.s.c; col <= range.e.c; col++) { |
|
for (let row = range.s.r; row <= range.e.r; row++) { |
|
const cellRef = XLSX.utils.encode_cell({ c: col, r: row }); |
|
if (!worksheet[cellRef]) worksheet[cellRef] = { v: '' }; |
|
if (!worksheet[cellRef].s) worksheet[cellRef].s = {}; |
|
worksheet[cellRef].s.alignment = { |
|
vertical: 'center', |
|
horizontal: 'center', |
|
wrapText: true, |
|
}; |
|
|
|
// 设置表头样式 |
|
if (row === 0) { |
|
worksheet[cellRef].s.font = { bold: true }; |
|
} |
|
} |
|
} |
|
}; |
|
</script> |
|
|
|
<style lang="scss" scoped> |
|
.el_TablePage { |
|
margin: auto; |
|
.el-transfer { |
|
display: flex; |
|
align-items: center; |
|
justify-content: space-between; |
|
} |
|
} |
|
.el_TablePage_btn { |
|
text-align: right; |
|
margin-top: 10px; |
|
} |
|
</style> |