前言:在列表页,根据搜索结果,导出数据;csv相对于excel的优点是数据量大,速度快;有些具体细节不多说了,自己打印调试;
1.html部分:使用一个简单的a标签,按钮也可以;
<a href="javascript:;" onclick="export_csv()" dialog-title="导出csv" class="btn btn-primary btn-sm">导出csv</a>
2.js部分:使用了jquery
function export_csv() {
//获取搜索字段值,一般是selcet和input,(自行查询各个标签的获取方法)
var param1 = $("select[name='area_1']").val();
var param2 = $("select[name='area_2']").val();
...
var param6 = $("input[name='num']").val();
var param7 = $("input[name='start_time']").val();
var param8 = $("input[name='end_time']").val();
//思考:有的时候搜索条件很多,不知道会不会超出get方法携带参数的大小
url = "/admin/some_model/toCsv?param1"+param1+"¶m2="+param2+...+"¶m8="+param8;
window.location.href = url;
}
3.后台处理
导出的代码要参考 列表的代码;这样就能保证导出的数据和列表的数据一样
public function toCsv()
{
$start = Request::param('start','');
$end = Request::param('end','');
$name = Request::param('name','');
$field = '*';
$where = [];
if ($start){
$where[] = ['create_time','>=',$start . ' 00:00:00'];
}
if ($end){
$where[] = ['create_time','<=',$end . ' 23:59:59'];
}
if ($name){
$where[] = ['name','like','%'.$name.'%'];
}
$query = Model::getQuery($where,$field,$order = 'id desc');
$head = [
'用户名', '角色', '最后一次登录时间', '最后一次登录ip', '创建时间'
];
$fileName = '管理员信息数据' . date('_YmdHis') . '.csv';
$this->putCsv($query,$head,$fileName);
}
public function putCsv($query,$head,$fileName){
//设置运行时间,单位秒
set_time_limit(1800);
//输出文件头
header("Content-type: text/csv");
header('Content-Type: application/vnd.ms-excel;charset=utf-8');
header("Content-Disposition: attachment;filename=$fileName");
header('Cache-Control: no-cache');
header('Expires: 0');
//总条数
$total = $query->count();
$pageSize = 10000;//每次只从数据库取10000条以防变量缓存太大
// 每隔$limit行,刷新一下输出buffer,不要太大,也不要太小
$limit = 10000;
// buffer计数器
$cnt = 0;
$fp = fopen('php://output', 'w');
$key = [];
foreach ($head as $i => $v) {
// CSV的Excel支持GBK编码,一定要转换,否则乱码
$head[$i] =iconv("utf-8","gb2312//IGNORE",$v);
array_push($key, $i);
}
fputcsv($fp, $head);
//这里可以先写一些测试数据,尝试是否成功
// $lists = [
// '小李','super','123','123',123
// ];
// fputcsv($fp,$lists);
// fclose($fp);
// exit();
for ($i = 0; $i < ceil($total/$pageSize); $i++){
$lists = $query->limit($i*$pageSize,$pageSize)->select();
foreach ($lists as $k => $v){
//做一些转换
if ($v['role_type'] == StatusCode::SUPER_ADMIN){
$v['role_type'] = '超级管理员';
}elseif ($v['role_type'] === StatusCode::ORDINARY_ADMIN){
$v['role_type'] = '普通管理员';
}else{
$v['role_type'] = '客服';
}
$row = [
$v['name'],$v['role_type'],$v['last_login_time'],$v['last_login_ip'],$v['create_time']
];
//字符集转换
foreach ($row as $key => $val) {
if (!empty($val)) {
$val=is_numeric($val) ? $val . "\t" : $val;
$row[$key] = iconv('utf-8', 'gb2312//IGNORE', $val);
}
}
$cnt++;
if ($limit == $cnt){
//刷新一下输出buffer,防止由于数据过多造成问题
ob_flush();
flush();
$cnt = 0;
}
fputcsv($fp, $row);//写入第一行数据
}
}
fclose($fp);
exit();
}
小tips:
- csv格式的文件,用excel打开数字会强制转换成科学记数法;想身份证号码可以前后端约定加个字母,将其转换成字符串,取用时切割去字母即可
- 有些偏僻汉字,无法正常显示时,编码问题:gbk的字符数量 大于gb2312,将gb2312替换成gbk
- Cannot modify header information - headers already sent by;这个报错很有可能是字段转换时,写错字段名,特别是导出字段非常多时,需要逐个排除;建议一边调试一边写代码
- 目前一次性全部导出过13W的多字段csv,速度还可以