vue中導入導出excel,並根據後臺返回類型進行判斷,導入到數據庫中css
功能:實現js導入導出excel,而且對導入的excel進行展現,當excel標題名稱和數據庫的名稱標題匹配時,則對應列導入的數據自動渲染展現在表格中,預覽展現10條,不足10條的的用空行表示。可經過下拉框動態切換對應列的值。圖片保存到系統中是將有src屬性的img值替換爲後臺傳遞過來的七牛雲地址,導入完成後,部分導入失敗的數據能夠下載到本地查看html
導入的excel文件前端
使用該導入功能需安裝依賴 npm install xlsxvue
須要使用導入導出功能的自行復制對應方法進行使用jquery
exportData是用於導入的
tableToExcel 和 exportPathMethod是用於導出的
<template> <div class="excel" > <el-dialog :visible.sync="centerDialogVisible" :title="titleName" :close-on-click-modal="false" :before-close="beforePausClose" width="1040px" > <div style="min-height: 550px;padding: 0 20px"> <div class="excel-header"> <el-select v-show="templateShow" v-model="value" placeholder="請選擇導入的模板" @change="changeTemplate($event)"> <el-option v-for="item in options" :key="item.template_table_name" :label="item.template_description" :value="item.template_table_name"/> </el-select> <el-button :disabled="selectPower" class="diybut" @click="btnClick">選擇Excel文件</el-button> <el-button :disabled="exportBtn" class="diybut" @click="exportExcel">下載模板</el-button> <el-checkbox v-show="checkBoxMutiplian" v-model="picSubmitShow">將圖片保存到系統中</el-checkbox> <div style="margin: 0 auto;display: inline-block;float: right"> <el-button :disabled="exportPower" class="diybut" @click="saveDataBase">導入</el-button> <el-button :disabled="canclePower" class="diybut" @click="cancleTemplate">關閉</el-button> </div> </div> <div v-show="errorPromptShow" class="error-prompt" style="max-height: 100px;overflow-y: auto"> <p v-for="(item, index) in errorList" :key="index" style="color: red;height: 20px;line-height: 14px;margin: 0"> {{ item }} </p> </div> <!-- 手動編寫的滾動條--> <div v-show="progressDebugShow" style="width: 100%;height: 20px;background: #4FA6E0;position: relative;border-radius: 5px;line-height: 20px;margin-bottom: 20px;overflow: hidden"> <div class="slider" style=" position:absolute;left: 10px;top: 1px;"> <div style="width: 10px;height: 10px;line-height: 10px;border-radius: 5px;background: white;display: inline-block" /> <div style="width: 10px;height: 10px;line-height: 10px;border-radius: 5px;background: white;display: inline-block" /> <div style="width: 10px;height: 10px;line-height: 10px;border-radius: 5px;background: white;display: inline-block" /> </div> </div> <div> <p v-show="resultShow" style="height: 30px;line-height: 30px;margin-top: 10px"> <span>成功:{{ successCount }}條</span> <span style="margin: 0 20px">失敗:{{ failCount }}條</span> <el-button v-show="failCount !== 0" type="text" @click="exportFailData">下載導入失敗數據</el-button> </p> </div> <!-- 表格--> <div v-loading="loading" style="width:100%;overflow-x: auto;min-height: 425px" element-loading-text="保存中,請稍等" element-loading-spinner="el-icon-loading"> <table border="1px solid gray" style="border-collapse: collapse;width: 960px" > <!--顯示數據庫查出來的標題--> <tr style="text-align: center;height: 30px;line-height: 0;width: 1000px;background: #F4F4F4"> <td v-for="(item ,index) in arr" :key="index" style=" height: 40px;"> <div class="tableWidth" style="min-width: 100px;white-space:nowrap;"> <span v-show="templateAllData[index].attribute_not_null" style="color: red">*</span>{{ item }} <input v-show="picSubmitShow" ref="mutiCheck" :value="item" v-model="checked" type="checkbox" style="margin-left: 10px;display: inline-block;position: relative;top: 3px"> </div> </td> </tr> <!--從excel中獲取的標題--> <tr style="height: 40px;overflow: hidden;line-height: 0"> <td v-for="(item ,index) in arr" :key="index" style="width: 30px;white-space:nowrap;"> <select v-model="changeList[item]" :value="item" class="selectedList" @change="changeListValue(index)"> <option v-for="(item1, index1) in arr1" :key="index1" :value="item1" > {{ item1 }} </option> </select> </td> </tr> <!--excel中獲取的具體數據展現--> <tr v-for="(item, index) in tableData" :key="index"> <td v-for="(item1, index1) in arr" :key="index1" style="height: 34px;"> <div :title="item[item1]" style="width: 150px;white-space:nowrap;overflow: hidden;line-height: 2;height: 20px"> {{ item[item1] }} </div> </td> </tr> <tr v-show="tableShow" class="tableShow"> <td v-for="(item1, index1) in arr" :key="index1" style="height: 34px;" /> </tr> <tr v-show="tableShow" class="tableShow"> <td v-for="(item1, index1) in arr" :key="index1" style="height: 34px;" /> </tr> <tr v-show="tableShow" class="tableShow"> <td v-for="(item1, index1) in arr" :key="index1" style="height: 34px;" /> </tr> <tr v-show="tableShow" class="tableShow"> <td v-for="(item1, index1) in arr" :key="index1" style="height: 34px;" /> </tr> <tr v-show="tableShow" class="tableShow"> <td v-for="(item1, index1) in arr" :key="index1" style="height: 34px;" /> </tr> <tr v-show="tableShow" class="tableShow"> <td v-for="(item1, index1) in arr" :key="index1" style="height: 34px;" /> </tr> <tr v-show="tableShow" class="tableShow"> <td v-for="(item1, index1) in arr" :key="index1" style="height: 34px;" /> </tr> <tr v-show="tableShow" class="tableShow"> <td v-for="(item1, index1) in arr" :key="index1" style="height: 34px;" /> </tr> <tr v-show="tableShow" class="tableShow"> <td v-for="(item1, index1) in arr" :key="index1" style="height: 34px;" /> </tr> <tr v-show="tableShow" class="tableShow"> <td v-for="(item1, index1) in arr" :key="index1" style="height: 34px;" /> </tr> </table> </div> <p style="text-align: center;line-height: 50px;margin-bottom: 0">(預覽數據)</p> </div> </el-dialog> <input accept=".csv, application/vnd.openxmlformats-officedocument.spreadsheetml.sheet, application/vnd.ms-excel" class="input-file" type="file" @change="exportData" > <el-button :type="buttonType" :disabled="disabled" :icon="buttonIcon" :size="buttonSize" @click="getAllTemplateData"> {{ titleName }} </el-button> <el-dialog :visible.sync="centerDialogVisibleTwo" title="導入結果" width="40%" center> <p style="text-align: center">成功條數:{{ successCount }}</p> <p style="text-align: center">失敗條數:{{ failCount }}</p> <span slot="footer" class="dialog-footer"> <el-button @click="centerDialogVisibleTwo = false">關閉</el-button> <el-button v-show="exportFale" type="primary" @click="exportFailData">導出失敗數據</el-button> </span> </el-dialog> </div> </template> <script> import { getTemplate, getTemplateHeader, saveExcel, uploadPicToQn, getFailData } from '@/api/excel' import XLSX from 'xlsx' import { mapGetters } from 'vuex' import $ from 'jquery' export default { props: { disabled: { type: Boolean, default: false // 是否有禁用權限 }, titleName: { type: String, default: '批量導入商品信息' // 傳入不一樣的標題 }, actionName: { type: String, default: 'commodity' // 後臺根據這個值返回對應模板以及導入時調用對應函數 }, buttonType: { type: String, default: '' // 控制Button的類型 }, buttonIcon: { type: String, default: '' // 控制Button中的圖標 (僅支持element-ui中自帶圖標) }, buttonSize: { type: String, default: '' // 控制Button的尺寸 } }, data() { return { arr: [], // 放從數據庫獲取的標題 arr1: [], // 導入的excel中的標題 tableData: [], // 用於循環展現的值 copyTableData: [], // 用於保存最初的json數據。以便進行數據更換 changeList: {}, // 動態綁定下拉框的值 submitLastValue: [], // 最終提交的值 centerDialogVisible: false, // 對話框1顯示 centerDialogVisibleTwo: false, // 對話框2顯示 options: [], // 模板列表 value: '', // 選擇的模板值 templateAllData: [], checked: [], // 用於圖片轉換的輸入框列表 debugCount: 0, copyTableDataTwo: [], // 用於下拉框切換時的數據展現 picSubmitShow: false, // 是否顯示圖片轉換輸入框 template: [], oneArr: 0, // 用於在圖片轉換時判斷是否轉換完成 twoArr: 0, // 用於在圖片轉換時判斷是否轉換完成 count: 0, loading: false, // 加載圖標 successCount: 0, // 成功條數 failCount: 0, // 失敗條數 exportBtn: true, // 導入按鈕權限 exportFale: true, // 用於判斷是否導出失敗數據 templateShow: true, checkBoxMutiplian: false, progressTimer: '', errorList: [], // 前端校驗錯誤提示 progress: 0, // 進度條百分比 progressDebugShow: false, // 滾動條是否顯示 errorPromptShow: false, // 校驗失敗提示是否顯示 resultShow: false, // 控制導入結果顯示 selectPower: false, // 選擇模板權限 exportPower: false, // 導入按鈕權限 canclePower: false, // 關閉按鈕權限 iconClickPower: 0, // 控制點擊對話框關閉圖標是否執行 tableShow: true // 顯示空表格 } }, computed: { ...mapGetters([ 'business_group_id' ]) }, watch: { debugCount: function(newV, oldV) { // if (newV === this.submitLastValue.length * this.checked.length) { // this.saveResult() // } }, twoArr: function(newV, oldV) { if (this.checked.length > 0) { setTimeout(this.PicTransfer, 100) } }, tableData: function(newV, oldV) { // if (this.tableData.length > 0) { // this.tableShow = false // } else { // this.tableShow = true // } } }, beforeDestroy() { clearInterval(this.progressTimer) }, methods: { getAllTemplateData: function() { this.arr1 = [] this.arr = [] this.value = '' this.tableData = [] this.copyTableDataTwo = [] this.copyTableData = [] this.centerDialogVisible = true this.progressDebugShow = false this.resultShow = false this.count = 0 this.oneArr = 0 this.twoArr = 0 this.checked = [] this.picSubmitShow = false this.getDefaultArr() }, // 獲取數據庫模板數據 getDefaultArr: function() { let group_id = '' if (this.actionName === 'commodity') { group_id = this.business_group_id } getTemplate(group_id, this.actionName) .then(res => { this.options = res.data if (this.options.length === 1) { this.value = this.options[0].template_table_name this.templateShow = false this.changeTemplate(this.value) } }) .catch(() => {}) }, // 點擊對話框的X圖標事件 beforePausClose() { if (this.iconClickPower === 1) { return } else { this.centerDialogVisible = false } }, // 取消 cancleTemplate: function() { this.value = '' this.arr = [] this.arr1 = [] this.value = '' this.tableData = [] this.centerDialogVisible = false this.centerDialogVisibleTwo = false this.exportBtn = true clearInterval(this.progressTimer) document.querySelector('.input-file').value = '' }, // 切換模板時 changeTemplate: function(data) { if (data !== '') { this.arr = [] getTemplateHeader(data) .then(res => { this.templateAllData = res.data.data this.checkBoxMutiplian = res.data.need_save_pictures this.template = [] const obj = {} res.data.data.forEach((item, index) => { obj[item.attribute_name] = '' this.arr.push(item.attribute_name) }) this.template.push(obj) this.exportBtn = false // 動態添加changeList的值 for (let i = 0; i < this.arr.length; i++) { this.changeList[this.arr[i]] = this.arr[i] } }) .catch(() => {}) } }, // 圖片轉換 將有src屬性而且爲img的值時,將src中的值改變爲後臺傳過來的值 PicTransfer: function() { const a = this.submitLastValue[this.twoArr][this.checked[this.oneArr]] if (typeof a === 'string' && a.indexOf('<img') > -1 && a.indexOf('src') > -1) { const arrimg = [] // 截取出相應的src屬性值 a.replace(/<img [^>]*src=['"]([^'"]+)[^>]*>/gi, function(match, capture) { arrimg.push(capture) }) uploadPicToQn(arrimg) .then(res => { for (let h = 0; h < arrimg.length; h++) { // this.tableData[j][this.checked[i]] = this.tableData[j][this.checked[i]].replace(arrimg[h], res.data[h].pic_name) this.submitLastValue[this.twoArr][this.checked[this.oneArr]] = this.submitLastValue[this.twoArr][this.checked[this.oneArr]].replace(arrimg[h], res.data[h].pic_name) this.count += 1 } this.debugCount += 1 if (this.oneArr === this.checked.length - 1 && this.twoArr === this.submitLastValue.length - 1) { // 判斷src的值是否轉換完成 this.saveResult() } else if (this.twoArr < this.submitLastValue.length - 1) { this.twoArr += 1 } else { this.oneArr += 1 this.twoArr = 0 } }) .catch(() => { if (this.oneArr === this.checked.length - 1 && this.twoArr === this.submitLastValue.length - 1) { this.saveResult() } else if (this.twoArr < this.submitLastValue.length - 1) { this.twoArr += 1 } else { this.oneArr += 1 this.twoArr = 0 } }) } else { this.debugCount += 1 if (this.oneArr === this.checked.length - 1 && this.twoArr === this.submitLastValue.length - 1) { this.saveResult() } else if (this.twoArr < this.submitLastValue.length - 1) { this.twoArr += 1 } else { this.oneArr += 1 this.twoArr = 0 } } // this.debugCount = 0 // for (let i = 0; i < this.checked.length; i++) { // for (let j = 0; j < this.submitLastValue.length; j++) { // const a = this.submitLastValue[j][this.checked[i]] // if (typeof a === 'string' && a.indexOf('<img') > -1 && a.indexOf('src') > -1) { // const arrimg = [] // // 截取出相應的src屬性值 // a.replace(/<img [^>]*src=['"]([^'"]+)[^>]*>/gi, function(match, capture) { // arrimg.push(capture) // }) // uploadPicToQn(arrimg) // .then(res => { // for (let h = 0; h < arrimg.length; h++) { // // this.tableData[j][this.checked[i]] = this.tableData[j][this.checked[i]].replace(arrimg[h], res.data[h].pic_name) // this.submitLastValue[j][this.checked[i]] = this.submitLastValue[j][this.checked[i]].replace(arrimg[h], res.data[h].pic_name) // } // this.debugCount += 1 // // this.resultData() // }) // .catch(() => {}) // } else { // this.debugCount += 1 // } // } // } }, btnClick() { if (this.value) { this.progressDebugShow = false clearInterval(this.progressTimer) this.resultShow = false document.querySelector('.input-file').click() } else { this.$message.warning('請先選擇模板') } },
// excel讀取2018/01/01這種時間格式是會將它裝換成數字相似於46254.1545151415 numb是傳過來的整數數字,format是之間間隔的符號
formatDate(numb, format) {
const time = new Date((numb - 1) * 24 * 3600000 + 1)
time.setYear(time.getFullYear() - 70)
const year = time.getFullYear() + ''
const month = time.getMonth() + 1 + ''
const date = time.getDate() - 1 + ''
if (format && format.length === 1) {
return year + format + month + format + date
}
return year + (month < 10 ? '0' + month : month) + (date < 10 ? '0' + date : date)
},
// 導入本地文件後取值
exportData(event) { if (!event.currentTarget.files.length) { return } const that = this // 拿取文件對象 const f = event.currentTarget.files[0] document.querySelector('.input-file').value = '' // 用FileReader來讀取 const reader = new FileReader() // 重寫FileReader上的readAsBinaryString方法 FileReader.prototype.readAsBinaryString = function(f) { let binary = '' let wb = '' // 讀取完成的數據 let outdata = [] // 你須要的數據 const reader = new FileReader() reader.onload = function(e) { // 讀取成Uint8Array,再轉換爲Unicode編碼(Unicode佔兩個字節) var bytes = new Uint8Array(reader.result) var length = bytes.byteLength for (let i = 0; i < length; i++) { binary += String.fromCharCode(bytes[i]) } // 接下來就是xlsx了,具體可看api wb = XLSX.read(binary, { type: 'binary' })
for (const i in wb.Sheets[wb.SheetNames[0]]) {
if (wb.Sheets[wb.SheetNames[0]][i]['z'] && wb.Sheets[wb.SheetNames[0]][i]['z'] === 'm/d/yy') {
wb.Sheets[wb.SheetNames[0]][i]['v'] = that.formatDate(parseInt(wb.Sheets[wb.SheetNames[0]][i]['v']), '-')
}
}
that.arr1 = [] that.tableData = [] that.copyTableDataTwo = [] that.copyTableData = [] outdata = XLSX.utils.sheet_to_json(wb.Sheets[wb.SheetNames[0]]) // 獲取excel表格中的全部標題 for (let i = 0; i < outdata.length; i++) { for (const j in outdata[i]) { let num = 0 for (let k = 0; k < that.arr1.length; k++) { if (that.arr1[k] === j) { num += 1 } } if (num === 0) { that.arr1.push(j) } } } that.arr1.unshift(' ') // 字段不存在或者沒有值時,則將它的值設置爲空 for (let i = 0; i < outdata.length; i++) { for (let j = 0; j < that.arr.length; j++) { if (!outdata[i][that.arr[j]] && outdata[i][that.arr[j]] !== 0) { outdata[i][that.arr[j]] = '' } } } // that.arr1 = [] // for (const i in outdata[0]) { // that.arr1.push(i) // } // console.log(outdata[0]) // console.log(that.arr1) for (let i = 0; i < 10 && i < outdata.length; i++) { const changeValue = JSON.stringify(outdata[i]) that.tableData.push(JSON.parse(changeValue)) that.copyTableData.push(JSON.parse(changeValue)) } // that.tableData = outdata // 因爲數組和對象是引用類型,在賦值時候會將地址也一塊兒賦值,當改變一個值得時候會將另一個值也改變,因此先轉爲字符串再轉回來(基本類型只會傳值不會傳地址) // that.copyTableData = JSON.stringify(outdata) that.copyTableDataTwo = JSON.stringify(outdata) // that.copyTableData = JSON.parse(that.copyTableData) that.copyTableDataTwo = JSON.parse(that.copyTableDataTwo) // 若是少於10行的補空格顯示十行 $('.tableShow').removeClass('hideTr') if (outdata.length < 10) { for (let i = 0; i < outdata.length; i++) { $('.tableShow').eq(i).addClass('hideTr') } } else { $('.tableShow').addClass('hideTr') } that.resultData() that.centerDialogVisible = true // 自定義方法向父組件傳遞數據 } reader.readAsArrayBuffer(f) } reader.readAsBinaryString(f) }, // 下拉框的值改變後改變對應的值 changeListValue(index) { // console.log(index) // 下標 // console.log(this.arr[index]) // console.log(this.changeList[this.arr[index]]) // 下拉框改變後的值 for (var i = 0; i < this.tableData.length; i++) { this.tableData[i][this.arr[index]] = this.copyTableData[i][this.changeList[this.arr[index]]] } // console.log(this.tableData) this.resultData() }, resultData() { this.submitLastValue = [] for (let i = 0; i < this.tableData.length; i++) { const list = {} for (let j = 0; j < this.arr.length; j++) { if (!this.tableData[i][this.arr[j]]) { list[this.arr[j]] = '' } else { list[this.arr[j]] = this.tableData[i][this.arr[j]] } } this.submitLastValue.push(list) } }, // 設置進度條定時器 setTimerProgress() { const that = this clearInterval(that.progressTimer) that.progress = 0 that.progressTimer = setInterval(function() { if (that.progress === 960) { that.progress = 0 } else { that.progress += 3 $('.slider').css('left', that.progress + 'px') } }, 20) }, // 保存到數據庫中 saveDataBase() { this.selectPower = true this.canclePower = true this.exportPower = true this.loading = true this.iconClickPower = 1 this.submitLastValue = [] this.resultShow = false this.progressDebugShow = false clearInterval(this.progressTimer) for (let j = 0; j < this.copyTableDataTwo.length; j++) { const obj = {} for (let i = 0; i < this.arr.length; i++) { if (this.copyTableDataTwo[j][this.changeList[this.arr[i]]] || this.copyTableDataTwo[j][this.changeList[this.arr[i]]] === 0) { obj[this.arr[i]] = this.copyTableDataTwo[j][this.changeList[this.arr[i]]] } else { obj[this.arr[i]] = '' } } this.submitLastValue.push(obj) } if (this.checked.length && this.checked.length !== 0) { this.PicTransfer() } else { this.saveResult() } }, // 校驗上傳數據 saveResult: function() { // 上傳數據校驗 if (this.submitLastValue.length === 0) { this.$message.warning('當前暫無數據') this.loading = false this.iconClickPower = 0 this.selectPower = false this.canclePower = false this.exportPower = false return } this.errorList = [] for (let i = 0; i < this.templateAllData.length; i++) { for (let j = 0; j < this.submitLastValue.length; j++) { if (this.templateAllData[i].attribute_not_null === true && !this.submitLastValue[j][this.templateAllData[i].attribute_name] && this.submitLastValue[j][this.templateAllData[i].attribute_name] !== 0) { // this.$message.error(this.templateAllData[i].attribute_name + '不能爲空') // this.loading = false // return this.errorList.push(this.templateAllData[i].attribute_name + '不能爲空') } if ((this.templateAllData[i].attribute_not_null === 'true' || this.templateAllData[i].attribute_not_null === true) && this.templateAllData[i].attribute_type === 'int4' && (!(/(^[0-9]\d*$)/.test(this.submitLastValue[j][this.templateAllData[i].attribute_name])))) { // 判斷長度 this.submitLastValue[j][this.templateAllData[i].attribute_name].toString().length > this.templateAllData[i].attribute_length // this.$message.error(this.templateAllData[i].attribute_name + '傳輸類型應爲整形') // this.loading = false // return this.errorList.push(this.templateAllData[i].attribute_name + '傳輸類型應爲整形') } if (this.templateAllData[i].attribute_type === 'numeric' && this.submitLastValue[j][this.templateAllData[i].attribute_name] && typeof this.submitLastValue[j][this.templateAllData[i].attribute_name] !== 'number') { // this.$message.error(this.templateAllData[i].attribute_name + '傳輸類型爲數字') // this.loading = false // return this.errorList.push(this.templateAllData[i].attribute_name + '傳輸類型爲數字') } if (this.templateAllData[i].attribute_type === 'date' && this.submitLastValue[j][this.templateAllData[i].attribute_name]) { this.submitLastValue[j][this.templateAllData[i].attribute_name] = this.submitLastValue[j][this.templateAllData[i].attribute_name].toString() this.submitLastValue[j][this.templateAllData[i].attribute_name] = this.submitLastValue[j][this.templateAllData[i].attribute_name].replace('年', '-') this.submitLastValue[j][this.templateAllData[i].attribute_name] = this.submitLastValue[j][this.templateAllData[i].attribute_name].replace('月', '-') this.submitLastValue[j][this.templateAllData[i].attribute_name] = this.submitLastValue[j][this.templateAllData[i].attribute_name].replace('日', '') if (isNaN(Date.parse(this.submitLastValue[j][this.templateAllData[i].attribute_name]))) { // this.$message.error(this.templateAllData[i].attribute_name + '格式有誤') // this.loading = false // return this.errorList.push(this.templateAllData[i].attribute_name + '格式有誤') } } if (this.templateAllData[i].attribute_type === 'bool') { if (this.submitLastValue[j][this.templateAllData[i].attribute_name] === '是' || this.submitLastValue[j][this.templateAllData[i].attribute_name].toString().toLowerCase() === 't' || this.submitLastValue[j][this.templateAllData[i].attribute_name].toString().toLowerCase() === 'true' || this.submitLastValue[j][this.templateAllData[i].attribute_name].toString().toLowerCase() === 'yes' || this.submitLastValue[j][this.templateAllData[i].attribute_name].toString().toLowerCase() === '1') { this.submitLastValue[j][this.templateAllData[i].attribute_name] = true continue } if (this.submitLastValue[j][this.templateAllData[i].attribute_name] === '否' || this.submitLastValue[j][this.templateAllData[i].attribute_name].toString().toLowerCase() === 'f' || this.submitLastValue[j][this.templateAllData[i].attribute_name].toString().toLowerCase() === 'false' || this.submitLastValue[j][this.templateAllData[i].attribute_name].toString().toLowerCase() === 'no' || this.submitLastValue[j][this.templateAllData[i].attribute_name].toString().toLowerCase() === '0') { this.submitLastValue[j][this.templateAllData[i].attribute_name] = false continue } if (this.submitLastValue[j][this.templateAllData[i].attribute_name] === '') { continue } // this.$message.error(this.templateAllData[i].attribute_name + '傳輸類型爲布爾值') // this.loading = false // return this.errorList.push(this.templateAllData[i].attribute_name + '傳輸類型爲布爾值') } } } if (this.errorList.length === 0) { this.progressDebugShow = true this.setTimerProgress() saveExcel(this.value, this.submitLastValue) .then(res => { this.successCount = parseInt(res.data.success) this.failCount = parseInt(res.data.fail) this.loading = false this.iconClickPower = 0 this.selectPower = false this.canclePower = false this.exportPower = false // this.tableData = [] // this.arr1 = [] // this.arr = [] // this.copyTableData = [] // this.copyTableDataTwo = [] // this.centerDialogVisible = false // this.centerDialogVisibleTwo = true this.resultShow = true clearInterval(this.progressTimer) this.progressDebugShow = false if (parseInt(this.failCount) === 0) { this.exportFale = false } else { this.exportFale = true } this.$emit('refleshParent') // 導入完成時在父組件刷新頁面 }) .catch(() => { this.$message({ message: '上傳失敗', type: 'error', duration: 2 * 1000 }) this.loading = false this.iconClickPower = 0 }) } else { // 數組去重 const saveArr = [] for (let i = 0; i < this.errorList.length; i++) { let num = 0 for (let j = 0; j < i; j++) { if (this.errorList[j] === this.errorList[i]) { num = 1 break } } if (num === 0) { saveArr.push(this.errorList[i]) } } this.errorList = saveArr this.errorPromptShow = true this.loading = false this.iconClickPower = 0 this.selectPower = false this.canclePower = false this.exportPower = false } }, // 獲取保存失敗的數據 exportFailData: function() { getFailData(this.value) .then(res => { this.JSONToExcelConvertor(res.data, '未導入成功的數據') // this.value = '' }).catch() }, // 導出數據到excel exportExcel() { let titleExcel = '' // 獲取表格標題 for (let i = 0; i < this.options.length; i++) { if (this.options[i].template_table_name === this.value) { titleExcel = this.options[i].template_description } } // this.tableToExcel(this.template) this.JSONToExcelConvertor(this.template, titleExcel) // this.exportPathMethod(this.template) // this.JSONToExcelConvertor(this.submitLastValue, 'report', this.arr, ['id']) }, exportPathMethod(data) { // 要導出的json數據 var jsonData = [] // for (var i = 0; i < data.length; i++) { // jsonData.push({ // index: i + 1, // title: data[i].title, // url: data[i].url, // createTime: data[i].createTime // }) // } // 列標題,逗號隔開,每個逗號就是隔開一個單元格 let str = `序號,標題,地址,時間\n` // 增長\t爲了避免讓表格顯示科學計數法或者其餘格式 for (let i = 0; i < jsonData.length; i++) { for (const item in jsonData[i]) { str += `${jsonData[i][item] + '\t'},` } str += '\n' } // encodeURIComponent解決中文亂碼 const uri = 'data:text/csv;charset=utf-8,\ufeff' + encodeURIComponent(str) // 經過建立a標籤實現 var link = document.createElement('a') link.href = uri // 對下載的文件命名 link.download = 'json數據表.xls' document.body.appendChild(link) link.click() }, // 只轉出excel標題 JSONToExcelConvertor(JSONData, FileName, title, filter) { if (!JSONData) { return } var arrData = typeof JSONData !== 'object' ? JSON.parse(JSONData) : JSONData var excel = '<table>' var row = '<tr>' if (title) { for (const i in title) { row += "<th align='center'>" + title[i] + '</th>' } } else { for (const i in arrData[0]) { let num = 0 for (let j = 0; j < this.templateAllData.length; j++) { if (i === this.templateAllData[j].attribute_name && this.templateAllData[j].attribute_not_null === true) { num += 1 } } if (num === 0) { row += "<th align='center'>" + '</span>' + i + '</th>' } else { // 導出時必填的有*號 row += "<th align='center'><span style='color: red'>" + '*' + '</span>' + i + '</th>' row += "<th align='center'> " + i + '</th>' } } } excel += row + '</tr>' // 若是有須要過濾的項則過濾 for (var i = 0; i < arrData.length; i++) { let row = '<tr>' for (var index in arrData[i]) { if (filter) { if (filter.indexOf(index) === -1) { var value = arrData[i][index] == null ? '' : arrData[i][index] row += '<td>' + value + '</td>' } } else { const value = arrData[i][index] == null ? '' : arrData[i][index] row += "<td align='center'>" + value + '</td>' } } excel += row + '</tr>' } excel += '</table>' var excelFile = "<html xmlns:o='urn:schemas-microsoft-com:office:office' xmlns:x='urn:schemas-microsoft-com:office:excel' xmlns='http://www.w3.org/TR/REC-html40'>" excelFile += '<meta http-equiv="content-type" content="application/vnd.ms-excel; charset=UTF-8">' excelFile += '<meta http-equiv="content-type" content="application/vnd.ms-excel' excelFile += '; charset=UTF-8">' excelFile += '<head>' excelFile += '<!--[if gte mso 9]>' excelFile += '<xml>' excelFile += '<x:ExcelWorkbook>' excelFile += '<x:ExcelWorksheets>' excelFile += '<x:ExcelWorksheet>' excelFile += '<x:Name>' excelFile += '{worksheet}' excelFile += '</x:Name>' excelFile += '<x:WorksheetOptions>' excelFile += '<x:DisplayGridlines/>' excelFile += '</x:WorksheetOptions>' excelFile += '</x:ExcelWorksheet>' excelFile += '</x:ExcelWorksheets>' excelFile += '</x:ExcelWorkbook>' excelFile += '</xml>' excelFile += '<![endif]-->' excelFile += '</head>' excelFile += '<body>' excelFile += excel excelFile += '</body>' excelFile += '</html>' var uri = 'data:application/vnd.ms-excel;charset=utf-8,' + encodeURIComponent(excelFile) var link = document.createElement('a') link.href = uri link.style = 'visibility:hidden' link.download = FileName + '.xls' document.body.appendChild(link) link.click() document.body.removeChild(link) }, // 轉出標題和數據 tableToExcel: function(jsonData) { // 列標題 let str = '<tr>' for (let i = 0; i < this.arr.length; i++) { str += `<td>${this.arr[i] + '\t'}</td>` } str += '</tr>' // 循環遍歷,每行加入tr標籤,每一個單元格加td標籤 for (let i = 0; i < jsonData.length; i++) { str += '<tr>' for (const item in jsonData[i]) { // 增長\t爲了避免讓表格顯示科學計數法或者其餘格式 str += `<td>${jsonData[i][item] + '\t'}</td>` } str += '</tr>' } // Worksheet名 const worksheet = 'Sheet1' // 下載的表格模板數據 const template = `<html xmlns:o="urn:schemas-microsoft-com:office:office" xmlns:x="urn:schemas-microsoft-com:office:excel" xmlns="http://www.w3.org/TR/REC-html40"> <head><!--[if gte mso 9]><xml><x:ExcelWorkbook><x:ExcelWorksheets><x:ExcelWorksheet> <x:Name>${worksheet}</x:Name> <x:WorksheetOptions><x:DisplayGridlines/></x:WorksheetOptions></x:ExcelWorksheet> </x:ExcelWorksheets></x:ExcelWorkbook></xml><![endif]--> </head><body><table>${str}</table></body></html>` // 下載模板 window.location.href = 'data:application/vnd.ms-excel;base64,' + this.base64(template) }, base64: function(s) { return window.btoa(unescape(encodeURIComponent(s))) } } } </script> <style scoped> .excel{ display: inline-block; /*position: relative;*/ /*right: 90px;*/ } .input-file { display: none; } .selectedList{ display: block; width: 100%; height: 34px; padding: 0px 0; font-size: 14px; line-height: 1.42857143; color: #555; background-color: #fff; background-image: none; border: 1px solid #ccc; border-radius: 4px; } .diybut{ display: inline-block; width: 135px; height: 40px; } .error-prompt{ margin: 15px 0; } .correct-prompt{ margin: 15px 0; } .hideTr{ display: none; } tr:nth-child(odd) { background: #F4F4F4; } </style>
css比較凌亂,見諒vuex