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;
|
|
|
|
|
|
|
|
|
|
|
|
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);
|
|
|
|
|
|
|
2025-09-04 07:19:17 +08:00
|
|
|
|
// // 写入数据
|
|
|
|
|
|
// foreach ($data as $rowIndex => $rowData) {
|
|
|
|
|
|
// for ($colIndex = 0; $colIndex < $columnCount; $colIndex++) {
|
|
|
|
|
|
// $sheet->setCellValueByColumnAndRow($colIndex + 1, $rowIndex + 1, $rowData[$colIndex]);
|
|
|
|
|
|
// }
|
|
|
|
|
|
// }
|
|
|
|
|
|
|
|
|
|
|
|
// 修改后的代码(强制文本格式)
|
|
|
|
|
|
use PhpOffice\PhpSpreadsheet\Cell\DataType; // 确保顶部已引入
|
|
|
|
|
|
|
2025-09-04 07:00:15 +08:00
|
|
|
|
foreach ($data as $rowIndex => $rowData) {
|
|
|
|
|
|
for ($colIndex = 0; $colIndex < $columnCount; $colIndex++) {
|
2025-09-04 07:19:17 +08:00
|
|
|
|
$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:19:17 +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;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|