一、配置api
javascript
// 题目导入模板下载接口
export function exportTemplate() {
return request({
url: '/edu/question/exportTemplate',
method: 'get',
//必加
header: {
headers: {
'Content-Type': 'application/x-download'
},
},
responseType: "blob",//必加
})
}
// 题目模板数据导入接口
export function importTemplate(file) {
const data = new FormData()//必加
data.append('file', file)//必加
return request({
url: '/edu/question/import',
method: 'post',
data
})
}
二、vue中引用Api
TypeScript
import {
exportTemplate,
importTemplate,
} from "@/api/edu/question";
三、引用下载文件的方法
TypeScript
//引用下载文件的方法
import { download } from "@/utils/excel";
方法:/utils/excel
javascript
/**
* 通用js方法封装处理
* Copyright (c) 2019
*/
/**
* 参数处理
* @param {*} params 参数
*/
// 封装exceljs
import ExcelJS from 'exceljs'
import FileSaver from 'file-saver'
export function tansParams(params) {
let result = ''
for (const propName of Object.keys(params)) {
const value = params[propName]
let part = `${encodeURIComponent(propName)}=`
if (value !== null && value !== '' && typeof value !== 'undefined') {
if (typeof value === 'object') {
for (const key of Object.keys(value)) {
if (
value[key] !== null &&
value[key] !== '' &&
typeof value[key] !== 'undefined'
) {
let params = `${propName}[${key}]`
let subPart = `${encodeURIComponent(params)}=`
result += `${subPart + encodeURIComponent(value[key])}&`
}
}
} else {
result += `${part + encodeURIComponent(value)}&`
}
}
}
return result
}
// 验证是否为blob格式
export function blobValidate(data) {
return data.type !== 'application/json'
}
// export function getSrc(url) {
// return `https://${url}`
// }
// 得到字典某个值的内容
export function getDictLabel(dict, value) {
let res = dict.filter((item) => item.value === value)
return res[0]
}
// promise 只执行一次
export function oncePromise(fn, p = null) {
return function (...arg) {
// eslint-disable-next-line no-return-assign
return p || (p = fn(...arg).finally(() => (p = null)))
}
}
/**
* 导出数据到Excel方法
* @param {Array[Object]} config.data 表格数据
* @param {Array[String]} config.fields 字段列表
* @param {Array[String]} config.headers excel表头列表[[]],可以是多级表头[['A1','B1'],['A2','B2']]
* @param {Array[Object]} config.merges 需要合并的单元格,需要考虑表头的行数[{row:1, col:1, rowspan: 1, colspan: 2}]
* @param {Array[Object]} config.attrs 单元格样式配置
* @param {Array[Object]} config.views 工作表视图配置
* @param {Array[Number]} columnsWidth 每个字段列对应的宽度
* @param {Object} config.protect 工作表保护【此配置会保护全表,一般推荐只针对单元格进行保护配置】
* @param {String} sheetName 工作表名称,默认从sheet1开始
* @param {String} fileName excel文件名称
*/
export function exportDataToExcel(config, fileName) {
if (!config) return
const options = {
fileName: fileName || `导出excel文件【${Date.now()}】.xlsx`,
worksheets: [],
}
if (!Array.isArray(config)) {
config = [config]
}
config.forEach((item) => {
// 深拷贝data【JSON.stringify有缺陷,可自行换成_.cloneDeep】
const data = JSON.parse(JSON.stringify(item.data))
const results = data.map((obj) => item.fields.map((key) => obj[key])) // 生成完整excel数据
let excelData = []
excelData = excelData.concat(item.headers).concat(results) // 单元格合并处理【excel数据的第一行/列是从1开始】
let excelMerges = []
excelMerges = item.merges.map((m) => [
m.row + 1,
m.col + 1,
m.row + m.rowspan,
m.col + m.colspan,
]) // 单元格配置处理【excel数据的第一行/列是从1开始】
let excelAttrs = []
excelAttrs = item.attrs.map((attr) => {
attr.rowStart += 1
attr.rowEnd += 1
attr.colStart += 1
attr.colEnd += 1
return attr
})
options.worksheets.push({
data: excelData,
merges: excelMerges,
attrs: excelAttrs,
views: item.views,
columnsWidth: item.columnsWidth,
protect: item.protect,
sheetName: item.sheetName,
})
})
createExcel(options)
}
// 创建Excel文件方法
async function createExcel(options) {
if (!options.worksheets.length) return // 创建工作簿
const workbook = new ExcelJS.Workbook()
for (let i = 0; i < options.worksheets.length; i++) {
const sheetOption = options.worksheets[i] // 创建工作表
const sheet = workbook.addWorksheet(
sheetOption.sheetName || `sheet${i + 1}`
) // 添加数据行
sheet.addRows(sheetOption.data) // 配置视图
sheet.views = sheetOption.views // 单元格合并处理【开始行,开始列,结束行,结束列】
if (sheetOption.merges) {
sheetOption.merges.forEach((item) => {
sheet.mergeCells(item)
})
} // 工作表保护
if (sheetOption.protect) {
const res = await sheet.protect(
sheetOption.protect.password,
sheetOption.protect.options
)
} // 单元格样式处理
if (sheetOption.attrs.length) {
sheetOption.attrs.forEach((item) => {
const attr = item.attr || {} // 获取开始行-结束行; 开始列-结束列
const { rowStart } = item
const { rowEnd } = item
const { colStart } = item
const { colEnd } = item
if (rowStart) {
// 设置行
for (let r = rowStart; r <= rowEnd; r++) {
// 获取当前行
const row = sheet.getRow(r)
if (colStart) {
// 列设置
for (let c = colStart; c <= colEnd; c++) {
// 获取当前单元格
const cell = row.getCell(c)
Object.keys(attr).forEach((key) => {
// 给当前单元格设置定义的样式
cell[key] = attr[key]
})
}
} else {
// 未设置列,整行设置【大纲级别】
Object.keys(attr).forEach((key) => {
row[key] = attr[key]
})
}
}
} else if (colStart) {
// 未设置行,只设置了列
for (let c = colStart; c <= colEnd; c++) {
// 获取当前列,整列设置【大纲级别】
const column = sheet.getColumn(c)
Object.keys(attr).forEach((key) => {
column[key] = attr[key]
})
}
} else {
// 没有设置具体的行列,则为整表设置
Object.keys(attr).forEach((key) => {
sheet[key] = attr[key]
})
}
})
} // 列宽设置
if (sheetOption.columnsWidth) {
for (let j = 0; j < sheet.columns.length; j++) {
sheet.columns[j].width = sheetOption.columnsWidth[j]
}
}
} // 生成excel文件
workbook.xlsx.writeBuffer().then((buffer) => {
// application/octet-stream 二进制数据
FileSaver.saveAs(
new Blob([buffer], { type: 'application/octet-stream' }),
options.fileName
)
})
}
// 下载文件流文件
export const download = (res, type, filename) => {
// 创建blob对象,解析流数据
const blob = new Blob([res], {
// 设置返回的文件类型
// type: 'application/pdf;charset=UTF-8' 表示下载文档为pdf,如果是word则设置为msword,excel为'application/vnd.ms-excel'
type,
}) // 这里就是创建一个a标签,等下用来模拟点击事件
const a = document.createElement('a') // 兼容webkix浏览器,处理webkit浏览器中href自动添加blob前缀,默认在浏览器打开而不是下载
const URL = window.URL || window.webkitURL // 根据解析后的blob对象创建URL 对象
const href = URL.createObjectURL(blob) // 下载链接
a.href = href // 下载文件名,如果后端没有返回,可以自己写a.download = '文件.pdf'
a.download = filename
document.body.appendChild(a) // 点击a标签,进行下载
a.click() // 收尾工作,在内存中移除URL 对象
document.body.removeChild(a)
window.URL.revokeObjectURL(href)
}
三、添加点击事件下载
HTML:
html
<template>
<!-- 导入对话框 -->
<el-dialog
:title="title"
:visible.sync="localImportShow"
width="600px"
@close="localImportClose"
append-to-body
>
<el-form ref="form" :model="form" :rules="rules" label-width="80px">
<el-row>
<el-col :span="24">
<el-form-item label="下载模板" prop="downloadTemplate">
<el-button type="primary" @click="downloadCClick">
下载
<i class="el-icon-download"></i>
</el-button>
</el-form-item>
</el-col>
</el-row>
<el-row>
<el-col :span="24">
<el-form-item label="导入数据" prop="file">
<el-upload
ref="uploadExcel"
class="upload-btn"
action="#"
:auto-upload="false"
accept=".xls, .xlsx"
:show-file-list="true"
:file-list="form.file"
:on-change="change"
:on-remove="handleRemove"
:limit="1"
>
<el-button slot="trigger" size="small" type="primary">
选取文件
</el-button>
</el-upload>
</el-form-item>
</el-col>
</el-row>
</el-form>
<div slot="footer" class="dialog-footer">
<el-button type="primary" @click="submitForm">确 定</el-button>
<el-button @click="cancel">取 消</el-button>
</div>
</el-dialog>
</template>
VUEJS:
javascript
<script>
import { exportTemplate, importTemplate } from "@/api/edu/question";
import { download } from "@/utils/excel";
export default {
props: {
//弹出框是否展示
importShow: {
type: Boolean,
default: false,
},
},
data() {
return {
title: "导入试题数据",
form: {
file: [],
},
// 弹出框是否展示
localImportShow: this.importShow,
rules: {
file: [{ required: true, message: "请导入数据", trigger: "change" }],
},
};
},
watch: {
importShow(newVal) {
this.localImportShow = newVal;
},
"form.file": {
handler(nval) {
if (nval.length) {
this.$refs.form.clearValidate(["file"]);
}
},
deep: true,
},
},
methods: {
localImportClose() {
this.$emit("update:importShow", false);
this.reset();
},
// 点击下载模板按钮
downloadCClick() {
exportTemplate().then((res) => {
download(res, "application/vnd.ms-excel", "试题模板.xlsx");
});
},
// 更换上传文件
change({ raw }) {
//使用set watch才能监测到有值
this.$set(this.form.file, 0, raw);
},
handleRemove(file, fileList) {
// 移除上传文件
this.form.file = [];
},
// 提交事件
submitForm() {
this.$refs["form"].validate((valid) => {
if (valid) {
importTemplate(this.form.file[0])
.then((res) => {
if (res.code === 200) {
this.localImportShow = false;
this.$modal.msgSuccess("导入成功");
this.$emit("getList");
}
})
.catch((err) => {
this.localImportShow = false;
});
this.$nextTick(() => {
this.reset();
});
}
});
},
// 取消按钮
cancel() {
this.localImportShow = false;
this.reset();
},
// 重置数据
reset() {
this.$refs.form.clearValidate();
this.form = {
// parentId: null,
file: [],
};
},
},
};
</script>