Excel表格上传解析与导出
# Excel表格上传解析与导出
# 安装依赖
npm install xlsx
1
# 工具类
// 设置异步延迟间隔
export function delay(interval = 0) {
return new Promise(resolve => {
let timer = setTimeout(_ => {
clearTimeout(timer)
resolve()
}, interval)
})
}
// 按照二进制读取文件
export function readFile(file) {
return new Promise(resolve => {
let reader = new FileReader()
reader.readAsBinaryString(file)
reader.onload = e => {
resolve(e.target.result)
}
})
}
// 字段对应表
export let character = {
name: {
text: '姓名',
type: 'string'
},
phone: {
text: '电话',
type: 'string'
}
}
// 时间字符串格式化
export function formatTime(str, tpl) {
let arr = str.match(/\d+/g).map(item => {
return item.length < 2 ? '0' + item : item
})
tpl = tpl || '{0}年{1}月{2}日 {3}时{4}分{5}秒'
return tpl.replace(/\{(\d+)\}/g, (_, group) => {
return arr[group] || '00'
})
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
# 导入表格数据
<!-- element-ui upload 上传组件 -->
<template>
<div class="uploadBox">
<!-- 返回主页 -->
<div class="homeBox">
<router-link to="/export">
<el-tooltip content="返回列表页面" placement="top">
<i class="el-icon-tickets"></i>
</el-tooltip>
</router-link>
</div>
<!-- 上传文件按钮 -->
<div class="buttonBox">
<el-upload
action
accept=".xlsx,.xls"
:auto-upload="false"
:show-file-list="false"
:on-change="handle"
>
<el-button type="primary" slot="trigger">选取 Excel 文件</el-button>
</el-upload>
<el-button type="success" @click="submit">采集数据提交</el-button>
</div>
<!-- 解析出来的数据 -->
<div class="tableBox" v-show="show">
<h3>
<i class="el-icon-info">
以下是采集完成的数据,请您检查无误后,点击“采集数据提交”按钮上传至服务器</i
>
</h3>
<el-table :data="tempData" border style="width: 100%" :height="height">
<el-table-column
prop="name"
label="姓名"
min-width="50%"
></el-table-column>
<el-table-column
prop="phone"
label="电话"
min-width="50%"
></el-table-column>
</el-table>
</div>
</div>
</template>
<script>
import * as xlsx from 'xlsx/xlsx.mjs'
import {Loading} from 'element-ui'
import {readFile, character, delay} from '../assets/lib/utils'
export default {
data() {
return {
height: document.documentElement.clientHeight - 130,
tempData: [],
show: false
}
},
methods: {
// 采集 EXCEL 数据
async handle(ev) {
let file = ev.raw // ev.raw 为上传的文件数据
if (!file) return
this.show = false
let loading = Loading.service({
text: '请您稍等片刻,正在处理中...',
background: 'rgba(0,0,0,.5)'
})
await delay(300)
// 读取file中的数据
let data = await readFile(file) //获取到的是二进制数据
let workbook = xlsx.read(data, {type: 'binary'})
let worksheet = workbook.Sheets[workbook.SheetNames[0]]
data = xlsx.utils.sheet_to_json(worksheet) // 将数据转换成JSON格式
//console.log(data)
// 把读取出来的数据变为最后可以传递给服务器的数据 (姓名=>name 电话=>phone)
let arr = []
// 对读取出来的数据做处理。将表格的汉字列名翻译为字典中对应的属性值
let oldData = JSON.parse(window.localStorage.getItem('excel') || '[]')
let index = oldData.length
data.forEach(item => {
let obj = {}
for (let key in character) {
if (!character.hasOwnProperty(key)) break
let v = character[key],
text = v.text,
type = v.type
v = item[text] || ''
type === 'string' ? (v = String(v)) : null
type === 'number' ? (v = Number(v)) : null
obj[key] = v
}
obj.id = ++index
obj.time = new Date()
arr.push(obj)
})
await delay(300)
// 展示到页面中
this.show = true
// console.log(arr)
this.tempData = arr
loading.close()
},
// 提交数据给服务器
submit() {
if (this.tempData.length <= 0) {
return this.$message({
message: '小主,请您先选择 EXCEL 文件!',
type: 'warning',
showClose: true
})
}
let oldData = JSON.parse(window.localStorage.getItem('excel') || '[]'),
newData = [...oldData, ...this.tempData]
window.localStorage.setItem('excel', JSON.stringify(newData))
}
}
}
</script>
<style lang="scss" scoped>
.homeBox {
position: fixed;
top: 10px;
right: 20px;
z-index: 9999;
font-size: 40px;
}
.buttonBox {
padding: 15px;
display: flex;
width: 35%;
justify-content: flex-start;
& .el-button {
margin-right: 20px !important;
}
}
.tableBox {
padding: 0 15px;
h3 {
font-size: 18px;
color: #f56c6c;
padding-bottom: 15px;
}
}
</style>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
// 读取file中的数据
let data = await readFile(file) //获取到的是二进制数据
let workbook = xlsx.read(data, { type: 'binary' })
1
2
3
2
3
读取到的文件信息
# 导出数据
支持勾选和自定义配置某些属性的导出
<template>
<div class="container">
<!-- 上传文件按钮 -->
<div class="buttonBox">
<router-link to="/excel">
<el-tooltip content="数据采集页面" placement="top">
<el-button type="primary" icon="el-icon-edit" circle></el-button>
</el-tooltip>
</router-link>
</div>
<!-- 搜索区域 -->
<div class="searchBox">
<el-input
v-model="search"
placeholder="基于姓名、手机号模糊搜索"
@change="searchHandle"
clearable
></el-input>
<el-button type="success" @click="submit" :disabled="disabled"
>导出选中的数据</el-button
>
</div>
<!-- 列表区域 -->
<div class="tableBox">
<el-table
:data="tableData"
:height="height"
border
style="width: 100%"
v-loading="loading"
element-loading-text="主人,奴家正在努力加载中..."
@selection-change="selectionChange"
>
<el-table-column
type="selection"
width="50"
align="center"
></el-table-column>
<el-table-column
prop="id"
label="编号"
min-width="10%"
></el-table-column>
<el-table-column
prop="name"
label="姓名"
min-width="20%"
></el-table-column>
<el-table-column
prop="phone"
label="电话"
min-width="20%"
></el-table-column>
<el-table-column
prop="time"
label="创建时间"
min-width="25%"
:formatter="formatter"
></el-table-column>
</el-table>
</div>
<!-- 分页区域 -->
<div class="pageBox">
<el-pagination
background
hide-on-single-page
layout="total,sizes,prev,pager,next"
:page-size="pageSize"
:current-page="page"
:total="total"
@size-change="sizeChange"
@current-change="prevNext"
@prev-click="prevNext"
@next-click="prevNext"
>
</el-pagination>
</div>
</div>
</template>
<script>
import * as xlsx from 'xlsx/xlsx.mjs'
import { Loading } from 'element-ui'
import { formatTime } from '../assets/lib/utils'
export default {
name: 'export',
data() {
return {
tableData: [],
loading: false,
height: document.documentElement.clientHeight - 120,
// 分页相关
pageSize: 20,
page: 1,
total: 10,
search: '',
// 选中数据
selectionList: [],
disabled: false
}
},
created() {
this.queryData()
},
methods: {
// 权限
selectionChange(val) {
this.selectionList = val
},
// 格式化
formatter(row, col, val) {
return formatTime(val, '{0}-{1}-{2} {3}:{4}:{5}')
},
// 获取数据
queryData() {
this.loading = true
let data = window.localStorage.getItem('excel') || '[]'
this.tableData = JSON.parse(data)
this.loading = false
},
// 搜索按钮
searchHandle() {
this.page = val
this.queryData()
},
// 分页出路
sizeChange(val) {
this.pageSize = val
this.page = 1
this.queryData()
},
prevNext(val) {
this.page = val
this.queryData()
},
// 导出数据
submit() {
if (this.selectionList.length <= 0) {
return this.$message({
message: '小主,请您先选择要导出的数据库哦!',
type: 'warning',
showClose: true
})
}
this.disabled = true
let loading = Loading.service({
text: '小主,请您稍等片刻,女家正在玩命处理中...',
background: 'rgba(0,0,0,.5)'
})
console.log(this.selectionList)
let arr = this.selectionList.map(item => {
return {
编号: item.id,
姓名: item.name,
电话: item.phone
}
})
// 将json数据转换为sheet
let sheet = xlsx.utils.json_to_sheet(arr),
// 创建一个excel文件
book = xlsx.utils.book_new()
// 向文件中写入数据
xlsx.utils.book_append_sheet(book, sheet, 'Sheet1')
// 保存文件
xlsx.writeFile(book, `user${new Date().getTime()}.xls`)
loading.close()
this.disabled = false
}
}
}
</script>
<style lang="scss" scoped>
.buttonBox {
position: fixed;
top: 10px;
right: 20px;
z-index: 9999;
}
.searchBox {
padding: 20px;
display: flex;
justify-content: flex-start;
& .el-input {
width: 25%;
}
& .el-button {
margin-left: 20px !important;
}
}
.tableBox {
padding: 0 15px;
}
</style>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
核心代码:
arr是表单数据,对表单数据进行筛选处理
let arr = this.selectionList.map(item => { return { 编号: item.id, 姓名: item.name, 电话: item.phone } }) // 将json数据转换为sheet let sheet = xlsx.utils.json_to_sheet(arr), // 创建一个excel文件 book = xlsx.utils.book_new() // 向文件中写入数据 xlsx.utils.book_append_sheet(book, sheet, 'Sheet1') // 保存文件 xlsx.writeFile(book, `user${new Date().getTime()}.xls`)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# 可能出现的问题
出现这种问题,xlsx的read方法报错,使用的xlsx版本是0.18.5
# 解决:
方案一:降低版本
npm install xlsx@0.16.0
1
或者
方案二:
直接将import xlsxm 'xlsx'
改为import * as xlsx from 'xlsx/xlsx.mjs'
即可
编辑 (opens new window)
上次更新: 2024/12/19, 09:15:30