个人笔记记录
使用PhpSpreadsheet 导出excel。
多重表头生成excel 表
//读取数据库
public function demo1()
{
// 连接数据库
$config = Config::get('databaseedc');
$db = Db::connect($config);
$data =$db->name("xxxx")
->alias('a')
->field('main_header, sub_header,fvi_value')
->join('')
->where('')
->select();
$this->exportDataToExcel($data);
}
// 将数据转换为Excel格式并保存
function exportDataToExcel($data) {
//从初始化表格
$spreadsheet = new Spreadsheet();
$sheet = $spreadsheet->getActiveSheet();
// 处理数据和表头
$mainHeaders = $this->getMainHeaders($data);
//提取次级表头和数据
$subHeadersAndData = $this->getSubHeadersAndData($data);
// 设置表头
$this->setHeaders($sheet, $mainHeaders, $subHeadersAndData);
//设置Excel的数据
$currentRow = 2;//初始行
$col=1; //初始列
//循环主表头
foreach ($mainHeaders as $subData){
//循环次级表头和数据
foreach ($subHeadersAndData as $subHeaderKey => $subHeaderData) {
// 获取主表头部分
$mainHeaderPart = explode('_', $subHeaderKey)[0];
//查找于当前表头一致的数据
if($mainHeaderPart==$subData){
echo("<pre>");
print_r($subHeaderKey);
//设置子标题:
$sheet->setCellValueByColumnAndRow($col, $currentRow, $subHeaderData['sub_header']);
//设置子标题相关的数据
foreach ($subHeaderData['data'] as $index => $value) {
$sheet->setCellValueByColumnAndRow($col, $currentRow + $index + 1, $value);
}
$col++;
}
}
}
// 保存文件
$writer = IOFactory::createWriter($spreadsheet, 'Xlsx');
$filename = './excel/' . date('YmdHis') . '.xlsx'; // 使用动态文件名避免冲突
$result = $writer->save($filename);
}
//从数据中提取主表头
public function getMainHeaders($data) {
$mainHeaders = [];
foreach ($data as $item) {
//检查 main_header 是否已在 $mainHeaders 中
if (!in_array($item['main_header'], $mainHeaders)) {
//不存在,加入数组
$mainHeaders[] = $item['main_header'];
}
}
return $mainHeaders;
}
//从数据中提取次级表头和数据
function getSubHeadersAndData($data) {
$subHeaders = [];//存储处理后的子标题及其相关数据
$rowData = [];
foreach ($data as $item) {
$subHeaderKey = $item['main_header'] . '_' . $item['sub_header'];
//检查 $subHeaders 数组中是否已经存在该子标题键
if (!isset($subHeaders[$subHeaderKey])) {
$subHeaders[$subHeaderKey] = [
'sub_header' => $item['sub_header'],
'data' => []
];
}
//$item 中的 'fvi_value' 添加到与该子标题关联的 'data' 数组中。
$subHeaders[$subHeaderKey]['data'][] = $item['fvi_value'];
}
return $subHeaders;
}
getSubHeadersAndData 中的数组如下。 “主表头_次级表头” 为了方便记录次级表头所属的表头是哪个。
sub_header:次级表头
data:当前列的内容。
//设置Excel的表头
function setHeaders($sheet, $mainHeaders, $subHeadersAndData) {
//从第一行第一列开始
$col = 1;
$row = 1;
//遍历主标题
foreach ($mainHeaders as $mainHeader) {
//设置主标题
$sheet->setCellValueByColumnAndRow($col, $row, $mainHeader);
//计算与当前主标题相关的子标题数量
$subHeadersCount = count(array_filter(array_keys($subHeadersAndData), function($key) use ($mainHeader) {
return strpos($key, $mainHeader . '_') === 0;
}));
//合并单元格
if ($subHeadersCount > 0) {
$sheet->mergeCells(Coordinate::stringFromColumnIndex($col) . $row . ':' . Coordinate::stringFromColumnIndex($col + $subHeadersCount - 1) . $row);
}
//更新列索引:
$col += $subHeadersCount;
}
}
第一行是主表头。第二行是次级表头。
补充
对其方式
靠右:HORIZONTAL_RIGHT
靠左:HORIZONTAL_LEFT
居中:HORIZONTAL_CENTER
// 设置该单元格左对齐
$style = $sheet->getStyleByColumnAndRow($col, $currentRow);
$style->getAlignment()->setHorizontal(Alignment::HORIZONTAL_LEFT);
//合并单元格
// 合并单元格,例如合并A1到B2的区域
//方法1
$sheet->mergeCells('A1:B2');
//方法2
$col = 1;//列
$row = 1;//行
//Coordinate::stringFromColumnIndex($col) //将起始列的数值索引转换为列名。
//. $row //将行号附加到列名的后面,形成起始单元格的完整坐标(如 'A1')。
//Coordinate::stringFromColumnIndex($col + $subHeadersCount - 1) //将结束列的数值索引(起始列加上需要合并的列数减 1)转换为列名。
//. $row //同样将行号附加到结束列的列名后面,形成结束单元格的完整坐标。
$sheet->mergeCells(Coordinate::stringFromColumnIndex($col) . $row . ':' . Coordinate::stringFromColumnIndex($col + $subHeadersCount - 1) . $row);