一、文件上传
1、html中
<!--
:show-file-list:是否显示文件列表
accept:过滤文件选择
action:上传路径
:on-success:上传后的回调
:on-error:上传失败的回调
:before-upload:上传中的回调
-->
<el-upload
:show-file-list="false"
accept=".xls,.xlsx,csv"
action="http://localhost:7091/member/uploadExcel"
:on-success="fileUploadSuccess"
:on-error="fileUploadError"
:disabled="fileUploadBtnText == '正在导入'"
:before-upload="beforeFileUpload"
style="display: inline; margin-left:10px;"
>
<el-button
type="success"
class="filter-item"
:icon="uploadBtnIcon"
:loading="fileUploadBtnText == '正在导入'"
><i class="fa fa-lg fa-level-up"></i>{{ fileUploadBtnText }}
</el-button>
</el-upload>
2、data中
fileUploadBtnText: "导入数据",
uploadBtnIcon: "el-icon-upload2",
3、method中
/* 文件上传成功后接收返回值 */
fileUploadSuccess(res) {
this.enabledUploadBtn = true;
this.uploadBtnIcon = "el-icon-upload2";
this.fileUploadBtnText = "导入数据";
if(res.status=='success'){
this.$message.success("数据导入成功!");
this.member.sort="-id";
// 表格数据重新赋值
this.getList();
}
},
/* 上传失败 */
fileUploadError() {
this.enabledUploadBtn = true;
this.uploadBtnIcon = "el-icon-upload2";
this.fileUploadBtnText = "导入数据";
},
/* 上传中 */
beforeFileUpload(file) {
this.enabledUploadBtn = false;
this.uploadBtnIcon = "el-icon-loading";
this.fileUploadBtnText = "正在导入";
},
4、后端接口中
观看:https://blog.csdn.net/qq_57404736/article/details/124240368?spm=1001.2014.3001.5501
二、批量删除()
实现结果:
-
数据列未选中前
-
数据列选中后
需要先实现表格的批量添加功能,这里看不懂的第五章有详细介绍。
1、html中
<el-button class="filter-item" type="danger"
icon="el-icon-delete"
@click="delAll()"
:disabled="multipleSelection.length === 0"
style="margin-left:10px;" >
批量删除
</el-button>
数据表格第一列多选框显示
<el-table-column label="全选" type="selection" width="55"></el-table-column>
2、data中
multipleSelection:[],
3、method中
//点击复选框触发,复选框样式的改变
handleSelectionChange(val) {
this.multipleSelection = val;
},
//点击行触发,选中或不选中复选框
handleRowClick(row, column, event) {
this.$refs.handSelectTest_multipleTable.toggleRowSelection(row);
},
//点击批量删除
delAll(){
var arr=[];
//遍历点击选择的对象集合,拿到每一个对象的id添加到新的集合中
this.multipleSelection.forEach(row=>arr.push(row.id));
this.$confirm('确定删除吗', {
confirmButtonText: '我就删',
cancelButtonText: '我不敢',
type: 'success',
callback: action => {
if (action === 'confirm') {
this.$axios.post("/member/delAll",arr).then(res=>{
if(res.status=='success'){
this.$notify({
title: '删除成功',
message: '',
type: 'success',
duration: 2000
})
this.getList() //重新加载页面的方法
}else{
this.$message('删除失败');
}
})
}
}
})
},
4、后端接口中
/**
* 根据id数组批量删除
* @param ids
* @return
*/
@RequestMapping("delAll")
public Object delAll(@RequestBody ArrayList<Integer> ids){
res.setStatus("success");
boolean b = mService.removeByIds(ids);
if(b){
return res;
}
res.setStatus("fail");
return res;
}
三、数据表格动态列显示(穿梭框实现)
实现结果:
1、html中
-
按钮样式:
-
代码:
<!-- 右侧小图标 --> <el-tooltip class="item" effect="dark" content="显隐列" placement="top" v-if="lists" style="float: right"> <el-button size="medium" circle icon="el-icon-menu" @click="showColumn()" style="background-color: #67C23A;" /> </el-tooltip> <!-- 弹框 --> <el-dialog :title="title" width="640px" :visible.sync="open" append-to-body> <el-transfer :titles="['显示', '隐藏']" v-model="value" :data="lists" @change="dataChange" ></el-transfer> </el-dialog>
-
表格每一列中添加:数组下标一次类推+1, 通过visible 来控制他的显示和隐藏,以此类推写下去就可以了
v-if="lists[0].visible"
2、data中
// 动态表格显隐数据
value: [],
// 弹出层标题
title: "显示/隐藏",
// 是否显示弹出层
open: false,
// 控制每列显示的对象
lists:[
{label:'学生编号',visible:true, key: 0},
{label:'学员姓名',visible:true, key: 1},
{label:'年龄',visible:true, key: 2},
{label:'性别',visible:true, key: 3},
{label:'学员电话',visible:true, key: 4},
{label:'学历',visible:true, key: 5},
{label:'个人状态',visible:true, key: 6},
{label:'来源渠道',visible:true, key: 7},
{label:'来源网址',visible:true, key: 8},
],
3、method中
// 右侧列表元素变化
dataChange(data) {
for (var item in this.lists) {
const key = this.lists[item].key;
this.lists[item].visible = !data.includes(key);
}
},
showColumn() {
this.open = true;
},
四、表格多行选择
实现结果:
1、html中
实现多选非常简单: 手动添加一个el-table-column
,设type
属性为selection
即可;
<el-table-column label="全选" type="selection" width="55"></el-table-column>
给表格添加两个事件@selection-change="handleSelectionChange" @row-click="handleRowClick"
以及一个ref属性ref="handSelectTest_multipleTable"
<el-table :key="tableKey" :data="list" border fit highlight-current-row
style="width: 100%;"
v-loading="pageLoding"
@sort-change="sortChange"
@selection-change="handleSelectionChange"
@row-click="handleRowClick"
ref="handSelectTest_multipleTable"
max-height="850">
html中总代码为:
<el-table :key="tableKey" :data="list" border fit highlight-current-row
style="width: 100%;"
@selection-change="handleSelectionChange"
@row-click="handleRowClick"
ref="handSelectTest_multipleTable"
max-height="850">
<el-table-column label="全选" type="selection" width="55"></el-table-column>
···省略显示每列的html代码
</el-table>
2、data中
// 表格多选列表
multipleSelection:[],
3、method中
//点击复选框触发,复选框样式的改变
handleSelectionChange(val) {
this.multipleSelection = val;
},
//点击行触发,选中或不选中复选框
handleRowClick(row, column, event) {
this.$refs.handSelectTest_multipleTable.toggleRowSelection(row);
},
五、树形控件(获取数据与右击事件)
实现结果:
1、获取数据
我这里使用的方法是在后台封装好数据以后显示给页面直接使用
1、html中
<!-- 用于搜索模块的 -->
<el-input
placeholder="输入模块名称进行过滤"
v-model="filterText"
style="width: 300px;">
</el-input>
<div class="block" style="margin-top: 30px;">
<el-tree :data="treeData" node-key="id"
:expand-on-click-node="false"
:filter-node-method="filterNode"
ref="tree"
icon-class="el-icon-folder-opened">
<span class="custom-tree-node" slot-scope="{ node, data }">
<span> {{ node.label }}</span>
</span>
</el-tree>
</div>
2、data中
// 过滤的文本
filterText: '',
// 级联数据
treeData: [],
3、method中
// 获取数据
getList(){
// 获得所有模块
// 后端必须要封装返回值类型,示例:[{id:1,label:学生管理,children:[id:2,label:新生报道]}]
this.$axios.get("/modules/getAllModules").then(res => {
this.treeData = res.data;
})
},
// 输入框的过滤事件
filterNode(value, data) {
if (!value) return true;
return data.label.indexOf(value) !== -1;
},
4、后台请求中
4.1、封装返回值类
创建一个名为ModulesTemp
的临时封装类
package com.crm.entity;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.util.List;
/**
* @author 宇辰
* @date 2022/5/24 - 13:46
*/
@Data
@AllArgsConstructor
@NoArgsConstructor
public class ModulesTemp {
private Integer id;
private String label;
private List<ModulesTemp> children;
// 用于下面右击事件添加的时候回显等,根据自己的表结构创建,用哪个列就声明哪个列的属性
private Integer parentId;
private String path;
private Integer weight;
}
4.2、控制层代码
/**
* 获取所有主模块
* @return
*/
@RequestMapping("getAllModules")
public Object getAllModules(){
res.setStatus("success");
QueryWrapper<Modules> queryWrapper = new QueryWrapper<>();
queryWrapper.eq("ParentId",0);
queryWrapper.orderByDesc("Weight");
// 获取所有的主模块并且按权重排序
List<Modules> list = mService.list(queryWrapper);
ArrayList<ModulesTemp> array = new ArrayList<>();
ModulesTemp mt = null;
for (Modules modules : list) {
mt = new ModulesTemp();
mt.setId(modules.getId());
mt.setLabel(modules.getName());
// 仔细体会这段代码,调用下面的方法
List childModules = this.getChildModules(modules.getId());
mt.setChildren(childModules);
mt.setPath(modules.getPath());
mt.setWeight(modules.getWeight());
mt.setParentId(modules.getParentId());
array.add(mt);
}
// 封装返回值类型,不用管
res.setData(array);
return res;
}
/**
* 根据主模块ID获取他的子模块
* @param parentId
* @return
*/
public List getChildModules(int parentId){
QueryWrapper<Modules> queryWrapper = new QueryWrapper<>();
queryWrapper.eq("ParentId",parentId);
queryWrapper.orderByDesc("weight");
// 根据获取当前主模块的子模块
List<Modules> modulesList = mService.list(queryWrapper);
List<ModulesTemp> arrayList = new ArrayList<>();
ModulesTemp mt = null;
for (Modules modules : modulesList) {
mt = new ModulesTemp();
mt.setId(modules.getId());
mt.setLabel(modules.getName());
mt.setPath(modules.getPath());
mt.setWeight(modules.getWeight());
mt.setParentId(modules.getParentId());
arrayList.add(mt);
}
return arrayList;
}
2、右击事件
所有代码:
<template>
<div class="app-container">
<el-input
placeholder="输入模块名称进行过滤"
v-model="filterText"
style="width: 300px;">
</el-input>
<el-button type="primary"
@click="treeAddMain()"
icon="el-icon-circle-plus-outline"
style="margin-left: 20px;">
添加主模块
</el-button>
<div class="block" style="margin-top: 30px;">
<el-tree :data="data" node-key="id"
:expand-on-click-node="false"
:filter-node-method="filterNode"
@node-contextmenu="rightClick"
ref="tree"
icon-class="el-icon-folder-opened">
<span class="custom-tree-node" slot-scope="{ node, data }">
<span> {{ node.label }}</span>
</span>
</el-tree>
</div>
<div id="menu" v-show="menuVisible" @mouseleave="menuVisible=!menuVisible">
<el-card class="box-card">
<div class="text item">
<el-link icon="el-icon-circle-plus-outline" @click="treeAdd()" :underline="false">添加</el-link>
</div>
<div class="text item">
<el-link icon="el-icon-edit" @click="treeUpdate()" :underline="false">修改</el-link>
</div>
<div class="text item">
<el-link icon="el-icon-remove-outline" @click="treeRemove()" :underline="false">删除</el-link> </div>
</el-card>
</div>
<!-- 表单 -->
<el-dialog :title="dialogStatus" :visible.sync="dialogFormVisible">
<el-form ref="dataForm" :rules="rules"
:model="modules"
label-position="left"
label-width="70px"
style="width: 400px; margin-left:50px;">
<el-form-item label="模块名" prop="name">
<el-input v-model="modules.name" />
</el-form-item>
<el-form-item label="路径" prop="" v-if="isShowPath">
<el-input v-model="modules.path" />
</el-form-item>
<el-form-item label="权重" prop="">
<el-input v-model.number="modules.weight" type="number" />
</el-form-item>
</el-form>
<div slot="footer" class="dialog-footer">
<el-button @click="closeForm()">
关闭
</el-button>
<el-button type="primary" @click="dialogStatus==='create'?createData():updateData()">
提交
</el-button>
</div>
</el-dialog>
</div>
</template>
<script>
export default{
name:"test",
watch: {
filterText(val) {
this.$refs.tree.filter(val);
},
},
data() {
return {
// 存储当前节点
node:'',
// 存当前节点数据
nodeData: {},
// 右键打开的卡片
menuVisible: false,
// 过滤的文本
filterText: '',
// 级联数据
data: [],
// 表单是否打开
dialogFormVisible: false,
// 表单状态
dialogStatus: '',
// 是否显示路径表单
isShowPath: true,
// 确定按钮判断打开的是哪个添加的方法
sureClick:'',
modules:{
id:null,
name:'',
parentId:null,
path:'',
weight:null
},
// 表单验证
rules:{
name: [
{ required: true, message: '模块名不能为空', trigger: 'change' }
],
},
}
},
created() {
this.getList();
},
methods: {
getList(){
// 获得所有模块
// 后端必须要封装返回值类型,示例:[{id:1,label:学生管理,children:[id:2,label:新生报道]}]
this.$axios.get("/modules/getAllModules").then(res => {
this.data = res.data;
})
},
// 初始化表单数据
restModules(){
this.modules = {
id:null,
name:'',
parentId:null,
path:'',
weight:null
}
},
// 添加主模块
treeAddMain(){
this.dialogStatus = 'create';
this.restModules();
this.dialogFormVisible = true;
// 隐藏路径表单 主模块不需要添加这个,所以当为主模块的时候就隐藏
this.isShowPath = false;
// 判断是哪个添加的表单
this.sureClick = "treeAddMain"
this.$nextTick(() => {
this.$refs['dataForm'].clearValidate()
})
},
// 鼠标右击事件
rightClick(MouseEvent, object, Node, element) {
this.node = Node;
this.nodeData = Node.data;
this.menuVisible = true;
// 样式追加
let menu = document.querySelector("#menu");
menu.style.cssText = "position: fixed; left: " + (MouseEvent.clientX - 10) + 'px' + "; top: " + (MouseEvent.clientY - 25) + 'px; z-index: 999; cursor:pointer;';
},
// 添加按钮的点击事件
treeAdd() {
// 子模块需要添加这个,所以显示出来了
this.isShowPath = true;
// 当前执行的是创建操作
this.dialogStatus = 'create';
// 重置数据
this.restModules();
// 打开表单
this.dialogFormVisible = true
// 判断是主模块的添加还是子模块的添加
this.sureClick = "treeAdd"
// 清空表单验证
this.$nextTick(() => {
this.$refs['dataForm'].clearValidate()
})
},
// 添加表单确定按钮的点击事件
createData(){
this.$refs['dataForm'].validate((valid) => {
if (valid) {
// 如果是添加子模块,则执行以下方法 否则执行添加主模块的方法
if(this.sureClick == "treeAdd"){
// 判断是否正在给子模块添加子模块,如果是则不能添加,最多只能由一个子模块
if(this.node.parent.parent == null){
this.modules.parentId = this.nodeData.id;
this.$axios.post("/modules/addModule",this.modules).then((res) => {
if(res.status=='success'){
this.menuVisible = false;
// 关闭表单
this.dialogFormVisible = false
this.getList();
this.$notify({
title: '成功',
message: '添加成功',
type: 'success',
duration: 2000
})
}else{
this.$message('添加失败,模块名可能重复');
}
})
}else{
this.dialogFormVisible = false
this.$message('添加失败,每个主模块下最多只能有一级子模块');
}
}else{
this.modules.parentId = 0;
this.$axios.post("/modules/addModule",this.modules).then((res) => {
if(res.status=='success'){
this.menuVisible = false;
// 关闭表单
this.dialogFormVisible = false
this.getList();
this.$notify({
title: '成功',
message: '主模块添加成功',
type: 'success',
duration: 2000
})
}else{
this.$message('主模块添加失败,主模块名可能重复');
}
})
}
}
})
},
// 修改按钮的点击事件
treeUpdate(){
this.dialogStatus = 'update';
this.isShowPath = true;
// 表单回显
let moduleData = this.nodeData;
this.modules.name = moduleData.label;
this.modules.path = moduleData.path;
this.modules.weight = moduleData.weight;
this.dialogFormVisible = true;
this.$nextTick(() => {
this.$refs['dataForm'].clearValidate()
})
},
updateData(){
this.$refs['dataForm'].validate((valid) => {
if (valid) {
this.modules.id = this.nodeData.id;
this.modules.parentId = this.nodeData.parentId;
this.$axios.post("/modules/updateModule",this.modules).then((res) => {
if(res.status=='success'){
// 关闭右键打开的卡片 但是不行
this.menuVisible = false;
// 关闭表单
this.dialogFormVisible = false
this.getList();
this.$notify({
title: '成功',
message: '修改成功',
type: 'success',
duration: 2000
})
}else{
this.$message('修改失败,模块名可能重复');
}
})
}
})
},
// 删除按钮的点击事件
treeRemove() {
this.$confirm('确定删除吗', {
confirmButtonText: '我就删',
cancelButtonText: '我不敢',
type: 'success',
callback: action => {
if (action === 'confirm') {
this.$axios.get("/modules/delModule",{params:{id:this.nodeData.id}}).then(res=>{
if(res.status=='success'){
this.$notify({
title: '删除成功',
message: '',
type: 'success',
duration: 2000
})
// 假删
const parent = this.node.parent;
const children = parent.data.children || parent.data;
const index = children.findIndex(d => d.id === this.nodeData.id);
children.splice(index, 1);
this.menuVisible = false;
}else{
this.$message('删除失败,请先删除此模块下的所有子模块');
this.menuVisible = false;
}
})
}
}
})
},
// 输入框的过滤事件
filterNode(value, data) {
if (!value) return true;
return data.label.indexOf(value) !== -1;
},
// 表单的关闭事件
closeForm(){
/* 关闭表单 */
this.dialogFormVisible = false;
},
}
}
</script>
<style>
html,
body {
height: 100%;
}
#dataPage {
margin: 0 0;
font-family: 'Microsoft Yahei', 'Avenir', Helvetica, Arial, sans-serif;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
text-align: center;
color: #2c3e50;
height: 100%;
}
// 右键会选中文字,为了美观将它禁用
#el-tree{
user-select:none;
}
.right-menu {
font-size: 14px;
position: fixed;
background: #fff;
border: solid 1px rgba(0, 0, 0, .2);
border-radius: 3px;
z-index: 999;
display: none;
}
.right-menu a {
width: 150px;
height: 28px;
line-height: 28px;
text-align: center;
display: block;
color: #1a1a1a;
}
.right-menu a:hover {
background: #eee;
color: #fff;
}
.right-menu {
border: 1px solid #eee;
box-shadow: 0 0.5em 1em 0 rgba(0,0,0,.1);
border-radius: 1px;
}
a {
text-decoration: none;
}
.right-menu a {
padding: 2px;
}
.right-menu a:hover {
background: #99A9BF;
}
</style>
六、树形控件作为弹窗打开(需要回显)
实现结果:
1、html中
属性解释:
show-checkbox
:显示选择框
:default-expanded-keys="defaultCheckAndExpand"
:默认展开的数组,根据node-key="id"
定义的属性值
:default-checked-keys="defaultCheckAndExpand"
:默认选中的节点,同上。
:expand-on-click-node="false"
:是否通过点击节点就能展开,否则只能点击前面的箭头才能展开
:check-strictly="true"
: 在显示复选框的情况下,是否严格的遵循父子不互相关联的做法,默认为 false
@check="handleTreeCheck"
: 当复选框被点击的时候触发
<!-- 按钮 -->
<el-button type="warning" size="mini" @click="handleSetModules(row)">
权限设置
</el-button>
<!-- 权限设置 -->
<el-dialog title="权限设置" :visible.sync="dialogSetModelsVisible" width="400px">
<el-tree
:data="treeData"
show-checkbox
node-key="id"
ref="tree"
:default-expanded-keys="defaultCheckAndExpand"
:default-checked-keys="defaultCheckAndExpand"
:props="defaultProps"
:expand-on-click-node="false"
:check-strictly="true"
@check="handleTreeCheck">
</el-tree>
</el-dialog>
2、data中
// 是否打开权限设置的树形组件
dialogSetModelsVisible: false,
// 左边树形数据
treeData: [],
// 规定
defaultProps: {
children: 'children',
label: 'label'
},
// 默认选中和展开的数组(存放的为对象的id,node-key定义过了)
defaultCheckAndExpand:[],
// 存放表格当前行的数据
rowData:{},
3、method中
getList() {
/* 获取表格数据 */
this.$axios.get("http://localhost:8888/roles/getRoles",{params:this.roles}).then((res)=>{
this.list = res.data;
this.total = res.total;
})
/* 获取所有模块数据渲染tree组件 依然需要像第五章一样,后台封装好数据再传入前端 */
this.$axios.get("/modules/getAllModules").then(res => {
this.treeData = res.data;
})
},
/* 权限设置按钮 */
handleSetModules(row){
// 先把当前行的数据存储到data中,否则下面的方法中获取不到。
this.rowData = row;
this.defaultCheckAndExpand = [];
// 当DOM出来的时候再清除选项
// 清空选择框 上面那个不管用
if (this.$refs.tree) {
this.$nextTick(() => {
this.$refs.tree.setCheckedKeys([]);
})
}
// 当点击按钮的时候,根据当前角色的id搜索拥有的权限,然后添加到 defaultCheckAndExpand 数组中
this.$axios.get("/rolemodules/getAllModulesByRoleId",{params:{"roleId":row.id}}).then(res => {
res.data.forEach(roleModules => {
this.defaultCheckAndExpand.push(roleModules.moduleId)
})
})
// 如果不延迟的话,那么DOM会渲染太快,导致数据没有回显上
setTimeout(() => {
this.dialogSetModelsVisible=true;
},'100')
},
/*
节点选项的点击事件
这个事件只能拿到当前点击的节点数据,以及所有选中的选择框所存放的集合,
获取不到当前点击的是选中还是取消选中,
所以我们只能进行循环判断。
*/
handleTreeCheck(data,checked){
// 定义一个是否在内的布尔值变量,默认为false
let isCheck = false;
// 循环所有被选中的数组,如果当前节点对象的id在数组内,则证明是选中事件,则跳出循环执行相应的添加或者删除的方法
for (var i = 0; i < checked.checkedKeys.length; i++) {
if(data.id == checked.checkedKeys[i]){
isCheck = true;
break;
}
}
if(isCheck){
this.$axios.get("/rolemodules/addRoleModules",{params:{"roleId":this.rowData.id,"moduleId":data.id}}).then(res => {
if (res.status == "success") {
this.$notify({
title: '成功',
message: '模块分配成功',
type: 'success',
duration: 2000
})
} else{
this.$notify.error({
title: '错误',
message: '模块分配失败',
type: 'error',
duration: 2000
})
}
})
}else{
this.$axios.get("/rolemodules/delRoleModules",{params:{"roleId":this.rowData.id,"moduleId":data.id}}).then(res => {
if (res.status == "success") {
this.$notify({
title: '成功',
message: '模块取消成功',
type: 'success',
duration: 2000
})
} else{
this.$notify.error({
title: '错误',
message: '模块取消失败',
type: 'error',
duration: 2000
})
}
})
}
},
七、穿梭框
实现结果:
1、html中
<!-- 穿梭框 -->
<el-transfer
filterable
filter-placeholder="请输入角色名称"
v-model="transferValue"
:data="transferData"
:titles="['所有角色', '已拥有角色']"
@change="handleTransferChange">
</el-transfer>
2、data中
transferValue:[],
transferData:[],
3、method中
getList() {
this.transferData = [];
// 获取穿梭框的数据
this.$axios.get("/roles/getAllRoles").then(res => {
for (var i = 0; i < res.data.length; i++) {
this.transferData.push({"label":res.data[i].name,"key":res.data[i].id})
}
})
},
/* 穿梭框发生变化时触发的事件 */
handleTransferChange(value, direction, movedKeys) {
// 如果是往右添加则执行添加操作,如果是往左移动则执行删除操作
if(direction === "right"){
this.$axios.post("/userroles/addUserRoles",{"userId":this.rowValue.id,"rolesId":movedKeys}).then(res => {
if (res.status=='success') {
this.$notify({
title: '成功',
message: '设置成功',
type: 'success',
duration: 2000
})
} else{
this.$notify.error({
title: '错误',
message: '设置失败',
type: 'error',
duration: 2000
})
}
})
}else{
this.$axios.post("/userroles/delUserRoles",{"userId":this.rowValue.id,"rolesId":movedKeys}).then(res => {
if (res.status=='success') {
this.$notify({
title: '成功',
message: '删除成功',
type: 'success',
duration: 2000
})
} else{
this.$notify.error({
title: '错误',
message: '删除失败',
type: 'error',
duration: 2000
})
}
})
}
},
八、文件下载
1、html中
<el-button @click="exportData" type="success" icon="el-icon-download">
导出数据
</el-button>
2、method中
// 导出数据
exportData() {
this.$http({
method: "GET",
url: "student/export",
params: {},
responseType: "blob"
})
.then(res => {
/* 方式1,文件名随机
let blob = new Blob([res.data], { type: "application/vnd.ms-excel" });
let url = window.URL.createObjectURL(blob);
window.location.href = url;
*/
/* 方式2,支持IE10;文件名自定义
*/
let blob = new Blob([res.data], { type: "application/vnd.ms-excel" }); // 将服务端返回的文件流(二进制)excel文件转化为blob
let fileName = "学生列表.xls";
if (window.navigator && window.navigator.msSaveOrOpenBlob) {
// IE
window.navigator.msSaveOrOpenBlob(blob, fileName);
} else {
let objectUrl = (window.URL || window.webkitURL).createObjectURL(
blob
);
let downFile = document.createElement("a");
downFile.style.display = "none";
downFile.href = objectUrl;
downFile.download = fileName; // 下载后文件名
document.body.appendChild(downFile);
downFile.click();
document.body.removeChild(downFile); // 下载完成移除元素
// window.location.href = objectUrl
window.URL.revokeObjectURL(objectUrl); // 只要映射存在,Blob就不能进行垃圾回收,因此一旦不再需要引用,就必须小心撤销URL,释放掉blob对象。
}
})
.catch(err => {
console.log(err);
});
},
3、后台中
@RequestMapping("exportExcel")
public void exportExcel(HttpServletResponse response) throws Exception {
// 创建工作簿
HSSFWorkbook workbook = new HSSFWorkbook();
// 创建工作表
HSSFSheet sheet = workbook.createSheet("学生列表");
// 设置导出的文件名称
String fileName = "学生列表.xls";
// 获取所有数据集合
List<Students> list = sService.list();
//标题行
HSSFRow row = sheet.createRow(0);
row.createCell(0).setCellValue("学生编号");
row.createCell(1).setCellValue("学员姓名");
row.createCell(2).setCellValue("年龄");
row.createCell(3).setCellValue("性别");
row.createCell(4).setCellValue("学员电话");
row.createCell(5).setCellValue("学历");
row.createCell(6).setCellValue("个人状态");
row.createCell(7).setCellValue("来源渠道");
row.createCell(8).setCellValue("来源网址");
Students s = null;
for (int i = 0; i < list.size(); i++) {
s = list.get(i);
// 从第二行开始
row = sheet.createRow(i+1);
// 依次往表格里填数据
row.createCell(0).setCellValue(s.getId());
row.createCell(1).setCellValue(s.getName());
row.createCell(2).setCellValue(s.getAge());
row.createCell(3).setCellValue(s.getSex());
row.createCell(4).setCellValue(s.getPhone());
row.createCell(5).setCellValue(s.getStuStatus());
row.createCell(6).setCellValue(s.getPerState());
row.createCell(7).setCellValue(s.getMsgSource());
row.createCell(8).setCellValue(s.getSourceUrl());
}
response.setContentType("application/octet-stream");
response.setHeader("Content-disposition",
"attachment;filename=" + java.net.URLEncoder.encode(fileName, "UTF-8"));
response.flushBuffer();
workbook.write(response.getOutputStream());
}