前端实现excel导出表格(纯前端实现)
梁子猫 2024-08-12 13:03:01 阅读 100
1.先安装相应的插件
<code>npm install xlsx@0.16.8
npm install file-saver
npm install xlsx-style-medalsoft
2.封装好公共导出功能。我这里在utils文件夹下的tools.js
import FileSaver from "file-saver";
import XLSX from "xlsx";
import XLSXStyle from "xlsx-style-medalsoft";
const OMS = {};
// 导出Excel-单表格Excel 带样式
OMS.downLoadXlsx = ({
dom = "el-table",
name = "文件",
ColumnWdth = [],
rowName = null,
}) => {
const table = document.getElementById(dom);
// 这里是如果前面设置了导出合并行列用display的话,这里要删除掉,不然会导出多空格
const hiddenCells = table.querySelectorAll('td[style*="display: none"]');
hiddenCells.forEach((cell) => cell.parentNode.removeChild(cell));
// 因为element-ui的表格的fixed属性导致多出一个table,会下载重复内容,这里删除掉
if (table.querySelector(".el-table__fixed")) {
table.removeChild(table.querySelector(".el-table__fixed"));
}
if (table.querySelector(".el-table__fixed-right")) {
table.removeChild(table.querySelector(".el-table__fixed-right"));
}
const et = XLSX.utils.table_to_book(table, { raw: true }); // 此处传入table的DOM节点,raw为true表示单元格为文本格式(未加工)
const wbs = et.Sheets.Sheet1;
// 删掉末尾空行
Object.keys(wbs).forEach((item, index) => {
if (!item.startsWith("!") && wbs[item].v === "") {
delete wbs[item];
}
if (rowName!='') {
if (item.includes(rowName)) {
delete wbs[item];
}
}
});
console.log(wbs, "wbs");
// debugger;
// 设置表格列行高
// 设置表格列宽度
if (ColumnWdth.length === 0) {
for (let i = 0; i < 30; i++) {
wbs["!cols"][i] = { wch: 12.5 };
// wbs["!rows"][i] = { hpt: 60 };
}
} else {
ColumnWdth.forEach((item, i) => {
// 这里设置全部行高
wbs["!cols"][i] = { wch: item };
wbs["!rows"][i] = { hpt: item };
});
}
// 循环遍历每一个表格,设置样式
for (const key in wbs) {
if (!key.startsWith("!")) {
wbs[key].s = {
font: {
sz: 11, // 字体大小
bold: false, // 加粗
name: "宋体", // 字体
color: {
rgb: "000000", // 十六进制,不带#
},
},
alignment: {
// 文字居中
horizontal: "center",
vertical: "center",
wrapText: false, // 文本自动换行
textIndent: 1, // 设置文本溢出时的自动缩进,单位为字符数
},
border: {
// 设置边框
// top: { style: "thin" },
// bottom: { style: "thin" },
// left: { style: "thin" },
// right: { style: "thin" },
},
};
}
}
const arr = [
"A",
"B",
"C",
"D",
"E",
"F",
"G",
"H",
"I",
"J",
"K",
"L",
"M",
"N",
"O",
"P",
"Q",
"R",
"S",
"T",
"U",
"V",
"W",
"X",
"Y",
"Z",
];
// 行列合并
const range = wbs["!merges"];
if (range) {
range.forEach((item) => {
const startColNumber = Number(item.s.r);
const endColNumber = Number(item.e.r);
const startRowNumber = Number(item.s.c);
const endRowNumber = Number(item.e.c);
const test = wbs[arr[startRowNumber] + (startColNumber + 1)];
for (let col = startColNumber; col <= endColNumber; col++) {
for (let row = startRowNumber; row <= endRowNumber; row++) {
wbs[arr[row] + (col + 1)] = test;
}
}
});
}
const etout = XLSXStyle.write(et, {
bookType: "xlsx",
type: "buffer",
});
// eslint-disable-next-line no-useless-catch
try {
FileSaver.saveAs(
new Blob([etout], { type: "application/octet-stream" }),
`${name}.xlsx`
); // 导出的文件名
} catch (e) {
throw e;
}
};
export default OMS;
3.页面中使用
给表格绑定一个id,通过获取dom来导出
import OMS from "@/utils/tools";
<el-table
v-if="showTable"code>
id="kuTable"code>
max-height="525"code>
v-loading="loading"code>
:data="wmsStockList"code>
@selection-change="handleSelectionChange"code>
>
</el-table>
watch: {
tableData: {
immediate: true,
async handler () {
console.log("tableData", this.tableData);
await this.$nextTick(); //根据实际选择延迟调用
// const tds = document.querySelectorAll('#table .el-table__fixed-footer-wrapper tr>td');//表格有固定列时 写法
const tds = document.querySelectorAll(
"#kuTable .el-table__footer-wrapper tr>td"
)
tds[0].colSpan = 3;
tds[1].colSpan = 0;
tds[2].colSpan = 0;
tds[1].rowSpan = 0;
tds[2].rowSpan = 0;
tds[0].style.textAlign = "center";
tds[1].style.display = "none";
tds[2].style.display = "none";
},
},
},
// 导出
handleExport() {
// const that = this
this.$confirm("是否确认导出入库列表?", "警告", {
confirmButtonText: "确定",
cancelButtonText: "取消",
type: "warning",
})
.then(() => {
// console.log(this.pmsSpuInfoList, "this.pmsSpuInfoList");
this.exportLoading = true;
OMS.downLoadXlsx({
dom: "kuTable",
name: "入库列表",
ColumnWdth: [
12, 12, 20, 30, 20, 20, 30, 20, 40, 12, 20, 12, 14, 15, 15,
], // 每一列的宽度,需要直接指定,接受数字
rowName: "P", //可以设置哪行不要的
});
this.exportLoading = false;
this.showTable = false;
this.$nextTick(() => {
// this.getList();
this.showTable = true;
});
})
.catch(function () {});
},
<template>
<BasicLayout>
<template #wrapper>
<el-card class="box-card">code>
<el-form ref="queryForm" :model="queryParams" label-width="68px">code>
<el-row :gutter="20">code>
<el-col :span="4">code>
<el-form-item label="供应商ID" prop="supplierId">code>
<el-input clearable v-model="queryParams.supplierId" placeholder="请填入供应商ID" />code>
</el-form-item>
</el-col>
<el-col :span="4">code>
<el-form-item label="支付:" label-width="50px">code>
<selector clearable :options="payOptions" :select-value.sync="queryParams.paymentMethod"code>
:placeholders="''" :widths="widths"></selector>code>
</el-form-item>
</el-col>
<el-col :span="4">code>
<el-form-item label="统计时间">code>
<el-date-picker style="width: 100%; padding-top: 2px" v-model="queryParams.at" type="month"code>
placeholder="选择月" :picker-options="pickerOptions" format="yyyy-MM">code>
</el-date-picker>
</el-form-item>
</el-col>
<el-col :span="3">code>
<el-form-item class="comClass" style="margin-left: 12px; margin-bottom: 0px">code>
<el-button type="primary" icon="el-icon-search" size="mini" @click="handleQuery"code>
v-permisaction="['srm-supplier:report']">查询</el-button>code>
<el-button style="margin-left: 12px" type="warning" icon="el-icon-download" size="mini"code>
@click="handleExport">导出</el-button>code>
</el-form-item>
</el-col>
</el-row>
<el-row> </el-row>
</el-form>
<el-table id="kuTable" :data="tableData" border style="width: 100%" v-loading="loading" :max-height="500"code>
show-summary :summary-method="getSummaries" ref="table">code>
<!-- :summary-method="getSummaries" -->code>
<el-table-column header-align="center" :label="headerItem">code>
<el-table-column label="供应商ID" align="center" width="120">code>
<template slot-scope="{ row }">code>
{ { row.supplierId }}
</template>
</el-table-column>
<el-table-column label="供应商名称(全称)" align="center" prop="catId" width="150"code>
:show-overflow-tooltip="true">code>
<template slot-scope="{ row }">code>
{ { row.supplierName }}
</template>
</el-table-column>
<el-table-column label="结款方式" align="center" :show-overflow-tooltip="true">code>
<template slot-scope="{ row }">code>
{ { row.settlementMethod }}
</template>
</el-table-column>
<el-table-column label="进货数量" align="center" prop="stockQuantity" :show-overflow-tooltip="true">code>
<template slot-scope="{ row }">code>
{ { row.stockQuantity }}
</template>
</el-table-column>
<el-table-column label="进货金额" align="center" prop="stockPrice" :show-overflow-tooltip="true">code>
<template slot-scope="{ row }">code>
{ { row.stockPrice }}
</template>
</el-table-column>
<el-table-column label="库存量" align="center" prop="remainingQuantity" :show-overflow-tooltip="true">code>
<template slot-scope="{ row }">code>
{ { row.remainingQuantity }}
</template>
</el-table-column>
<el-table-column label="库存金额" align="center" prop="remainingPrice" :show-overflow-tooltip="true">code>
<template slot-scope="{ row }">code>
{ { row.remainingPrice }}
</template>
</el-table-column>
<el-table-column label="发货量" align="center" prop="quantity" width="180">code>
<template slot-scope="scope">code>
<div>{ { scope.row.quantity }}</div>
</template>
</el-table-column>
<el-table-column label="发货金额" align="center" prop="amount" width="180">code>
<template slot-scope="scope">code>
<div>{ { scope.row.amount }}</div>
</template>
</el-table-column>
<el-table-column label="收货量" align="center" prop="real_quantity" width="180">code>
<template slot-scope="scope">code>
<div>{ { scope.row.real_quantity }}</div>
</template>
</el-table-column>
<el-table-column label="收货金额" align="center" prop="realAmount" width="180">code>
<template slot-scope="scope">code>
<div>{ { scope.row.realAmount }}</div>
</template>
</el-table-column>
</el-table-column>
</el-table>
<pagination v-show="total > 0" :total="total" :page.sync="queryParams.pageIndex"code>
:limit.sync="queryParams.pageSize" @pagination="getList" />code>
</el-card>
</template>
</BasicLayout>
</template>
<script>
import OMS from "@/utils/tools";
import moment from "moment";
const selector = () => import("@/views/compoments/selector.vue");
import { getSupplierSalesReport } from "@/api/purchase/supplier";
import { listSrmSupplier } from "@/api/purchase/supplier";
export default {
name: "supplierSales",
components: {
selector,
},
data () {
return {
// 查询参数
queryParams: {
pageIndex: 1,
pageSize: 10,
at: "",
},
form: {},
title: "",
supplierSelect: "",
total: 0,
tableData: [],
loading: false,
widths: "195px",
pickerOptions: {
disabledDate (time) {
const currentYear = new Date().getFullYear();
const currentMonth = new Date().getMonth() + 1;
const selectedYear = time.getFullYear();
const selectedMonth = time.getMonth() + 1;
return (
selectedYear > currentYear ||
(selectedYear === currentYear && selectedMonth > currentMonth)
);
},
},
headerItem: "",
selectList: [],
payOptions: [],
};
},
created () {
this.queryParams.at = moment().format("YYYY-MM");
this.headerItem =
moment(this.queryParams.at).format("YYYY年MM月") + "供应商进销报表";
this.getList();
this.getDict();
},
watch: {
"queryParams.at": {
handler (v) {
if (v == "" || v == undefined) {
this.queryParams.at = moment().format("YYYY-MM");
}
},
},
tableData: {
immediate: true,
async handler () {
console.log("tableData", this.tableData);
await this.$nextTick(); //根据实际选择延迟调用
// const tds = document.querySelectorAll('#table .el-table__fixed-footer-wrapper tr>td');//表格有固定列时 写法
const tds = document.querySelectorAll(
"#kuTable .el-table__footer-wrapper tr>td"
)
tds[0].colSpan = 3;
tds[1].colSpan = 0;
tds[2].colSpan = 0;
tds[1].rowSpan = 0;
tds[2].rowSpan = 0;
tds[0].style.textAlign = "center";
tds[1].style.display = "none";
tds[2].style.display = "none";
},
},
},
updated () {
this.$nextTick(() => {
console.log("表格重新渲染了");
this.$refs["table"].doLayout();
});
},
methods: {
/** 查询参数列表 */
getList () {
this.loading = true;
getSupplierSalesReport(this.queryParams).then((response) => {
this.tableData = response.data.list;
this.total = response.data.count;
this.loading = false;
});
},
// 供应商列表
getSupplier () {
listSrmSupplier(this.addDateRange(this.queryParams, this.dateRange)).then(
(response) => {
this.selectList = response.data.list;
}
);
},
// getSummaries (param) {
// const { columns, data } = param;
// const sums = [];
// columns.forEach((column, index) => {
// if (index === 0) {
// sums[index] = "总价";
// return;
// }
// const values = data.map((item) => Number(item[column.property]));
// if (!values.every((value) => isNaN(value))) {
// sums[index] = values.reduce((prev, curr) => {
// const value = Number(curr);
// if (!isNaN(value)) {
// return prev + curr;
// } else {
// return prev;
// } index.vue
// }, 0);
// // sums[index] += sums[index];
// } else {
// sums[index] = "N/A";
// }
// });
// return sums;
// },
// 获取字段值
async getDict () {
const queryArr = [
{ query: { type: "sys_payment_method" }, key: "payOptions" },
];
const promises = queryArr.map(async (item) => {
const res = await this.getDicts(item.query.type);
this[item.key] = res.data;
});
await Promise.all(promises);
},
getSummaries (param) {
const { columns, data } = param;
const sums = [];
columns.forEach((column, index) => {
if (index === 0) { // 需要显示'总价'的列 坐标 :0
sums[index] = '总价';
return;
}
const indexes = [2, 3, 4, 5, 6, 7, 8, 9, 10]; // 需要显示总和的列的索引
if (indexes.includes(index)) {
const values = data.map(item => Number(item[column.property]));
if (!values.some(isNaN)) {
const sum = values.reduce((prev, curr) => prev + curr, 0);
sums[index] = `${sum}元`;
} else {
sums[index] = 'N/A';
}
}
});
return sums;
},
// 表单重置
reset () {
this.form = {
supplier: undefined,
groupDetails: undefined,
};
this.resetForm("form");
},
/** 搜索按钮操作 */
handleQuery () {
this.queryParams.pageIndex = 1;
this.$nextTick(() => {
this.headerItem =
moment(this.queryParams.at).format("YYYY年MM月") + "供应商进销报表";
});
this.getList();
},
handleExport () {
// const that = this
this.$confirm("是否确认导出供应商进销报表?", "警告", {
confirmButtonText: "确定",
cancelButtonText: "取消",
type: "warning",
})
.then(() => {
this.exportLoading = true;
const tds = document.querySelectorAll('.el-table__footer td')
tds[0].setAttribute('rowspan', '1')
tds[1].setAttribute('rowspan', '1')
OMS.downLoadXlsx({
dom: "kuTable",
name: `${this.headerItem}`,
ColumnWdth: [
12, 20, 20, 30, 20, 20, 30, 20, 20, 12, 20,
], // 每一列的宽度,需要直接指定,接受数字
rowName: "L,M", // 哪行不要的
});
this.exportLoading = false;
this.showTable = false;
this.$nextTick(() => {
// this.getList();
this.showTable = true;
});
})
.catch(function () { });
},
},
};
</script>
<style lang="scss" scoped>code>
::v-deep .comClass .el-form-item__content {
margin-left: 0px !important;
}
::v-deep .el-input__inner {
height: 32px !important;
}
</style>
4.效果图
声明
本文内容仅代表作者观点,或转载于其他网站,本站不以此文作为商业用途
如有涉及侵权,请联系本站进行删除
转载本站原创文章,请注明来源及作者。