本文目录导读:

要为PHP项目实现考勤报表的自动生成和统计,通常需要结合数据库查询、PHP脚本处理以及报表导出功能,下面是完整的实现方案,包含核心逻辑和代码示例。
整体流程设计
考勤数据表 → PHP查询统计 → 计算各类指标 → 生成报表(HTML/Excel/PDF)
↓
自动定时任务(cron)
数据库表结构示例
假设有以下表:
考勤记录表 attendance
CREATE TABLE attendance (
id INT PRIMARY KEY AUTO_INCREMENT,
user_id INT NOT NULL,
date DATE NOT NULL,
clock_in DATETIME, -- 上班打卡
clock_out DATETIME, -- 下班打卡
status VARCHAR(20), -- normal / late / early_leave / absent
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
用户表 users(假设已有)
-- user_id, name, department, work_start_time, work_end_time 等
PHP统计逻辑实现
基础统计类
class AttendanceReportGenerator {
private $db;
private $startDate;
private $endDate;
public function __construct($pdo, $startDate, $endDate) {
$this->db = $pdo;
$this->startDate = $startDate;
$this->endDate = $endDate;
}
/**
* 获取所有用户的考勤统计
*/
public function getReport() {
$sql = "SELECT
u.id,
u.name,
u.department,
COUNT(a.id) as total_days,
SUM(CASE WHEN a.status = 'late' THEN 1 ELSE 0 END) as late_days,
SUM(CASE WHEN a.status = 'early_leave' THEN 1 ELSE 0 END) as early_leave_days,
SUM(CASE WHEN a.status = 'absent' THEN 1 ELSE 0 END) as absent_days,
SUM(CASE WHEN a.status = 'normal' THEN 1 ELSE 0 END) as normal_days,
SUM(TIMESTAMPDIFF(HOUR, a.clock_in, a.clock_out)) as total_work_hours
FROM users u
LEFT JOIN attendance a ON u.id = a.user_id
AND a.date BETWEEN :start AND :end
GROUP BY u.id
ORDER BY u.department, u.name";
$stmt = $this->db->prepare($sql);
$stmt->execute([
':start' => $this->startDate,
':end' => $this->endDate
]);
return $stmt->fetchAll(PDO::FETCH_ASSOC);
}
/**
* 计算出勤率
*/
public function calculateAttendanceRate($data) {
if ($data['total_days'] == 0) return 0;
return round(($data['normal_days'] / $data['total_days']) * 100, 2);
}
/**
* 计算平均工时
*/
public function calculateAverageHours($data) {
if ($data['total_days'] == 0) return 0;
return round($data['total_work_hours'] / $data['total_days'], 2);
}
}
生成统计报表(HTML预览 + 导出Excel)
class ReportExporter {
/**
* 导出为Excel(使用 PhpSpreadsheet)
*/
public function exportToExcel($data, $filename = 'attendance_report.xlsx') {
require_once 'vendor/autoload.php';
$spreadsheet = new \PhpOffice\PhpSpreadsheet\Spreadsheet();
$sheet = $spreadsheet->getActiveSheet();
// 表头
$headers = ['姓名', '部门', '出勤天数', '迟到', '早退', '缺勤', '正常', '总工时', '出勤率(%)', '平均工时'];
$sheet->fromArray($headers, NULL, 'A1');
// 数据填充
$row = 2;
foreach ($data as $item) {
$sheet->setCellValue('A' . $row, $item['name']);
$sheet->setCellValue('B' . $row, $item['department']);
$sheet->setCellValue('C' . $row, $item['total_days']);
$sheet->setCellValue('D' . $row, $item['late_days']);
$sheet->setCellValue('E' . $row, $item['early_leave_days']);
$sheet->setCellValue('F' . $row, $item['absent_days']);
$sheet->setCellValue('G' . $row, $item['normal_days']);
$sheet->setCellValue('H' . $row, $item['total_work_hours']);
$sheet->setCellValue('I' . $row, $this->calculateAttendanceRate($item));
$sheet->setCellValue('J' . $row, $this->calculateAverageHours($item));
$row++;
}
// 自动列宽
foreach (range('A', 'J') as $col) {
$sheet->getColumnDimension($col)->setAutoSize(true);
}
$writer = new \PhpOffice\PhpSpreadsheet\Writer\Xlsx($spreadsheet);
header('Content-Type: application/vnd.openxmlformats-officedocument.spreadsheetml.sheet');
header('Content-Disposition: attachment;filename="' . $filename . '"');
header('Cache-Control: max-age=0');
$writer->save('php://output');
exit;
}
/**
* 生成HTML表格预览
*/
public function generateHtmlTable($data) {
$html = '<table class="table table-bordered">';
$html .= '<thead><tr>
<th>姓名</th>
<th>部门</th>
<th>出勤天数</th>
<th>迟到</th>
<th>早退</th>
<th>缺勤</th>
<th>正常</th>
<th>总工时</th>
<th>出勤率</th>
<th>平均工时</th>
</tr></thead><tbody>';
foreach ($data as $item) {
$html .= '<tr>';
$html .= '<td>' . htmlspecialchars($item['name']) . '</td>';
$html .= '<td>' . htmlspecialchars($item['department']) . '</td>';
$html .= '<td>' . $item['total_days'] . '</td>';
$html .= '<td>' . $item['late_days'] . '</td>';
$html .= '<td>' . $item['early_leave_days'] . '</td>';
$html .= '<td>' . $item['absent_days'] . '</td>';
$html .= '<td>' . $item['normal_days'] . '</td>';
$html .= '<td>' . $item['total_work_hours'] . '</td>';
$html .= '<td>' . $this->calculateAttendanceRate($item) . '%</td>';
$html .= '<td>' . $this->calculateAverageHours($item) . 'h</td>';
$html .= '</tr>';
}
$html .= '</tbody></table>';
return $html;
}
}
自动定时生成(cron任务)
创建自动执行脚本 cron_report.php
<?php
// cron_report.php
require_once 'config.php';
require_once 'AttendanceReportGenerator.php';
require_once 'ReportExporter.php';
// 上月1号到上月末(也可以传入特定日期)
$lastMonth = new DateTime('first day of last month');
$startDate = $lastMonth->format('Y-m-d');
$endDate = (new DateTime('last day of last month'))->format('Y-m-d');
// 生成统计
$generator = new AttendanceReportGenerator($pdo, $startDate, $endDate);
$reportData = $generator->getReport();
// 保存为Excel文件到指定目录
$exporter = new ReportExporter();
$filename = 'report_' . date('Y_m') . '.xlsx';
$filepath = __DIR__ . '/reports/' . $filename;
// 写入文件(注意:需要修改exporter支持保存到文件而不是直接输出)
$exporter->saveToFile($reportData, $filepath);
// 记录日志
file_put_contents('report_log.txt', date('Y-m-d H:i:s') . " 生成成功: $filename\n", FILE_APPEND);
设置cron(Linux服务器)
# 每天凌晨1点执行 0 1 * * * /usr/bin/php /path/to/project/cron_report.php
Windows计划任务(使用PHP CLI)
schtasks /create /tn "AttendanceReport" /tr "php.exe C:\project\cron_report.php" /sc daily /st 01:00
完整调用示例(Web页面)
<?php
// report_page.php
require_once 'config.php';
require_once 'AttendanceReportGenerator.php';
require_once 'ReportExporter.php';
$startDate = $_GET['start'] ?? date('Y-m-01');
$endDate = $_GET['end'] ?? date('Y-m-t');
$generator = new AttendanceReportGenerator($pdo, $startDate, $endDate);
$reportData = $generator->getReport();
?>
<!DOCTYPE html>
<html>
<head>考勤报表</title>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css">
</head>
<body>
<div class="container mt-4">
<h2>考勤统计报表(<?= $startDate ?> ~ <?= $endDate ?>)</h2>
<form method="get" class="row mb-4">
<div class="col">
<input type="date" name="start" value="<?= $startDate ?>" class="form-control">
</div>
<div class="col">
<input type="date" name="end" value="<?= $endDate ?>" class="form-control">
</div>
<div class="col">
<button type="submit" class="btn btn-primary">查询</button>
<a href="export.php?start=<?= $startDate ?>&end=<?= $endDate ?>" class="btn btn-success">导出Excel</a>
</div>
</form>
<?php
$exporter = new ReportExporter();
echo $exporter->generateHtmlTable($reportData);
?>
</div>
</body>
</html>
优化建议
| 功能 | 实现方式 |
|---|---|
| 缓存查询结果 | 使用Redis或文件缓存,避免频繁查库 |
| 大数据量处理 | 使用MySQL索引(user_id, date联合索引),分页查询 |
| 图表统计 | 结合Chart.js生成趋势图(月出勤率、迟到次数等) |
| 多维度统计 | 按部门、职级、项目分组统计 |
| 异常标记 | 自动标记异常数据(重复打卡、未打卡等) |
关键技术点总结
- 核心SQL:使用
LEFT JOIN+SUM(CASE WHEN)实现多维度统计 - 时间计算:
TIMESTAMPDIFF计算工时,BETWEEN筛选日期范围 - 报表导出:推荐
PhpSpreadsheet或SimpleXLSXGen - 自动任务:cron定期执行,配合文件锁防止重复运行
- 错误处理:记录生成日志,发送邮件告警
如果需要更复杂的排班统计、加班计算、请假整合等功能,可以在此基础上扩展。