## 依赖库
大名鼎鼎的phpexcel
<http://phpexcel.codeplex.com>
## 效果
![](https://box.kancloud.cn/2015-11-28_56597975de34b.png)
![](https://box.kancloud.cn/2015-11-28_565979760cca9.png)
![](https://box.kancloud.cn/2015-11-28_565979761f10f.png)
![](https://box.kancloud.cn/2015-11-28_5659797636177.png)
![](https://box.kancloud.cn/2015-11-28_565979764a158.png)
是用方法就是后台初始化report数据库后,然后自己建好数据表。
然后新建模板->上传一个excel模板,指定好查询的数据,和填充的开始项。然后数据随便后台操作数据库。前台就是把excel报表显示输出来即可。
感谢写好这个系统的吴学海同学。其实数据填充那步相当于excel软件导入的数据源。
这套模板管理系统支持多子excel和对应多数据源。组合起来不是特别复杂的excel报表都能满足。
像第一个签到模板,我的excel模板![](https://box.kancloud.cn/2015-11-28_56597976593e4.png),excel中的竖线自己设格式。
然后我的数据源,![](https://box.kancloud.cn/2015-11-28_565979766671d.png)
就是序列化字段里的那个 select name,time from sign limit 10。然后开始位置是每行的第一个单元格德位置如 A2 表示第二行第一列。
要更完善的话,就是数据源支持选api就更好了。配置最好用json 可读性更高
## 实现
随书项目yang_book/examples/excel里。
我们只看excel的相关代码:
前台具体显示某一个模板的excel
~~~
/**
* 查询数据库填充excel并展示为html。
* @throws \PHPExcel_Exception
* @throws \PHPExcel_Reader_Exception
* @throws \PHPExcel_Writer_Exception
*/
public function showReport(){
//是否导出
$export = I('export',0,'int');
$id = I('report_id',0,'int');
if(!$id){
$this->error('参数有误');
}
$reportInfo = M('report')->where(array('id'=>$id))->find();
//导入第三方类
import("Vendor.PHPExcel");
import("Vendor.PHPExcel.Reader.Excel2007");
import("Vendor.PHPExcel.Reader.Excel5");
import("Vendor.PHPExcel.Reader.HTML");
import("Vendor.PHPExcel.Writer.Excel2007");
import("Vendor.PHPExcel.Writer.CSV");
import("Vendor.PHPExcel.IOFactory");
$totalPHPExcel = [];
$tempInfo = unserialize($reportInfo['tempinfo']);
foreach($tempInfo as $k=>$va){
$PHPReader = new \PHPExcel_Reader_Excel2007();
if(!$PHPReader->canRead('./Uploads/template'.$va['path'])){
$PHPReader = new \PHPExcel_Reader_Excel5();
if(!$PHPReader->canRead('./Uploads/template'.$va['path'])){
$this->error('该excel模板无法读取。请联系管理员');
return ;
}
}
//读取模板
$PHPExcel = $PHPReader->load('./Uploads/template'.$va['path']);
$currentSheet = $PHPExcel->getSheet(0);
foreach($va['config'] as $cnf){
//根据配置信息,查询数据
$sql = $cnf['sql'];
$start_x = preg_split("/([a-zA-Z]+)/", $cnf['start_x'], 0, PREG_SPLIT_NO_EMPTY | PREG_SPLIT_DELIM_CAPTURE);
if(empty($sql)){
break;
$this->error('sql错误');
}
$data = M()->query($sql);
//row坐标计数器
$i = 0;
foreach($data as $v){
if(is_array($v) && !empty($v)){
$AZ = strtoupper($start_x[0]);
//循环填充数据
foreach($v as $value){
$currentSheet->setCellValue($AZ.($start_x[1]+$i),$value);
$objStyleA1 = $currentSheet->getStyle($AZ.($start_x[1]+$i));
$objAlignA1 = $objStyleA1->getAlignment();
$objAlignA1->setHorizontal(\PHPExcel_Style_Alignment::HORIZONTAL_CENTER);
$AZ = $this->nextAZ($AZ);
if(!$AZ){
$this->error('A-Z超值,请联系管理员');
}
}
}
$i++;
}
}
if(!$export){
//显示模板
$objWriteHTML =new \PHPExcel_Writer_HTML($PHPExcel);
$objWriteHTML->save("php://output");
}else{
$objWrite = new \PHPExcel_Writer_Excel2007($PHPExcel);
$objWrite->save ($k.'.xls');
$totalPHPExcel[] = $k.'.xls';
}
}
//excel文件导出,所有模板打包一起下载
if($export){
@unlink(iconv("UTF-8","gbk//TRANSLIT",$reportInfo['name'].'.zip'));
$zip = new \ZipArchive();
if($zip->open(iconv("UTF-8","gbk//TRANSLIT",$reportInfo['name'].'.zip'),\ZipArchive::OVERWRITE) === true){
foreach($totalPHPExcel as $v){
$zip->addFile($v);
}
}
$zip->close();
//下面是输出下载;
header ( "Cache-Control: max-age=0" );
header ( "Content-Description: File Transfer" );
header ( 'Content-disposition: attachment; filename=' . basename (iconv("UTF-8","gbk//TRANSLIT",$reportInfo['name'].'.zip')) ); // 文件名
header ( "Content-Type: application/zip" ); // zip格式的
header ( "Content-Transfer-Encoding: binary" );
header ( 'Content-Length: ' . filesize (iconv("UTF-8","gbk//TRANSLIT",$reportInfo['name'].'.zip') ) ); // 告诉浏览器,文件大小
@readfile ( iconv("UTF-8","gbk//TRANSLIT",$reportInfo['name'].'.zip'));//输出文件;
}
}
~~~
类私有方法nextAZ:
~~~
/**
* 返回下一个字母
* @param $currAZ
* @return bool
*/
private function nextAZ($currAZ){
$defaultAZ = array(
'A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P','Q','R','S','T','U','V','W','X','Y','Z'
);
$countLength = count($currAZ);
if($countLength > 1){
//TODO:大于1位未实现
substr($currAZ,-1,1);
return false;
}else{
if($currAZ != 'Z'){
$index = array_search($currAZ,$defaultAZ);
return $defaultAZ[$index+1];
}else{
//TODO:超过Z未实现
return false;
}
}
}
~~~
大家具体看看 主要是用了excel的打开模板`$PHPReader->load`、遍历填值`$currentSheet->setCellValue($AZ.($start_x[1]+$i),$value);` 还有下载文件和压缩下载
## 参考
<http://www.seo0395.com/archives-211>介绍的比较全,英文不好的可以看看,好的直接看官方文档 <https://github.com/PHPOffice/PHPExcel/wiki/User%20Documentation>
- 序
- 前言
- 内容简介
- 目录
- 基础知识
- 起步
- 控制器
- 模型
- 模板
- 命名空间
- 进阶知识
- 路由
- 配置
- 缓存
- 权限
- 扩展
- 国际化
- 安全
- 单元测试
- 拿来主义
- 调试方法
- 调试的步骤
- 调试工具
- 显示trace信息
- 开启调试和关闭调试的区别
- netbeans+xdebug
- Socketlog
- PHP常见错误
- 小黄鸭调试法,每个程序员都要知道的
- 应用场景
- 第三方登录
- 图片处理
- 博客
- SAE
- REST实践
- Cli
- ajax分页
- barcode条形码
- excel
- 发邮件
- 汉字转全拼和首字母,支持带声调
- 中文分词
- 浏览器useragent解析
- freelog项目实战
- 需求分析
- 数据库设计
- 编码实践
- 前端实现
- rest接口
- 文章发布
- 文件上传
- 视频播放
- 音乐播放
- 图片幻灯片展示
- 注册和登录
- 个人资料更新
- 第三方登录的使用
- 后台
- 微信的开发
- 首页及个人主页
- 列表
- 归档
- 搜索
- 分页
- 总结经验
- 自我提升
- 进行小项目的锻炼
- 对现有轮子的重构和移植
- 写技术博客
- 制作视频教程
- 学习PHP的知识和新特性
- 和同行直接沟通、交流
- 学好英语,走向国际
- 如何参与
- 浏览官网和极思维还有看云
- 回答ThinkPHP新手的问题
- 尝试发现ThinkPHP的bug,告诉官方人员或者push request
- 开发能提高效率的ThinkPHP工具
- 尝试翻译官方文档
- 帮新手入门
- 创造基于ThinkPHP的产品,进行连带推广
- 展望未来
- OneThink
- ThinkPHP4
- 附录