diff --git a/README-en.md b/README-en.md
index 6f9ffa0b50e069da2c71b701f6c5937da9e68305..39d4c8921bbac78b980cb1eba4845c6c448367b8 100644
--- a/README-en.md
+++ b/README-en.md
@@ -33,6 +33,7 @@
 - 401, 404 error page
 - Error log
 - Exporting to Excel
+- Upload Excel
 - Table example
 - Interactive table example
 - Drag & drop table example
diff --git a/README.md b/README.md
index 7e6135e804dedf031a78e751665a07b2aab94eb1..34e78b920725cb79b317593c875a26bcde379419 100644
--- a/README.md
+++ b/README.md
@@ -63,6 +63,7 @@
 - 401,404错误页面
 - 错误日志
 - 导出excel
+- 前端可视化excel
 - table example
 - 动态table example
 - 拖拽table example
diff --git a/src/components/UploadExcel/index.vue b/src/components/UploadExcel/index.vue
new file mode 100644
index 0000000000000000000000000000000000000000..f02aeae7f82a37c04ae0f265f2fbf36002e39d79
--- /dev/null
+++ b/src/components/UploadExcel/index.vue
@@ -0,0 +1,78 @@
+<template>
+  <div>
+    <el-button :loading="loading" type="primary" @click="handleUpload">select excel file</el-button>
+    <input id="excel-upload-input" type="file" accept=".xlsx, .xls" class="c-hide" @change="handkeFileChange">
+  </div>
+</template>
+
+<script>
+import XLSX from 'xlsx'
+
+export default {
+  data() {
+    return {
+      loading: false,
+      excelData: {
+        header: null,
+        results: null
+      }
+    }
+  },
+  methods: {
+    generateDate({ header, results }) {
+      this.excelData.header = header
+      this.excelData.results = results
+      this.loading = false
+      this.$emit('on-selected-file', this.excelData)
+    },
+    handleUpload() {
+      document.getElementById('excel-upload-input').click()
+    },
+    handkeFileChange(e) {
+      this.loading = true
+      const files = e.target.files
+      const itemFile = files[0] // only use files[0]
+      const reader = new FileReader()
+      reader.onload = e => {
+        const data = e.target.result
+        const fixedData = this.fixdata(data)
+        const workbook = XLSX.read(btoa(fixedData), { type: 'base64' })
+        const firstSheetName = workbook.SheetNames[0]
+        const worksheet = workbook.Sheets[firstSheetName]
+        const header = this.get_header_row(worksheet)
+        const results = XLSX.utils.sheet_to_json(worksheet)
+        this.generateDate({ header, results })
+      }
+      reader.readAsArrayBuffer(itemFile)
+    },
+    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_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
+    }
+  }
+}
+</script>
+
+<style scoped>
+#excel-upload-input{
+  display: none;
+  z-index: -9999;
+}
+</style>
diff --git a/src/router/index.js b/src/router/index.js
index d4d504be6e7c7dfb5118d7b62aaadb8b525527a3..c235005a74120b6fc860047ca257ef81234ef6c9 100644
--- a/src/router/index.js
+++ b/src/router/index.js
@@ -150,7 +150,8 @@ export const asyncRouterMap = [
     icon: 'EXCEL',
     children: [
       { path: 'download', component: _import('excel/index'), name: '导出excel' },
-      { path: 'download2', component: _import('excel/selectExcel'), name: '导出已选择项' }
+      { path: 'download2', component: _import('excel/selectExcel'), name: '导出已选择项' },
+      { path: 'upload', component: _import('excel/uploadExcel'), name: 'upload excel' }
     ]
   },
   {
diff --git a/src/views/excel/uploadExcel.vue b/src/views/excel/uploadExcel.vue
new file mode 100644
index 0000000000000000000000000000000000000000..731ea26533b4707281ff8365915837e31b5f7cd8
--- /dev/null
+++ b/src/views/excel/uploadExcel.vue
@@ -0,0 +1,29 @@
+<template>
+  <div class="app-container">
+    <upload-excel @on-selected-file='selected'></upload-excel>
+    <el-table :data="tableData" border highlight-current-row style="width: 100%;margin-top:20px;">
+      <el-table-column v-for='item of tableHeader' :prop="item" :label="item" :key='item'>
+      </el-table-column>
+    </el-table>
+  </div>
+</template>
+
+<script>
+import uploadExcel from 'components/UploadExcel/index.vue'
+
+export default {
+  components: { uploadExcel },
+  data() {
+    return {
+      tableData: [],
+      tableHeader: []
+    }
+  },
+  methods: {
+    selected(data) {
+      this.tableData = data.results
+      this.tableHeader = data.header
+    }
+  }
+}
+</script>