Vue project upload and download excel chart (content)

 

content

1. request.js in the until folder, axios response interception

2. excel.js in the api folder

3. The index.js interface in the mock file

4. The excel.js interface in the mock file

5. The home page in the layout under the components file

6. The home page in the layout under the components file

7. The LeftMenu page in the layout under the components file

8. UploadExcelComponent.vue in excel in the components created in the views file

9. UploadExcelComponent.vue in the file of views

10. upload-excel.vue in the file of views

 11. Export2Excel.js of vendor in the file of views

 12. Export2Zip.js of vendor in the file of views

13 Configured routes

14. Main.js configuration


1. request.js in the until folder, axios response interception

// 封装axios
import axios from 'axios';

// 创建axios实例
let service = axios.create({
    baseURL: "http://localhost:8080",
    timeout: 5000   // 请求超时时长
})

// 请求拦截
service.interceptors.request.use( config => {
    // 查看是否有token
    // 从store中找  是否有token
    return config;
}, error => Promise.reject(error))

// 响应拦截
service.interceptors.response.use( response => {
    /* 
        根据不同响应 status code 进行 配置
        code
            200  // 接口正常
            5001  // 非法token
            5002  // 其他客户端登录
            5003  // token已过期
    */
    let res = response.data;
    if( res.code !== 200 ) {
        return Promise.reject('error');
    } else {
        return res;
    }
}, error => Promise.reject(error));

export default service;

2. excel.js in the api folder

import request from './../utils/request';

export function getDateList () {
  return request({
    url: '/excel/get', 
    method: 'get',
    params: {}
  })
} 

3. The index.js interface in the mock file

//接口文件
import Mock from 'mockjs'
import excel from './excel'
// 设置全局延时 没有延时的话有时候会检测不到数据变化
Mock.setup({
    timeout: '300-600'
})


Mock.mock(/\/excel\/get/, 'get', excel.getMoneyList)

export default Mock

4. The excel.js interface in the mock file

//模拟资金管理后台数据
import Mock from 'mockjs' // 导入mockjs 模块

let List = []// 定义我们需要的数据
const count = 10

for (let i = 0; i < count; i++) {
  List.push(Mock.mock({// 根据数据模板生成模拟数据
    id: Mock.Random.guid(),// 随机生成一个id
    username: Mock.Random.cname(),// 随机生成一个常见的中文姓名。
    address: Mock.mock('@county(true)'),// @county(true)为数据模板
    createTime: Mock.Random.datetime(),//生成时间
    income: Mock.Random.integer(0, 9999),//生成随机数
    pay: Mock.Random.integer(0, 9999), //生成随机数
    accoutCash: Mock.Random.integer(0, 9999),//生成随机数
	checked:false//标识当前数据状态
  }))

}
export default{
	getMoneyList:config =>{
		return{
			code:200,
			data:{
				list:List,
			}
		}
	}
}

5. The home page in the layout under the components file

<template>
	<div class="container">
		<div class="c_header">
			<HeadNav></HeadNav>
		</div>
		<div class="c_left">
			<left-menu></left-menu>
		</div>
		<div class="c_right">
			<div class="main">
				<router-view></router-view>
			</div>
		</div>
	</div>
</template>

<script>
	import HeadNav from './HeadNav.vue'
	import LeftMenu from './LeftMenu'
	export default{
		data(){
			return{
				menuWidth:180
			}
		},
		components:{
			HeadNav,
			LeftMenu,
		},
	}
</script>

<style scoped lang="less">
	.container{
		.c_header{
			box-sizing: border-box;
			position: fixed;
			top:0;
			left:0;
			height: 56px;
			width:100%;
			font-size: 12px;
			text-align: center;
			background-color: #fff;
			z-index: 999;
		}
		.c_left{
			position: absolute;
			top:0;
			left:0;
			bottom: 0;
			width: 200px;
			margin-top:56px;
			background-color: #f90;
		}
		.c_right{
			box-sizing: border-box;
			overflow-y:auto;
			overflow-x:hidden;
			position: absolute;
			right:0px;
			top:56px;
			bottom: 0;
			left: 200px;
			background-color: #afb1b3;
			.main{
				box-sizing: border-box;
				width: 100%;
				padding: 20px;
			}
		}
	}
	
</style>

6. The home page in the layout under the components file

<template>
   <div class="container">
	 <div class="mylg">
		 <img class="logo" :src="logo" alt="" >
		 <span>智能物流管理系统</span>
	 </div>
     <div class="userinfo">
        <el-menu>
           <el-submenu index="2"  popper-class="infoItem">
                <template  slot="title">
                    <span>你好</span>
                </template>
                <el-menu-item index="2-1" >个人信息</el-menu-item>
                <el-menu-item index="2-2">修改信息</el-menu-item>
                <el-menu-item index="2-3">退出</el-menu-item>
            </el-submenu>
        </el-menu>
    </div>
   </div>
</template>

<script>
    import logoImg from "../assets/logo.png";
    export default {
          name: 'head-nav',
          data(){
            return{
               logo:logoImg,
            }
          },
          methods:{
              
          },
    }
</script>

<style scoped lang='less'>
.container{
	width:100%;
    display:flex;
	justify-content:space-between;
	align-items: center;
	border-bottom: 1px solid #C0CCDA;
	.mylg{
		font-size: 22px;
		font-weight: bold;
		margin-left: 50px;
		.logo{
			height: 36px;
			width: 36px;
			vertical-align: middle;
			display: inline-block;
		}
	}
	.userinfo{
		height: 56px;
		width: 200px;
		padding: 0 6px;
    
    .el-menu{
      background-color: none !important;
    } 
	}

	.avatar{
	        width: 32px;
	        height: 32px;
	        border-radius: 50%;
	        vertical-align: middle;
	        display: inline-block;
	    }
}
</style>

7. The LeftMenu page in the layout under the components file

<template>
  <div class="menu">
    <el-menu default-active="2" class="el-menu-vertical-demo">
      <el-submenu index="1">
        <template slot="title">
          <i class="el-icon-location"></i>
          <span>excel</span>
        </template>
        <router-link to="/excel/upload-excel">
          <el-menu-item index="1-1">导入</el-menu-item>
        </router-link>
        <router-link to="/excel/download-excel">
          <el-menu-item index="1-2">导出</el-menu-item>
        </router-link>
      </el-submenu>
    </el-menu>
  </div>
</template>

<script>
export default {
  methods: {},
};
</script>


<style lang="less" scoped>
</style>

8. UploadExcelComponent.vue in excel in the components created in the views file

<template>
  <div>
    
    <input ref="excel-upload-input" class="excel-upload-input" type="file" accept=".xlsx, .xls" @change="handleClick">
      <el-button :loading="loading" style="margin-left:16px;" size="mini" type="primary" @click="handleUpload">
        上传
      </el-button>
  </div>
</template>

<script>
import XLSX from 'xlsx'

export default {
  props: {
    beforeUpload: Function, // eslint-disable-line
    onSuccess: Function// eslint-disable-line
  },
  data() {
    return {
      loading: false,
      excelData: {
        header: null,
        results: null
      }
    }
  },
  methods: {
    generateData({ header, results }) {
      this.excelData.header = header
      this.excelData.results = results
      this.onSuccess && this.onSuccess(this.excelData)
    },
    handleUpload() {
      this.$refs['excel-upload-input'].click()
    },
    handleClick(e) {
      console.log("e:", e);
      const files = e.target.files;
      console.log("files:", files);
      const rawFile = files[0] // only use files[0]
      if (!rawFile) return
      this.upload(rawFile)
    },
    upload(rawFile) {
      this.$refs['excel-upload-input'].value = null // fix can't select the same excel

      if (!this.beforeUpload) {
        this.readerData(rawFile)
        return
      }
      const before = this.beforeUpload(rawFile)
      if (before) {
        this.readerData(rawFile)
      }
    },
    readerData(rawFile) {
      this.loading = true
      return new Promise((resolve, reject) => {
        const reader = new FileReader()  //读取文件对象
        reader.onload = e => {
          const data = e.target.result //文件流
          const workbook = XLSX.read(data, { type: 'array' })  //转成数组
          console.log("workbook:", workbook);
          const firstSheetName = workbook.SheetNames[0]
          const worksheet = workbook.Sheets[firstSheetName]
          const header = this.getHeaderRow(worksheet) //获取excel的头
          const results = XLSX.utils.sheet_to_json(worksheet)
          this.generateData({ header, results })
          this.loading = false
          resolve()
        }
        reader.readAsArrayBuffer(rawFile)
      })
    },
    getHeaderRow(sheet) {
      const headers = []
      const range = XLSX.utils.decode_range(sheet['!ref']);
      console.log("range:", range);
      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 */
        const cell = sheet[XLSX.utils.encode_cell({ c: C, r: R })]
        /* find the cell in the first row */
        let 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;
}
.drop{
  border: 2px dashed #bbb;
  width: 600px;
  height: 160px;
  line-height: 160px;
  margin: 0 auto;
  font-size: 24px;
  border-radius: 5px;
  text-align: center;
  color: #bbb;
  position: relative;
}
</style>

9. UploadExcelComponent.vue in the file of views

<template>
  <div>
    <el-table :data="tableData" style="width: 100%" align="center">
      <el-table-column v-if="false" prop="id" label="id" width="180">
      </el-table-column>
      <el-table-column type="selection" align="center" width="60">
      </el-table-column>
      <el-table-column prop="username" label="用户姓名" width="100">
      </el-table-column>
      <el-table-column prop="address" label="籍贯" width="180">
        <template slot-scope="scope">
          <span style="color: #00d053"
            >+ {
   
   { scope.row.tableAddress || scope.row.address }}</span
          >
        </template>
      </el-table-column>
      <el-table-column prop="createTime" sortable width="180" label="投资时间">
      </el-table-column>
      <el-table-column prop="income" label="收入" sortable width="100">
        <template slot-scope="scope">
          <span style="color: #00d053">+ {
   
   { scope.row.income }}</span>
        </template>
      </el-table-column>
      <el-table-column prop="pay" label="支出" sortable width="100">
        <template slot-scope="scope">
          <span style="color: #f56767">- {
   
   { scope.row.pay }}</span>
        </template>
      </el-table-column>
      <el-table-column prop="accoutCash" label="账户现金" sortable width="130">
        <template slot-scope="scope">
          <span style="color: #4db3ff"> {
   
   { scope.row.accoutCash }}</span>
        </template>
      </el-table-column>
      <el-table-column prop="operation" label="操作" width="180">
        <template>
          <el-button type="warning" icon="edit" size="mini">编辑</el-button>
          <el-button type="danger" icon="delete" size="mini">删除</el-button>
        </template>
      </el-table-column>
    </el-table>
    <el-button
      :loading="downloadLoading"
      style="margin: 0 0 20px 20px"
      type="primary"
      icon="el-icon-document"
      @click="handleDownload"
    >
      导出excel
    </el-button>
  </div>
</template>

<script>
import { getDateList } from "./../../api/excel";
import { export_json_to_excel } from "../vendor/Export2Excel.js";
export default {
  data() {
    return {
      tableData: [],
      downloadLoading: false,
    };
  },
  created() {
    this.getDateFn();
  },
  methods: {
    getDateFn() {
      getDateList().then((res) => {
        this.tableData = res.data.list;
      });
    },
    handleDownload() {
      this.downloadLoading = true;
      //自定义的头部
      const tHeader = ["姓名", "籍贯", "投资时间", "收入", "支出", "账户现金"];
      //自定义的字段
      const filterVal = [
        "username",
        "address",
        "createTime",
        "income",
        "pay",
        "accoutCash",
      ];
      getDateList().then((res) => {
        if (res.code == 200) {
          const data = this.formatJson(filterVal, res.data.list);
          export_json_to_excel({
            header: tHeader, //excel头部列表
            data, //数据
            filename: "2109_测试文件", //文件名称
            autoWidth: true, //自适应宽
            bookType: "xlsx", //文件类型
          });
          this.downloadLoading = false;
        }
      });
    },
    formatJson(filterVal, jsonData) {
      return jsonData.map((v) =>
        filterVal.map((j) => {
          return v[j];
        })
      );
    },
  },
};
</script>

<style scoped></style>

10. upload-excel.vue in the views file

<template>
  <div class="app-container">
    <upload-excel-component :on-success="handleSuccess" :before-upload="beforeUpload" />
    <el-table :data="tableData" border highlight-current-row style="width: 100%;margin-top:20px;">
      <el-table-column v-for="item of tableHeader" :key="item" :prop="item" :label="item" />
    </el-table>
   
  </div>
</template>

<script>
import UploadExcelComponent from './components/UploadExcelComponent.vue'

export default {
  name: 'UploadExcel',
  components: { 
     UploadExcelComponent
  },
  data() {
    return {
      tableData: [],
      tableHeader: []
    }
  },
  methods: {
      handleSuccess({ results, header }) {
        this.tableData = results
        this.tableHeader = header
      },
      beforeUpload(file) {
        const isLt1M = file.size / 1024 / 1024 < 1   //文件不能超过1m
        if (isLt1M) {
          return true
        }
        this.$message({
          message: '文件不能超过1m',
          type: 'warning'
        })
        return false
      },
  }
}
</script>

 11. Export2Excel.js of vendor in views file

<template>
  <div class="app-container">
    <upload-excel-component :on-success="handleSuccess" :before-upload="beforeUpload" />
    <el-table :data="tableData" border highlight-current-row style="width: 100%;margin-top:20px;">
      <el-table-column v-for="item of tableHeader" :key="item" :prop="item" :label="item" />
    </el-table>
   
  </div>
</template>

<script>
import UploadExcelComponent from './components/UploadExcelComponent.vue'

export default {
  name: 'UploadExcel',
  components: { 
     UploadExcelComponent
  },
  data() {
    return {
      tableData: [],
      tableHeader: []
    }
  },
  methods: {
      handleSuccess({ results, header }) {
        this.tableData = results
        this.tableHeader = header
      },
      beforeUpload(file) {
        const isLt1M = file.size / 1024 / 1024 < 1   //文件不能超过1m
        if (isLt1M) {
          return true
        }
        this.$message({
          message: '文件不能超过1m',
          type: 'warning'
        })
        return false
      },
  }
}
</script>

 12. Export2Zip.js of vendor in views file

/* eslint-disable */
import { saveAs } from 'file-saver'
import JSZip from 'jszip'

export function export_txt_to_zip(th, jsonData, txtName, zipName) {
  const zip = new JSZip()
  const txt_name = txtName || 'file'
  const zip_name = zipName || 'file'
  const data = jsonData
  let txtData = `${th}\r\n`
  data.forEach((row) => {
    let tempStr = ''
    tempStr = row.toString()
    txtData += `${tempStr}\r\n`
  })
  zip.file(`${txt_name}.txt`, txtData)
  zip.generateAsync({
    type: "blob"
  }).then((blob) => {
    saveAs(blob, `${zip_name}.zip`)
  }, (err) => {
    alert('导出失败')
  })
}

13 Configured routes

//路由配置文件
import Vue from 'vue'
import Router from 'vue-router'

import Home from '../layout/Home.vue'

//使用路由
Vue.use(Router)
//白名单
export const  whiteList = [ //'/','/index',
	'/login'
]
//路由配置  放行路由
export const constantRouterMap = [
  {
    path:'/',
    redirect:'/excel',
    meta:{hidden:true}
  }, {
    path:'/excel',
    name:'Home',
    component:Home,
    redirect:'/excel/upload-excel',
    meta:{title:'excel'},//自定义属性和值
    children:[
      {
        path:'upload-excel',
        name:'upload-excel',
        component: ()=> import('../views/excel/upload-excel.vue'),
        meta:{
          title:'上传excel'
        },
      },
      {
        path:'download-excel',
        name:'download-excel',
        component: ()=> import('../views/excel/download-excel.vue'),
        meta:{
          title:'下载excel'
        },
      }
    ]
  }
]

export default new Router({
	mode:'history',//默认值 hash  可选history
	//base:'/base/',//统一可以在路由上加前缀
	routes: constantRouterMap
})

14. Main.js configuration

import Vue from 'vue'
import App from './App.vue'
import router from './router'
import store from './store'
import ElementUI from 'element-ui'
Vue.use(ElementUI,{ size: 'mini'})
import 'element-ui/lib/theme-chalk/index.css'
Vue.config.productionTip = false
import './mock/index.js';
new Vue({
  router,
  store,
  render: h => h(App)
}).$mount('#app')

Guess you like

Origin blog.csdn.net/weixin_59519449/article/details/123858449