You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

CodeIgniter3日期范围Excel报表:如何转置日期列展示考勤数据

考勤报表Excel导出格式转置实现方案需求

我已经用CodeIgniter3实现了日期范围考勤数据的Excel导出功能,当前导出的Excel里每行对应一位员工的单日考勤记录。现在需要把报表格式转置:每一行对应一位员工,各列对应日期,单元格内显示该员工当日的考勤详情。以下是现有实现代码、当前报表样式和期望样式,求技术实现方案。


现有视图代码(views.php)

<div class="form-group row">
    <label for="attn_date" class="col-sm-4 col-form-label">From</label>
    <div class="col-sm-8">
        <input type="date" class="form-control" id="attn_from" name="attn_from">
        <?= form_error('attn_from'); ?>
    </div>
</div>
<div class="form-group row">
    <label for="attn_date" class="col-sm-4 col-form-label">To</label>
    <div class="col-sm-8">
        <input type="date" class="form-control" id="attn_to" name="attn_to">
        <?= form_error('attn_to'); ?>
    </div>
</div>
<div class="form-group row">
    <label for="daily_export_file" class="col-sm-4 col-form-label">Export Data</label>
    <div class="col-sm-8">
        <?= form_dropdown('export_file', ['report' => 'Report'], set_value('export_file'), 'class="form-control" id="export_file"'); ?>
        <?= form_error('export_file'); ?>
    </div>
</div>

现有控制器代码(controller.php)

$querydata = $this->db->query("select a.*, b.* from db_attn a
                                    LEFT JOIN tbl_wrkhour b 
                                    ON b.id_wrkhour = a.wrk_hour WHERE attn_date between '". $this->input->post('attn_from')."' 
AND '". $this->input->post('attn_to')."'order by attn_date desc")->result();

$spreadsheet = new PhpOffice\PhpSpreadsheet\Spreadsheet();
$sheet_name = $spreadsheet->getActiveSheet()->setTitle("Attendance Report");
$sheet = $spreadsheet->getActiveSheet();
$highestRow = $sheet->getHighestRow();
$highestColumm = $sheet->getHighestColumn();
$dataattn = $querydata;
$sheet->setCellValue('A5', 'No');
$sheet->setCellValue('B5', 'Employee Name');
$sheet->setCellValue('C5', 'Date');
$sheet->setCellValue('D5', 'Detail');
$no = 1;
$rowx = 6;
foreach ($dataattn as $rowattn) {
    $sheet->setCellValue('A' . $rowx, $no++);
    $sheet->setCellValue('B' . $rowx, $rowattn->emp_name);
    $sheet->setCellValue('C' . $rowx, $rowattn->date);
    $sheet->setCellValue('D' . $rowx, $rowattn->attn_detail);

}

当前导出Excel样式

NoEmployee NameDateDetail
1aaaa03-01-2023Present
2bbbb03-01-2023leave
3cccc03-01-2023late
4aaaa04-01-2023Present
5bbbb04-01-2023Present
6cccc04-01-2023Present

期望导出Excel样式

NoEmployee Name03-01-202304-01-2023next column date range
1aaaaPresentPresentnext
2bbbbleavePresentnext
3cccclatePresentnext

实现方案

步骤1:重构查询数据格式

先把数据库返回的原始数据转换成以员工名称为键、日期为子键、考勤详情为值的二维数组,方便后续填充Excel:

// 优化SQL查询,只取需要的字段,并添加防注入处理
$fromDate = $this->input->post('attn_from');
$toDate = $this->input->post('attn_to');
$querydata = $this->db->query("select a.emp_name, a.attn_date, a.attn_detail from db_attn a
                                    LEFT JOIN tbl_wrkhour b 
                                    ON b.id_wrkhour = a.wrk_hour 
                                    WHERE attn_date BETWEEN ? AND ? 
                                    ORDER BY a.emp_name, a.attn_date", [$fromDate, $toDate])->result();

// 重构数据结构
$employeeAttendance = [];
$allDates = [];
foreach ($querydata as $row) {
    $empName = $row->emp_name;
    $date = $row->attn_date;
    // 收集所有不重复的日期,用于生成表头
    if (!in_array($date, $allDates)) {
        $allDates[] = $date;
    }
    // 按员工+日期存储考勤详情
    $employeeAttendance[$empName][$date] = $row->attn_detail;
}
// 对日期排序,保证表头顺序正确
sort($allDates);

步骤2:生成Excel表头

表头包含序号、员工姓名,以及查询范围内的所有日期:

$spreadsheet = new PhpOffice\PhpSpreadsheet\Spreadsheet();
$sheet = $spreadsheet->getActiveSheet()->setTitle("Attendance Report");

// 表头起始行保持原代码的第5行
$headerRow = 5;
$sheet->setCellValue('A' . $headerRow, 'No');
$sheet->setCellValue('B' . $headerRow, 'Employee Name');

// 填充日期列表头
$currentCol = 'C';
foreach ($allDates as $date) {
    $sheet->setCellValue($currentCol . $headerRow, $date);
    // 列名自增(C→D→E...)
    $currentCol++;
}

步骤3:填充员工考勤数据

遍历重构后的数组,逐行填充员工的考勤记录:

$rowx = 6;
$no = 1;
foreach ($employeeAttendance as $empName => $attendanceByDate) {
    // 填充序号和员工姓名
    $sheet->setCellValue('A' . $rowx, $no++);
    $sheet->setCellValue('B' . $rowx, $empName);
    
    // 填充对应日期的考勤详情,无记录则留空
    $currentCol = 'C';
    foreach ($allDates as $date) {
        $detail = isset($attendanceByDate[$date]) ? $attendanceByDate[$date] : '';
        $sheet->setCellValue($currentCol . $rowx, $detail);
        $currentCol++;
    }
    $rowx++;
}

额外优化建议

  1. 日期格式统一:如果数据库日期格式和期望显示格式不一致,可通过date()转换:
$formattedDate = date('d-m-Y', strtotime($row->attn_date));
  1. Excel样式优化:给表头添加样式、自动调整列宽提升可读性:
// 表头样式:加粗+黄色背景
$headerStyle = [
    'font' => ['bold' => true],
    'fill' => ['fillType' => \PhpOffice\PhpSpreadsheet\Style\Fill::FILL_SOLID, 'startColor' => ['argb' => 'FFFFCC00']]
];
$sheet->getStyle('A' . $headerRow . ':' . ($currentCol-1) . $headerRow)->applyFromArray($headerStyle);

// 自动调整所有列宽
foreach(range('A', $currentCol-1) as $col) {
    $sheet->getColumnDimension($col)->setAutoSize(true);
}

内容的提问来源于stack exchange,提问作者Ady Putra

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.03 03:15:42