本文目录导读:

使用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+)直接运行,你可以根据实际业务需求逐步扩展功能。
版权声明:足球直播
足球直播
足球直播
足球直播
足球直播
中超直播
中超直播
中超直播
中超直播
中超直播
英超直播
英超直播
英超直播
英超直播
英超直播
德甲直播
德甲直播
德甲直播
德甲直播
德甲直播
西甲直播
西甲直播
西甲直播
西甲直播
西甲直播
意甲直播
意甲直播
意甲直播
意甲直播
意甲直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
篮球直播
篮球直播
篮球直播
篮球直播
篮球直播
足球直播
足球直播
足球直播
足球直播
足球直播
中超直播
中超直播
中超直播
中超直播
中超直播
英超直播
英超直播
英超直播
英超直播
英超直播
德甲直播
德甲直播
德甲直播
德甲直播
德甲直播
西甲直播
西甲直播
西甲直播
西甲直播
西甲直播
意甲直播
意甲直播
意甲直播
意甲直播
意甲直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
篮球直播
篮球直播
篮球直播
篮球直播
篮球直播
足球直播
足球直播
足球直播
足球直播
足球直播
中超直播
中超直播
中超直播
中超直播
中超直播
英超直播
英超直播
英超直播
英超直播
英超直播
德甲直播
德甲直播
德甲直播
德甲直播
德甲直播
西甲直播
西甲直播
西甲直播
西甲直播
西甲直播
意甲直播
意甲直播
意甲直播
意甲直播
意甲直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
篮球直播
篮球直播
篮球直播
篮球直播
篮球直播