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样式
| No | Employee Name | Date | Detail |
|---|---|---|---|
| 1 | aaaa | 03-01-2023 | Present |
| 2 | bbbb | 03-01-2023 | leave |
| 3 | cccc | 03-01-2023 | late |
| 4 | aaaa | 04-01-2023 | Present |
| 5 | bbbb | 04-01-2023 | Present |
| 6 | cccc | 04-01-2023 | Present |
期望导出Excel样式
| No | Employee Name | 03-01-2023 | 04-01-2023 | next column date range |
|---|---|---|---|---|
| 1 | aaaa | Present | Present | next |
| 2 | bbbb | leave | Present | next |
| 3 | cccc | late | Present | next |
实现方案
步骤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++; }
额外优化建议
- 日期格式统一:如果数据库日期格式和期望显示格式不一致,可通过
date()转换:
$formattedDate = date('d-m-Y', strtotime($row->attn_date));
- 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
相关产品推荐
相关产品推荐

