コンテンツ
1. untilフォルダー内のrequest.js、axios応答インターセプト
7.コンポーネントファイルの下のレイアウトのLeftMenuページ
8.ビューファイルで作成されたコンポーネントのExcelのUploadExcelComponent.vue
9.ビューのファイルにUploadExcelComponent.vue
11.ビューのファイル内のベンダーのExport2Excel.js
12.ビューのファイル内のベンダーのExport2Zip.js
1. untilフォルダー内のrequest.js、axios応答インターセプト
// 封装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.apiフォルダーのexcel.js
import request from './../utils/request';
export function getDateList () {
return request({
url: '/excel/get',
method: 'get',
params: {}
})
}
3.モックファイルのindex.jsインターフェース
//接口文件
import Mock from 'mockjs'
import excel from './excel'
// 设置全局延时 没有延时的话有时候会检测不到数据变化
Mock.setup({
timeout: '300-600'
})
Mock.mock(/\/excel\/get/, 'get', excel.getMoneyList)
export default Mock
4.モックファイルのexcel.jsインターフェース
//模拟资金管理后台数据
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.コンポーネントファイルの下のレイアウトのホームページ
<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.コンポーネントファイルの下のレイアウトのホームページ
<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.コンポーネントファイルの下のレイアウトのLeftMenuページ
<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.ビューファイルで作成されたコンポーネントのExcelのUploadExcelComponent.vue
<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
<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
<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
<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
/* 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構成されたルート
//路由配置文件
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の構成
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')