当前位置:   article > 正文

前端实现excel导出表格(纯前端实现)_前端导出excel

前端导出excel

1.先安装相应的插件

  1. npm install xlsx@0.16.8
  2. npm install file-saver
  3. npm install xlsx-style-medalsoft

2.封装好公共导出功能。我这里在utils文件夹下的tools.js

  1. import FileSaver from "file-saver";
  2. import XLSX from "xlsx";
  3. import XLSXStyle from "xlsx-style-medalsoft";
  4. const OMS = {};
  5. // 导出Excel-单表格Excel 带样式
  6. OMS.downLoadXlsx = ({
  7. dom = "el-table",
  8. name = "文件",
  9. ColumnWdth = [],
  10. rowName = null,
  11. }) => {
  12. const table = document.getElementById(dom);
  13. // 这里是如果前面设置了导出合并行列用display的话,这里要删除掉,不然会导出多空格
  14. const hiddenCells = table.querySelectorAll('td[style*="display: none"]');
  15. hiddenCells.forEach((cell) => cell.parentNode.removeChild(cell));
  16. // 因为element-ui的表格的fixed属性导致多出一个table,会下载重复内容,这里删除掉
  17. if (table.querySelector(".el-table__fixed")) {
  18. table.removeChild(table.querySelector(".el-table__fixed"));
  19. }
  20. if (table.querySelector(".el-table__fixed-right")) {
  21. table.removeChild(table.querySelector(".el-table__fixed-right"));
  22. }
  23. const et = XLSX.utils.table_to_book(table, { raw: true }); // 此处传入table的DOM节点,raw为true表示单元格为文本格式(未加工)
  24. const wbs = et.Sheets.Sheet1;
  25. // 删掉末尾空行
  26. Object.keys(wbs).forEach((item, index) => {
  27. if (!item.startsWith("!") && wbs[item].v === "") {
  28. delete wbs[item];
  29. }
  30. if (rowName!='') {
  31. if (item.includes(rowName)) {
  32. delete wbs[item];
  33. }
  34. }
  35. });
  36. console.log(wbs, "wbs");
  37. // debugger;
  38. // 设置表格列行高
  39. // 设置表格列宽度
  40. if (ColumnWdth.length === 0) {
  41. for (let i = 0; i < 30; i++) {
  42. wbs["!cols"][i] = { wch: 12.5 };
  43. // wbs["!rows"][i] = { hpt: 60 };
  44. }
  45. } else {
  46. ColumnWdth.forEach((item, i) => {
  47. // 这里设置全部行高
  48. wbs["!cols"][i] = { wch: item };
  49. wbs["!rows"][i] = { hpt: item };
  50. });
  51. }
  52. // 循环遍历每一个表格,设置样式
  53. for (const key in wbs) {
  54. if (!key.startsWith("!")) {
  55. wbs[key].s = {
  56. font: {
  57. sz: 11, // 字体大小
  58. bold: false, // 加粗
  59. name: "宋体", // 字体
  60. color: {
  61. rgb: "000000", // 十六进制,不带#
  62. },
  63. },
  64. alignment: {
  65. // 文字居中
  66. horizontal: "center",
  67. vertical: "center",
  68. wrapText: false, // 文本自动换行
  69. textIndent: 1, // 设置文本溢出时的自动缩进,单位为字符数
  70. },
  71. border: {
  72. // 设置边框
  73. // top: { style: "thin" },
  74. // bottom: { style: "thin" },
  75. // left: { style: "thin" },
  76. // right: { style: "thin" },
  77. },
  78. };
  79. }
  80. }
  81. const arr = [
  82. "A",
  83. "B",
  84. "C",
  85. "D",
  86. "E",
  87. "F",
  88. "G",
  89. "H",
  90. "I",
  91. "J",
  92. "K",
  93. "L",
  94. "M",
  95. "N",
  96. "O",
  97. "P",
  98. "Q",
  99. "R",
  100. "S",
  101. "T",
  102. "U",
  103. "V",
  104. "W",
  105. "X",
  106. "Y",
  107. "Z",
  108. ];
  109. // 行列合并
  110. const range = wbs["!merges"];
  111. if (range) {
  112. range.forEach((item) => {
  113. const startColNumber = Number(item.s.r);
  114. const endColNumber = Number(item.e.r);
  115. const startRowNumber = Number(item.s.c);
  116. const endRowNumber = Number(item.e.c);
  117. const test = wbs[arr[startRowNumber] + (startColNumber + 1)];
  118. for (let col = startColNumber; col <= endColNumber; col++) {
  119. for (let row = startRowNumber; row <= endRowNumber; row++) {
  120. wbs[arr[row] + (col + 1)] = test;
  121. }
  122. }
  123. });
  124. }
  125. const etout = XLSXStyle.write(et, {
  126. bookType: "xlsx",
  127. type: "buffer",
  128. });
  129. // eslint-disable-next-line no-useless-catch
  130. try {
  131. FileSaver.saveAs(
  132. new Blob([etout], { type: "application/octet-stream" }),
  133. `${name}.xlsx`
  134. ); // 导出的文件名
  135. } catch (e) {
  136. throw e;
  137. }
  138. };
  139. export default OMS;

3.页面中使用

给表格绑定一个id,通过获取dom来导出

  1. import OMS from "@/utils/tools";
  2. <el-table
  3. v-if="showTable"
  4. id="kuTable"
  5. max-height="525"
  6. v-loading="loading"
  7. :data="wmsStockList"
  8. @selection-change="handleSelectionChange"
  9. >
  10. </el-table>
  11. watch: {
  12. tableData: {
  13. immediate: true,
  14. async handler () {
  15. console.log("tableData", this.tableData);
  16. await this.$nextTick(); //根据实际选择延迟调用
  17. // const tds = document.querySelectorAll('#table .el-table__fixed-footer-wrapper tr>td');//表格有固定列时 写法
  18. const tds = document.querySelectorAll(
  19. "#kuTable .el-table__footer-wrapper tr>td"
  20. )
  21. tds[0].colSpan = 3;
  22. tds[1].colSpan = 0;
  23. tds[2].colSpan = 0;
  24. tds[1].rowSpan = 0;
  25. tds[2].rowSpan = 0;
  26. tds[0].style.textAlign = "center";
  27. tds[1].style.display = "none";
  28. tds[2].style.display = "none";
  29. },
  30. },
  31. },
  32. // 导出
  33. handleExport() {
  34. // const that = this
  35. this.$confirm("是否确认导出入库列表?", "警告", {
  36. confirmButtonText: "确定",
  37. cancelButtonText: "取消",
  38. type: "warning",
  39. })
  40. .then(() => {
  41. // console.log(this.pmsSpuInfoList, "this.pmsSpuInfoList");
  42. this.exportLoading = true;
  43. OMS.downLoadXlsx({
  44. dom: "kuTable",
  45. name: "入库列表",
  46. ColumnWdth: [
  47. 12, 12, 20, 30, 20, 20, 30, 20, 40, 12, 20, 12, 14, 15, 15,
  48. ], // 每一列的宽度,需要直接指定,接受数字
  49. rowName: "P", //可以设置哪行不要的
  50. });
  51. this.exportLoading = false;
  52. this.showTable = false;
  53. this.$nextTick(() => {
  54. // this.getList();
  55. this.showTable = true;
  56. });
  57. })
  58. .catch(function () {});
  59. },
  1. <template>
  2. <BasicLayout>
  3. <template #wrapper>
  4. <el-card class="box-card">
  5. <el-form ref="queryForm" :model="queryParams" label-width="68px">
  6. <el-row :gutter="20">
  7. <el-col :span="4">
  8. <el-form-item label="供应商ID" prop="supplierId">
  9. <el-input clearable v-model="queryParams.supplierId" placeholder="请填入供应商ID" />
  10. </el-form-item>
  11. </el-col>
  12. <el-col :span="4">
  13. <el-form-item label="支付:" label-width="50px">
  14. <selector clearable :options="payOptions" :select-value.sync="queryParams.paymentMethod"
  15. :placeholders="''" :widths="widths"></selector>
  16. </el-form-item>
  17. </el-col>
  18. <el-col :span="4">
  19. <el-form-item label="统计时间">
  20. <el-date-picker style="width: 100%; padding-top: 2px" v-model="queryParams.at" type="month"
  21. placeholder="选择月" :picker-options="pickerOptions" format="yyyy-MM">
  22. </el-date-picker>
  23. </el-form-item>
  24. </el-col>
  25. <el-col :span="3">
  26. <el-form-item class="comClass" style="margin-left: 12px; margin-bottom: 0px">
  27. <el-button type="primary" icon="el-icon-search" size="mini" @click="handleQuery"
  28. v-permisaction="['srm-supplier:report']">查询</el-button>
  29. <el-button style="margin-left: 12px" type="warning" icon="el-icon-download" size="mini"
  30. @click="handleExport">导出</el-button>
  31. </el-form-item>
  32. </el-col>
  33. </el-row>
  34. <el-row> </el-row>
  35. </el-form>
  36. <el-table id="kuTable" :data="tableData" border style="width: 100%" v-loading="loading" :max-height="500"
  37. show-summary :summary-method="getSummaries" ref="table">
  38. <!-- :summary-method="getSummaries" -->
  39. <el-table-column header-align="center" :label="headerItem">
  40. <el-table-column label="供应商ID" align="center" width="120">
  41. <template slot-scope="{ row }">
  42. {{ row.supplierId }}
  43. </template>
  44. </el-table-column>
  45. <el-table-column label="供应商名称(全称)" align="center" prop="catId" width="150"
  46. :show-overflow-tooltip="true">
  47. <template slot-scope="{ row }">
  48. {{ row.supplierName }}
  49. </template>
  50. </el-table-column>
  51. <el-table-column label="结款方式" align="center" :show-overflow-tooltip="true">
  52. <template slot-scope="{ row }">
  53. {{ row.settlementMethod }}
  54. </template>
  55. </el-table-column>
  56. <el-table-column label="进货数量" align="center" prop="stockQuantity" :show-overflow-tooltip="true">
  57. <template slot-scope="{ row }">
  58. {{ row.stockQuantity }}
  59. </template>
  60. </el-table-column>
  61. <el-table-column label="进货金额" align="center" prop="stockPrice" :show-overflow-tooltip="true">
  62. <template slot-scope="{ row }">
  63. {{ row.stockPrice }}
  64. </template>
  65. </el-table-column>
  66. <el-table-column label="库存量" align="center" prop="remainingQuantity" :show-overflow-tooltip="true">
  67. <template slot-scope="{ row }">
  68. {{ row.remainingQuantity }}
  69. </template>
  70. </el-table-column>
  71. <el-table-column label="库存金额" align="center" prop="remainingPrice" :show-overflow-tooltip="true">
  72. <template slot-scope="{ row }">
  73. {{ row.remainingPrice }}
  74. </template>
  75. </el-table-column>
  76. <el-table-column label="发货量" align="center" prop="quantity" width="180">
  77. <template slot-scope="scope">
  78. <div>{{ scope.row.quantity }}</div>
  79. </template>
  80. </el-table-column>
  81. <el-table-column label="发货金额" align="center" prop="amount" width="180">
  82. <template slot-scope="scope">
  83. <div>{{ scope.row.amount }}</div>
  84. </template>
  85. </el-table-column>
  86. <el-table-column label="收货量" align="center" prop="real_quantity" width="180">
  87. <template slot-scope="scope">
  88. <div>{{ scope.row.real_quantity }}</div>
  89. </template>
  90. </el-table-column>
  91. <el-table-column label="收货金额" align="center" prop="realAmount" width="180">
  92. <template slot-scope="scope">
  93. <div>{{ scope.row.realAmount }}</div>
  94. </template>
  95. </el-table-column>
  96. </el-table-column>
  97. </el-table>
  98. <pagination v-show="total > 0" :total="total" :page.sync="queryParams.pageIndex"
  99. :limit.sync="queryParams.pageSize" @pagination="getList" />
  100. </el-card>
  101. </template>
  102. </BasicLayout>
  103. </template>
  104. <script>
  105. import OMS from "@/utils/tools";
  106. import moment from "moment";
  107. const selector = () => import("@/views/compoments/selector.vue");
  108. import { getSupplierSalesReport } from "@/api/purchase/supplier";
  109. import { listSrmSupplier } from "@/api/purchase/supplier";
  110. export default {
  111. name: "supplierSales",
  112. components: {
  113. selector,
  114. },
  115. data () {
  116. return {
  117. // 查询参数
  118. queryParams: {
  119. pageIndex: 1,
  120. pageSize: 10,
  121. at: "",
  122. },
  123. form: {},
  124. title: "",
  125. supplierSelect: "",
  126. total: 0,
  127. tableData: [],
  128. loading: false,
  129. widths: "195px",
  130. pickerOptions: {
  131. disabledDate (time) {
  132. const currentYear = new Date().getFullYear();
  133. const currentMonth = new Date().getMonth() + 1;
  134. const selectedYear = time.getFullYear();
  135. const selectedMonth = time.getMonth() + 1;
  136. return (
  137. selectedYear > currentYear ||
  138. (selectedYear === currentYear && selectedMonth > currentMonth)
  139. );
  140. },
  141. },
  142. headerItem: "",
  143. selectList: [],
  144. payOptions: [],
  145. };
  146. },
  147. created () {
  148. this.queryParams.at = moment().format("YYYY-MM");
  149. this.headerItem =
  150. moment(this.queryParams.at).format("YYYY年MM月") + "供应商进销报表";
  151. this.getList();
  152. this.getDict();
  153. },
  154. watch: {
  155. "queryParams.at": {
  156. handler (v) {
  157. if (v == "" || v == undefined) {
  158. this.queryParams.at = moment().format("YYYY-MM");
  159. }
  160. },
  161. },
  162. tableData: {
  163. immediate: true,
  164. async handler () {
  165. console.log("tableData", this.tableData);
  166. await this.$nextTick(); //根据实际选择延迟调用
  167. // const tds = document.querySelectorAll('#table .el-table__fixed-footer-wrapper tr>td');//表格有固定列时 写法
  168. const tds = document.querySelectorAll(
  169. "#kuTable .el-table__footer-wrapper tr>td"
  170. )
  171. tds[0].colSpan = 3;
  172. tds[1].colSpan = 0;
  173. tds[2].colSpan = 0;
  174. tds[1].rowSpan = 0;
  175. tds[2].rowSpan = 0;
  176. tds[0].style.textAlign = "center";
  177. tds[1].style.display = "none";
  178. tds[2].style.display = "none";
  179. },
  180. },
  181. },
  182. updated () {
  183. this.$nextTick(() => {
  184. console.log("表格重新渲染了");
  185. this.$refs["table"].doLayout();
  186. });
  187. },
  188. methods: {
  189. /** 查询参数列表 */
  190. getList () {
  191. this.loading = true;
  192. getSupplierSalesReport(this.queryParams).then((response) => {
  193. this.tableData = response.data.list;
  194. this.total = response.data.count;
  195. this.loading = false;
  196. });
  197. },
  198. // 供应商列表
  199. getSupplier () {
  200. listSrmSupplier(this.addDateRange(this.queryParams, this.dateRange)).then(
  201. (response) => {
  202. this.selectList = response.data.list;
  203. }
  204. );
  205. },
  206. // getSummaries (param) {
  207. // const { columns, data } = param;
  208. // const sums = [];
  209. // columns.forEach((column, index) => {
  210. // if (index === 0) {
  211. // sums[index] = "总价";
  212. // return;
  213. // }
  214. // const values = data.map((item) => Number(item[column.property]));
  215. // if (!values.every((value) => isNaN(value))) {
  216. // sums[index] = values.reduce((prev, curr) => {
  217. // const value = Number(curr);
  218. // if (!isNaN(value)) {
  219. // return prev + curr;
  220. // } else {
  221. // return prev;
  222. // } index.vue
  223. // }, 0);
  224. // // sums[index] += sums[index];
  225. // } else {
  226. // sums[index] = "N/A";
  227. // }
  228. // });
  229. // return sums;
  230. // },
  231. // 获取字段值
  232. async getDict () {
  233. const queryArr = [
  234. { query: { type: "sys_payment_method" }, key: "payOptions" },
  235. ];
  236. const promises = queryArr.map(async (item) => {
  237. const res = await this.getDicts(item.query.type);
  238. this[item.key] = res.data;
  239. });
  240. await Promise.all(promises);
  241. },
  242. getSummaries (param) {
  243. const { columns, data } = param;
  244. const sums = [];
  245. columns.forEach((column, index) => {
  246. if (index === 0) { // 需要显示'总价'的列 坐标 :0
  247. sums[index] = '总价';
  248. return;
  249. }
  250. const indexes = [2, 3, 4, 5, 6, 7, 8, 9, 10]; // 需要显示总和的列的索引
  251. if (indexes.includes(index)) {
  252. const values = data.map(item => Number(item[column.property]));
  253. if (!values.some(isNaN)) {
  254. const sum = values.reduce((prev, curr) => prev + curr, 0);
  255. sums[index] = `${sum}元`;
  256. } else {
  257. sums[index] = 'N/A';
  258. }
  259. }
  260. });
  261. return sums;
  262. },
  263. // 表单重置
  264. reset () {
  265. this.form = {
  266. supplier: undefined,
  267. groupDetails: undefined,
  268. };
  269. this.resetForm("form");
  270. },
  271. /** 搜索按钮操作 */
  272. handleQuery () {
  273. this.queryParams.pageIndex = 1;
  274. this.$nextTick(() => {
  275. this.headerItem =
  276. moment(this.queryParams.at).format("YYYY年MM月") + "供应商进销报表";
  277. });
  278. this.getList();
  279. },
  280. handleExport () {
  281. // const that = this
  282. this.$confirm("是否确认导出供应商进销报表?", "警告", {
  283. confirmButtonText: "确定",
  284. cancelButtonText: "取消",
  285. type: "warning",
  286. })
  287. .then(() => {
  288. this.exportLoading = true;
  289. const tds = document.querySelectorAll('.el-table__footer td')
  290. tds[0].setAttribute('rowspan', '1')
  291. tds[1].setAttribute('rowspan', '1')
  292. OMS.downLoadXlsx({
  293. dom: "kuTable",
  294. name: `${this.headerItem}`,
  295. ColumnWdth: [
  296. 12, 20, 20, 30, 20, 20, 30, 20, 20, 12, 20,
  297. ], // 每一列的宽度,需要直接指定,接受数字
  298. rowName: "L,M", // 哪行不要的
  299. });
  300. this.exportLoading = false;
  301. this.showTable = false;
  302. this.$nextTick(() => {
  303. // this.getList();
  304. this.showTable = true;
  305. });
  306. })
  307. .catch(function () { });
  308. },
  309. },
  310. };
  311. </script>
  312. <style lang="scss" scoped>
  313. ::v-deep .comClass .el-form-item__content {
  314. margin-left: 0px !important;
  315. }
  316. ::v-deep .el-input__inner {
  317. height: 32px !important;
  318. }
  319. </style>

4.效果图

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/小惠珠哦/article/detail/928226
推荐阅读
相关标签
  

闽ICP备14008679号