本文目录导读:

使用PHP搭建工时统计系统,通常包含前端展示、后端逻辑、数据库存储三个部分,下面提供一个从0到1的完整基础搭建方案,包含表结构、核心功能代码和关键设计思路。
系统功能设计
一个最小可用系统需要包含:
- 项目/任务管理:创建项目或具体任务。
- 打卡/计时:开始工作、结束工作、手动录入工时。
- 数据统计:按项目、人员、日期范围汇总工时。
数据库设计(MySQL)
创建一个简单的工时表 work_logs 和一个项目表 projects。
CREATE TABLE `projects` (
`id` INT(11) NOT NULL AUTO_INCREMENT,
`name` VARCHAR(100) NOT NULL COMMENT '项目名称',
`created_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
CREATE TABLE `work_logs` (
`id` INT(11) NOT NULL AUTO_INCREMENT,
`user_id` INT(11) NOT NULL COMMENT '用户ID(假设已有用户表)',
`project_id` INT(11) NOT NULL COMMENT '关联项目',
`description` TEXT COMMENT '工作描述',
`start_time` DATETIME NOT NULL COMMENT '开始时间',
`end_time` DATETIME DEFAULT NULL COMMENT '结束时间',
`duration_minutes` INT(11) DEFAULT 0 COMMENT '持续分钟数(可由程序计算后写入,提高统计效率)',
`created_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (`id`),
INDEX `idx_user_date` (`user_id`, `start_time`),
INDEX `idx_project` (`project_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
核心PHP实现
项目列表与创建(projects.php)
<?php
// 简单连接数据库(生产环境请使用PDO或mysqli预处理)
$db = new mysqli('localhost', 'root', 'password', 'timesheet');
// 创建项目
if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['project_name'])) {
$stmt = $db->prepare("INSERT INTO projects (name) VALUES (?)");
$stmt->bind_param('s', $_POST['project_name']);
$stmt->execute();
}
// 获取所有项目
$projects = $db->query("SELECT id, name FROM projects ORDER BY created_at DESC");
// 假设用户ID为1(实际应从session获取)
$user_id = 1;
?>
<!DOCTYPE html>
<html>
<head> <title>工时统计</title> </head>
<body>
<h2>项目与工时记录</h2>
<form method="POST">
<input type="text" name="project_name" placeholder="新项目名称" required>
<button type="submit">创建项目</button>
</form>
<hr>
<h3>记录工时</h3>
<form action="log_time.php" method="POST">
<select name="project_id" required>
<option value="">选择项目</option>
<?php while($row = $projects->fetch_assoc()): ?>
<option value="<?php echo $row['id']; ?>"><?php echo htmlspecialchars($row['name']); ?></option>
<?php endwhile; ?>
</select>
<input type="text" name="description" placeholder="工作内容描述" required>
<label>开始:<input type="datetime-local" name="start_time" required></label>
<label>结束:<input type="datetime-local" name="end_time" required></label>
<button type="submit">提交</button>
</form>
</body>
</html>
工时记录处理(log_time.php)
<?php
require 'db.php'; // 假设有数据库连接文件
$user_id = 1; // 从session获取
$project_id = $_POST['project_id'] ?? 0;
$description = $_POST['description'] ?? '';
$start_time = $_POST['start_time'] ?? '';
$end_time = $_POST['end_time'] ?? '';
if ($project_id && $start_time && $end_time) {
// 计算持续时间(分钟)
$start = new DateTime($start_time);
$end = new DateTime($end_time);
$duration = $start->diff($end);
$minutes = ($duration->days * 24 * 60) + ($duration->h * 60) + $duration->i;
if ($minutes <= 0) {
die("结束时间必须晚于开始时间");
}
$stmt = $db->prepare("INSERT INTO work_logs (user_id, project_id, description, start_time, end_time, duration_minutes) VALUES (?, ?, ?, ?, ?, ?)");
$stmt->bind_param('iisssi', $user_id, $project_id, $description, $start_time, $end_time, $minutes);
$stmt->execute();
header("Location: projects.php?success=1");
exit;
} else {
echo "请填写完整信息";
}
?>
工时统计报表(statistics.php)
<?php
require 'db.php';
$user_id = 1; // 从session获取
$start_date = $_GET['start_date'] ?? date('Y-m-d', strtotime('-7 days'));
$end_date = $_GET['end_date'] ?? date('Y-m-d');
// 按项目汇总工时
$sql = "SELECT p.name AS project_name, SUM(w.duration_minutes) AS total_minutes
FROM work_logs w
JOIN projects p ON w.project_id = p.id
WHERE w.user_id = ? AND DATE(w.start_time) BETWEEN ? AND ?
GROUP BY w.project_id
ORDER BY total_minutes DESC";
$stmt = $db->prepare($sql);
$stmt->bind_param('iss', $user_id, $start_date, $end_date);
$stmt->execute();
$result = $stmt->get_result();
$total_minutes_all = 0;
?>
<!DOCTYPE html>
<html>
<head>工时统计报表</title>
<style>
body { font-family: Arial; margin: 20px; }
.summary-card { background: #f5f5f5; padding: 10px; margin: 10px 0; border-radius: 5px; }
table { border-collapse: collapse; width: 100%; }
th, td { border: 1px solid #ddd; padding: 8px; text-align: left; }
th { background-color: #4CAF50; color: white; }
</style>
</head>
<body>
<h2>工时统计报表</h2>
<form method="GET">
开始日期:<input type="date" name="start_date" value="<?php echo $start_date; ?>">
结束日期:<input type="date" name="end_date" value="<?php echo $end_date; ?>">
<button type="submit">查询</button>
</form>
<h3>项目汇总</h3>
<table>
<tr><th>项目</th><th>总工时(小时)</th><th>占比</th></tr>
<?php while ($row = $result->fetch_assoc()):
$hours = round($row['total_minutes'] / 60, 1);
$total_minutes_all += $row['total_minutes'];
?>
<tr>
<td><?php echo htmlspecialchars($row['project_name']); ?></td>
<td><?php echo $hours; ?></td>
<td><?php echo $total_minutes_all > 0 ? round($row['total_minutes']/$total_minutes_all*100, 1) : 0; ?>%</td>
</tr>
<?php endwhile; ?>
</table>
<div class="summary-card">
<strong>总工时:</strong><?php echo round($total_minutes_all / 60, 1); ?> 小时
</div>
<h3>每日明细</h3>
<?php
// 按天汇总
$daily_sql = "SELECT DATE(start_time) AS work_date, SUM(duration_minutes) AS daily_minutes
FROM work_logs
WHERE user_id = ? AND DATE(start_time) BETWEEN ? AND ?
GROUP BY work_date ORDER BY work_date";
$daily_stmt = $db->prepare($daily_sql);
$daily_stmt->bind_param('iss', $user_id, $start_date, $end_date);
$daily_stmt->execute();
$daily_result = $daily_stmt->get_result();
?>
<table>
<tr><th>日期</th><th>工时(小时)</th></tr>
<?php while ($daily = $daily_result->fetch_assoc()): ?>
<tr>
<td><?php echo $daily['work_date']; ?></td>
<td><?php echo round($daily['daily_minutes'] / 60, 1); ?></td>
</tr>
<?php endwhile; ?>
</table>
</body>
</html>
关键优化与建议
- 使用框架:生产环境建议使用 Laravel、ThinkPHP 或 Symfony,它们提供了完整的 ORM、路由验证和模板引擎。
- 计时器功能:可以增加一个“开始计时”按钮,点击后在前端记录当前时间,提交时同时包含开始时间和结束时间,或使用 AJAX 定期发送心跳包。
- 权限与多用户:引入用户表,区分管理员和普通员工,管理员可以查看所有人的工时。
- 数据验证:服务端必须验证时间逻辑(结束时间>=开始时间),防止负数工时。
- 性能优化:
- 使用索引(已建
user_id, start_time联合索引)。 - 如果数据量大,将
duration_minutes在写入时计算好,避免每次查询都计算TIMESTAMPDIFF。
- 使用索引(已建
- 可视化:可以配合 Chart.js 在前端绘制柱状图或饼图,让统计更直观。
扩展功能思路
- 审批流程:增加工时记录状态(草稿、提交、已审核)。
- Excel导出:使用 PhpSpreadsheet 库导出统计数据。
- API接口:将统计逻辑封装为 REST API,方便移动端或第三方集成。
这个基础系统可以用一台普通的 Web 服务器(如 Apache/Nginx + PHP 7.4+ + MySQL 5.7+)直接运行,你可以根据实际业务需求逐步扩展功能。