This commit is contained in:
2025-04-18 01:20:11 +08:00
commit 03e2d4f092
15 changed files with 4824 additions and 0 deletions

642
generate_report.php Normal file
View File

@@ -0,0 +1,642 @@
<?php
/**
* 定期报告生成脚本
*
* 此脚本生成任务报告并保存到服务器
* 可以通过群晖的计划任务定期执行
*/
// 设置错误报告
ini_set('display_errors', 1);
error_reporting(E_ALL);
// 启用网页输出模式
header('Content-Type: text/html; charset=utf-8');
// 配置信息
$config = [
// 数据库配置
'db_host' => '192.168.2.4',
'db_port' => 3307,
'db_name' => 'task_reporter',
'db_user' => 'task_reporter',
'db_pass' => 'Pass12349ers!',
// 报告生成选项
'author' => 'CGNICO Task Reporter', // 报告作者
// 报告配置
'report_days' => 7, // 报告包含的天数例如7表示过去一周
'report_title' => 'CGNICO工具使用报告', // 报告标题
];
// 根据报告天数设置标题
if (isset($_GET['days'])) {
$config['report_days'] = intval($_GET['days']);
// 根据天数调整报告标题
if ($config['report_days'] == 7) {
$config['report_title'] = 'CGNICO工具使用周报';
} elseif ($config['report_days'] == 30) {
$config['report_title'] = 'CGNICO工具使用月报';
} elseif ($config['report_days'] == 90) {
$config['report_title'] = 'CGNICO工具使用季报';
} elseif ($config['report_days'] == 365) {
$config['report_title'] = 'CGNICO工具使用年报';
}
}
// 创建数据库连接
try {
$pdo = new PDO(
"mysql:host={$config['db_host']};port={$config['db_port']};dbname={$config['db_name']}",
$config['db_user'],
$config['db_pass']
);
$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
$pdo->exec("SET NAMES utf8");
} catch (PDOException $e) {
die("数据库连接失败: " . $e->getMessage());
}
// 生成报告
function generate_report($pdo, $days) {
$report = [];
// 获取日期范围
$end_date = date('Y-m-d');
$start_date = date('Y-m-d', strtotime("-{$days} days"));
// 1. 总体统计
$stmt = $pdo->prepare("
SELECT
COUNT(*) as total_tasks,
SUM(time_saved) as total_time_saved,
COUNT(DISTINCT username) as total_users,
COUNT(DISTINCT tool_name) as total_tools
FROM task
WHERE timestamp BETWEEN :start_date AND :end_date
AND tool_name NOT LIKE '%(Debug)%'
");
$stmt->bindParam(':start_date', $start_date);
$stmt->bindParam(':end_date', $end_date);
$stmt->execute();
$report['summary'] = $stmt->fetch(PDO::FETCH_ASSOC);
// 2. 工具使用统计
$stmt = $pdo->prepare("
SELECT
tool_name,
COUNT(*) as usage_count,
SUM(time_saved) as time_saved
FROM task
WHERE timestamp BETWEEN :start_date AND :end_date
AND tool_name NOT LIKE '%(Debug)%'
GROUP BY tool_name
ORDER BY usage_count DESC
LIMIT 10
");
$stmt->bindParam(':start_date', $start_date);
$stmt->bindParam(':end_date', $end_date);
$stmt->execute();
$report['tools'] = $stmt->fetchAll(PDO::FETCH_ASSOC);
// 3. 用户使用统计
$stmt = $pdo->prepare("
SELECT
username,
COUNT(*) as usage_count,
SUM(time_saved) as time_saved
FROM task
WHERE timestamp BETWEEN :start_date AND :end_date
AND tool_name NOT LIKE '%(Debug)%'
GROUP BY username
ORDER BY usage_count DESC
LIMIT 10
");
$stmt->bindParam(':start_date', $start_date);
$stmt->bindParam(':end_date', $end_date);
$stmt->execute();
$report['users'] = $stmt->fetchAll(PDO::FETCH_ASSOC);
// 4. 每日使用趋势
$stmt = $pdo->prepare("
SELECT
DATE(timestamp) as date,
COUNT(*) as usage_count,
SUM(time_saved) as time_saved
FROM task
WHERE timestamp BETWEEN :start_date AND :end_date
AND tool_name NOT LIKE '%(Debug)%'
GROUP BY DATE(timestamp)
ORDER BY date
");
$stmt->bindParam(':start_date', $start_date);
$stmt->bindParam(':end_date', $end_date);
$stmt->execute();
$report['daily'] = $stmt->fetchAll(PDO::FETCH_ASSOC);
return [
'report' => $report,
'start_date' => $start_date,
'end_date' => $end_date
];
}
// 生成HTML报告
function generate_html_report($report_data) {
$report = $report_data['report'];
$start_date = $report_data['start_date'];
$end_date = $report_data['end_date'];
$html = '
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>CGNICO工具使用报告</title>
<style>
body {
font-family: Arial, sans-serif;
line-height: 1.6;
color: #333;
max-width: 800px;
margin: 0 auto;
padding: 20px;
}
h1, h2, h3 {
color: #0066cc;
}
table {
width: 100%;
border-collapse: collapse;
margin: 20px 0;
}
th, td {
padding: 10px;
border: 1px solid #ddd;
text-align: left;
}
th {
background-color: #f2f2f2;
}
tr:nth-child(even) {
background-color: #f9f9f9;
}
.summary {
background-color: #f0f7ff;
padding: 15px;
border-radius: 5px;
margin-bottom: 20px;
}
.highlight {
color: #0066cc;
font-weight: bold;
}
</style>
</head>
<body>
<h1>CGNICO工具使用报告</h1>
<p>报告时间范围: ' . $start_date . ' 至 ' . $end_date . '</p>
<div class="summary">
<h2>总体统计</h2>
<p>在过去的 ' . round((strtotime($end_date) - strtotime($start_date)) / 86400) . ' 天中:</p>
<ul>
<li>总任务数: <span class="highlight">' . number_format($report['summary']['total_tasks']) . '</span></li>
<li>总节省时间: <span class="highlight">' . number_format($report['summary']['total_time_saved'], 2) . ' 小时</span></li>
<li>活跃用户数: <span class="highlight">' . $report['summary']['total_users'] . '</span></li>
<li>使用的工具数: <span class="highlight">' . $report['summary']['total_tools'] . '</span></li>
</ul>
</div>
<h2>工具使用排名</h2>
<table>
<tr>
<th>排名</th>
<th>工具名称</th>
<th>使用次数</th>
<th>节省时间 (小时)</th>
</tr>';
$rank = 1;
foreach ($report['tools'] as $tool) {
$html .= '
<tr>
<td>' . $rank++ . '</td>
<td>' . htmlspecialchars($tool['tool_name']) . '</td>
<td>' . number_format($tool['usage_count']) . '</td>
<td>' . number_format($tool['time_saved'], 2) . '</td>
</tr>';
}
$html .= '
</table>
<h2>用户使用排名</h2>
<table>
<tr>
<th>排名</th>
<th>用户名</th>
<th>使用次数</th>
<th>节省时间 (小时)</th>
</tr>';
$rank = 1;
foreach ($report['users'] as $user) {
$html .= '
<tr>
<td>' . $rank++ . '</td>
<td>' . htmlspecialchars($user['username']) . '</td>
<td>' . number_format($user['usage_count']) . '</td>
<td>' . number_format($user['time_saved'], 2) . '</td>
</tr>';
}
$html .= '
</table>
<h2>每日使用趋势</h2>
<table>
<tr>
<th>日期</th>
<th>使用次数</th>
<th>节省时间 (小时)</th>
</tr>';
foreach ($report['daily'] as $day) {
$html .= '
<tr>
<td>' . $day['date'] . '</td>
<td>' . number_format($day['usage_count']) . '</td>
<td>' . number_format($day['time_saved'], 2) . '</td>
</tr>';
}
$html .= '
</table>
<div style="margin-top: 30px; color: #666; font-size: 12px; text-align: center;">
<p>此报告由CGNICO Task Reporter自动生成于 ' . date('Y-m-d H:i:s') . '</p>
</div>
</body>
</html>';
return $html;
}
// 记录日志
function log_message($message) {
$log_dir = __DIR__ . '/logs';
if (!is_dir($log_dir)) {
mkdir($log_dir, 0755, true);
}
$log_file = $log_dir . '/report_' . date('Y-m-d') . '.log';
$time = date('Y-m-d H:i:s');
file_put_contents($log_file, "[$time] $message\n", FILE_APPEND);
}
// 主程序
try {
// 创建报告目录(如果不存在)
$report_dir = __DIR__ . '/reports/';
if (!is_dir($report_dir)) {
mkdir($report_dir, 0755, true);
}
// 检查是否需要生成新报告
$generate_new_report = false;
$report_file = $report_dir . 'report_' . date('Y-m-d') . '.html';
if (isset($_GET['generate']) && $_GET['generate'] == '1') {
$generate_new_report = true;
} elseif (!file_exists($report_file)) {
// 如果今天的报告不存在,自动生成
$generate_new_report = true;
}
if ($generate_new_report) {
log_message('===== 开始执行报告生成脚本 =====');
// 生成报告数据
log_message('开始生成报告数据...');
$days = $config['report_days'];
$report_data = generate_report($pdo, $days);
log_message('报告数据生成完成');
// 生成HTML报告
log_message('生成HTML报告...');
$html_report = generate_html_report($report_data);
log_message('HTML报告生成完成');
// 保存报告到文件
file_put_contents($report_file, $html_report);
log_message('报告已保存到: ' . $report_file);
}
// 开始HTML输出
?>
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>CGNICO工具使用报告生成器</title>
<style>
body {
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
margin: 0;
padding: 20px;
background-color: #f5f5f5;
color: #333;
}
.container {
max-width: 1000px;
margin: 0 auto;
background-color: #fff;
padding: 20px;
border-radius: 8px;
box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1);
}
h1 {
color: #ff8c00;
text-align: center;
margin-bottom: 30px;
}
h3 {
color: #555;
margin-top: 0;
}
.success-message {
background-color: #dff0d8;
border: 1px solid #d6e9c6;
color: #3c763d;
border-radius: 4px;
padding: 15px;
margin-bottom: 20px;
}
.action-buttons {
display: flex;
gap: 10px;
margin-bottom: 20px;
}
.btn {
display: inline-block;
padding: 10px 15px;
text-decoration: none;
border-radius: 4px;
font-weight: 500;
cursor: pointer;
border: none;
transition: background-color 0.3s;
}
.btn-primary {
background-color: #337ab7;
color: white;
}
.btn-primary:hover {
background-color: #286090;
}
.btn-success {
background-color: #4CAF50;
color: white;
}
.btn-success:hover {
background-color: #3d8b40;
}
.btn-secondary {
background-color: #6c757d;
color: white;
}
.btn-secondary:hover {
background-color: #5a6268;
}
.panel {
background-color: #f5f5f5;
border: 1px solid #e3e3e3;
border-radius: 4px;
padding: 15px;
margin-bottom: 20px;
}
.form-group {
margin-bottom: 15px;
}
label {
display: inline-block;
margin-bottom: 5px;
font-weight: bold;
}
select {
padding: 8px 12px;
border: 1px solid #ccc;
border-radius: 4px;
width: 100%;
max-width: 300px;
}
table {
width: 100%;
border-collapse: collapse;
margin-top: 10px;
}
th, td {
padding: 10px;
border: 1px solid #ddd;
text-align: left;
}
th {
background-color: #f0f0f0;
font-weight: bold;
}
tr:nth-child(even) {
background-color: #f9f9f9;
}
tr:hover {
background-color: #f1f1f1;
}
.table-actions {
text-align: center;
}
.footer {
text-align: center;
margin-top: 30px;
padding-top: 15px;
border-top: 1px solid #eee;
color: #777;
font-size: 0.9em;
}
</style>
</head>
<body>
<div class="container">
<h1>CGNICO工具使用报告生成器</h1>
<?php if ($generate_new_report): ?>
<div class="success-message">
<p><strong>报告已生成成功!</strong></p>
<p>报告时间范围: 过去<?php echo $config['report_days']; ?>天 (<?php echo date('Y-m-d', strtotime("-{$config['report_days']} days")); ?> 至 <?php echo date('Y-m-d'); ?>)</p>
</div>
<?php endif; ?>
<div class="action-buttons">
<a href="reports/report_<?php echo date('Y-m-d'); ?>.html" target="_blank" class="btn btn-primary">查看最新报告</a>
<a href="reports/report_<?php echo date('Y-m-d'); ?>.html" download class="btn btn-success">下载最新报告</a>
<a href="index.php" class="btn btn-secondary">返回首页</a>
</div>
<div class="panel">
<h3>生成新报告</h3>
<form method="get" action="">
<div class="form-group">
<label for="days">报告时间范围:</label>
<select name="days" id="days">
<option value="7" <?php echo ($config['report_days'] == 7) ? 'selected' : ''; ?>>过去7天 (一周)</option>
<option value="30" <?php echo ($config['report_days'] == 30) ? 'selected' : ''; ?>>过去30天 (一个月)</option>
<option value="90" <?php echo ($config['report_days'] == 90) ? 'selected' : ''; ?>>过去90天 (一季度)</option>
<option value="365" <?php echo ($config['report_days'] == 365) ? 'selected' : ''; ?>>过去365天 (一年)</option>
</select>
</div>
<input type="hidden" name="generate" value="1">
<button type="submit" class="btn btn-primary">生成报告</button>
</form>
</div>
<?php
// 历史报告列表
$reports_dir = __DIR__ . '/reports/';
if (is_dir($reports_dir)) {
$reports = glob($reports_dir . 'report_*.html');
if (!empty($reports)) {
echo "<div class=\"panel\">\n";
echo "<h3>历史报告</h3>\n";
echo "<table>\n";
echo "<tr>\n";
echo "<th>报告日期</th>\n";
echo "<th>报告类型</th>\n";
echo "<th>操作</th>\n";
echo "</tr>\n";
rsort($reports); // 按日期降序排序
foreach (array_slice($reports, 0, 10) as $report) { // 只显示最近10个
$filename = basename($report);
$date = substr($filename, 7, 10); // 从 report_YYYY-MM-DD.html 提取日期
// 尝试确定报告类型
$report_type = "常规报告";
$file_content = file_get_contents($report);
if (strpos($file_content, "工具使用周报") !== false) {
$report_type = "周报";
} elseif (strpos($file_content, "工具使用月报") !== false) {
$report_type = "月报";
} elseif (strpos($file_content, "工具使用季报") !== false) {
$report_type = "季报";
} elseif (strpos($file_content, "工具使用年报") !== false) {
$report_type = "年报";
}
echo "<tr>\n";
echo "<td>{$date}</td>\n";
echo "<td>{$report_type}</td>\n";
echo "<td class=\"table-actions\">\n";
echo "<a href='reports/{$filename}' target='_blank' class='btn btn-primary' style='padding: 5px 10px; margin-right: 5px;'>查看</a>\n";
echo "<a href='reports/{$filename}' download class='btn btn-success' style='padding: 5px 10px;'>下载</a>\n";
echo "</td>\n";
echo "</tr>\n";
}
echo "</table>\n";
echo "</div>\n";
}
}
?>
<div class="footer">
<p>CGNICO Task Report System &copy; <?php echo date('Y'); ?> | 联系方式: <a href="mailto:jeffreytsai1004@gmail.com">jeffreytsai1004@gmail.com</a></p>
</div>
</div>
</body>
</html>
<?php
} catch (Exception $e) {
log_message('错误: ' . $e->getMessage());
?>
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>错误 - CGNICO工具使用报告生成器</title>
<style>
body {
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
margin: 0;
padding: 20px;
background-color: #f5f5f5;
color: #333;
}
.container {
max-width: 800px;
margin: 0 auto;
background-color: #fff;
padding: 20px;
border-radius: 8px;
box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1);
}
h1 {
color: #d9534f;
}
.error-message {
background-color: #f2dede;
border: 1px solid #ebccd1;
color: #a94442;
padding: 15px;
border-radius: 4px;
margin-bottom: 20px;
}
.btn {
display: inline-block;
padding: 10px 15px;
background-color: #6c757d;
color: white;
text-decoration: none;
border-radius: 4px;
}
</style>
</head>
<body>
<div class="container">
<h1>发生错误</h1>
<div class="error-message">
<p><strong>错误:</strong> <?php echo $e->getMessage(); ?></p>
</div>
<a href="index.php" class="btn">返回首页</a>
</div>
</body>
</html>
<?php
}
?>