PHP 项目周报自动生成

wen PHP项目 3

本文目录导读:

PHP 项目周报自动生成

  1. 项目结构
  2. 核心代码实现
  3. 使用说明
  4. 扩展功能建议

我来帮你创建一个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/

使用流程

  1. 添加任务:通过Web界面添加任务信息
  2. 自动生成:选择周数自动生成周报
  3. 导出格式:支持HTML、Markdown、PDF格式导出
  4. 数据统计:自动计算完成率、工时等统计信息

示例任务数据

[
    {
        "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
    }
]

扩展功能建议

  1. 自动邮件发送:集成邮件服务自动发送周报
  2. 多项目支持:支持多个项目同时管理
  3. 数据库存储:用MySQL替代JSON文件存储
  4. 权限系统:不同角色(成员/管理者)不同权限
  5. 自动汇总:从Git、Jira等系统自动拉取任务状态

这个系统可以根据你的具体需求进行调整,比如添加更多统计维度、自定义模板样式、集成第三方工具等,需要我帮你调整某个具体功能吗?

抱歉,评论功能暂时关闭!