浏览代码

feat: 添加excel控件

double 5 年之前
父节点
当前提交
ffa4189034
共有 4 个文件被更改,包括 142 次插入25 次删除
  1. 13 0
      src/api/modules/sys_attachment.js
  2. 109 0
      src/components/ExportButton/index.vue
  3. 14 0
      src/utils/download.js
  4. 6 25
      src/views/user/index.vue

+ 13 - 0
src/api/modules/sys_attachment.js

@@ -22,6 +22,19 @@ module.exports.upload = (data) => {
   })
 }
 
+// export 附件导出
+module.exports.export = (data) => {
+  let url = '/api/sys/attachment/export?'
+  for (var key in data) {
+    url += key + '=' + encodeURIComponent(data[key]) + '&'
+  }
+  return axios({
+    url: url,
+    method: 'get',
+    responseType: 'blob'
+  })
+}
+
 // del 删除附件
 module.exports.del = (data) => {
   const url = '/api/sys/attachment/del'

+ 109 - 0
src/components/ExportButton/index.vue

@@ -0,0 +1,109 @@
+<template>
+  <el-button :loading="isExporting" class="export-button" type="primary" :size="size" @click="onClick">
+    <slot>Export</slot>
+  </el-button>
+</template>
+
+<script>
+import { mapGetters } from 'vuex'
+import download from '@/utils/download'
+
+export default {
+  name: 'ExportButton',
+  props: {
+    name: {
+      type: String,
+      default: ''
+    },
+    api: {
+      type: [Function, String],
+      default() {
+        return Promise.reject()
+      }
+    },
+    columns: {
+      type: [Array, Function],
+      default() {
+        return []
+      }
+    },
+    dataQuery: {
+      type: Object,
+      default() {
+        return () => {}
+      }
+    },
+    rows: {
+      type: Number,
+      default: 10000
+    }
+  },
+  data() {
+    return {
+      isExporting: false
+    }
+  },
+  computed: {
+    ...mapGetters([
+      'size'
+    ])
+  },
+  methods: {
+    onClick() {
+      this.isExporting = true
+      this.api(this.getExportQuery()).then(({ data }) => {
+        download(this.$api.sysAttachment.export(data)).then(() => {
+          this.isExporting = false
+        })
+      })
+    },
+    getExportColumns() {
+      const columns = this.deepCopy(this.checkFunc(this.columns))
+      return columns
+        .filter(column => {
+          return typeof column.show === 'undefined' || column.show
+        })
+        .map(column => {
+          if (typeof column.formatter === 'string') {
+            column.code = column.formatter
+          } else {
+            delete column.code
+          }
+          if (column.width) {
+            column.width = column.width * 0.125 || 0
+          }
+          return column
+        })
+    },
+    getExportQuery() {
+      const query = this.deepCopy(this.dataQuery)
+      query.page = 1
+      query.rows = this.rows
+      query.__export__ = true
+      query.__name__ = this.name
+      query.__columns__ = JSON.stringify(this.getExportColumns())
+      this.$emit('beforeExport', query)
+      return query
+    },
+    checkFunc(data) {
+      return typeof data === 'function' ? data() : data
+    },
+    deepCopy(data) {
+      if (typeof data !== 'object') {
+        return data
+      }
+      if (Array.isArray(data)) {
+        return data.map(this.deepCopy)
+      }
+      const copyData = {}
+      for (const [key, value] of Object.entries(data)) {
+        copyData[key] = this.deepCopy(value)
+      }
+      return copyData
+    }
+  }
+}
+</script>
+
+<style scoped lang="scss">
+</style>

+ 14 - 0
src/utils/download.js

@@ -0,0 +1,14 @@
+
+export default async function download(fetch) {
+  const res = await fetch
+  const blob = new Blob([res.data], { type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet;charset=utf-8' })
+  const a = window.document.createElement('a')
+  const href = window.URL.createObjectURL(blob)
+  const disposition = res.headers['content-disposition']
+  console.log(window.decodeURIComponent(new RegExp('filename="(.*)"').exec(disposition)))
+  const filename = window.decodeURIComponent(new RegExp('filename=(.*)').exec(disposition)[1])
+  a.href = href
+  a.download = filename
+  a.click()
+  window.URL.revokeObjectURL(href)
+}

+ 6 - 25
src/views/user/index.vue

@@ -8,13 +8,7 @@
           </el-aside>
           <el-container>
             <el-header height="82">
-              <el-form
-                ref="searchForm"
-                :model="dataQuery"
-                :size="size"
-                label-position="left"
-                label-width="80px"
-              >
+              <el-form ref="searchForm" :model="dataQuery" :size="size" label-position="left" label-width="80px">
                 <el-row :gutter="20">
                   <el-col :span="6">
                     <el-form-item label="Mobile:" prop="mobile" class="notice-input" label-width="60px">
@@ -30,6 +24,7 @@
                     <el-form-item>
                       <el-button type="primary" icon="el-icon-search" :size="size" @click="search">Search</el-button>
                       <el-button icon="el-icon-refresh" :size="size" @click="resetFields">Reset</el-button>
+                      <export-button :api="this.$api.sysUser.page" :columns="tableColumns" :data-query="dataQuery" name="用户列表.xlsx" />
                     </el-form-item>
                   </el-col>
                 </el-row>
@@ -133,27 +128,11 @@
         >
           <el-input v-if="item.type == 0" v-model.number="temp_items[i].value" placeholder="Please ente" clearable />
           <el-input v-if="item.type == 2" v-model="temp_items[i].value" placeholder="Please ente" clearable />
-          <!--<template v-if="item.type == 3">-->
-          <!--<el-table :data="temp_items[i].value" class="tb-edit" style="width: 100%" highlight-current-row @row-click="handleCurrentChange">-->
-          <!--<el-table-column v-for="col of JSON.parse(temp_items[i].content)" :prop="col.prop" :label="col.label" :width="col.width">-->
-          <!--<template scope="scope">-->
-          <!--<el-input v-model="temp_items[i].value[scope.$index][col.prop]" size="small" placeholder="请输入内容" @change="handleEdit(scope.$index, scope.row.prop)" /> <span>{{ temp_items[i].value[scope.$index][col.prop] }}</span>-->
-          <!--</template>-->
-          <!--</el-table-column>-->
-          <!--<el-table-column label="操作">-->
-          <!--<template scope="scope">-->
-          <!--<el-button size="small" type="text" @click="handleDelete(scope.$index, i)">删除</el-button>-->
-          <!--<el-button v-if="scope.$index == temp_items[i].value.length - 1" size="small" type="text" @click="addRow(i)">添加</el-button>-->
-          <!--</template>-->
-          <!--</el-table-column>-->
-          <!--</el-table>-->
-          <!--</template>-->
         </el-form-item>
       </el-form>
       <footer slot="footer" class="dialog-footer">
         <el-button :size="size" @click="dialogVisible = false">取 消</el-button>
-        <el-button :size="size" type="primary" @click="dialogStatus==='create'?createData():updateData()">确 定
-        </el-button>
+        <el-button :size="size" type="primary" @click="dialogStatus==='create'?createData():updateData()">确 定</el-button>
       </footer>
     </el-dialog>
     <el-dialog title="Change password" :visible.sync="updatePswDialog" width="30%">
@@ -183,12 +162,14 @@ import { deepClone } from '@/utils/index'
 import checkPermission from '@/utils/permission'
 import Tree from '@/components/Tree'
 import Sheet from '@/components/Sheet'
+import ExportButton from '@/components/ExportButton'
 
 export default {
   name: 'User',
   components: {
     Tree,
-    Sheet
+    Sheet,
+    ExportButton
   },
   data() {
     return {