Laravel Excel 结合 Ajax 方式实现导出功能
最近在做一个导出Excel的功能,经过两天的努力,终于算是搞定了~
要求:
1.同页面友好提示
2.无数据禁止下载
网上已经有很多类似的教程,这里就不啰嗦了,重点介绍一下,“下载中...”弹出框的实现。
这里使用了bootstrap和amazeui插件,以及jquery.fileDownload.js,下面是代码实现:
前端:
<html>
<head>
...
...
...
<link rel="stylesheet" href="http://cdn.amazeui.org/amazeui/2.7.2/css/amazeui.css">
<script src="http://cdn.amazeui.org/amazeui/2.7.2/js/amazeui.js"></script>
<script src="https://cdn.bootcss.com/jquery.fileDownload/1.4.2/jquery.fileDownload.js"></script>
</head>
<body>
<a href="javascript:void(0);" onclick="fileDown();">导出</a>
{{--询问框begin--}}
<div class="am-modal am-modal-confirm" tabindex="-1" id="my-confirm">
<div class="am-modal-dialog">
<div class="am-modal-bd tk_title">
内容
</div>
<div class="am-modal-footer">
<span class="am-modal-btn" data-am-modal-cancel>取消</span>
<span class="am-modal-btn" data-am-modal-confirm>下载账单</span>
</div>
</div>
</div>
{{--询问框end--}}
{{--弹出层begin--}}
<div class="am-modal am-modal-alert" tabindex="-1" id="my-alert">
<div class="am-modal-dialog">
<div class="am-modal-hd">Amaze UI</div>
<div class="am-modal-bd">
Hello world!
</div>
<div class="am-modal-footer">
<span class="am-modal-btn">确定</span>
</div>
</div>
</div>
{{--弹出层end--}}
{{--加载中begin--}}
<div class="am-modal am-modal-loading am-modal-no-btn" tabindex="-1" id="my-modal-loading">
<div class="am-modal-dialog">
<div class="am-modal-hd">正在载入...</div>
<div class="am-modal-bd">
<span class="am-icon-spinner am-icon-spin"></span>
</div>
</div>
</div>
{{--加载中end--}}
<script>
// 询问框
function fileDown() {
var content = '确定要导出表格吗?'; // 提示内容
$('.tk_title').text(content);
$('#my-confirm').modal({ // 询问框id名称
relatedTarget: this,
onConfirm: function(options) {
downloading();
},
onCancel: function() {
//点击了取消
}
});
}
// 弹出框
var modal = $('#my-alert');
function my_alert(title, content, open) {
modal.find('.am-modal-hd').html(title);
modal.find('.am-modal-bd').html(content);
if (open) {
modal.modal();
} else {
modal.modal('close');
}
}
// 加载框
var modal_loading = $('#my-modal-loading');
function my_loading(title, open) {
modal_loading.find('.am-modal-hd').html(title);
if (open) {
modal_loading.modal();
} else {
modal_loading.modal('close');
}
}
// 下载事件
function downloading() {
my_loading( '加载中,请稍后...', true);
$.ajax({
type: "POST",
dataType: "json",
data: {
_token: "{{ csrf_token() }}",
types: 2, //重要,体现在后端
// 其他参数
},
url: "{{ route('user.exports') }}",
// 其他参数
success: function (result, textStatus) {
if (result.status == 'success') {
my_loading("加载中,请稍后...", false);
$.fileDownload("{{ route('user.exports') }}", {
data: date,
prepareCallback: function (url) {
my_loading("正在下载,请稍后...", true);
},
successCallback: function (url) {
my_loading("正在下载,请稍后...", false);
my_alert("SUCCESS", "导出完成!", true);
},
failCallback: function (html, url) {
my_loading("正在下载,请稍后...", false);
my_alert("ERROR", "导出失败,未知的异常!", true);
}
});
} else {
my_loading("正在下载,请稍后...", false);
my_alert(result.msg, true);
}
},
error: function(XMLHttpRequest, textStatus, errorThrown) {
my_alert("ERROR", textStatus, true);
}
});
}
</script>
</body>
</html>
基本功能实现,其他的可以根据实际情况作出相应修改,例如根据时间段导出,可以传参等。
后端代码:
UserController.php
<?php
namespace App\Http\Controllers\User;
use Illuminate\Http\Request;
use App\Http\Controllers\Controller;
use Mockery\CountValidator\Exception;
use App\Models\User;
class UserController extends Controller
{
public function exports(Request $request)
{
$type = $request->input('types', 1);
$users = User::get();
if (!$users->count()) {
return json([
'code' => '201',
'status' => 'error',
'msg' => '暂无数据',
]);
}
if ($types != 1) {
return json([
'code' => 200,
'status' => 'success',
'msg' => '导出成功'
]);
}
/**
* 数据处理
*/
$cellData['title'] = ['表头'];
$cellData['columns'] = ['A1', 'B1', 'C1']; // 表头列名
$cellData['body'] = $users;
Excel::create(iconv('utf-8', 'gbk', '文件名'), function ($excel) use ($cellData) {
$excel->sheet('score', function ($sheet) use ($cellData) {
// 表头插入
$sheet->appendRow(1, $cellData['title']);
$sheet->appendRow(2, $cellData['columns']);
// 填充数据
$sheet->rows($cellData['body']);
// 设置列宽
$sheet->setWidth(array(
'A1" => '50px',
'B1" => '100px',
'C1" => '150px',
));
// 冻结表头
$sheet->setFreeze('A3');
// 横向 合并单元格 A1 到 C1
$sheet->mergeCells("A1:C1");
// 纵向合并
$sheet->setMergeColumn(array(
'columns' => array('B'), // 列数
// 行数,一个二维数组
'rows' => array(
array(3, 5),
array(6, 14),
array(15, 23),
...
...
...
)
));
// 字体居中
$sheet->cells("A1:C23", function ($cells) {
$cells->setAlignment('center');
$cells->setValignment('center');
});
});
})->export('xls', ['Set-Cookie' => 'fileDownload=true; path=/']);
}
}
到这里,基本就算完成了,其中最重要的就是 export() 中的 ['Set-Cookie' => 'fileDownload=true; path=/'], 这关系到前端 $.fileDownload 判断是否下载成功的标志,本来是怎么都搞不定,还是看了源代码的结果,才注意到的。
有需要的小伙伴,可以参考一下,下面是效果图:
询问框:
加载框:
成功下载:
失败下载:
至此就搞定了。
第一次写,有些啰嗦,见谅。。。
本帖已被设为精华帖!
本帖由系统于 6年前 自动加精
很好
性能怎么样啊? 可以快速导什么量级的.
@Teles 具体多少量级没有详细测试,我做的项目,因为要关联三张表,30天的数据,时间约在5秒内,如果要测试大量数据,你可以试一下
真棒
还可以,收藏了
哥好多错误啊。不能正常运行 :sob:
@Asa_c 哪里报错呢?
@OneLight 首先后端代码缺了一些括号。补上括号后 前端页面需要再引入一个jquery 引入后还是报错 500
@Asa_c 后端括号已改正,谢谢指正! 有些地方的省略号,是要加入自己的东西,比如jquery/css等的引入,再排查一下看看
@OneLight
@OneLight
@Asa_c 按照提示, 明显是你的data不存在啊!
@OneLight 哥你这个歧义太多 照着你这个教程 = = 你确定可以直接用json 后台 不是 response()->json()
@Asa_c 你要是有好方法, 也可以指导一下我嘛, 我在网上找了好久, 都没找到, 最后还是拼凑起来, 基本不影响功能实现才记录下来的.
我加了fileDownload=true;path=/ 一样不触发successCallback 回调是怎么回事 :joy: