test/src/components/MyComponents/ExportExcel/index.vue
2025-03-30 22:24:27 +08:00

221 lines
6.5 KiB
Vue

<template>
<el-button @click="onDownload" v-loading="props.exportInfo.loading" :disabled="props.exportInfo.disabled"
><el-icon><Download /></el-icon><span>导出</span>
</el-button>
<section class="sheets-wrapper">
<el-table v-for="(sheet, i) in props.exportSheets.filter(item => item.data.length > 0)" :key="i" :data="sheet.data">
<el-table-column align="center" :label="sheet.title">
<el-table-column label="序号" type="index" align="center" width="55" v-if="sheet.index" />
<el-table-column :prop="item.prop" :label="item.title" v-for="(item, j) in sheet.column" :key="j">
<template #default="scope">
<span v-if="item.slot">
<template v-if="item.prop === 'sblx'">
<dict-tag :options="props.ditData.D_TB_JCYWLX" :value="scope.row[item.prop]" :tag="false" />
</template>
<template v-if="item.prop === 'changeType'">
<dict-tag :options="props.ditData.D_TB_BGLB" :value="scope.row[item.prop]" :tag="false" />
</template>
<template v-if="item.prop === 'hazardousfactors'">
{{ getLabels(scope.row[item.prop]) }}
</template>
<template v-if="item.prop === 'state'">
<dict-tag
v-if="scope.row[item.prop]"
:options="props.ditData.D_BZ_SYZT"
:value="scope.row[item.prop]"
:tag="false"
:color="scope.row[item.prop] == '01' ? 'green' : 'red'"
/>
<span v-else>无</span>
</template>
<template v-if="item.prop === 'blockingDeviceFlag'">
{{ scope.row[item.prop] == "true" ? "是" : "否" }}
</template>
<template v-if="['coveraera', 'buildaera'].includes(item.prop)">
<span v-if="scope.row[item.prop]">{{ scope.row[item.prop] }}/㎡</span>
<span v-else>无</span>
</template>
<template v-if="item.prop === 'status'">
<dict-tag v-if="scope.row[item.prop]" :options="props.ditData.D_BZ_SGZT" :value="scope.row[item.prop]" :tag="false" />
<span v-else></span>
</template>
</span>
<span v-else>{{ scope.row[item.prop] }}</span>
</template>
</el-table-column>
</el-table-column>
</el-table>
</section>
</template>
<script setup>
import { nextTick, watch } from "vue"
import FileSaver from "file-saver"
import * as XLSX from "xlsx"
import * as XLSXStyle from "xlsx-style"
const emit = defineEmits(["getSheets"])
const props = defineProps({
exportSheets: Object,
exportInfo: Object,
ditData: Object
})
const onExport = () => {
nextTick(() => {
var xlsxParam = {
raw: true,
styles: true
}
let _arr = props.exportSheets.filter(item => item.data.length > 0)
let workbook = XLSX.utils.book_new()
document.querySelectorAll(".sheets-wrapper .el-table").forEach((dom, i) => {
let ws = XLSX.utils.table_to_sheet(dom, xlsxParam)
setExcelStyle(ws)
XLSX.utils.book_append_sheet(workbook, ws, _arr[i].name)
})
let wbout = XLSXStyle.write(workbook, {
bookType: "xlsx",
bookSST: true,
type: "binary"
})
try {
FileSaver.saveAs(
new Blob([s2ab(wbout)], {
type: 'application/octet-stream;charset=utf-8"'
}),
props.exportInfo.name + ".xlsx"
)
} catch (e) {
if (typeof console !== "undefined") console.log(e, wbout)
}
return wbout
})
}
const s2ab = s => {
var buf = new ArrayBuffer(s.length)
var view = new Uint8Array(buf)
for (var i = 0; i != s.length; ++i) view[i] = s.charCodeAt(i) & 0xff
return buf
}
const setExcelStyle = ws => {
let borderAll = {
top: {
style: "thin"
},
bottom: {
style: "thin"
},
left: {
style: "thin"
},
right: {
style: "thin"
}
}
// return ws
for (let key in ws) {
const itemWidth = []
// 所有单元格列宽为15
// itemWidth.push({ wch: 25 })
if (key !== "!cols" && key !== "!ref" && key !== "!rows") {
//https://blog.csdn.net/weixin_44945533/article/details/133994847
if (ws[key] instanceof Object) {
// console.log(ws[key])
ws[key].s = {
border: borderAll,
alignment: {
horizontal: "center",
vertical: "center"
},
font: {
sz: 11
},
bold: true,
numFmt: 0
}
}
}
// ws["!cols"] = itemWidth // 列宽
}
let range = XLSX.utils.decode_range(ws["!ref"])
let cWidth = []
for (let C = range.s.c; C < range.e.c; ++C) {
//SHEET列
let len = 100 //默认列宽
let len_max = 400 //最大列宽
for (let R = range.s.r; R <= range.e.r; ++R) {
//SHEET行
let cell = { c: C, r: R } //二维 列行确定一个单元格
let cell_ref = XLSX.utils.encode_cell(cell) //单元格 A1、A2
// console.log('cell_ref', cell_ref)
if (ws[cell_ref] && !cell_ref.includes("A")) {
//动态自适应:计算列宽
let va = JSON.parse(JSON.stringify(ws[cell_ref].v))
var card1 = JSON.parse(JSON.stringify(va)).match(/[\u4e00-\u9fa5]/g) //匹配中文
var card11 = ""
if (card1) {
card11 = card1.join("")
}
var card2 = JSON.parse(JSON.stringify(va)).replace(/([^\u0000-\u00FF])/g, "") //剔除中文
let st = 0
if (card11) {
// st += card11.length * 16 //中文字节码长度
st += card11.length * 20 //中文字节码长度
}
if (card2) {
// st += card2.length * 8 //非中文字节码长度
st += card2.length * 10 //非中文字节码长度
}
if (st > len) {
len = st
}
}
}
if (len > len_max) {
//最大宽度
len = len_max
}
cWidth.push({ wpx: len }) //列宽
}
ws["!cols"] = cWidth
// console.log(77, ws)
return ws
}
const getLabels = keys => {
if (!keys) return ""
keys = keys.split(",")
let res = []
keys.forEach(key => {
props.ditData.D_TB_ZYJK_WHYS.forEach(item => {
if (item.value == key) {
res.push(item.label)
}
})
})
return res.toString()
}
const onDownload = () => {
emit("getSheets", onExport)
}
</script>
<style lang="scss" scoped>
.sheets-wrapper {
opacity: 0;
height: 0;
width: 0;
overflow: hidden;
}
</style>