增加EXCEL导入导出功能

增加EXCEL导入导出功能
This commit is contained in:
madlight-du 2018-08-02 22:12:21 +08:00
parent 46d23c33da
commit a76241694c
7 changed files with 3019 additions and 2528 deletions

5148
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -27,7 +27,8 @@
"vue-i18n": "^7.8.0",
"vue-router": "^3.0.1",
"vuex": "^3.0.1",
"wangeditor": "^3.1.1"
"wangeditor": "^3.1.1",
"xlsx": "^0.13.3"
},
"devDependencies": {
"@vue/cli-plugin-babel": "^3.0.0-beta.10",

106
src/libs/excel.js Normal file
View File

@ -0,0 +1,106 @@
/* eslint-disable */
import XLSX from 'xlsx';
function auto_width(ws, data){
/*set worksheet max width per col*/
const colWidth = data.map(row => row.map(val => {
/*if null/undefined*/
if (val == null) {
return {'wch': 10};
}
/*if chinese*/
else if (val.toString().charCodeAt(0) > 255) {
return {'wch': val.toString().length * 2};
} else {
return {'wch': val.toString().length};
}
}))
/*start in the first row*/
let result = colWidth[0];
for (let i = 1; i < colWidth.length; i++) {
for (let j = 0; j < colWidth[i].length; j++) {
if (result[j]['wch'] < colWidth[i][j]['wch']) {
result[j]['wch'] = colWidth[i][j]['wch'];
}
}
}
ws['!cols'] = result;
}
function json_to_array(key, jsonData){
return jsonData.map(v => key.map(j => { return v[j] }));
}
// fix data,return string
function fixdata(data) {
let o = ''
let l = 0
const w = 10240
for (; l < data.byteLength / w; ++l) o += String.fromCharCode.apply(null, new Uint8Array(data.slice(l * w, l * w + w)))
o += String.fromCharCode.apply(null, new Uint8Array(data.slice(l * w)))
return o
}
// get head from excel file,return array
function get_header_row(sheet) {
const headers = []
const range = XLSX.utils.decode_range(sheet['!ref'])
let C
const R = range.s.r /* start in the first row */
for (C = range.s.c; C <= range.e.c; ++C) { /* walk every column in the range */
var cell = sheet[XLSX.utils.encode_cell({ c: C, r: R })] /* find the cell in the first row */
var hdr = 'UNKNOWN ' + C // <-- replace with your desired default
if (cell && cell.t) hdr = XLSX.utils.format_cell(cell)
headers.push(hdr)
}
return headers
}
function export_table_to_excel(id, filename) {
const table = document.getElementById(id);
const wb = XLSX.utils.table_to_book(table);
XLSX.writeFile(wb, filename);
/* the second way */
// const table = document.getElementById(id);
// const wb = XLSX.utils.book_new();
// const ws = XLSX.utils.table_to_sheet(table);
// XLSX.utils.book_append_sheet(wb, ws, filename);
// XLSX.writeFile(wb, filename);
}
export function export_json_to_excel(params = {data: [], key: [], title: {}, filename: '', autoWidth: true}) {
const wb = XLSX.utils.book_new();
params.data.unshift(params.title);
const ws = XLSX.utils.json_to_sheet(params.data, {header: params.key, skipHeader: true});
if(params.autoWidth){
const data = json_to_array(params.key, params.data);
auto_width(ws, data);
}
XLSX.utils.book_append_sheet(wb, ws, params.filename);
XLSX.writeFile(wb, params.filename + '.xlsx');
}
export const export_array_to_excel = ({key, data, title, filename, autoWidth}) => {
const wb = XLSX.utils.book_new();
const arr = json_to_array(key, data);
arr.unshift(title);
const ws = XLSX.utils.aoa_to_sheet(arr);
if(autoWidth){
auto_width(ws, arr);
}
XLSX.utils.book_append_sheet(wb, ws, filename);
XLSX.writeFile(wb, filename + '.xlsx');
}
export const read = (data, type) => {
/* if type == 'base64' must fix data first */
// const fixedData = fixdata(data)
// const workbook = XLSX.read(btoa(fixedData), { type: 'base64' })
const workbook = XLSX.read(data, { type: type })
const firstSheetName = workbook.SheetNames[0]
const worksheet = workbook.Sheets[firstSheetName]
const header = get_header_row(worksheet)
const results = XLSX.utils.sheet_to_json(worksheet)
return {header, results}
}

View File

@ -162,6 +162,35 @@ export default [
}
]
},
{
path: '/excel',
name: 'excel',
meta: {
icon: 'ios-stats',
title: 'EXCEL导入导出'
},
component: Main,
children: [
{
path: 'upload-excel',
name: 'upload-excel',
meta: {
icon: 'md-add',
title: '导入EXCEL'
},
component: () => import('@/view/excel/upload-excel.vue')
},
{
path: 'export-excel',
name: 'export-excel',
meta: {
icon: 'md-download',
title: '导出EXCEL'
},
component: () => import('@/view/excel/export-excel.vue')
}
]
},
{
path: '/directive',
name: 'directive',

64
src/view/excel/excel.less Normal file
View File

@ -0,0 +1,64 @@
.margin-top-8{
margin-top: 8px;
}
.margin-top-10{
margin-top: 10px;
}
.margin-top-20{
margin-top: 20px;
}
.margin-left-10{
margin-left: 10px;
}
.margin-bottom-10{
margin-bottom: 10px;
}
.margin-bottom-100{
margin-bottom: 100px;
}
.margin-right-10{
margin-right: 10px;
}
.padding-left-6{
padding-left: 6px;
}
.padding-left-8{
padding-left: 5px;
}
.padding-left-10{
padding-left: 10px;
}
.padding-left-20{
padding-left: 20px;
}
.height-100{
height: 100%;
}
.height-120px{
height: 100px;
}
.height-200px{
height: 200px;
}
.height-492px{
height: 492px;
}
.height-460px{
height: 460px;
}
.line-gray{
height: 0;
border-bottom: 2px solid #dcdcdc;
}
.notwrap{
word-break:keep-all;
white-space:nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
.padding-left-5{
padding-left: 10px;
}
[v-cloak]{
display: none;
}

View File

@ -0,0 +1,82 @@
<style lang="less">
@import "./excel.less";
</style>
<template>
<div>
<Card title="导出EXCEL">
<Row>
<Button icon="md-download" :loading="exportLoading" @click="exportExcel">导出文件</Button>
</Row>
</Card>
<Row class="margin-top-10">
<Table :columns="tableTitle" :data="tableData"></Table>
</Row>
</div>
</template>
<script>
export default {
name: 'export-excel',
data () {
return {
exportLoading: false,
tableTitle: [
{
title: '一级分类',
key: 'category1'
},
{
title: '二级分类',
key: 'category2'
},
{
title: '三级分类',
key: 'category3'
}
],
tableData: [
{
category1: 1,
category2: 2,
category3: 3
},
{
category1: 4,
category2: 5,
category3: 6
},
{
category1: 7,
category2: 8,
category3: 9
}
]
}
},
methods: {
exportExcel () {
if (this.tableData.length) {
this.exportLoading = true
import('@/libs/excel').then(excel => {
const params = {
title: ['一级分类', '二级分类', '三级分类'],
key: ['category1', 'category2', 'category3'],
data: this.tableData,
autoWidth: true,
filename: '分类列表'
}
excel.export_array_to_excel(params)
this.exportLoading = false
})
} else {
this.$Message.info('表格数据不能为空!')
}
}
},
created () {
},
mounted () {
}
}
</script>

View File

@ -0,0 +1,115 @@
<style lang="less">
@import "./excel.less";
</style>
<template>
<div>
<Card title="导入EXCEL">
<Row>
<Upload action="" :before-upload="handleBeforeUpload" accept=".xls, .xlsx">
<Button icon="ios-cloud-upload-outline" :loading="uploadLoading" @click="handleUploadFile">上传文件</Button>
</Upload>
</Row>
<Row>
<div class="ivu-upload-list-file" v-if="file !== null">
<Icon type="ios-stats"></Icon>
{{ file.name }}
<Icon v-show="showRemoveFile" type="ios-close" class="ivu-upload-list-remove" @click.native="handleRemove()"></Icon>
</div>
</Row>
<Row>
<transition name="fade">
<Progress v-if="showProgress" :percent="progressPercent" :stroke-width="2">
<div v-if="progressPercent == 100">
<Icon type="ios-checkmark-circle"></Icon>
<span>成功</span>
</div>
</Progress>
</transition>
</Row>
</Card>
<Row class="margin-top-10">
<Table :columns="tableTitle" :data="tableData" :loading="tableLoading"></Table>
</Row>
</div>
</template>
<script>
export default {
name: 'upload-excel',
data () {
return {
uploadLoading: false,
progressPercent: 0,
showProgress: false,
showRemoveFile: false,
file: null,
tableData: [],
tableTitle: [],
tableLoading: false
}
},
methods: {
initUpload () {
this.file = null
this.showProgress = false
this.loadingProgress = 0
this.tableData = []
this.tableTitle = []
},
handleUploadFile () {
this.initUpload()
},
handleRemove () {
this.initUpload()
this.$Message.info('上传的文件已删除!')
},
handleBeforeUpload (file) {
const fileExt = file.name.split('.').pop().toLocaleLowerCase()
if (fileExt === 'xlsx' || fileExt === 'xls') {
this.readFile(file)
this.file = file
} else {
this.$Notice.warning({
title: '文件类型错误',
desc: '文件:' + file.name + '不是EXCEL文件请选择后缀为.xlsx或者.xls的EXCEL文件。'
})
}
return false
},
//
readFile (file) {
const reader = new FileReader()
reader.readAsArrayBuffer(file)
reader.onloadstart = e => {
this.uploadLoading = true
this.tableLoading = true
this.showProgress = true
}
reader.onprogress = e => {
this.progressPercent = Math.round(e.loaded / e.total * 100)
}
reader.onerror = e => {
this.$Message.error('文件读取出错')
}
reader.onload = e => {
this.$Message.info('文件读取成功')
const data = e.target.result
import('@/libs/excel').then(excel => {
const {header, results} = excel.read(data, 'array')
const tableTitle = header.map(item => { return { title: item, key: item } })
this.tableData = results
this.tableTitle = tableTitle
this.uploadLoading = false
this.tableLoading = false
this.showRemoveFile = true
})
}
}
},
created () {
},
mounted () {
}
}
</script>