SchoolPhysicalExamination/application/download/controller/Excel.php

223 lines
8.2 KiB
PHP
Raw Permalink Normal View History

2025-09-04 07:00:15 +08:00
<?php
namespace app\download\controller;
use think\Controller;
use PhpOffice\PhpSpreadsheet\Spreadsheet;
use PhpOffice\PhpSpreadsheet\Writer\Xlsx;
use PhpOffice\PhpSpreadsheet\Style\Border;
use PhpOffice\PhpSpreadsheet\Style\Fill;
use PhpOffice\PhpSpreadsheet\Style\Alignment;
use PhpOffice\PhpSpreadsheet\Style\Color;
2025-09-04 07:24:06 +08:00
use PhpOffice\PhpSpreadsheet\Cell\DataType;
2025-09-04 07:00:15 +08:00
class Excel extends Controller
{
// public function exportWithCustomStyle()
// {
// $data = [
// ['订单号', '客户名称', '订单金额', '下单日期', '状态'],
// ['ORD20230001', '张三', 1580.00, '2023-05-10', '已完成'],
// ['ORD20230002', '李四', 2399.00, '2023-05-11', '已发货'],
// ['ORD20230003', '王五', 899.00, '2023-05-12', '待付款'],
// ];
// $options = [
// 'sheet_title' => '五月订单', // 工作表名称
// 'header_style' => [
// 'font' => [
// 'bold' => true,
// 'color' => ['argb' => 'FFFFFFFF'] // 白色文字
// ],
// 'fill' => [
// 'fillType' => Fill::FILL_SOLID,
// 'startColor' => ['argb' => 'FF0070C0'] // 蓝色背景
// ],
// 'alignment' => [
// 'horizontal' => Alignment::HORIZONTAL_CENTER,
// ],
// ],
// 'stripe_color1' => 'FFE6F1FF', // 浅蓝色
// 'stripe_color2' => 'FFD6E6FF', // 稍深一点的蓝色
// ];
// $excel = new \app\download\controller\Excel();
// $excel->export($data, '五月订单报表', $options);
// }
/**
* 导出 Excel 文件(带斑马纹效果)
*
* @param array $data 要导出的数据,格式为二维数组,第一行为表头
* @param string $filename 下载的文件名(不带扩展名)
* @param array $options 可选配置项
* - 'sheet_title' => string 工作表标题
* - 'header_style' => array 自定义表头样式
* - 'content_style' => array 自定义内容样式
* - 'zebra_stripe' => bool 是否启用斑马纹效果默认true
* - 'stripe_color1' => string 斑马纹第一种颜色(默认白色)
* - 'stripe_color2' => string 斑马纹第二种颜色(默认浅灰色)
* - 'auto_width' => bool 是否自动调整列宽
* @return void
*/
public function export(array $data, string $filename = 'export', array $options = [])
{
// 验证数据
if (empty($data) || !is_array($data) || !is_array($data[0])) {
throw new \InvalidArgumentException('导出数据格式不正确,应为二维数组且第一行为表头');
}
// 默认配置
$defaultOptions = [
'sheet_title' => 'Sheet1',
'header_style' => [
'font' => ['bold' => true],
'fill' => [
'fillType' => Fill::FILL_SOLID,
'startColor' => ['argb' => Color::COLOR_YELLOW],
],
'alignment' => ['horizontal' => Alignment::HORIZONTAL_CENTER],
'borders' => [
'outline' => ['borderStyle' => Border::BORDER_THIN],
'inside' => ['borderStyle' => Border::BORDER_THIN]
],
],
'content_style' => [
'alignment' => ['horizontal' => Alignment::HORIZONTAL_CENTER],
'borders' => [
'outline' => ['borderStyle' => Border::BORDER_THIN],
'inside' => ['borderStyle' => Border::BORDER_THIN]
],
],
'zebra_stripe' => true, // 默认启用斑马纹
'stripe_color1' => 'FFFFFFFF', // 白色
'stripe_color2' => 'FFEEEEEE', // 浅灰色
'auto_width' => true,
];
// 合并用户配置和默认配置
$options = array_merge($defaultOptions, $options);
// 创建 Spreadsheet 对象
$spreadsheet = new Spreadsheet();
$sheet = $spreadsheet->getActiveSheet();
$sheet->setTitle($options['sheet_title']);
// 获取列数和行数
$columnCount = count($data[0]);
$rowCount = count($data);
// // 写入数据
// foreach ($data as $rowIndex => $rowData) {
// for ($colIndex = 0; $colIndex < $columnCount; $colIndex++) {
// $sheet->setCellValueByColumnAndRow($colIndex + 1, $rowIndex + 1, $rowData[$colIndex]);
// }
// }
// 修改后的代码(强制文本格式)
2025-09-04 07:24:06 +08:00
// use PhpOffice\PhpSpreadsheet\Cell\DataType; // 确保顶部已引入
2025-09-04 07:00:15 +08:00
foreach ($data as $rowIndex => $rowData) {
for ($colIndex = 0; $colIndex < $columnCount; $colIndex++) {
$cellValue = $rowData[$colIndex];
// 强制设置为文本格式
$sheet->setCellValueExplicitByColumnAndRow(
$colIndex + 1,
$rowIndex + 1,
(string)$cellValue,
DataType::TYPE_STRING
);
2025-09-04 07:00:15 +08:00
}
}
2025-09-04 07:00:15 +08:00
// 设置表头样式
$headerRange = 'A1:' . $this->getExcelColumnName($columnCount) . '1';
$sheet->getStyle($headerRange)->applyFromArray($options['header_style']);
// 设置内容样式
$contentRange = 'A2:' . $this->getExcelColumnName($columnCount) . $rowCount;
$sheet->getStyle($contentRange)->applyFromArray($options['content_style']);
// =============================================
// 重点:斑马纹效果实现
// =============================================
if ($options['zebra_stripe']) {
$this->applyZebraStripe(
$sheet,
$columnCount,
$rowCount,
$options['stripe_color1'],
$options['stripe_color2']
);
}
// 自动调整列宽
if ($options['auto_width']) {
for ($colIndex = 1; $colIndex <= $columnCount; $colIndex++) {
$sheet->getColumnDimensionByColumn($colIndex)->setAutoSize(true);
}
}
// 设置响应头以触发文件下载
header('Content-Type: application/vnd.openxmlformats-officedocument.spreadsheetml.sheet');
header('Content-Disposition: attachment;filename="' . $filename . '.xlsx"');
header('Cache-Control: max-age=0');
// 保存并输出 Excel 文件
$writer = new Xlsx($spreadsheet);
$writer->save('php://output');
exit;
}
/**
* 应用斑马纹效果(核心实现)
*
* @param \PhpOffice\PhpSpreadsheet\Worksheet\Worksheet $sheet
* @param int $columnCount 总列数
* @param int $totalRows 总行数(包括表头)
* @param string $color1 第一种颜色
* @param string $color2 第二种颜色
*/
protected function applyZebraStripe($sheet, $columnCount, $totalRows, $color1, $color2)
{
// 从第二行开始应用斑马纹(跳过表头)
for ($rowIndex = 2; $rowIndex <= $totalRows; $rowIndex++) {
// 计算当前行应该使用哪种颜色
$color = ($rowIndex % 2 == 0) ? $color1 : $color2;
// 设置行样式
$rowStyle = [
'fill' => [
'fillType' => Fill::FILL_SOLID,
'startColor' => ['argb' => $color],
],
];
// 应用样式到整行
$range = 'A' . $rowIndex . ':' . $this->getExcelColumnName($columnCount) . $rowIndex;
$sheet->getStyle($range)->applyFromArray($rowStyle);
}
}
/**
* 获取 Excel 列名
*
* @param int $index 列索引从1开始
* @return string Excel 列名
*/
protected function getExcelColumnName($index)
{
$columnName = '';
while ($index > 0) {
$remainder = ($index - 1) % 26;
$columnName = chr(65 + $remainder) . $columnName;
$index = intval(($index - 1) / 26);
}
return $columnName;
}
}