本文目录导读:

我来帮你创建一个PHP项目周报自动生成系统,这需要一个完整的解决方案,包括数据模型、生成逻辑和输出功能。
项目结构
project-report/
├── config/
│ └── config.php
├── src/
│ ├── ReportGenerator.php
│ ├── DataCollector.php
│ ├── TemplateManager.php
│ └── ExportManager.php
├── templates/
│ ├── default.html
│ └── compact.html
├── data/
│ └── tasks.json
└── index.php
核心代码实现
配置文件 (config/config.php)
<?php
return [
'project_name' => 'XX项目',
'team_members' => [
'张三' => '后端开发',
'李四' => '前端开发',
'王五' => '测试工程师'
],
'templates' => [
'default' => 'templates/default.html',
'compact' => 'templates/compact.html'
],
'export' => [
'format' => ['markdown', 'html', 'pdf']
]
];
数据收集器 (src/DataCollector.php)
<?php
class DataCollector {
private $dataFile;
private $tasks = [];
public function __construct($dataFile) {
$this->dataFile = $dataFile;
$this->loadExistingData();
}
public function loadExistingData() {
if (file_exists($this->dataFile)) {
$json = file_get_contents($this->dataFile);
$this->tasks = json_decode($json, true) ?? [];
}
}
public function saveTask($task) {
$task['id'] = uniqid();
$task['created_at'] = date('Y-m-d H:i:s');
$task['week'] = date('W');
$task['year'] = date('Y');
$this->tasks[] = $task;
$this->saveToFile();
return $task;
}
public function getTasksByWeek($year, $week) {
$weekTasks = array_filter($this->tasks, function($task) use ($year, $week) {
return $task['year'] == $year && $task['week'] == $week;
});
return $weekTasks;
}
public function saveToFile() {
file_put_contents($this->dataFile, json_encode($this->tasks, JSON_PRETTY_PRINT));
}
public function getTaskStats($tasks) {
return [
'total' => count($tasks),
'completed' => count(array_filter($tasks, fn($t) => $t['status'] == 'completed')),
'in_progress' => count(array_filter($tasks, fn($t) => $t['status'] == 'in_progress')),
'pending' => count(array_filter($tasks, fn($t) => $t['status'] == 'pending')),
'hours' => array_sum(array_column($tasks, 'hours'))
];
}
}
报告生成器 (src/ReportGenerator.php)
<?php
class ReportGenerator {
private $collector;
private $templateManager;
private $config;
public function __construct(DataCollector $collector, TemplateManager $templateManager, $config) {
$this->collector = $collector;
$this->templateManager = $templateManager;
$this->config = $config;
}
public function generate($year, $week, $template = 'default') {
// 获取本周任务
$tasks = $this->collector->getTasksByWeek($year, $week);
// 按状态分组
$groupedTasks = [
'completed' => [],
'in_progress' => [],
'pending' => []
];
foreach ($tasks as $task) {
$groupedTasks[$task['status']][] = $task;
}
// 获取统计数据
$stats = $this->collector->getTaskStats($tasks);
// 准备报告数据
$reportData = [
'project_name' => $this->config['project_name'],
'year' => $year,
'week' => $week,
'date_range' => $this->getDateRange($year, $week),
'stats' => $stats,
'tasks' => $groupedTasks,
'team_members' => $this->config['team_members'],
'summary' => $this->generateSummary($stats),
'highlights' => $this->findHighlights($tasks),
'risks' => $this->findRisks($tasks)
];
return $this->templateManager->render($template, $reportData);
}
private function getDateRange($year, $week) {
$start = new DateTime();
$start->setISODate($year, $week);
$start->setTime(0, 0, 0);
$end = clone $start;
$end->add(new DateInterval('P6D'));
$end->setTime(23, 59, 59);
return [
'start' => $start->format('Y-m-d'),
'end' => $end->format('Y-m-d')
];
}
private function generateSummary($stats) {
if ($stats['total'] === 0) {
return '本周暂无任务记录。';
}
$completionRate = round(($stats['completed'] / $stats['total']) * 100, 2);
return sprintf(
'本周共完成 %d 项任务,%d 项正在进行,%d 项待处理,任务完成率为 %.2f%%,累计工时 %.1f 小时。',
$stats['completed'],
$stats['in_progress'],
$stats['pending'],
$completionRate,
$stats['hours']
);
}
private function findHighlights($tasks) {
$highlights = [];
foreach ($tasks as $task) {
if ($task['priority'] == 'high' && $task['status'] == 'completed') {
$highlights[] = $task;
}
}
return $highlights;
}
private function findRisks($tasks) {
$risks = [];
foreach ($tasks as $task) {
if ($task['status'] == 'pending' && strtotime($task['deadline']) < strtotime('+1 week')) {
$risks[] = $task;
}
}
return $risks;
}
}
模板管理器 (src/TemplateManager.php)
<?php
class TemplateManager {
private $templatePath;
public function __construct($templatePath) {
$this->templatePath = $templatePath;
}
public function render($template, $data) {
$templateFile = $this->templatePath . '/' . $template . '.html';
if (!file_exists($templateFile)) {
throw new Exception("Template not found: $template");
}
$content = file_get_contents($templateFile);
// 提取并替换占位符
foreach ($data as $key => $value) {
if (is_array($value)) {
$content = $this->renderArray($content, $key, $value);
} else {
$content = str_replace('{{' . $key . '}}', $value, $content);
}
}
return $content;
}
private function renderArray($content, $key, $data) {
// 处理任务列表
if ($key == 'tasks') {
$pattern = '/{{'.$key.'}}.*?{{\/'.$key.'}}/s';
preg_match_all($pattern, $content, $matches);
foreach ($matches[0] as $match) {
$rendered = '';
foreach ($data as $status => $tasks) {
foreach ($tasks as $task) {
$taskTemplate = $match;
$taskTemplate = str_replace('{{status}}', $status, $taskTemplate);
$taskTemplate = str_replace('{{title}}', $task['title'], $taskTemplate);
$taskTemplate = str_replace('{{assignee}}', $task['assignee'], $taskTemplate);
$taskTemplate = str_replace('{{hours}}', $task['hours'], $taskTemplate);
$taskTemplate = str_replace('{{priority}}', $task['priority'], $taskTemplate);
$taskTemplate = str_replace('{{deadline}}', $task['deadline'], $taskTemplate);
$taskTemplate = str_replace('{{description}}', $task['description'] ?? '', $taskTemplate);
$rendered .= $taskTemplate;
}
}
$content = str_replace($match, $rendered, $content);
}
}
return $content;
}
}
导出管理器 (src/ExportManager.php)
<?php
class ExportManager {
private $config;
public function __construct($config) {
$this->config = $config;
}
public function export($html, $format = 'html') {
switch ($format) {
case 'html':
return $this->exportHTML($html);
case 'markdown':
return $this->exportMarkdown($html);
case 'pdf':
return $this->exportPDF($html);
default:
throw new Exception("Unsupported format: $format");
}
}
private function exportHTML($content) {
header('Content-Type: text/html; charset=utf-8');
header('Content-Disposition: attachment; filename="weekly-report-' . date('Y-m-d') . '.html"');
echo $content;
}
private function exportMarkdown($html) {
// 简单的HTML转Markdown
$markdown = $html;
$markdown = preg_replace('/<h1[^>]*>/', '# ', $markdown);
$markdown = preg_replace('/<h2[^>]*>/', '## ', $markdown);
$markdown = preg_replace('/<h3[^>]*>/', '### ', $markdown);
$markdown = str_replace(['<li>', '</li>'], ['- ', ''], $markdown);
$markdown = preg_replace('/<[^>]+>/', '', $markdown);
header('Content-Type: text/markdown; charset=utf-8');
header('Content-Disposition: attachment; filename="weekly-report-' . date('Y-m-d') . '.md"');
echo $markdown;
}
private function exportPDF($html) {
// 需要安装wkhtmltopdf或使用其他PDF库
// 这里使用简单的文本导出做示例
header('Content-Type: text/plain; charset=utf-8');
header('Content-Disposition: attachment; filename="weekly-report-' . date('Y-m-d') . '.txt"');
echo strip_tags($html);
}
}
默认模板 (templates/default.html)
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">周报 - {{project_name}} - 第{{week}}周</title>
<style>
body { font-family: Arial, sans-serif; margin: 20px; }
h1 { color: #2c3e50; border-bottom: 2px solid #3498db; padding-bottom: 10px; }
h2 { color: #34495e; margin-top: 20px; }
.summary { background-color: #ecf0f1; padding: 15px; border-radius: 5px; margin: 20px 0; }
.stats { display: flex; justify-content: space-around; margin: 20px 0; }
.stat-item { background: #fff; padding: 10px 20px; border-radius: 5px; box-shadow: 0 2px 5px rgba(0,0,0,0.1); }
.task { border: 1px solid #ddd; padding: 10px; margin: 10px 0; border-radius: 5px; }
.completed { border-left: 4px solid #27ae60; }
.in_progress { border-left: 4px solid #f39c12; }
.pending { border-left: 4px solid #e74c3c; }
.highlights { background-color: #d4efdf; padding: 10px; border-radius: 5px; }
.risks { background-color: #fadbd8; padding: 10px; border-radius: 5px; }
table { border-collapse: collapse; width: 100%; }
th, td { border: 1px solid #ddd; padding: 8px; text-align: left; }
th { background-color: #f2f2f2; }
.date-range { color: #7f8c8d; font-size: 14px; }
</style>
</head>
<body>
<h1>{{project_name}} - 第{{week}}周周报</h1>
<p class="date-range">时间范围:{{date_range.start}} 至 {{date_range.end}}</p>
<div class="summary">
<h2>📊 工作总结</h2>
<p>{{summary}}</p>
</div>
<div class="stats">
<div class="stat-item">总数: {{stats.total}}</div>
<div class="stat-item">✔ 完成: {{stats.completed}}</div>
<div class="stat-item">🔄 进行中: {{stats.in_progress}}</div>
<div class="stat-item">⏳ 待处理: {{stats.pending}}</div>
<div class="stat-item">⏱ 工时: {{stats.hours}}h</div>
</div>
<h2>📝 任务详情</h2>
{{tasks}}
<div class="task {{status}}">
<strong>{{title}}</strong>
<span style="color:#7f8c8d;"> - {{assignee}}</span>
<div>优先级: {{priority}} | 预计工时: {{hours}}h | 截止日期: {{deadline}}</div>
<div style="margin-top:5px;">{{description}}</div>
</div>
{{/tasks}}
<h2>🌟 亮点成果</h2>
<div class="highlights">
{{highlights}}
<div>- {{title}} ({{assignee}})</div>
{{/highlights}}
</div>
<h2>⚠️ 风险预警</h2>
<div class="risks">
{{risks}}
<div>- {{title}} - 截止: {{deadline}}</div>
{{/risks}}
</div>
<h2>👥 团队成员</h2>
<table>
<tr><th>姓名</th><th>角色</th></tr>
{{team_members}}
<tr><td>{{name}}</td><td>{{role}}</td></tr>
{{/team_members}}
</table>
</body>
</html>
主入口文件 (index.php)
<?php
require_once 'src/DataCollector.php';
require_once 'src/ReportGenerator.php';
require_once 'src/TemplateManager.php';
require_once 'src/ExportManager.php';
$config = require 'config/config.php';
// 初始化
$collector = new DataCollector('data/tasks.json');
$templateManager = new TemplateManager('templates');
$generator = new ReportGenerator($collector, $templateManager, $config);
$exporter = new ExportManager($config);
// 处理任务添加
if ($_SERVER['REQUEST_METHOD'] == 'POST' && isset($_POST['add_task'])) {
$task = [
'title' => $_POST['title'],
'description' => $_POST['description'],
'assignee' => $_POST['assignee'],
'status' => $_POST['status'],
'priority' => $_POST['priority'],
'hours' => (float)$_POST['hours'],
'deadline' => $_POST['deadline']
];
$collector->saveTask($task);
}
// 获取页码参数
$year = isset($_GET['year']) ? (int)$_GET['year'] : date('Y');
$week = isset($_GET['week']) ? (int)$_GET['week'] : date('W');
// 生成报告
$report = $generator->generate($year, $week);
$exportFormat = isset($_GET['export']) ? $_GET['export'] : 'html';
if (isset($_GET['export'])) {
$exporter->export($report, $exportFormat);
exit;
}
?>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">项目周报系统</title>
<style>
body { font-family: Arial, sans-serif; margin: 20px; }
.nav { display: flex; gap: 10px; margin-bottom: 20px; }
.btn { padding: 8px 16px; border: none; border-radius: 4px; cursor: pointer; }
.btn-primary { background: #3498db; color: white; }
.btn-success { background: #27ae60; color: white; }
.btn-warning { background: #f39c12; color: white; }
.btn-danger { background: #e74c3c; color: white; }
.task-form { border: 1px solid #ddd; padding: 20px; border-radius: 5px; margin: 20px 0; }
input, textarea, select { width: 100%; padding: 8px; margin: 5px 0; }
label { font-weight: bold; }
</style>
</head>
<body>
<h1>项目周报自动生成系统</h1>
<div class="nav">
<form method="get" style="display:inline;">
<input type="number" name="year" value="<?php echo $year; ?>" min="2024" max="2030">
第<input type="number" name="week" value="<?php echo $week; ?>" min="1" max="53">周
<button type="submit" class="btn btn-primary">生成报告</button>
</form>
<a href="?year=<?php echo $year; ?>&week=<?php echo $week; ?>&export=html" class="btn btn-success btn-primary">导出HTML</a>
<a href="?year=<?php echo $year; ?>&week=<?php echo $week; ?>&export=markdown" class="btn btn-primary">导出Markdown</a>
<a href="?year=<?php echo $year; ?>&week=<?php echo $week; ?>&export=pdf" class="btn btn-warning">导出PDF</a>
</div>
<div class="task-form">
<h2>添加新任务</h2>
<form method="post">
<label>任务标题:</label>
<input type="text" name="title" required>
<label>任务描述:</label>
<textarea name="description" rows="3"></textarea>
<div style="display:flex; gap:10px;">
<div style="flex:1;">
<label>负责人:</label>
<select name="assignee">
<?php foreach ($config['team_members'] as $member => $role): ?>
<option value="<?php echo $member; ?>"><?php echo $member; ?></option>
<?php endforeach; ?>
</select>
</div>
<div style="flex:1;">
<label>状态:</label>
<select name="status">
<option value="pending">待处理</option>
<option value="in_progress">进行中</option>
<option value="completed">已完成</option>
</select>
</div>
</div>
<div style="display:flex; gap:10px;">
<div style="flex:1;">
<label>优先级:</label>
<select name="priority">
<option value="low">低</option>
<option value="medium">中</option>
<option value="high">高</option>
</select>
</div>
<div style="flex:1;">
<label>预计工时:</label>
<input type="number" name="hours" step="0.5" value="4">
</div>
<div style="flex:1;">
<label>截止日期:</label>
<input type="date" name="deadline" required>
</div>
</div>
<button type="submit" name="add_task" class="btn btn-primary" style="margin-top:10px;">添加任务</button>
</form>
</div>
<div class="report-content">
<?php echo $report; ?>
</div>
</body>
</html>
使用说明
安装部署
# 创建项目目录结构
mkdir -p project-report/{config,src,templates,data}
# 将上述代码保存到对应文件中
cd project-report
# 确保有写入权限
chmod 755 data/
使用流程
- 添加任务:通过Web界面添加任务信息
- 自动生成:选择周数自动生成周报
- 导出格式:支持HTML、Markdown、PDF格式导出
- 数据统计:自动计算完成率、工时等统计信息
示例任务数据
[
{
"id": "6651e9a5c0f64",
"title": "用户登录功能开发",
"description": "实现OAuth2.0认证流程",
"assignee": "张三",
"status": "completed",
"priority": "high",
"hours": 16,
"deadline": "2024-05-25",
"created_at": "2024-05-20 10:30:00",
"week": 21,
"year": 2024
}
]
扩展功能建议
- 自动邮件发送:集成邮件服务自动发送周报
- 多项目支持:支持多个项目同时管理
- 数据库存储:用MySQL替代JSON文件存储
- 权限系统:不同角色(成员/管理者)不同权限
- 自动汇总:从Git、Jira等系统自动拉取任务状态
这个系统可以根据你的具体需求进行调整,比如添加更多统计维度、自定义模板样式、集成第三方工具等,需要我帮你调整某个具体功能吗?
版权声明:NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播